有时候想想,国内有些资源确实比较稀缺,但是我们一样不会落后!学习python和ROS这么久了,一直很少去实战,另外看到基于python编程的ROS话题通信教程实在是稀缺了,或者对小白不是那么的友好,所以写下这篇教程与你一起进步。
关于ROS很基本的知识,比如:怎么启动roscore;怎么创建工作空间;source环境;python脚本的执行权限等我就不讲解了。主要是代码部分讲解!
一、初始化工作空间
二、source环境
把下面的内容:
source /home/xiaolong/ros_practice/devel/setup.bash
放在.bashrc末尾,这个不懂得看我之前的博客
传送门:/qq_45152498/article/details/108652439
三、创建功能包
创建好的src:
四、Writing the Publisher Node
在scripts下创建talker.py
并确保它有可执行权限。
让我先把整体代码给你,让你有一个整体的印象:
#!/usr/bin/env python# license removed for brevityimport rospyfrom std_msgs.msg import Stringdef talker():pub = rospy.Publisher('chatter', String, queue_size=10)rospy.init_node('talker', anonymous=True)rate = rospy.Rate(10) # 10hzwhile 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
然后开始一点点分析:
#!/usr/bin/env python
每一个python ROS节点在顶部都有一个声明,它使你的程序被作为python脚本来执行。
import rospyfrom std_msgs.msg import String
如果要编写ROS节点,则需要导入rospy。std_msgs.msg的导入是为了使我们可以重用std_msgs/String消息类型进行发布。
pub = rospy.Publisher('chatter', String, queue_size=10)
声明你的节点正在使用消息类型String发布到chatter话题上。String实际上是std_msgs.msg.String类。queue_size=10表示队列长度是10,如果任何订阅者没有足够快地接收它们,则限制已排队消息的数量。
rospy.init_node('talker', anonymous=True)
这个非常重要,因为它告诉rospy你的节点名称。直到rospy获得此信息之前,它才能开始与ROS Master进行通信。节点将使用名称talker。注意:名称不能包含任何斜杠“/”。anonymous = True通过在名称的末尾添加随机数来确保你的节点具有唯一名称。
rate = rospy.Rate(10)
rate对象可以允许你指定自循环的频率。它会追踪记录自上一次调用rate.sleep()后时间的流逝,并休眠直到一个频率周期的时间。参数为10时,我们期望每秒执行10次循环。简单理解:以每秒 10 次的频率在 chatter 上发布消息。
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)。hello_str = “hello world %s” % rospy.get_time()定义了发布消息的内容是"hello world 时间"。至于这个%的用法,你可以查查python语法。
rospy.loginfo(hello_str)
此循环调用rospy.loginf(),它执行三项任务:将消息打印到屏幕上,将消息写入node的日志文件,并将消息写入rosout。rosout是一个方便的调试工具:你可以使用rqt_console提取消息,而不必查找带有node输出的控制台窗口。
pub.publish(hello_str)
将字符串发布到chatter话题上。
rate.sleep()
该循环调用rate.sleep(),该睡眠刚好足够长是为了在整个循环中保持所需的速度,和rate = rospy.Rate(10)对应。
try:talker()except rospy.ROSInterruptException:pass
它会捕获rospy.ROSInterruptException异常,当按Ctrl-C或关闭node时,rospy.sleep()和rospy.rate.sleep()可能会引发该异常。
总结:如何实现一个发布者? • 初始化ROS节点; • 向ROS Master注册节点信息,包括发布的话题名和话题中的消息类型; • 创建消息数据; • 按照一定频率循环发布消息。
五、Writing the Subscriber Node
在scripts下创建listener.py
并确保它有可执行权限。
#!/usr/bin/env pythonimport rospyfrom std_msgs.msg import Stringdef 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 stoppedrospy.spin()if __name__ == '__main__':listener()
这个和talker.py
类似,除了我们已经引入了一种新的基于回调的机制来订阅消息。
rospy.Subscriber("chatter", String, callback)rospy.spin()
这声明你的节点订阅了消息类型为std_msgs.msg.String的chatter话题。收到新消息时,将以消息(String)作为第一个参数来调用回调函数。rospy.spin()只是使节点无法退出,直到该节点已关闭。与roscpp不同,rospy.spin()不会影响订阅者回调函数机制,因为它们具有自己的线程。
总结:如何实现一个订阅者? • 初始化ROS节点; • 订阅需要的话题; • 循环等待话题消息,接收到消息后进入回调函数; • 在回调函数中完成消息处理。
六、测试
1.让我们看看src:
2.启动ROS Master:
roscore
3.启动发布者和订阅者:
4.rqt可视化:
七、探索
1.在运行节点后可以关闭roscore,此时也可以正常发布和接收。但是不启动ROS Master直接运行程序却不行。
2.python脚本可以不用编译直接执行,相当于你不用修改CMakeLists.txt文件。但是编译运行需要添加东西。官方Wiki是说:
但是在工作空间catkin_make却不能通过,而下面这样可以:
3.scripts文件夹可以不要,直接放在topic功能包下,这是因为我们的程序以及功能简单,但是我还是希望你放在scripts下,因为以后你的功能包下基本不会只有python脚本,而没有其它文件。
4.可以用下面两行代替上面一行,这样执行效果一样:
5.关于回调函数:
def callback(data):rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
这说明传递过来的是String对象,而消息内容的话当然是String.data(即data.data)。
注意:String是不能直接更改的,因为这是ROS内部封装好的,你只能引用,要是直接更改岂不是乱套了嘛。就像上面的hello_str = String(),然后hello_str = “hello world %s” % rospy.get_time() 而使用String.data替代hello_str.data是错误的。
注:以上完全是自己摸索出来的,小白看不懂没有关系,还有大家摸索出来其他东西或者和我的类似,或者知道这其中原理的,欢迎交流哟!
八、话题通信机制
1.基本概念:
2.话题通信机制:
本文内容参考: ROS官方wiki: 古月——ROS入门21讲 《ROS机器人开发实践》
如有错误或者不足之处,欢迎大家留言指正!
如果觉得《ROS发布者(Publisher)和订阅者(Subscriber)的python编程实现(讲解超级详细)》对你有帮助,请点赞、收藏,并留下你的观点哦!