# 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