1. 程式人生 > >ROS學習筆記16(編寫簡單的訊息釋出器和訂閱器 (Python))

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