目录
2.实现
一、理论模型
1.概念和作用
话题通信是基于发布订阅模式的,也即:一个节点发布消息,另一个节点订阅该消息。话题通信的应用场景也极其广泛,比如下面一个常见场景:
机器人在执行导航功能,使用的传感器是激光雷达,机器人会采集激光雷达感知到的信息并计算,然后生成运动控制信息驱动机器人底盘运动。
在上述场景中,就不止一次使用到了话题通信。
- 以激光雷达信息的采集处理为例,在 ROS 中有一个节点需要时时的发布当前雷达采集到的数据,导航模块中也有节点会订阅并解析雷达数据。
- 再以运动消息的发布为例,导航模块会根据传感器采集的数据时时的计算出运动控制信息并发布给底盘,底盘也可以有一个节点订阅运动信息并最终转换成控制电机的脉冲信号
作用
用于不断更新的、少逻辑处理的数据传输场景。
2.理论模型
"bar"话题 foo:1234 通讯地址
涉及到三个角色:
- ROS Master:管理者
- Talker:发布者
- Listener:订阅者
ROS Master 负责保管 Talker 和 Listener 注册的信息,并将话题相同的 Talker 与 Listener进行匹配,帮助 Talker 与 Listener 建立连接,连接建立后,Talker 可以发布消息,且发布的消息会被 Listener 订阅。
具体实现流程
0.Talker注册
Talker启动后,会通过RPC在 ROS Master 中注册自身信息,其中包含所发布消息的话题名称。ROS Master 会将节点的注册信息加入到注册表中。
1.Listener注册
Listener启动后,也会通过RPC在 ROS Master 中注册自身信息,包含需要订阅消息的话题名。ROS Master 会将节点的注册信息加入到注册表中。
2.ROS Master实现信息匹配
ROS Master 会根据注册表中的信息匹配Talker 和 Listener,并通过 RPC 向 Listener 发送 Talker 的 RPC 地址信息。
3.Listener向Talker发送请求
Listener 根据接收到的 RPC 地址,通过 RPC 向 Talker 发送连接请求,传输订阅的话题名称、消息类型以及通信协议(TCP/UDP)。
4.Talker确认请求
Talker 接收到 Listener 的请求后,也是通过 RPC 向 Listener 确认连接信息,并发送自身的 TCP 地址信息。
5.Listener与Talker件里连接
Listener 根据步骤4 返回的消息使用 TCP 与 Talker 建立网络连接。
6.Talker向Listener发送消息
连接建立后,Talker 开始向 Listener 发布消息。
注意1:上述实现流程中,前五步使用的 RPC协议,最后两步使用的是 TCP 协议
注意2: Talker 与 Listener 的启动无先后顺序要求
注意3: Talker 与 Listener 都可以有多个
注意4: Talker 与 Listener 连接建立后,不再需要 ROS Master。也即,即便关闭ROS Master,Talker 与 Listern 照常通信。
二、基本操作(python)
1.流程
需求:
编写发布订阅实现,要求发布方以10HZ(每秒10次)的频率发布文本消息,订阅方订阅消息并将消息内容打印输出。
分析:
在模型实现中,ROS master 不需要实现,而连接的建立也已经被封装了,需要关注的关键点有三个:
- 发布方
- 接收方
- 数据(此处为普通文本)
流程:
- 编写发布方实现;
- 编写订阅方实现;
- 为python文件添加可执行权限;
- 编辑配置文件;
- 编译并执行。
2.VScode操作
发布方实现:
src文件夹下新建功能包,添加依赖
创建python文件
代码如下:
#! /usr/bin/env python
# coding=UTF-8
"""
需求: 实现基本的话题通信,一方发布数据,一方接收数据,
实现的关键点:
1.发送方
2.接收方
3.数据(此处为普通文本)
PS: 二者需要设置相同的话题
消息发布方:
循环发布信息:HelloWorld 后缀数字编号
实现流程:
1.导包
2.初始化 ROS 节点:命名(唯一)
3.创建发布者对象
4.编写发布逻辑并发布数据
"""
# 导包
import rospy
from std_msgs.msg import String #消息类型 std_msgs.msg导入是为了使我们可以重用std_msgs/String消息类型进行发布
if __name__ == "__main__":
#2.初始化 ROS 节点:命名(唯一
rospy.init_node("chenmo") #传入节点名称
# 3.创建发布者对象
pub=rospy.Publisher("che",String,queue_size=10) #话题名称,消息类型
# 4..编写发布逻辑并发布数据
# 创建数据
msg=String() #创建空的消息类型为String的消息,
msg_front="hellocehnmo"
count=0 #计数器
# 设置循环频率
rate=rospy.Rate(10)
# 循环体
while not rospy.is_shutdown():
msg.data=msg_front+str(count)
# 发布数据 #发布对象: 前面创建的pub, 发布函数:.publish(),发布数据:前面创建的消息msg, 消息类型String
pub.publish(msg) #将字符串发布到chatter话题上
rate.sleep()
# 此循环调用rospy.loginf(), 它执行三项任务:将消息打印到屏幕上,将消息写入node的日志文件,并将消息写入rosout。
# rosout是一个方便的调试工具:你可以使用rqt_console提取消息,而不必查找带有node输出的控制台窗口。
rospy.loginfo("写出的数据:%s",msg.data)
count += 1
为python文件添加可执行权限:
在scripts终端输入代码:chmod +x *.py
编译python文件:ctrl+shift+B
在终端启动roscore:
roscore
在终端添加ros环境,运行python文件:
source ./devel/setup.bash
rosrun plumbing_pub_sub demo01_pub_p.py
订阅方实现
建立python文件,代码如下
#! /usr/bin/env python
# coding=UTF-8
"""
需求: 实现基本的话题通信,一方发布数据,一方接收数据,
实现的关键点:
1.发送方
2.接收方
3.数据(此处为普通文本)
消息订阅方:
订阅话题并打印接收到的消息
实现流程:
1.导包
2.初始化 ROS 节点:命名(唯一)
3创建 订阅者 对象
4.处理订阅的消息(回调函数)
5.设置循环调用回调函数 Spin()
"""
#1.导包
import rospy
from std_msgs.msg import String #消息格式
#这声明你的节点订阅了消息类型为std_msgs.msg.String的chatter话题。收到新消息时,将以消息(String)作为第一个参数来调用回调函数。
def callback(msg): #msg是接收到的消息
rospy.loginfo("我订阅的数据:%s",msg.data)
if __name__ == "__main__":
#2.初始化 ROS 节点:命名(唯一)
rospy.init_node("xiaomo")
#3.创建 订阅者 对象
sub = rospy.Subscriber("che",String,callback,queue_size=10) #话题名字要和发布者一致
#4.处理订阅的消息(回调函数)
#5.设置循环调用回调函数
rospy.spin() #rospy.spin()只是使节点无法退出,直到该节点已关闭。
订阅方和发布方的话题要一致
订阅图查看发布订阅模型:
三.话题通信自定义msg
1.流程
在 ROS 通信协议中,数据载体是一个较为重要组成部分,ROS 中通过 std_msgs 封装了一些原生的数据类型,比如:String、Int32、Int64、Char、Bool、Empty.... 但是,这些数据一般只包含一个 data 字段,结构的单一意味着功能上的局限性,当传输一些复杂的数据,比如: 激光雷达的信息... std_msgs 由于描述性较差而显得力不从心,这种场景下可以使用自定义的消息类型
ROS中还有一种特殊类型:Header
,标头包含时间戳和ROS中常用的坐标帧信息。会经常看到msg文件的第一行具有Header标头
需求:创建自定义消息,该消息包含人的信息:姓名、身高、年龄等。
流程:
- 按照固定格式创建 msg 文件
- 编辑配置文件
- 编译生成可以被 Python 或 C++ 调用的中间文件
2.实现
在src文件夹下 ---> 创建msg文件夹 --->chenmo.msg文件
1.定义msg文件
功能包下新建 msg 目录,添加文件 Person.msg
string name
uint16 age
float64 height
2.编辑配置文件
package.xml中添加编译依赖与执行依赖
CMakeLists.txt编辑 msg 相关配置
配置步骤
1.配置编译时依赖 message_generation
2.配置msg源文件
3.配置message_generation依赖关系。 自定义msg依赖std_msgs功能包
4.配置运行时依赖 message_runtime
编译功能包时依赖: message_generation
意味着等会编译的chenmo.msg文件,配置 msg 源文件
配置依赖关系。自定义msg依赖std_msgs
运行时依赖 message_runtime
3.编译后的中间文件查看:
3.话题通信自定义msg调用B(Python)
1.需求 流程
需求:
编写发布订阅实现,要求发布方以1HZ(每秒1次)的频率发布自定义消息,订阅方订阅自定义消息并将消息内容打印输出。
分析:
在模型实现中,ROS master 不需要实现,而连接的建立也已经被封装了,需要关注的关键点有三个:
- 发布方
- 接收方
- 数据(此处为自定义消息)
流程:
- 编写发布方实现;
- 编写订阅方实现;
- 为python文件添加可执行权限;
- 编辑配置文件;
- 编译并执行。
0.vscode配置
为了方便代码提示以及误抛异常,需要先配置 vscode,将前面生成的 python 文件路径配置进 settings.json
终端中打开python2.7,得到存储路径
将路径添加到settings.json中
2.编写发布方实现
在scripts文件夹下创建文件demo03_pub_person_p.py,并填写以下代码:
#! /usr/bin/env python
# coding=UTF-8
"""实现流程:
1.导包
2.初始化 ROS 节点:命名(唯一)
3.创建发布者对象
4.编写发布逻辑并发布数据"""
#1 导包
import rospy
from plumbing_pub_sub.msg import chenmo #导入消息类型的包 chenmo是自定义的,在plumbing_pub_sub.msg下
# 。默认的在std_msgs.msg 下,如类型为String。/其他的如 消息格式为geometry_msgs/Twis 导包从geometry_msgs.msg(话题通信的消息包)下的Twis
if __name__ == "__main__":
#2初始化ROS节点
rospy.init_node("chl") #chl是自定义的节点名称
#3.创建发布者对象
pub=rospy.Publisher("xuexi",chenmo,queue_size=10) #话题名称,消息类型
#4.编写发布逻辑并发布数据
# 4.1创建发布的数据
p=chenmo() #创建一个空的消息类型为chenmo的消息(消息格式已经由chenmo确定)
p.name="陈默"
p.age=23
p.height=1.75
# 4.2创建Rate对象
rate=rospy.Rate(1) #发布频率
#4.3循环发布数据
while not rospy.is_shutdown():
pub.publish(p) #发布对象: 前面创建的pub, 发布函数:.publish(),发布数据:前面创建的消息p, 消息类型是自定的chenmo
rate.sleep() #休眠
rospy.loginfo("姓名:%s, 年龄:%d, 身高:%.2f",p.name, p.age, p.height) #日志
添加python权限 ---> 配置CmakeLists.txt文件 ---> 编译这python文件 ---> 终端启动roscore ---> 添加环境 ---> 运行python文件
3.编写订阅方实现:
建立python文件,代码如下
#! /usr/bin/env python
# coding=UTF-8
"""
实现流程:
1.导包
2.初始化 ROS 节点:命名(唯一)
3创建 订阅者 对象
4.处理订阅的消息(回调函数)
5.设置循环调用回调函数 Spin()
"""
#1.导包
import rospy
from plumbing_pub_sub.msg import chenmo
def callback(p): #p是接收到的消息
rospy.loginfo("我订阅的数据:%s, %d, %.2f",p.name, p.age, p.height)
if __name__ == "__main__":
#2.初始化 ROS 节点:命名(唯一)
rospy.init_node("xiaomo")
#3.创建 订阅者 对象
sub = rospy.Subscriber("xuexi",chenmo,callback,queue_size=10) #话题名字要和发布者一致
#4.处理订阅的消息(回调函数)
#5.设置循环调用回调函数
rospy.spin()
编译执行
参考引用
https://zhuanlan.zhihu.com/p/439062895
http://www.autolabor.com.cn/book/ROSTutorials/di-2-zhang-ros-jia-gou-she-ji.html