1. 程式人生 > >ROS學習第五彈(釋出和訂閱 Python寫 Publisher and Subscriber)

ROS學習第五彈(釋出和訂閱 Python寫 Publisher and Subscriber)

1.寫一個釋出節點

節點是ROS中被ROS網路連線起來的可執行的項,我們將建立一個釋出節點來持續廣播訊息。

首先去教程包的地址:

roscd beginner_tutorials
1.1 程式碼

需要建立一個script的指令碼資料夾並儲存Python程式碼:

$ mkdir scripts
$ cd scripts
然後下載所需指令碼:
$ wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/talker.py
完成後給許可權:
$ chmod +x talker.py
可以檢視一下程式碼:

#!/usr/bin/env python

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 程式碼解釋

其實要是Python學得好的話,這一段可以不看,不過看一下並沒什麼壞處:

第一行:#!/usr/bin/env python

每一個Python的ROS節點都會在第一行申明所有的編譯語言,確保是用Python來執行這個指令碼。

import rospy
from std_msgs.msg import String

如果你是正在寫一個ROS節點,那你需要匯入rospy包。 而std_msgs.msg匯入是為了讓我們能夠重新使用std_msgs/String 的message型別來寫一個釋出。


def talker():
    pub = rospy.Publisher('chatter', String, queue_size=10)
    rospy.init_node('talker', anonymous=True)

定義一個Python函式talker,這裡可以理解為開始寫ROS節點,而接下來的兩行是定義talker和其他ROS包之間的介面

pub = rospy.Publisher('chatter', String, queue_size=10) 申明瞭該節點是用chatter主題,String型別的message,而這裡的String其實是std_msgs.msg.String

引數queue_size是在ROS hydro中是NEW,是為了限制在訂閱節點沒有很快的接收發布的資訊時的限制排隊的數量,以前的版本中都沒有這個特性。

rospy.init_node('talker', anonymous=True)這一行是非常重要的,它負責告訴rospy申明節點的名稱,除非在rospy已經知道的情況下,否則,我們申明的節點將沒法和主節點通訊。

在本例中,名稱將申明為talker,注意名稱中不得含有‘/’字元

anonymous = True 這一行在我們的例子中沒有,但官方文件中有,它的作用是在節點名稱的末尾加上一個隨機數確保節點名稱唯一。這個屬於ROS節點的初始化,更多屬性可以參考:http://wiki.ros.org/rospy/Overview/Initialization%20and%20Shutdown#Initializing_your_ROS_Node

rate = rospy.Rate(10) # 10hz 這一行建立了一個速率物件,它其實是用的sleep函式來實現的。10的意思是每秒發出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_shudown()標誌然後執行執行一些命令。如果你的程式要退出,你必須檢查check_is_shutdown(),在本例中,

迴圈當中要做的工作是pub.publish(hello_str),就是傳送一個字串到chatter主題,迴圈呼叫rate.sleep(),產生我們所需的迴圈速率。

(你也可以執行rospy.sleep(),它和time.sleep()很相似,不過它還有個特性是與模擬時間一起使用)

rospy.loginfo(hello_str),它執行有三個用處:第一,這個字串資訊將會列印到螢幕上;第二,資訊將會被寫入節點的日誌檔案;第三,資訊將會被寫入rosout,這樣究可以方便的

呼叫rqt_console檢視除錯結果而不用Node的輸出找到控制檯視窗。

std.msgs.msg.String是一個非常簡單的資訊型別,所有你可能會想釋出更加複製的資訊型別將會是什麼效果。一般的經驗法則是,建構函式args與.msg檔案中的順序相同。您也可以傳遞任何引數,也可以直接初始化欄位。

例:

msg = String()
msg.data = str
或者你可以初始化一些欄位,讓另一些欄位保持預設值:
String(data=str)

這個檔案中最後的一塊塊內容:
if __name__ == '__main__':
    try:
        talker()
    except rospy.ROSInterruptException:
        pass

除了標準的Python_main_檢查外,這段程式碼還會捕獲一個ros.ROSInterruptException異常,當終端被ctrl+C或者節點被關閉時,它將被rospy.sleep()和rospy.Rate.sleep()方法丟擲。

捕獲這個異常是讓sleep()被關閉後,其餘程式碼不會一直在執行。

接下來寫一個接收訊息的節點。

2. 寫一個訂閱節點(Subscriber Node)

2.1  程式碼

下載監聽檔案到指令碼目錄:

roscd beginner_tutorials/scripts/

wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/listener.py

給許可權 :chmod +x listener.py

程式碼:

#!/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
    # name 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()

以上程式碼是一種新的基於回撥機制的訂閱資訊方法,  rospy.Subscriber('chatter', String, callback)申明瞭節點訂閱型別為std_msgs.msg.String的

chatter主題的資訊。當收到資訊時,callback將作為第一個引數被呼叫。

而在rospy.init_node('listener', anonymous=True)的呼叫中,也有些不一樣,添加了anonymous=True的關鍵字引數。ROS要求每一個節點都有唯一的名稱。

如果有重名,在使用節點時就會啟用之前的節點,而這個關鍵字的運用將避免產生這一狀況,讓我們可以輕鬆的執行很多listener.py的節點。

最後是rospy.spin(), 它的新增是為了讓你的節點不會退出直到節點被關閉。與roscpp不同,rospy.spin()不會影響到訂閱者的回撥函式,他們有自己的執行緒。

3. 編譯你的節點

我們用cmake來編譯系統,即便是使用的Python節點,也必須使用它。這是自動生成的Python訊息和服務被建立:

cd ~/catkin_ws

catkin_make

現在,一個簡單的Python訂閱和釋出已經做好了,如何執行請看第下一彈。