赞
踩
关于ROS的通信机制
机器人是个高度复杂的系统性的实现,机器人上可能集成各种传感器(雷达、摄像头、GPS......)以及控制系统的实现,在ROS中每一个功能点都是一个单独的进程,每一个进程都是单独运行的。因为这些进程可能分布在不同的主机,不同主机协同工作,从而分散计算压力。随之而来就遇到了一个问题:不同的进程是如何通信的?即不同进程如何实现数据的交换。这就涉及到ROS的通信机制了。
ROS中的基本通信机制主要有以下三种实现策略
话题通信是ROS中使用频率最高的一种通信模式,话题通信是基于发布订阅模式的,也即:一个节点发布消息,另一个节点订阅该消息。话题通信的应用场景也极其广泛,比如下面一个常见场景:
机器人在执行导航功能,使用的传感器是激光雷达,机器人会采集激光雷达感知到的信息并计算,然后生成运动控制信息驱动机器人底盘运动。
在上述场景中,就不止一次使用到了话题通信。
以此类推,像雷达、摄像头、GPS.... 等等一些传感器数据的采集,也都是使用了话题通信,换言之,话题通信适用于不断更新的数据传输相关的应用场景。
以发布订阅的方式实现不同节点之间数据交互的通信模式
话题通信实现模型是比较复杂的,该模型如下图所示,该模型中涉及到三个角色:
ROS Master 负责保管 Talker 和 Listener 注册的信息,并匹配话题相同的 Talker 与 Listener,帮助 Talker 与 Listener 建立连接,连接建立后,Talker 可以发布消息,且发布的消息会被 Listener 订阅。
单纯就图可能不是很好理解,我们以现实为例
0.男方提供自身的信息给媒婆,这个信息包含2个部分185(话题)和手机号(RPC地址)
1.女方提交自身的信息给媒婆,这个信息就是女方的要求也就是185(话题)
媒婆进行要求匹配(话题匹配),发现男方符合女方要求
2.把男方的手机号(RPC地址)给女方
3.女方通过手机号打电话给男方,希望可以加微信(TCP地址)
4.男方把自己的微信(TCP地址)给女方
5.女方加男方微信(TCP地址)
6.俩人开始通过微信交流
注意
需求:编写发布订阅实现,要求发布方以10HZ(每秒10次)的频率发布文本消息,订阅方订阅消息并将消息内容打印输出
分析: 在模型实现中,ROS master是不需要我们考虑的,同时发布方与接收方之间的连接已经被封装了,需要关注的关键点有三个:
流程:编写发布者实现
编写订阅方实现
编写配置文件
编译并执行
1. 创建C++文件
2. 编程流程如下
- //ros里的文本类型——————>std_msgs/String.h
- //1.包含头文件;
- #include"ros/ros.h" //包含了标准ROS类的声明
- #include"std_msgs/String.h" //文本被封装成单独的数据类型了std_msgs功能包里的string.h
- #include<sstream> //支持字符串的流输入输出
包可以根据程序的使用一个个添加,下面这个是必备的
#include"ros/ros.h" //包含了标准ROS类的声明
- setlocale(LC_ALL,"");//防止乱码
- //2.初始化 ROS 节点
- ros::init(argc,argv,"talker");//看定义
因为后面有一段字符输出“发布的数据是” ,在ROS中可能会存在乱码情况,这个函数可以解决。
ros::和 std::差不多,是一个命名空间的标识符号,如果不想每次都写ros::可以在函数定义前加上如下代码:
using namespace ros;
下面类似的同理
- // 3.创建节点句柄
- ros::NodeHandle nh;//相当于一个重命名 NodeHandle = nh
改个名字而已,毕竟NodeHandle太长。
- //4.创建发布者对象
- ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",10);
同样改个名字,但后面的参数没有理解。
- /5.编写发布逻辑并发布数据
- //要求以10hz的频率发布,文本后添加编号
- //先创建被发布的消息
- std_msgs::String msg;//创建一个名为msg,在std_msgs/String里
- //发布频率
- ros::Rate rate(10);
- //设置编号
- int count = 0;//定义一个int数据类型的count
- //编写循环,循环中发布数据
- while (ros::ok())
- {
- count++;
-
- //msg.data = "hello";消息内容为hello
- //实现字符串拼接数字,https://blog.csdn.net/shs1992shs/article/details/83051298
- std::stringstream ss;//因为是字符串与数字的组合,所以需要字符串流stringstream
- ss << "hello ---> " <<count;//C++中"<<“叫做插入运算符,第一个相当于把右边赋值给左边,第二紧接其后也一样。
- msg.data = ss.str(); //把流里面的变成字符串给msg.data,我们之前定义的消息是字符串string,所以要用到stringstream里的str
- pub.publish(msg);//用这个发布者对象发布消息,看定义,也和我们之前的创建发布者那边有关,他只能发布string的
- //添加日志
- ROS_INFO("发布的数据是:%s",ss.str().c_str());//%s表示字符串
- rate.sleep();
- }
-
- return 0;
逐行解析
- //先创建被发布的消息
- std_msgs::String msg;//创建一个名为msg,在std_msgs/String里
创建被发布的消息,按照要求是个字符串的类型,此消息被我们命名为msg
- //发布频率
- ros::Rate rate(10);
按照要求设置频率,详情可见此函数的定义。
- //设置编号
- int count = 0;//定义一个int数据类型的count
按照要求我们需要在发布的消息后面假如数字,所以我们这里定义了个int型的变量count
因为是不间断的发送,所以我们用个循环语句while
while (ros::ok())
节点不死,循环不休。
循环体里的内容如下
count++;
变量不断加1.
- //实现字符串拼接数字,https://blog.csdn.net/shs1992shs/article/details/83051298
- std::stringstream ss;//因为是字符串与数字的组合,所以需要字符串流stringstream
定义一个字符串流ss,用来存储字符串和数字的组合 。
ss << "hello ---> " <<count;//C++中"<<“叫做插入运算符,第一个相当于把右边赋值给左边,第二紧接其后也一样。
<<:在C++中称为插入运算符,通俗点的理解就是把右边的给左边。这里面给了2个:hello———> 和 count(不停改变)。
msg.data = ss.str(); //把流里面的变成字符串给msg.data,我们之前定义的消息是字符串string,所以要用到stringstream里的str
因为我们设置发布消息是字符串,所以我们需要利用str()将输出的数据变成字符串送给发布的消息。
pub.publish(msg);//用这个发布者对象发布消息,看定义,也和我们之前的创建发布者那边有关,他只能发布string的
消息发布,这个函数的参数也要求是字符串的形式。
ROS_INFO("发布的数据是:%s",ss.str().c_str());//%s表示字符串
日志输出
rate.sleep();
关闭发布的频率。
总的程序如下:
-
- /*
- 发布方实现
- 1.包含头文件;
- 2.初始化 ROS 节点
- 3.创建节点句柄
- 4.创建发布者对象
- 5.编写发布逻辑并发布数据
- */
-
- //ros里的文本类型——————>std_msgs/String.h
- //1.包含头文件;
- #include"ros/ros.h" //包含了标准ROS类的声明
- #include"std_msgs/String.h" //文本被封装成单独的数据类型了std_msgs功能包里的string.h
- #include<sstream> //支持字符串的流输入输出
-
- int main(int argc, char *argv[])
- {
- setlocale(LC_ALL,"");//防止乱码
- //2.初始化 ROS 节点
- ros::init(argc,argv,"talker");//定义了解
-
- // 3.创建节点句柄
- ros::NodeHandle nh;//相当于一个重命名 NodeHandle = nh
-
- //4.创建发布者对象
- ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",10);
-
- //5.编写发布逻辑并发布数据
- //要求以10hz的频率发布,文本后添加编号
- //先创建被发布的消息
- std_msgs::String msg;//创建一个名为msg,在std_msgs/String里
- //发布频率
- ros::Rate rate(10);
- //设置编号
- int count = 0;//定义一个int数据类型的count
- //编写循环,循环中发布数据
- while (ros::ok())
- {
- count++;
-
- //msg.data = "hello";消息内容为hello
- //实现字符串拼接数字,https://blog.csdn.net/shs1992shs/article/details/83051298
- std::stringstream ss;//因为是字符串与数字的组合,所以需要字符串流stringstream
- ss << "hello ---> " <<count;//C++中"<<“叫做插入运算符,第一个相当于把右边赋值给左边,第二紧接其后也一样。
- msg.data = ss.str(); //把流里面的变成字符串给msg.data,我们之前定义的消息是字符串string,所以要用到stringstream里的str
- pub.publish(msg);//用这个发布者对象发布消息,看定义,也和我们之前的创建发布者那边有关,他只能发布string的
- //添加日志
- ROS_INFO("发布的数据是:%s",ss.str().c_str());//%s表示字符串
- rate.sleep();
- }
-
- return 0;
- }
运行的结果如下
发布方的代码实现结束。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。