本教程介绍如何在python中编写发布者和订阅者节点
1、编写Publisher节点
“节点”是连接到ROS网络的可执行文件的ROS术语。在这里,我们将创建广播消息的 publisher(“talker”)节点。
将目录更改为之前教程中创建的beginner_tutorials包:
$ roscd beginner_tutorials
1.1 代码
首先,创建一个'scripts'文件夹来存储你的Python脚本:
$ mkdir scripts
$ cd scripts
talker.py源代码如下:
#!/usr/bin/env python
# license removed for brevity
import rospy
from std_msgs.msg import String
def talker():
pub = rospy.Publisher('chatter', String, queue_size=10)
rospy.init_node('talker', anonymous=True)
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
1.2 代码解释
#!/usr/bin/env python
每个Python ROS节点都会在顶部显示此声明。第一行确保您的脚本作为Python脚本执行。
import rospy
from std_msgs.msg import String
编写ROS节点,则需要导入rospy。std_msgs.msg导入是为了可以重用std_msgs / String消息类型(一个简单的字符串容器)进行发布。
pub = rospy.Publisher('chatter', String, queue_size=10)
rospy.init_node('talker', anonymous=True)
这部分代码定义了talker与其它ROS的接口。pub = rospy.Publisher("chatter", String, queue_size=10) 声明节点使用String消息类型,发布到chatter主题。这里的字符串实际上是类std_msgs.msg.String。queue_size参数在ROS hydro中是新的类型,如果任何订户没有足够快地接收它们,则限制排队消息的数量。在旧的ROS发行版中,只省略了这个论点。
下一行rospy.init_node(NAME,...)非常重要,因为它发布rospy节点的名称 - 直到rospy有这个信息,它才能开始与ROS 主机通信。在这种情况下,节点将采用名称talker。注意:名称必须是基本名称,即它不能包含任何斜杠“/”。
anonymous = True通过在NAME末尾添加随机数来确保您的节点具有唯一名称。有关节点初始化选项的更多信息,请参阅Initialization and Shutdown - Initializing your ROS Node。
rate = rospy.Rate(10) # 10hz
此行创建Rate对象速率。借助其方法sleep(),它提供了一种以所需速率循环的便捷方式。它的参数为10,我们应该期望每秒循环10次(只要我们的处理时间不超过1/10秒!)
while not rospy.is_shutdown():
hello_str = "hello world %s" % rospy.get_time()
rospy.loginfo(hello_str)
pub.publish(hello_str)
rate.sleep()
这个循环是一个相当标准的rospy构造:检查rospy.is_shutdown()标志然后做工作。检查程序是否应该退出(例如,如果有Ctrl-C或其他)。在这种情况下,“work”是对pub.publish(hello_str)的调用,它将字符串发布到我们的talker主题。循环调用rate.sleep(),保持循环所需的速率。
也可以运行rospy.sleep(),它类似于time.sleep(),但它也适用于模拟时间(请参阅Clock)。
这个循环还调用rospy.loginfo(str),它执行三重任务:消息被打印到屏幕,它被写入Node的日志文件,并被写入rosout。rosout对于调试非常方便:您可以使用rqt_console来提取消息,而不必使用Node的输出找到控制台窗口。
std_msgs.msg.String是一种非常简单的消息类型。一般的经验法则是构造函数args的顺序与.msg文件中的顺序相同。也可以不传入参数并直接初始化字段,例如
msg = String()
msg.data = str
或者可以初始化某些字段,并将其余字段保留为默认值:
String(data=str)
最后一点:
try:
talker()
except rospy.ROSInterruptException:
pass
除了标准的Python __main__检查之外,这还会捕获一个rospy.ROSInterruptException异常,当按下Ctrl-C或者你的节点关闭时,rospy.sleep()和rospy.Rate.sleep()方法可以抛出该异常。引发此异常的原因是不会在sleep()之后意外地继续执行代码。
2、编写Subscriber节点
2.1 代码
#!/usr/bin/env python
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
# node 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()
2.2 代码解释
listener.py的代码类似于talker.py,除了引入了一个新的基于回调的机制来订阅消息。
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("chatter", String, callback)
# spin() simply keeps python from exiting until this node is stopped
rospy.spin()
这声明的节点订阅了std_msgs.msgs.String类型的chatter主题。收到新消息时,将调用回调函数,并将消息作为第一个参数。
也稍微改变了对rospy.init_node()的调用。添加了anonymous = True关键字参数。ROS要求每个节点都有唯一的名称。如果出现具有相同名称的节点,则会突然显示前一个节点。这样可以很容易地将故障节点从网络中踢出。anonymous = True标志告诉rospy为节点生成一个唯一的名称,以便可以轻松运行多个listener.py节点。
最后添加,rospy.spin()只是让节点退出,直到节点关闭。与roscpp不同,rospy.spin()不会影响订阅者回调函数,因为它们有自己的线程。
3、编译 nodes
使用CMake作为构建系统,即使是Python节点也必须使用它。这是为了确保创建消息和服务的自动生成的Python代码。
转到catkin工作区并运行catkin_make
$ cd ~/catkin_ws
$ catkin_make
既然已经编写了一个简单的发布者和订阅者,让我们来查看ROS教程五-运行简单的发布者和订阅者。