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

#!/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

#!/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通信模型。

results matching ""

    No results matching ""