Note: This tutorial assumes that you have completed the previous tutorials: 创建ROS消息和ROS服务.
Description: 本教程将通过Python编写一个发布器节点和订阅器节点。
1. 写发布节点
“节点”是连接到ROS网络的可执行文件的ROS术语。在这里,我们将创建发布者(“talker”)节点,该节点将持续广播消息。
将目录更改为在早期教程中创建的初学者教程包,创建一个包 http://wiki.ros.org/cn/ROS/Tutorials/CreatingPackage:
$ roscd beginner_tutorials
1.1 代码
首先,让我们创建一个“scripts”文件夹来存储我们的python脚本:
$ mkdir scripts
$ cd scripts
将示例script talker.py下载到新的脚本目录并使其可执行:
$ wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/talker.py
$ chmod +x talker.py
You can view and edit the file with $ rosed beginner_tutorials talker.py or just look below.
#!/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)
这段代码定义了说话者与其他ROS的接口。pub=rospy.publisher(“chatter”,string,queue_size=10”)声明您的节点正在使用消息类型字符串发布到chatter主题。这里的字符串实际上是std msgs.msg.string类。在ROS hydro中,queue-size参数是新的,它限制了排队消息的数量(如果任何订户没有足够快地接收到这些消息)。在旧的ROS分布中,只需省略这个参数。
下一行,rospy.init_node(name,…)非常重要,因为它告诉rospy您的节点的名称——除非rospy有此信息,否则它无法开始与rospy主机通信。在这种情况下,您的节点将使用名称talker。注意:名称必须是基名称,即不能包含任何斜杠“/”。
anonymous=true通过在名称末尾添加随机数来确保节点具有唯一的名称。有关节点初始化选项的更多信息,请参阅Rospy文档中的初始化和关闭-初始化您的ROS节点。
rate = rospy.Rate(10) # 10hz
此行创建速率对象速率。借助其方法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()标志,然后执行工作。您必须检查is_shutdown()以检查程序是否应该退出(例如,如果存在ctrl-c或其他)。在这种情况下,“工作”是对pub.publish(hello_str)的调用,它将字符串发布到Chatter主题。循环调用rate.sleep(),它的睡眠时间刚好足够维持循环中所需的速率。
(您也可以运行rospy.sleep(),它与time.sleep()类似,只是它也可以与模拟时间一起工作(参见时钟)。
这个循环还调用rospy.loginfo(str),它执行三重任务:消息被打印到屏幕上,它被写入节点的日志文件,然后被写入rosout。Rosout对于调试是很方便的:您可以使用RQT控制台调出消息,而不必查找带有节点输出的控制台窗口。
std msgs.msg.string是一种非常简单的消息类型,因此您可能想知道发布更复杂的类型是什么样子的。一般的经验法则是,构造函数参数的顺序与.msg文件中的顺序相同。您还可以不传入任何参数并直接初始化字段,例如
msg = String()
msg.data = str
或者,您可以初始化某些字段并将其余字段保留为默认值:
String(data=str)
你可能想知道最后一点:
try:
talker()
except rospy.ROSInterruptException:
pass
除了标准的 Python __main__ check 检查之外,这还会捕获一个rospy.ROSInterruptException 异常,当按下ctrl-c或关闭节点时,rospy.sleep()和rospy.rate.sleep()方法会抛出异常。引发此异常的原因是,您不会在sleep()之后意外地继续执行代码。
现在我们需要编写一个节点来接收消息。
2. 写入订阅服务器节点
2.1 代码
将listener.py文件下载到脚本目录中:
$ roscd beginner_tutorials/scripts/
$ wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/listener.py
文件内容看起来接近:
#!/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
# 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()
别忘了要让节点executable:
$ chmod +x listener.py
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. 构建你的节点
我们使用cmake作为构建系统,是的,您甚至必须将其用于Python节点。这是为了确保为消息和服务创建了自动生成的python代码。
Go to your catkin workspace and run catkin_make:
$ cd ~/catkin_ws
$ catkin_make
既然你写完了一个简单的消息发布器和订阅器,让我们来测试消息发布器和订阅器.