ROS学习笔记16(编写简单的消息发布器和订阅器 (Python))

1 编写发布者节点

“节点”是连接到ROS网络的可执行文件ROS术语。在这里,我们将创建一个持续广播消息的发布者(“talker”)节点。

将目录更改为您在早期教程中创建的的beginner_tutorials包,并创建一个包:

$ roscd beginner_tutorials

1.1 代码

首先,我们创建一个“scripts”文件夹来存储我们的Python脚本:

$ mkdir scripts
$ cd scripts

然后将示例脚本talker.py下载到新脚本目录并使其可执行(更改权限):

$ wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/talker.py
$ chmod +x talker.py

您可以使用 $ rosed beginner_tutorials talker.py 这个操作查看和编辑该文件。

   1 #!/usr/bin/env python
   2 # license removed for brevity
   3 import rospy
   4 from std_msgs.msg import String
   5 
   6 def talker():
   7     pub = rospy.Publisher('chatter', String, queue_size=10)
   8     rospy.init_node('talker', anonymous=True)
   9     rate = rospy.Rate(10) # 10hz
  10     while not rospy.is_shutdown():
  11         hello_str = "hello world %s" % rospy.get_time()
  12         rospy.loginfo(hello_str)
  13         pub.publish(hello_str)
  14         rate.sleep()
  15 
  16 if __name__ == '__main__':
  17     try:
  18         talker()
  19     except rospy.ROSInterruptException:
  20         pass

1.2 程序解释

现在,我们在这里停顿

   1 #!/usr/bin/env python

每个Python ROS 节点都会在顶部进行此声明。第一行是确保您的脚本作为Python脚本执行。

   3 import rospy
   4 from std_msgs.msg import String

如果您正在编写ROS 节点,则需要导入rospy(以Python语言的确如此)。

导入std_msgs.msg则是使得我们可以重新使用std_msgs /String消息类型(一个简单的字符串容器)。

   7     pub = rospy.Publisher('chatter', String, queue_size=10)
   8     rospy.init_node('talker', anonymous=True)

这部分代码定义了talker与其余ROS的接口。

pub = rospy.Publisher(“chatter”,String,queue_size = 10)声明您的节点使用消息类型String,以及发布话题名为“chatter”。

这里的String实际上是类std_msgs.msg.String。

queue_size表示队列的大小(适用于hydro以后的版本)。在旧版本中,则被漏掉了这个参数。

ospy.init_node(NAME,...)则是非常重要,因为它告诉rospy这个节点的名称。直到rospy有这个信息,它才能开始与ROS Master通信。在这种情况下,节点将采用名称“talker”。

注意:名称必须是基本名称,即它不能包含任何斜杠“/”。

anonymous = True这行程序则通过在NAME末尾添加随机数来确保您的节点具有唯一名称。

有关节点初始化选项的更多信息,请参阅rospy文档中的Initialization and Shutdown - Initializing your ROS Node

   9     rate = rospy.Rate(10) # 10hz

此行创建Rate对象 rate。借助其方法sleep(),它提供了一种以所需速率的便捷循环方式。它的参数为10,我们应该期望每秒循环10次(只要我们的处理时间不超过1/10秒即可!)

  10     while not rospy.is_shutdown():
  11         hello_str = "hello world %s" % rospy.get_time()
  12         rospy.loginfo(hello_str)
  13         pub.publish(hello_str)
  14         rate.sleep()

这个循环是一个相当标准的rospy构造:检查rospy.is_shutdown()标志位然后开始循环。使用is_shutdown()以检查你的程序是否应该退出(例如,如果有Ctrl-C或其他)。

然后,程序对pub.publish(hello_str)进行调用,然后将字符串发布到我们的“chatter”话题上。

循环调用rate.sleep(),它睡眠的时间足够长,可以保持循环所需的速率。

(您也可以运行rospy.sleep(),有点类似于time.sleep(),但在模拟时间有差别,具体可以参考Clock

这个循环调用rospy.loginfo(str),它执行三重任务:消息被输出到屏幕,它被写入Node的日志文件,也被写入rosout

rosout对于调试非常方便:您可以使用rqt_console来提取消息,而不必使用Node输出的控制台窗口。

std_msgs.msg.String是一种非常简单的消息类型,因此您可能想知道发布更复杂类型的样子。一般的经验法则是构造函数的参数的顺序与.msg文件中的顺序相同。您也可以不传递参数并直接初始化字段,例如

msg = String()
msg.data = str

或者您可以初始化某些字段,并将其余字段保留为默认值:

String(data=str)

你可能想知道最后一点:

  17     try:
  18         talker()
  19     except rospy.ROSInterruptException:
  20         pass

除了标准的Python __main__检查之外,这还会捕获一个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

文件内容看起来接近:

   1 #!/usr/bin/env python
   2 import rospy
   3 from std_msgs.msg import String
   4 
   5 def callback(data):
   6     rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
   7     
   8 def listener():
   9 
  10     # In ROS, nodes are uniquely named. If two nodes with the same
  11     # node are launched, the previous one is kicked off. The
  12     # anonymous=True flag means that rospy will choose a unique
  13     # name for our 'listener' node so that multiple listeners can
  14     # run simultaneously.
  15     rospy.init_node('listener', anonymous=True)
  16 
  17     rospy.Subscriber("chatter", String, callback)
  18 
  19     # spin() simply keeps python from exiting until this node is stopped
  20     rospy.spin()
  21 
  22 if __name__ == '__main__':
  23     listener()

不要忘记使节点更改文件权限使得可执行:

$ chmod +x listener.py

2.2 程序解释

listener.py的代码类似于talker.py,除了我们引入了一个新的回调函数机制来订阅消息。

  15     rospy.init_node('listener', anonymous=True)
  16 
  17     rospy.Subscriber("chatter", String, callback)
  18 
  19     # spin() simply keeps python from exiting until this node is stopped
  20     rospy.spin()

声明了一个类型是std_msgs.msgs.String的“chatter”话题。收到新消息时,将调用回调函数,并将消息作为第一个参数传递到函数里。当然我们也稍微改变了对rospy.init_node()的调用。我们添加了anonymous = True关键字参数。ROS要求每个节点都有唯一的名称。如果出现具有相同名称的节点,那么ROS就会中止之前同名的节点,这样可以很容易地将故障节点从网络中踢出。该anonymous=True标志位告诉rospy为节点生成一个唯一的名称,以便您可以有多个listener.py节点同时运行。

最后添加rospy.spin()只是保持节点运行,直到节点关闭。与roscpp不同,rospy.spin()不会影响订阅者回调函数,因为它们有自己独立的线程。

3 构建节点

我们使用CMake作为构建系统,是的,即使是Python节点也必须使用它。这确保针对消息和服务能自动生成Python代码。

转到catkin工作区并运行catkin_make:

$ cd~ / catkin_ws
$ catkin_make

猜你喜欢

转载自blog.csdn.net/qq_27806947/article/details/82937366