ubuntu16.04中进行ROS通信编程

基础知识学习

🌟 话题与服务的区别

-话题服务
同步性异步同步
通信模型发布/订阅服务端/客户端
底层协议ROSTCP/ROSUDPROSTCP/ROSUDP
反馈机制
缓冲区
实时性
节点关系多对多一对多
适用场景数据传输逻辑处理

本文中所有ROS通信小例子都是话题

字段ROS通信小例子

一、创建一个工作区

  1. 创建名为ros的工作区
mkdir -p ~/ros/src
  1. 进入创建工作区的src文件夹
cd ~/ros/src
  1. 生成工作区
catkin_init_workspace
  1. 此时工作区为空,可编译
//进入工作区
cd ~/ros/
//编译
catkin_make
  1. 把工作区在bash中注册
//bash注册
source devel/setup.bash
//验证
echo $ROS_PACKAGE_PATH
//如果能看到自己工作区的文件路径就说明工作区创建成功

二、创建一个ROS工程包

  1. 切换到我们的工作区
cd ~/ros/src
  1. 使用catkin_create_pkg命令去创建一个叫comm(通信)的包,这个包依靠std_msgs、roscpp、rospy
catkin_create_pkg comm std_msgs rospy roscpp
  1. 在工作区编译这个工程包
//进入工作区
cd ~/ros/
//编译
catkin_make

三、创建通信的发、收节点

  1. 把目录切换到我们的comm工程包中
cd ~/ros/src/comm
  1. 进入src子目录
cd src
  1. 在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;
}
  1. 在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;
}
  1. 编辑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

四、测试程序的正确性

  1. 新开一个终端,启动ROS核心程序roscore
roscore
  1. 在开始运行我们的程序之前,在原来的终端、把程序注册
//切换为工作区
cd ~/ros
//程序注册
source ./devel/setup.bash
  1. 运行talker节点
rosrun comm talker
  1. 新建一个终端,运行listener节点
//回到工作区
cd ~/ros
//程序注册
source ./devel/setup.bash
//运行listener节点
rosrun comm listener

看到两个终端的发布和订阅就证明成功啦!

图像ROS通信小例子

创建工作区步骤与字段通信相同

  1. 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();
  }
}
  1. 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");
}
  1. 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>
 
  <!-- The export tag contains other, unspecified, tags -->
  <export>
  </export>
</package>
  1. 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通信小例子

创建工作区步骤与字段通信相同

  1. 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节点初始化
    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;
        
    // opencv准备读取视频
    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;
}
  1. 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;
}
  1. 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>
 
  <!-- The export tag contains other, unspecified, tags -->
  <export>
  </export>
</package>
  1. 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.

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值