# 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通信模型。
- 前言
- 第一章 ROS简介
- 机器人时代的到来
- ROS发展历程
- 什么是ROS
- 安装ROS
- 安装ROS-Academy-for-Beginners教学包
- 二进制与源码包
- 安装RoboWare Studio
- 单元测试一
- 第二章 ROS文件系统
- Catkin编译系统
- Catkin工作空间
- Package软件包
- CMakeLists.txt
- package.xml
- Metapacakge软件元包
- 其他常见文件类型
- 单元测试二
- 第三章 ROS通信架构(一)
- Node & Master
- Launch文件
- Topic
- Msg
- 常见msg类型
- 单元测试三
- 第四章 ROS通信架构(二)
- Service
- Srv
- Parameter server
- Action
- 常见srv类型
- 常见action类型
- 单元测试四
- 第五章 常用工具
- Gazebo
- RViz
- Rqt
- Rosbag
- Rosbridge
- moveit!
- 单元测试五
- 第六章 roscpp
- Client Library与roscpp
- 节点初始、关闭与NodeHandle
- Topic in roscpp
- Service in roscpp
- Param in roscpp
- 时钟
- 日志与异常
- 第七章 rospy
- Rospy与主要接口
- Topic in rospy
- Service in rospy
- Param与Time
- 第八章 TF与URDF
- 认识TF
- TF消息
- tf in c++
- tf in python
- 统一机器人描述格式
- 附录:TF数学基础
- 三维空间刚体运动---旋转矩阵
- 三维空间刚体运动---欧拉角
- 三维空间刚体运动---四元数
- 第九章 SLAM
- 地图
- Gmapping
- Karto
- Hector
- 第十章 Navigation
- Navigation Stack
- move_base
- costmap
- Map_server & Amcl
- 附录:Navigation工具包说明
- amcl
- local_base_planner
- carrot_planner
- clear_costmap_recovery
- costmap_2d
- dwa_local_planner
- fake_localization
- global_planner
- map_server
- move_base_msg
- move_base
- move_slow_and_clear
- navfn
- nav_core
- robot_pose_ekf
- rotate_recovery