ROS通信学习
- 基础知识学习
- 字段ROS通信小例子
- 一、创建一个工作区
- 二、创建一个ROS工程包
- 三、创建通信的发、收节点
- 四、测试程序的正确性
- 图像ROS通信小例子
- 视频ROS通信小例子
- 多机ROS通信
基础知识学习
🌟 话题与服务的区别
- | 话题 | 服务 |
---|
同步性 | 异步 | 同步 |
通信模型 | 发布/订阅 | 服务端/客户端 |
底层协议 | ROSTCP/ROSUDP | ROSTCP/ROSUDP |
反馈机制 | 无 | 有 |
缓冲区 | 有 | 无 |
实时性 | 弱 | 强 |
节点关系 | 多对多 | 一对多 |
适用场景 | 数据传输 | 逻辑处理 |
本文中所有ROS通信小例子都是话题
字段ROS通信小例子
一、创建一个工作区
- 创建名为ros的工作区
mkdir -p ~/ros/src
- 进入创建工作区的src文件夹
cd ~/ros/src
- 生成工作区
catkin_init_workspace
- 此时工作区为空,可编译
//进入工作区
cd ~/ros/
//编译
catkin_make
- 把工作区在bash中注册
//bash注册
source devel/setup.bash
//验证
echo $ROS_PACKAGE_PATH
//如果能看到自己工作区的文件路径就说明工作区创建成功
二、创建一个ROS工程包
- 切换到我们的工作区
cd ~/ros/src
- 使用catkin_create_pkg命令去创建一个叫comm(通信)的包,这个包依靠std_msgs、roscpp、rospy
catkin_create_pkg comm std_msgs rospy roscpp
- 在工作区编译这个工程包
//进入工作区
cd ~/ros/
//编译
catkin_make
三、创建通信的发、收节点
- 把目录切换到我们的comm工程包中
cd ~/ros/src/comm
- 进入src子目录
cd src
- 在src目录中创建一个talker.cpp文件,写一个发布(Publisher)节点
touch talker.cpp
打开talker.cpp,并且将里面的内容替换为如下:
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
int main(int argc, char **argv)
{
ros::init(argc, argv, "talker");
ros::NodeHandle n;
ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
ros::Rate loop_rate(10);
int count = 0;
while (ros::ok())
{
std_msgs::String msg;
std::stringstream ss;
ss << "hello world " << count;
msg.data = ss.str();
ROS_INFO("%s", msg.data.c_str());
chatter_pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
++count;
}
return 0;
}
- 在src目录中创建一个listener.cpp文件,写一个订阅(Subscriber)节点
touch listener.cpp
#include "ros/ros.h"
#include "std_msgs/String.h"
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("I heard: [%s]", msg->data.c_str());
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "listener");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
ros::spin();
return 0;
}
- 编辑Cmakelist.txt文件(注意:是comm项目包下的CMakelist文件)
include_directories(include ${catkin_INCLUDE_DIRS})
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker comm_generate_messages_cpp)
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener comm_generate_messages_cpp)
注意:以上相邻代码之间不要有间隔哦,就是不要空一行,一定要相邻挨着,不然后面编译的时候会报错
6. 将目录切换到工作区目录,并执行catkin_make运行命令
//进入工作区
cd ~/ros/
//编译
catkin_make
四、测试程序的正确性
- 新开一个终端,启动ROS核心程序roscore
roscore
- 在开始运行我们的程序之前,在原来的终端、把程序注册
//切换为工作区
cd ~/ros
//程序注册
source ./devel/setup.bash
- 运行talker节点
rosrun comm talker
- 新建一个终端,运行listener节点
//回到工作区
cd ~/ros
//程序注册
source ./devel/setup.bash
//运行listener节点
rosrun comm listener
看到两个终端的发布和订阅就证明成功啦!
图像ROS通信小例子
创建工作区步骤与字段通信相同
- image_publisher.cpp
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>
int main(int argc, char** argv)
{
ros::init(argc, argv, "image_publisher");
ros::NodeHandle nh;
image_transport::ImageTransport it(nh);
image_transport::Publisher pub = it.advertise("camera/image", 1);
cv::Mat image = cv::imread(argv[1], CV_LOAD_IMAGE_COLOR);
sensor_msgs::ImagePtr msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", image).toImageMsg();
ros::Rate loop_rate(5);
while (nh.ok()) {
pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
}
}
- image_subscrber.cpp
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>
void imageCallback(const sensor_msgs::ImageConstPtr& msg)
{
try
{
cv::imshow("view", cv_bridge::toCvShare(msg, "bgr8")->image);
}
catch (cv_bridge::Exception& e)
{
ROS_ERROR("Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str());
}
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "image_listener");
ros::NodeHandle nh;
cv::namedWindow("view");
cv::startWindowThread();
image_transport::ImageTransport it(nh);
image_transport::Subscriber sub = it.subscribe("camera/image", 1, imageCallback);
ros::spin();
cv::destroyWindow("view");
}
- package.xml
<?xml version="1.0"?>
<package format="2">
<name>ros_cv_image</name>
<version>0.0.0</version>
<description>The ros_cv_image package</description>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>cv_bridge</build_depend>
<build_depend>image_transport</build_depend>
<build_depend>roscpp</build_depend>
<build_depend>rospy</build_depend>
<build_depend>std_msgs</build_depend>
<build_depend>opencv2</build_depend>
<build_export_depend>cv_bridge</build_export_depend>
<build_export_depend>image_transport</build_export_depend>
<build_export_depend>roscpp</build_export_depend>
<build_export_depend>rospy</build_export_depend>
<build_export_depend>std_msgs</build_export_depend>
<build_export_depend>opencv2</build_export_depend>
<exec_depend>cv_bridge</exec_depend>
<exec_depend>image_transport</exec_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>rospy</exec_depend>
<exec_depend>std_msgs</exec_depend>
<exec_depend>opencv2</exec_depend>
<export>
</export>
</package>
- CMakeList.xml
cmake_minimum_required(VERSION 2.8.3)
project(ros_cv_image)
find_package(catkin REQUIRED COMPONENTS
cv_bridge
image_transport
roscpp
rospy
std_msgs
)
#增加的这句
find_package(OpenCV REQUIRED)
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES ros_cv_image
# CATKIN_DEPENDS cv_bridge image_transport roscpp rospy std_msgs
# DEPENDS system_lib
)
#添加 ${OpenCV_INCLUDE_DIRS}
include_directories(
./include
${catkin_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
)
## Add cmake target dependencies of the library
## as an example, code may need to be generated before libraries
## either from message generation or dynamic reconfigure
# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Add folders to be run by python nosetests
# catkin_add_nosetests(test)
add_executable(image_publisher src/image_publisher)
target_link_libraries(image_publisher ${catkin_LIBRARIES} ${OpenCV_LIBRARIES})
add_executable(image_subscriber src/image_subscriber)
target_link_libraries(image_subscriber ${catkin_LIBRARIES} ${OpenCV_LIBRARIES})
⚠️ 运行publisher过程中,需要添加参数:rosrun comm publisher xxx.jpg
视频ROS通信小例子
创建工作区步骤与字段通信相同
- imagepub.cpp
#include<ros/ros.h>
#include<cv_bridge/cv_bridge.h>
#include<sensor_msgs/image_encodings.h>
#include<image_transport/image_transport.h>
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<stdio.h>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
ros::init(argc, argv, "image_publisher");
ros::NodeHandle n;
ros::Time time = ros::Time::now();
ros::Rate loop_rate(5);
image_transport::ImageTransport it(n);
image_transport::Publisher pub = it.advertise("video_image", 1);
sensor_msgs::ImagePtr msg;
cv::VideoCapture video;
video.open("/home/vlt/Pictures/1.mp4");
if( !video.isOpened() )
{
ROS_INFO("Read Video failed!\n");
return 0;
}
Mat frame;
int count = 0;
while(1)
{
video >> frame;
if( frame.empty() )
break;
count++;
msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", frame).toImageMsg();
pub.publish(msg);
ROS_INFO( "read the %dth frame successfully!", count );
loop_rate.sleep();
ros::spinOnce();
}
video.release();
return 0;
}
- imagesub.cpp
#include<ros/ros.h>
#include<cv_bridge/cv_bridge.h>
#include<sensor_msgs/image_encodings.h>
#include<image_transport/image_transport.h>
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<stdio.h>
#include<math.h>
#include<vector>
void imageCalllback(const sensor_msgs::ImageConstPtr& msg)
{
ROS_INFO("Received \n");
try{
cv::imshow( "video", cv_bridge::toCvShare(msg, "bgr8")->image );
cv::waitKey(30);
}
catch( cv_bridge::Exception& e )
{
ROS_ERROR( "Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str() );
}
}
int main(int argc, char** argv)
{
ros::init(argc, argv, "image_listener");
ros::NodeHandle n;
cv::namedWindow("video");
cv::startWindowThread();
image_transport::ImageTransport it(n);
image_transport::Subscriber sub = it.subscribe( "video_image", 1, imageCalllback );
ros::spin();
cv::destroyWindow("video");
return 0;
}
- package.xml
<?xml version="1.0"?>
<package format="2">
<name>ros_cv_image</name>
<version>0.0.0</version>
<description>The ros_cv_image package</description>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>cv_bridge</build_depend>
<build_depend>image_transport</build_depend>
<build_depend>roscpp</build_depend>
<build_depend>rospy</build_depend>
<build_depend>sensor_msgs</build_depend>
<build_depend>std_msgs</build_depend>
<build_depend>opencv2</build_depend>
<build_export_depend>cv_bridge</build_export_depend>
<build_export_depend>image_transport</build_export_depend>
<build_export_depend>roscpp</build_export_depend>
<build_export_depend>rospy</build_export_depend>
<build_export_depend>sensor_msgs</build_export_depend>
<build_export_depend>std_msgs</build_export_depend>
<build_export_depend>opencv2</build_export_depend>
<exec_depend>cv_bridge</exec_depend>
<exec_depend>image_transport</exec_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>rospy</exec_depend>
<exec_depend>std_msgs</exec_depend>
<exec_depend>opencv2</exec_depend>
<export>
</export>
</package>
- CMakeList.xml
cmake_minimum_required(VERSION 2.8.3)
project(ros_cv_image)
find_package(catkin REQUIRED COMPONENTS
cv_bridge
image_transport
roscpp
rospy
sensor_msgs
std_msgs
)
#增加的这句
find_package(OpenCV REQUIRED)
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES ros_cv_image
# CATKIN_DEPENDS cv_bridge image_transport roscpp rospy std_msgs
# DEPENDS system_lib
)
#添加 ${OpenCV_INCLUDE_DIRS}
include_directories(
./include
${catkin_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
)
## Add cmake target dependencies of the library
## as an example, code may need to be generated before libraries
## either from message generation or dynamic reconfigure
# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Add folders to be run by python nosetests
# catkin_add_nosetests(test)
add_executable(imagepub src/imagepub.cpp)
target_link_libraries(imagepub ${catkin_LIBRARIES} ${OpenCV_LIBRARIES})
add_executable(imagesub src/imagesub.cpp)
target_link_libraries(imagesub ${catkin_LIBRARIES} ${OpenCV_LIBRARIES})
多机ROS通信
配置ip和hostname
sudo gedit /etc/hosts
//添加待通信两主机之间的ip和hostname,例如:
192.168.3.172 hero2
192.168.3.203 ivip-To-be-filled-by-O-E-M
两主机或多个主机都需要添加 ip和hostname
参考链接:
[1] ROS学习【2】-----ubuntu16.04中进行ROS通信编程(话题编程) link.
[2] ROS编写图片订阅与发布 link.
[3] ROS中订阅和发布视频中的图像消息 link.
[4] ROS官方教程:link.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)