iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 3
0
Software Development

ROS進階學習筆記系列 第 3

Day 03 - Callback Function的好朋友 Spin & SpinOnce

  • 分享至 

  • xImage
  •  

在實作topic的publish/subscribe時,一定會用到的rospy::spin()ros::spin()ros::spinOnce(),那麼這三者的差異是什麼呢? 讓筆者一個一個解釋吧!

rospy::spin()

rospy::spin()是撰寫python程式時所使用的API,目的是為了讓程式hang在那行而不會shutdown,所以在定義完接收的message topic和callback function後,呼叫rospy::spin()就可以讓程式不會終止,而收到別的publisher傳來的topic就可以執行原來定義的callback了。
這個API跟c++版本的ros::spin()不太一樣,原因是因為他並沒有實作到c++的spin()所具有的功能,在ros官網提到這件事情的時候只是簡短的寫了兩行帶過:

The final addition, rospy.spin() simply keeps your node from exiting until the node has been shutdown. Unlike roscpp, rospy.spin() does not affect the subscriber callback functions, as those have their own threads.
用法:

if __name__ == '__main__':
    rospy.init_node('listener', anonymous=True)
    rospy.Subscriber("tester", String, callback)
    rospy.spin() #讓程式停在這行不會繼續往下執行

因為rospy::spin()的用途只是讓程式停在這行不會繼續往下執行,所以其實用while + ros sleep 也可以達到相同的效果。

ros::spin()

ros::spin()基本上就是c++版本的rospy::spin(),不過多了一個功能是在呼叫該API時才會一併執行已收到topic message的callback function。聽起來很抽象吧哈哈,用code來介紹好了:

int main(int argc, char **argv){
    ros::init(argc, argv, "node_name");
    ros::NodeHandle n;
    ros::Subscriber sub = n.subscribe("topic", 1000, D);

    A();
    B(); //假設在執行其他行程式碼的時候收到/topic送來的message
    C();

    ros::spin();  //在呼叫這行的時候才會執行上面已經定義的callback function D()
    return 0;
}

假設ABCD四支程式都是print一個英文字母,程式執行的結果就會如下:

A
B
C
D
D
D
... //假設一直收到topic的話

跟python版的差異應該就是,python版只要定義好subscriber以後,一收到topic就會馬上執行callback,而c++版的則要一直到呼叫ros::spin()以後才會執行callback,兩支API的共通點是會讓程式停在那行不繼續往下實作或終止。

ros::spinOnce()

最後一個ros::spinOnce(),看名字就知道他只會執行一次,跟ros::spin()一樣,呼叫到此API時才會一併執行callback。至於為什麼需要這樣做呢?目的是為了控制callback function,避免race condition(什麼是race condition?)。
spinOnce的通常用法是包在迴圈內,在迴圈的開始或結束的地方呼叫,如下:

int main(int argc, char **argv){
    ros::init(argc, argv, "node_name");
    ros::NodeHandle n;
    ros::Subscriber sub = n.subscribe("topic", 1000, D);

    while(ros::ok()){    
        A();
        B();
        C();
        ros::spinOnce();
    }
    
    return 0;
}

執行結果如下:

A
B
C
D
A
B
C
D
... //假設一直收到topic的話

因此,在一支程式內需要使用迴圈進行運算,並且需要透過callback function來改變迴圈內的運算時,就可以使用spinOnce()進行控制囉!

總結

rospy::spin() 是python版本的spin(),用來避免程式終止。
ros::spin()是C++版本,其目的也是避免程式終止,不過只有在呼叫到該API時才開始執行callback function。
ros::spinOnce()是C++版本才有的功能,其目的是為了避免程式產生race condtion,在呼叫到該API時才執行callback function,並且只會執行一次。

Reference

http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber%28python%29
https://get-help.robotigniteacademy.com/t/what-is-rospy-spin-ros-spin-ros-spinonce-and-what-are-they-for/58
https://programming.vip/docs/ros-ros-spin-and-ros-spinonce-differences-and-use.html
https://www.itread01.com/content/1545056495.html
http://wiki.ros.org/roscpp/Overview/Callbacks%20and%20Spinning


上一篇
Day 02 - ROS / ROS2.0 都幾?
下一篇
Day 04 - Callback Function Arguments加在哪?
系列文
ROS進階學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言