參考資料:
https://www.icourse163.org/course/ISCAS-1002580008?tid=1003713012 //中國大學MOOC
https://www.bilibili.com/video/av23401751 //B站
《ROS操作系統入門講義》PDF下載
鏈接:https://pan.baidu.com/s/1OCja2WLDRnjYXMrpnZ3-sQ
提取碼:mziy
第七章 rospy
一、rospy VS roscpp
1、位於 /opt/ros/kinetic/lib/python2.7/dist-packages/rospy //可以視為一個python的模塊
2、區別
(1)rospy沒有一個NodeHandle,創建publisher、subscriber等操作都被直接封裝成了rospy中的函數或類,調用起來簡單直觀
(2)一些接口的命名不一致
注:
- 相比於C++的開發,用Python來寫ROS程序開發效率大大提高
- 但Python的執行效率較低,同樣一個功能用Python運行的耗時會高於C++。因此我們開發SLAM、路徑規划、機器視覺等方面的算法時,往往優先選擇C++
- ROS中絕大多數基本指令,例如 rostopic, roslaunch 都是用python開發的,簡單輕巧
二、ROS中Python代碼的組織方式
1、單獨的python腳本:放於script/路徑下 //適用於簡單程序
your_package
——scripts/
————your_script.py
2、Python模塊 //體量較大的程序
your_package
——src/
————your_package/
——————_init_.py
——————modulefiles.py
——scripts/
————your_script.py
——setup.py
注:
- 在src下建立一個與package同名的文件夾,存放_init_.py和模塊文件
- 常用的ROS命令,大多數其實都是一個個Python模塊,源代碼存放在ros_comm倉庫的tools路徑下:https://github.com/ros/ros_comm/tree/lunar-devel/tools
三、rospy常用API
1、Node相關
2、Topic相關
(1)函數
(2)Publisher類
(3)Subscriber類
3、Service相關
(1)函數
(2)Service類(server)
(3)ServiceProxy類(client)
4、Param相關
(1)函數
5、時鍾相關
(1)函數
(2)Time類
(3)Duration類
(4)Rate類
四、topic in rospy
1、自定義消息及模塊生成
(1)gps.msg的定義:
string state #工作狀態 float32 x #x坐標 float32 y #y坐標
(2)消息模塊生成:創建的msg在catkin_make之后會在~/catkin_ws/devel/lib/python2.7/dist-packages/topic_demo下生成msg模塊(module);隨后可以在python程序中通過 from topic_demo import gps 進行調用
2、消息發布節點
(1)topic_demo/scripts/pytalker.py:
(2)與C++的區別
- rospy中沒有設計NodeHandle句柄,創建topic、service等等操作都直接用rospy里對應的方法
- rospy中節點的初始化不一定得放在程序的開頭,在Publisher建立后再初始化也沒問題
- 消息的創建更加簡單,比如gps類型的消息可以直接用類似於構造函數的方式 gps(state,x,y) 來創建
- 日志的輸出方式不同:C++中是 ROS_INFO() ,而Python中是 rospy.loginfo()
- 判斷節點是否關閉的函數不同:C++用的是 ros::ok() 而Python中的接口是 rospy.is_shutdown()
注:roscpp和rospy的接口並不一致;ROS2中解決了這個問題,不同的客戶端庫rclcpp和rclpy等都是基於共同的核心ROS客戶端庫rcl來開發的
3、消息訂閱節點
(1)topic_demo/scripts/pylistener.py:
(2)與C++區別:rospy里沒有 spinOnce() ,只有spin()
注:建立完talker和listener之后,經過 catkin_make ,就完成了python版的topic通信模型
Python是解釋性語言,不需要使用Cmake進行編譯,可以直接運行,但是“message_generation”需要經過Cmake編譯,生成msg類型
五、service in rospy
1、srv文件 Greeting.srv
string name int32 age --- string feedback
注:必須先修改CMakeLists.txt文件,隨后catkin編譯系統會自動構建自定義的msg、srv和action文件,生成對應的C++、Python、LISP等語言下可用的庫或模塊
建立了一個msg或srv文件,不可以直接在程序中使用,必須在 CMakeLists.txt 中添加關於消息創建、指定消息/服務文件那幾個宏命令
2、提供服務節點(server)
(1)service_demo/scripts/server_demo.py:
(2)與C++區別:server端的處理函數
C++的handle_function()傳入的參數是整個srv對象的request和response兩部分,返回值是bool型,顯示這次服務是否成功地處理
Python的handle_function()傳入的只有request,返回值是response
3、服務請求節點(client)
(1)service_demo/scripts/client_demo.py:
六、param與time
1、相比roscpp中有兩套對param操作的API,rospy關於param的函數就顯得簡單多了,包括了增刪查改等:
rospy.get_param() , rospy.set_param() , rospy.has_param() , rospy.delete_param() , rospy.search_param() , rospy.get_param_names()
2、param_demo:
3、時鍾:rospy中的關於時鍾的操作和roscpp是一致的,都有Time、Duration和Rate三個類 //Time標識的是某個時刻,如22:00;而Duration表示的是時長,如一周;
Time和Duration結構相同:
int32 secs #秒
int32 nsecs #納秒
(1)創建Time和Duration:都是 _init_(self,secs=0, nsecs=0) ,指定秒和納秒
time_now1 = rospy.get_rostime() #當前時刻的Time對象 返回Time對象 time_now2 = rospy.Time.now() #同上 time_now3 = rospy.get_time() #得到當前時間,返回float 4單位秒 time_4 = rospy.Time(5) #創建5s的時刻 duration = rospy.Duration(3*60) #創建3min時長
注:於Time、Duration之間的加減法和類型轉換,和roscpp中的完全一致
4、sleep
duration.sleep() #掛起 rospy.sleep(duration) #同上,這兩種方式效果完全一致 loop_rate = Rate(5) #利用Rate來控制循環頻率 while(rospy.is_shutdown()): loop_rate.sleep() #掛起,會考慮上次loop_rate.sleep的時間
注:Rate類中的sleep主要用來保持一個循環按照固定的頻率,會考慮上次sleep的時間,從而使整個循環嚴格按照指定的頻率
5、定時器Timer:不是用句柄來創建,而是直接 rospy.Timer(Duration, callback) ,第一個參數是時長,第二個參數是回調函數
def my_callback(event): #回調函數的傳入值是 TimerEvent 類型 print 'Timer called at ' + str(event.current_real)
rospy.Timer(rospy.Duration(2), my_callback) #每2s觸發一次callback函數 rospy.spin() #觸發回調函數
注:TimerEvent 類型包括以下屬性
rospy.TimerEvent
last_expected
理想情況下為上一次回調應該發生的時間
last_real
上次回調實際發生的時間
current_expected
本次回調應該發生的時間
current_real
本次回調實際發生的時間
last_duration
上次回調所用的時間(結束-開始)