ROS 发布/订阅节点示例(Python)
本文将基于 rospy 客户端库创建一个简单的 Hello World 软件包,实现一个发布节点(Publisher)和一个订阅节点(Subscriber),两个节点之间会循环传递“Hello World”字符串消息。
完成本次实验,你将学会如何使用 Python 编写一个 ROS 节点。
创建软件包
在 ROS 中,源代码是以包的形式组织的,所以在编写任何 ROS 程序之前,都必须先创建一个 ROS 软件包。当然创建软件包之前,你还需要创建工作空间,创建步骤参考 ROS Catkin 工作空间,这里假设你已经创建好了工作空间。
切换到 Catkin 工作空间 的 src 目录,执行以下命令创建软件包:
$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
创建 ROS 节点
该示例包含两个 ROS 节点:talker 和 listener,对应 talker.py 和 listener.py 源文件。注意:和 C++ 代码不同,Python 代码需要放在 scripts 目录。切换到 beginner_tutorials/src 目录,执行下面命令创建目录和文件。
$ mkdir scripts
$ cd scripts/
$ touch talker.py
$ touch listener.py
talker 节点
#!/usr/bin/env python3
import rospy
from std_msgs.msg import String
def talker():
rospy.init_node('talker', anonymous=True)
pub = rospy.Publisher('chatter', String, queue_size=10)
rate = rospy.Rate(10) # 10hz
while not rospy.is_shutdown():
hello_str = "hello world %s" % rospy.get_time()
rospy.loginfo(hello_str)
pub.publish(hello_str)
rate.sleep()
if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException:
pass
在 talker.py 代码中,首先导入了 rospy 和 ros 消息模块中的 String 数据类型。然后在 talker()
函数中,我们对 ROS 节点进行了初始化,并创建了一个新的 ROS 发布器。之后,我们使用 while 循环来向 /chatter
话题发布“hello world”字符串消息。
listener 节点
#!/usr/bin/env python3
import rospy
from std_msgs.msg import String
def callback(data):
rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
def listener():
# In ROS, nodes are uniquely named. If two nodes with the same
# name are launched, the previous one is kicked off. The
# anonymous=True flag means that rospy will choose a unique
# name for our 'listener' node so that multiple listeners can
# run simultaneously.
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("chatter", String, callback)
# spin() simply keeps python from exiting until this node is stopped
rospy.spin()
if __name__ == '__main__':
listener()
在 listener.py 代码中,首先对节点进行初始化,然后创建一个订阅器,订阅 /chatter
话题,之后就开始等待 ROS 消息了,这里的等待由 rospy.spin()
函数完成。当接收到消息,就会在 callback()
函数中打印出来。
运行 ROS 节点
和 C++ 节点不同,Python 编写的 ROS 节点不需要编译即可运行。
打开 3 个终端,分别执行下面命令设置环境变量
$ source devel/setup.bash
先在第一个终端启动 roscore
$ roscore
在第二个终端启动 talker 节点,这里使用 rosrun 命令启动
$ rosrun beginner_tutorials talker.py
在第三个终端启动 listener 节点,同样使用 rosrun 命令启动
$ rosrun beginner_tutorials listener.py
可以看到终端在不断地打印消息。此时我们可以通过 rostopic
命令检查当前系统中的 ROS 话题,如下:
$ rostopic list
/chatter
/rosout
/rosout_agg
这里的 chatter
就是 talker 节点发布的话题;rosout
则是用于日志记录的话题,当我们启动 roscore
后就已经创建好了。
创建启动文件
启动文件(launch)的好处是可以通过一条命令快速启动任意多个 ROS 节点。在软件包中(beginner_tutorials 目录)创建一个名为 launch 的目录用于存放启动文件,并新建一个 talker_listener_python.launch 文件。
$ mkdir launch
$ cd launch
$ touch talker_listener_python.launch
talker_listener_python.launch 启动文件的内容如下:
<launch>
<node name="listener_node" pkg="beginner_tutorials" type="listener.py" output="screen"/>
<node name="talker_node" pkg="beginner_tutorials" type="talker.py" output="screen"/>
</launch>
现在,我们可以使用 roslaunch
命令执行该启动文件:
$ roslaunch beginner_tutorials talker_listener_python.launch
运行效果和前面类似,如果要终止运行启动文件,在终端中按 Ctrl + C 即可。