ROS學習筆記16(編寫簡單的訊息釋出器和訂閱器 (Python))
1 編寫釋出者節點
“節點”是連線到ROS網路的可執行檔案ROS術語。在這裡,我們將建立一個持續廣播訊息的釋出者(“talker”)節點。
將目錄更改為您在早期教程中建立的的beginner_tutorials包,並建立一個包:
$ roscd beginner_tutorials
1.1 程式碼
首先,我們建立一個“scripts”資料夾來儲存我們的Python指令碼:
$ mkdir scripts
$ cd scripts
然後將示例指令碼talker.py下載到新指令碼目錄並使其可執行(更改許可權):
$ wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/talker.py $ chmod +x talker.py
您可以使用 $ rosed beginner_tutorials talker.py 這個操作檢視和編輯該檔案。
1 #!/usr/bin/env python 2 # license removed for brevity 3 import rospy 4 from std_msgs.msg import String 5 6 def talker(): 7 pub = rospy.Publisher('chatter', String, queue_size=10) 8 rospy.init_node('talker', anonymous=True) 9 rate = rospy.Rate(10) # 10hz 10 while not rospy.is_shutdown(): 11 hello_str = "hello world %s" % rospy.get_time() 12 rospy.loginfo(hello_str) 13 pub.publish(hello_str) 14 rate.sleep() 15 16 if __name__ == '__main__': 17 try: 18 talker() 19 except rospy.ROSInterruptException: 20 pass
1.2 程式解釋
現在,我們在這裡停頓
1 #!/usr/bin/env python
每個Python ROS 節點都會在頂部進行此宣告。第一行是確保您的指令碼作為Python指令碼執行。
3 import rospy
4 from std_msgs.msg import String
如果您正在編寫ROS 節點,則需要匯入rospy(以Python語言的確如此)。
匯入std_msgs.msg則是使得我們可以重新使用std_msgs /String訊息型別(一個簡單的字串容器)。
7 pub = rospy.Publisher('chatter', String, queue_size=10) 8 rospy.init_node('talker', anonymous=True)
這部分程式碼定義了talker與其餘ROS的介面。
pub = rospy.Publisher(“chatter”,String,queue_size = 10)宣告您的節點使用訊息型別String,以及釋出話題名為“chatter”。
這裡的String實際上是類std_msgs.msg.String。
queue_size表示佇列的大小(適用於hydro以後的版本)。在舊版本中,則被漏掉了這個引數。
ospy.init_node(NAME,...)則是非常重要,因為它告訴rospy這個節點的名稱。直到rospy有這個資訊,它才能開始與ROS Master通訊。在這種情況下,節點將採用名稱“talker”。
注意:名稱必須是基本名稱,即它不能包含任何斜槓“/”。
anonymous = True這行程式則通過在NAME末尾新增隨機數來確保您的節點具有唯一名稱。
9 rate = rospy.Rate(10) # 10hz
此行建立Rate物件 rate。藉助其方法sleep(),它提供了一種以所需速率的便捷迴圈方式。它的引數為10,我們應該期望每秒迴圈10次(只要我們的處理時間不超過1/10秒即可!)
10 while not rospy.is_shutdown():
11 hello_str = "hello world %s" % rospy.get_time()
12 rospy.loginfo(hello_str)
13 pub.publish(hello_str)
14 rate.sleep()
這個迴圈是一個相當標準的rospy構造:檢查rospy.is_shutdown()標誌位然後開始迴圈。使用is_shutdown()以檢查你的程式是否應該退出(例如,如果有Ctrl-C或其他)。
然後,程式對pub.publish(hello_str)進行呼叫,然後將字串釋出到我們的“chatter”話題上。
迴圈呼叫rate.sleep(),它睡眠的時間足夠長,可以保持迴圈所需的速率。
(您也可以執行rospy.sleep(),有點類似於time.sleep(),但在模擬時間有差別,具體可以參考Clock)
這個迴圈呼叫rospy.loginfo(str),它執行三重任務:訊息被輸出到螢幕,它被寫入Node的日誌檔案,也被寫入rosout。
rosout對於除錯非常方便:您可以使用rqt_console來提取訊息,而不必使用Node輸出的控制檯視窗。
std_msgs.msg.String是一種非常簡單的訊息型別,因此您可能想知道釋出更復雜型別的樣子。一般的經驗法則是建構函式的引數的順序與.msg檔案中的順序相同。您也可以不傳遞引數並直接初始化欄位,例如
msg = String()
msg.data = str
或者您可以初始化某些欄位,並將其餘欄位保留為預設值:
String(data=str)
你可能想知道最後一點:
17 try: 18 talker() 19 except rospy.ROSInterruptException: 20 pass
除了標準的Python __main__檢查之外,這還會捕獲一個rospy.ROSInterruptException異常,當按下Ctrl-C或者你的節點關閉時,rospy.sleep()和rospy.Rate.sleep()方法可以丟擲該異常。新增此異常的原因是程式不會在sleep()之後繼續執行。
現在我們需要編寫一個節點來接收訊息。
2 編寫訂戶節點
2.1 程式碼
$ roscd beginner_tutorials / scripts /
$ wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/listener.py
檔案內容看起來接近:
1 #!/usr/bin/env python 2 import rospy 3 from std_msgs.msg import String 4 5 def callback(data): 6 rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data) 7 8 def listener(): 9 10 # In ROS, nodes are uniquely named. If two nodes with the same 11 # node are launched, the previous one is kicked off. The 12 # anonymous=True flag means that rospy will choose a unique 13 # name for our 'listener' node so that multiple listeners can 14 # run simultaneously. 15 rospy.init_node('listener', anonymous=True) 16 17 rospy.Subscriber("chatter", String, callback) 18 19 # spin() simply keeps python from exiting until this node is stopped 20 rospy.spin() 21 22 if __name__ == '__main__': 23 listener()
不要忘記使節點更改檔案許可權使得可執行:
$ chmod +x listener.py
2.2 程式解釋
listener.py的程式碼類似於talker.py,除了我們引入了一個新的回撥函式機制來訂閱訊息。
15 rospy.init_node('listener', anonymous=True) 16 17 rospy.Subscriber("chatter", String, callback) 18 19 # spin() simply keeps python from exiting until this node is stopped 20 rospy.spin()
聲明瞭一個型別是std_msgs.msgs.String的“chatter”話題。收到新訊息時,將呼叫回撥函式,並將訊息作為第一個引數傳遞到函式裡。當然我們也稍微改變了對rospy.init_node()的呼叫。我們添加了anonymous = True關鍵字引數。ROS要求每個節點都有唯一的名稱。如果出現具有相同名稱的節點,那麼ROS就會中止之前同名的節點,這樣可以很容易地將故障節點從網路中踢出。該anonymous=True標誌位告訴rospy為節點生成一個唯一的名稱,以便您可以有多個listener.py節點同時執行。
最後新增rospy.spin()只是保持節點執行,直到節點關閉。與roscpp不同,rospy.spin()不會影響訂閱者回調函式,因為它們有自己獨立的執行緒。
3 構建節點
我們使用CMake作為構建系統,是的,即使是Python節點也必須使用它。這確保針對訊息和服務能自動生成Python程式碼。
轉到catkin工作區並執行catkin_make:
$ cd~ / catkin_ws
$ catkin_make