ROS入门学习5:理解话题中Publier与Subscriber(Python)

  话题(topic)是ROS中一种异步通信模式,其中消息以单向发布/订阅(Publish/Subscribe)的方式传递。

  • 发布者(Publier):给指定的话题发布消息。
  • 订阅者(Subscriber):订阅指定的话题接收消息。
  • 关系:Publier-Subscriber 多对多

  话题是单向的,适用于需要连续发送消息的传感器数据,因为它们通过一次的连接连续发送和接收消息。
  例如,通过计算移动机器人的两个车轮的编码器值生成可以描述机器人当前位置的里程计(odometry) 信息,并以话题信息(x, y, i)传达,以此实现异步单向的连续消息传输。

(图)话题通信模式

  话题是一种多对多的通信,即一个话题可以有多个发布者和订阅者。发布者和订阅者并不了解彼此的存在,系统中可能有多个节点发布和订阅同一个话题。单个发布者可以与多个订阅者进行通信,相反,一个订阅者可以在单个话题上与多个发布者进行通信。当然,这两家发布者都可以和多个订阅者进行通信。

话题程序编写

本例程放在ros_learning功能包script文件夹下,新建ros_learning功能包:

$ cs
$ catkin_create_pkg ros_learning std_msgs rospy roscpp
$ cm

创建发布者(Publier)

路径:catkin_ws/src/ros_learning/script/publisher.py

publisher.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import rospy
from std_msgs.msg import String

def talker():
# 创建发布者pub,发布的话题chatter数据类型为String类型
# queue_size=10,消息队列,即如果收到的数据大于10,则将开始抛弃最初收到的第一个数据
pub = rospy.Publisher('chatter', String, queue_size=10)

# ROS要求每个节点要有唯一名称,如果相同的名称,就会中止之前同名的节点。
# anoymous=True 通过在你名字的后边添加一个随机数,来保证你的节点独一无二。
rospy.init_node('talker', anonymous=True) # 初始化节点talker
rate = rospy.Rate(10) # 10hz 每秒10次
while not rospy.is_shutdown():
hello_str = "hello world %s" % rospy.get_time() # 要发布的消息hello_str 
rospy.loginfo(hello_str) # 打印消息
pub.publish(hello_str) # 发布消息
rate.sleep() # 节点休眠100ms后开始下一个循环

if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException:
pass

创建发布者完成后,使用命令sudo chmod +x XXX.py为Python文件添加可执行权限:

tao@ubuntu:~/catkin_ws/src/ros_learning/script$ sudo chmod +x publisher.py

创建订阅者(Subscriber)

路径:catkin_ws/src/ros_learning/script/subscriber.py

subscriber.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import rospy
from std_msgs.msg import String

def callback(data):
rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data) # 回调函数

def listener():
rospy.init_node('listener', anonymous=True) # 初始化节点listener
rospy.Subscriber("chatter", String, callback) # 节点listener订阅话题chatter,调用回调函数

# 简单保持你的节点一直运行,直到程序关闭。
rospy.spin()

if __name__ == '__main__':
listener()

创建订阅者完成后,使用sudo chmod +x XXX.py命令为Python文件添加可执行权限:

tao@ubuntu:~/catkin_ws/src/ros_learning/script$ sudo chmod +x subscriber.py

运行测试

运行一组话题节点

  • 打开新终端,编译功能包,启动ROS:

    $ cm
    $ roscore

  • 打开新终端,运行订阅者,此时发布者还没发送消息:

$ rosrun ros_learning subscriber.py
(图)订阅者(Subscriber)
  • 打开新终端,运行发布者,可以看到打印的发布消息和订阅消息:
$ rosrun ros_learning publisher.py 
(图)发布者(Publier)
  • 查看话题列表rostopic list和节点列表rosnode list
tao@ubuntu:~$ rostopic list
/chatter
/rosout
/rosout_agg
tao@ubuntu:~$ rosnode list
/listener_17529_1575516478892
/rosout
/talker_17632_1575516514932
  • 查看节点关系rqt_graph,可以看到每一个节点后面都有编号,都是独一无二的。
(图)节点关系

运行两组话题节点

接着上一组,再运行一组节点。

  • 打开新终端,运行订阅者:
$ rosrun ros_learning subscriber.py
  • 打开新终端,运行发布者:
$ rosrun ros_learning publisher.py 
(图)发布者(Publier)
  • 查看话题列表rostopic list和节点列表rosnode list
tao@ubuntu:~$ rostopic list
/chatter
/rosout
/rosout_agg
tao@ubuntu:~$ rosnode list
/listener_17529_1575516478892
/listener_18076_1575516788711
/rosout
/talker_17632_1575516514932
/talker_17809_1575516645091
  • 查看节点关系rqt_graph,可以看到每一个节点后面都有编号,都是独一无二的。
(图)节点关系

到此,已经简单了解一下话题的通信模式。

+