前沿知识
在ROS(Robot Operating System)中,话题通信是一种基本的通信方式,它允许节点之间通过发布和订阅消息来进行数据交换。本文将介绍如何使用Python编写一个简单的ROS话题发布者和订阅者,并演示它们之间的通信过程。
话题数据传输的特性是从一个节点到另外一个节点,发送数据的对象称之为发布者,接收数据的对象称之为订阅者,每一个话题都需要有一个名字,传输的数据也需要有固定的数据类型。
例如,大家平时关注的公众号,比如有一个公众号,它的名字叫做“星之轨科技”,这个星之轨科技就是话题名称,公众号的发布者是星之轨科技的小编,他会把组织好的机器人知识排版成要求格式的公众号文章,发布出去,这个文章格式,就是话题的数据类型。如果大家对这个话题感兴趣,就可以订阅“星之轨科技”,成为订阅者之后自然就可以收到星之轨科技的公众号文章,没有订阅的话,也就无法收到。
类似这样的发布/订阅模型在生活中随处可见,比如订阅报纸、订阅杂志等等。
大家再仔细想下这些可以订阅的东西,是不是并不是唯一的,我们每个人可以订阅很多公众号、报纸、杂志,这些公众号、报纸、杂志也可以被很多人订阅,没错,ROS里的话题也是一样,发布者和订阅者的数量并不是唯一的,可以称之为是多对多的通信模型。
因为话题是多对多的模型,发布控制指令的摇杆可以有一个,也可以有2个、3个,订阅控制指令的机器人可以有1个,也可以有2个、3个,大家可以想象一下这个画面,如果存在多个发送指令的节点,建议大家要注意区分优先级,不然机器人可能不知道该听谁的了。
1.异步通信
所谓异步,只要是指发布者发出数据后,并不知道订阅者什么时候可以收到,类似星之轨科技公众号发布一篇文章,你什么时候阅读的,星之轨科技根本不知道,报社发出一份报纸,你什么时候收到,报社也是不知道的。这就叫做异步。
异步的特性也让话题更适合用于
一些周期发布的数据,比如传感器的数据,运动控制的指令等等,如果某些逻辑性较强的指令,比如修改某一个参数,用话题传输就不太合适了。
2.消息接口
最后,既然是数据传输,发布者和订阅者就得统一数据的描述格式,不能一个说英文,一个理解成了中文。在ROS中,话题通信数据的描述格式称之为消息,对应编程语言中数据结构的概念。比如这里的一个图像数据,就会包含图像的长宽像素值、每个像素的RGB等等,在ROS中都有标准定义。
消息是ROS中的一种接口定义方式,与编程语言无关,我们也可以通过.msg后缀的文件自行定义,有了这样的接口,各种节点就像积木块一样,通过各种各样的接口进行拼接,组成复杂的机器人系统。
一、话题发布者(Publisher)
首先,我们需要编写一个Python脚本作为话题发布者。该脚本将创建一个名为talker
的节点,并在chatter
话题上发布字符串类型的消息。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
from std_msgs.msg import String
def talker():
# 创建一个Publisher对象,用于在chatter话题上发布String类型的消息
pub = rospy.Publisher('chatter', String, queue_size=10)
# 初始化名为talker的ROS节点,设置匿名标志为True
rospy.init_node('talker', anonymous=True)
# 设置发布频率为10Hz
rate = rospy.Rate(10)
# 循环发布消息,直到节点被关闭
while not rospy.is_shutdown():
hello_str = "hello world"
rospy.loginfo(hello_str)
pub.publish(hello_str)
rate.sleep()
if __name__ == '__main__':
try:
# 调用talker函数启动发布者节点
talker()
except rospy.ROSInterruptException:
pass
将上述代码保存为talker.py
文件,并确保该文件位于ROS工作空间的catkin_ws/src/xzbot_msgs/src目录下。
二、话题订阅者(Subscriber)
接下来,我们需要编写一个Python脚本作为话题订阅者。该脚本将创建一个名为listener
的节点,并订阅chatter
话题上的消息。每当收到消息时,它将调用一个回调函数来处理消息。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
from std_msgs.msg import String
# 回调函数,用于处理接收到的消息
def callback(data):
rospy.loginfo(data.data)
def listener():
# 初始化名为listener的ROS节点,设置匿名标志为True
rospy.init_node('listener', anonymous=True)
# 创建一个Subscriber对象,用于订阅chatter话题上的String类型消息,并指定回调函数
rospy.Subscriber("chatter", String, callback)
# 保持Python程序不退出,直到节点被关闭
rospy.spin()
if __name__ == '__main__':
# 调用listener函数启动订阅者节点
listener()
将上述代码保存为listener.py
文件,同样确保该文件位于ROS工作空间的catkin_ws/src/xzbot_msgs/src目录下。
三、运行发布者与订阅者
1.添加执行权限:
首先,您需要确保 talker.py、listener.py
脚本具有执行权限。您可以使用 chmod
命令来添加执行权限:
cd ~/catkin_ws/src/xzbot_msgs/src/
chmod +x talker.py
chmod +x listener.py
2.编译代码
在ROS工作空间中,你可以使用catkin_make
命令编译代码,然后使用rosrun
命令来运行发布者和订阅者节点。
cd catkin_ws/
catkin_make
source devel/setup.bash
3.首先,启动ROS核心:
roscore
4.运行发布者节点:
rosrun xzbot_msgs talker.py
5.运行订阅者节点:
rosrun xzbot_msgs listener.py
现在,你应该可以在订阅者节点的终端窗口中看到发布者发布的消息。每次发布者发布消息时,订阅者都会调用回调函数并打印出接收到的消息内容。