ROS教程四——編寫Publisher和Subscriber節點(Python篇)
本教程介紹如何在python中編寫釋出者和訂閱者節點
1、編寫Publisher節點
“節點”是連線到ROS網路的可執行檔案的ROS術語。在這裡,我們將建立廣播訊息的 publisher(“talker”)節點。
將目錄更改為之前教程中建立的beginner_tutorials包:
$ roscd beginner_tutorials
1.1 程式碼
首先,建立一個'scripts'資料夾來儲存你的Python指令碼:
$ mkdir scripts
$ cd scripts
talker.py原始碼如下:
#!/usr/bin/env python # license removed for brevity import rospy from std_msgs.msg import String def talker(): pub = rospy.Publisher('chatter', String, queue_size=10) rospy.init_node('talker', anonymous=True) rate = rospy.Rate(10) # 10hz while not rospy.is_shutdown(): hello_str = "hello world %s" % rospy.get_time() rospy.loginfo(hello_str) pub.publish(hello_str) rate.sleep() if __name__ == '__main__': try: talker() except rospy.ROSInterruptException: pass
1.2 程式碼解釋
#!/usr/bin/env python
每個Python ROS節點都會在頂部顯示此宣告。第一行確保您的指令碼作為Python指令碼執行。
import rospy
from std_msgs.msg import String
編寫ROS節點,則需要匯入rospy。std_msgs.msg匯入是為了可以重用std_msgs / String訊息型別(一個簡單的字串容器)進行釋出。
pub = rospy.Publisher('chatter', String, queue_size=10) rospy.init_node('talker', anonymous=True)
這部分程式碼定義了talker與其它ROS的介面。pub = rospy.Publisher("chatter", String, queue_size=10) 宣告節點使用String訊息型別,釋出到chatter主題。這裡的字串實際上是類std_msgs.msg.String。queue_size引數在ROS hydro中是新的型別,如果任何訂戶沒有足夠快地接收它們,則限制排隊訊息的數量。在舊的ROS發行版中,只省略了這個論點。
下一行rospy.init_node(NAME,...)非常重要,因為它釋出rospy節點的名稱 - 直到rospy有這個資訊,它才能開始與ROS 主機通訊。在這種情況下,節點將採用名稱talker。注意:名稱必須是基本名稱,即它不能包含任何斜槓“/”。
rate = rospy.Rate(10) # 10hz
此行建立Rate物件速率。藉助其方法sleep(),它提供了一種以所需速率迴圈的便捷方式。它的引數為10,我們應該期望每秒迴圈10次(只要我們的處理時間不超過1/10秒!)
while not rospy.is_shutdown():
hello_str = "hello world %s" % rospy.get_time()
rospy.loginfo(hello_str)
pub.publish(hello_str)
rate.sleep()
這個迴圈是一個相當標準的rospy構造:檢查rospy.is_shutdown()標誌然後做工作。檢查程式是否應該退出(例如,如果有Ctrl-C或其他)。在這種情況下,“work”是對pub.publish(hello_str)的呼叫,它將字串釋出到我們的talker主題。迴圈呼叫rate.sleep(),保持迴圈所需的速率。
也可以執行rospy.sleep(),它類似於time.sleep(),但它也適用於模擬時間(請參閱Clock)。
這個迴圈還呼叫rospy.loginfo(str),它執行三重任務:訊息被列印到螢幕,它被寫入Node的日誌檔案,並被寫入rosout。rosout對於除錯非常方便:您可以使用rqt_console來提取訊息,而不必使用Node的輸出找到控制檯視窗。
std_msgs.msg.String是一種非常簡單的訊息型別。一般的經驗法則是建構函式args的順序與.msg檔案中的順序相同。也可以不傳入引數並直接初始化欄位,例如
msg = String()
msg.data = str
或者可以初始化某些欄位,並將其餘欄位保留為預設值:
String(data=str)
最後一點:
try:
talker()
except rospy.ROSInterruptException:
pass
除了標準的Python __main__檢查之外,這還會捕獲一個rospy.ROSInterruptException異常,當按下Ctrl-C或者你的節點關閉時,rospy.sleep()和rospy.Rate.sleep()方法可以丟擲該異常。引發此異常的原因是不會在sleep()之後意外地繼續執行程式碼。
2、編寫Subscriber節點
2.1 程式碼
#!/usr/bin/env python
import rospy
from std_msgs.msg import String
def callback(data):
rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
def listener():
# In ROS, nodes are uniquely named. If two nodes with the same
# node are launched, the previous one is kicked off. The
# anonymous=True flag means that rospy will choose a unique
# name for our 'listener' node so that multiple listeners can
# run simultaneously.
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("chatter", String, callback)
# spin() simply keeps python from exiting until this node is stopped
rospy.spin()
if __name__ == '__main__':
listener()
2.2 程式碼解釋
listener.py的程式碼類似於talker.py,除了引入了一個新的基於回撥的機制來訂閱訊息。
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("chatter", String, callback)
# spin() simply keeps python from exiting until this node is stopped
rospy.spin()
這宣告的節點訂閱了std_msgs.msgs.String型別的chatter主題。收到新訊息時,將呼叫回撥函式,並將訊息作為第一個引數。
也稍微改變了對rospy.init_node()的呼叫。添加了anonymous = True關鍵字引數。ROS要求每個節點都有唯一的名稱。如果出現具有相同名稱的節點,則會突然顯示前一個節點。這樣可以很容易地將故障節點從網路中踢出。anonymous = True標誌告訴rospy為節點生成一個唯一的名稱,以便可以輕鬆執行多個listener.py節點。
最後新增,rospy.spin()只是讓節點退出,直到節點關閉。與roscpp不同,rospy.spin()不會影響訂閱者回調函式,因為它們有自己的執行緒。
3、編譯 nodes
使用CMake作為構建系統,即使是Python節點也必須使用它。這是為了確保建立訊息和服務的自動生成的Python程式碼。
轉到catkin工作區並執行catkin_make
$ cd ~/catkin_ws
$ catkin_make
既然已經編寫了一個簡單的釋出者和訂閱者,讓我們來檢視ROS教程五-執行簡單的釋出者和訂閱者。