💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 7.2 topic in rospy 与5.3节类似,我们用python来写一个节点间消息收发的demo,同样还是创建一个自定义的gps类型的消息,一个节点发布模拟的gps信息,另一个接收和计算距离原点的距离。 ## 7.2.1 自定义消息的生成 `gps.msg`定义如下: ``` string state #工作状态 float32 x #x坐标 float32 y #y坐标 ``` 我们需要修改`CMakeLists.txt`文件,方法见5.3节,这里需要强调一点的就是,对创建的msg进行`catkin_make`会在`~/catkin_ws/devel/lib/python2.7/dist-packages/topic_demo`下生成msg模块(module)。 有了这个模块,我们就可以在python程序中`from topic_demo.msg import gps`,从而进行gps类型消息的读写。 ## 7.2.2 消息发布节点 与C++的写法类似,我们来看topic用Python如何编写程序,见`topic_demo/scripts/pytalker.py`: ```python #!/usr/bin/env python #coding=utf-8 import rospy #导入自定义的数据类型 from topic_demo.msg import gps def talker(): #Publisher 函数第一个参数是话题名称,第二个参数 数据类型,现在就是我们定义的msg 最后一个是缓冲区的大小 #queue_size: None(不建议) #这将设置为阻塞式同步收发模式! #queue_size: 0(不建议)#这将设置为无限缓冲区模式,很危险! #queue_size: 10 or more #一般情况下,设为10 。queue_size太大了会导致数据延迟不同步。 pub = rospy.Publisher('gps_info', gps , queue_size=10) rospy.init_node('pytalker', anonymous=True) #更新频率是1hz rate = rospy.Rate(1) x=1.0 y=2.0 state='working' while not rospy.is_shutdown(): #计算距离 rospy.loginfo('Talker: GPS: x=%f ,y= %f',x,y) pub.publish(gps(state,x,y)) x=1.03*x y=1.01*y rate.sleep() if __name__ == '__main__': talker() ``` 以上代码与C++的区别体现在这几个方面: 1. rospy创建和初始化一个node,不再需要用NodeHandle。rospy中没有设计NodeHandle这个句柄,我们创建topic、service等等操作都直接用rospy里对应的方法就行。 2. rospy中节点的初始化并一定得放在程序的开头,在Publisher建立后再初始化也没问题。 3. 消息的创建更加简单,比如gps类型的消息可以直接用类似于构造函数的方式`gps(state,x,y)`来创建。 4. 日志的输出方式不同,C++中是`ROS_INFO()`,而Python中是`rospy.loginfo()` 5. 判断节点是否关闭的函数不同,C++用的是`ros::ok()`而Python中的接口是`rospy.is_shutdown()` 通过以上的区别可以看出,roscpp和rospy的接口并不一致,在名称上要尽量避免混用。在实现原理上,两套客户端库也有各自的实现,并没有基于一个统一的核心库来开发。这也是ROS在设计上不足的地方。 ROS2就解决了这个问题,ROS2中的客户端库包括了`rclcpp`(ROS Clinet Library C++)、`rclpy`(ROS Client Library Python),以及其他语言的版本,他们都是基于一个共同的核心ROS客户端库`rcl`来开发的,这个核心库由C语言实现。 ## 7.2.3 消息订阅节点 见`topic_demo/scripts/pylistener.py`: ```cpp #!/usr/bin/env python #coding=utf-8 import rospy import math #导入mgs from topic_demo.msg import gps #回调函数输入的应该是msg def callback(gps): distance = math.sqrt(math.pow(gps.x, 2)+math.pow(gps.y, 2)) rospy.loginfo('Listener: GPS: distance=%f, state=%s', distance, gps.state) def listener(): rospy.init_node('pylistener', anonymous=True) #Subscriber函数第一个参数是topic的名称,第二个参数是接受的数据类型 第三个参数是回调函数的名称 rospy.Subscriber('gps_info', gps, callback) rospy.spin() if __name__ == '__main__': listener() ``` 在订阅节点的代码里,rospy与roscpp有一个不同的地方:rospy里没有`spinOnce()`,只有`spin()`。 建立完talker和listener之后,经过`catkin_make`,就完成了python版的topic通信模型。