【轉】ros::spin() 和 ros::spinOnce() 區別及詳解

來源:互聯網
上載者:User

標籤:理解   丟失   als   roc   周期性   意義   border   info   http   

本文轉載自: http://www.cnblogs.com/liu-fa/p/5925381.html

博主提示:本文基於ROS Kinetic Kame,如有更(gèng)新版本,可能存在細微差別,請大兄弟以官方資料為準。

博主向來愚鈍,若大兄弟發現該文章有不妥之處,還請速速告知。

1 函數意義

首先要知道,這倆兄弟學名叫ROS訊息回調處理函數。它倆通常會出現在ROS的主迴圈中,程式需要不斷調用ros::spin() 或 ros::spinOnce(),兩者區別在於前者調用後不會再返回,也就是你的主程式到這兒就不往下執行了,而後者在調用後還可以繼續執行之後的程式。

其實訊息回調處理函數的原理非常簡單。我們都知道,ROS存在訊息發布訂閱機制,什嗎?不知道?不知道還不快去:http://wiki.ros.org/ROS/Tutorials (ROS官方基礎教程) 瞅瞅。

好,我們繼續,如果你的程式寫了相關的訊息訂閱函數,那麼程式在執行過程中,除了主程式以外,ROS還會自動在後台按照你規定的格式,接受訂閱的訊息,但是所接到的訊息並不是立刻就被處理,而是必須要等到ros::spin()或ros::spinOnce()執行的時候才被調用,這就是訊息回到函數的原理,怎麼樣,簡單吧,至於為什麼這麼設計?咳咳,嗯,肯定有他的道理。。。

2 區別

就像上面說的,ros::spin() 在調用後不會再返回,也就是你的主程式到這兒就不往下執行了,而 ros::spinOnce() 後者在調用後還可以繼續執行之後的程式。

其實看函數名也能理解個差不多,一個是一直調用;另一個是只調用一次,如果還想再調用,就需要加上迴圈了。

這裡一定要記住,ros::spin()函數一般不會出現在迴圈中,因為程式執行到spin()後就不調用其他語句了,也就是說該迴圈沒有任何意義,還有就是spin()函數後面一定不能有其他語句(return 0 除外),有也是白搭,不會執行的。ros::spinOnce()的用法相對來說很靈活,但往往需要考慮調用訊息的時機,調用頻率,以及訊息池的大小,這些都要根據現實情況協調好,不然會造成資料丟包或者延遲的錯誤。

3 常見使用方法

這裡需要特彆強調一下,如果大兄弟你的程式寫了相關的訊息訂閱函數,那千萬千萬千萬不要忘了在相應位置加上ros::spin()或者ros::spinOnce()函數,不然你是永遠都得不到另一邊發出的資料或訊息的,博主血的教訓,萬望緊記。。。

3.1 ros::spin()

ros::spin()函數用起來比較簡單,一般都在主程式的最後,加入該語句就可。例子如下:

發送端:
123456789101112131415161718192021222324252627282930 #include "ros/ros.h"#include "std_msgs/String.h"#include <sstream> int main(int argc, char **argv){    ros::init(argc, argv, "talker");    ros::NodeHandle n;    ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);    ros::Rate loop_rate(10);     int count = 0;    while (ros::ok())    {        std_msgs::String msg;        std::stringstream ss;        ss << "hello world " << count;        msg.data = ss.str();        ROS_INFO("%s", msg.data.c_str());         /**         * 向 Topic: chatter 發送訊息, 發送頻率為10Hz(1秒發10次);訊息池最大容量1000。         */        chatter_pub.publish(msg);         loop_rate.sleep();        ++count;    }    return 0;}
接收端:
123456789101112131415161718192021 #include "ros/ros.h"#include "std_msgs/String.h" void chatterCallback(const std_msgs::String::ConstPtr& msg){    ROS_INFO("I heard: [%s]", msg->data.c_str());} int main(int argc, char **argv){    ros::init(argc, argv, "listener");    ros::NodeHandle n;    ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);     /**     * ros::spin() 將會進入迴圈, 一直調用回呼函數chatterCallback(),每次調用1000個資料。     * 當使用者輸入Ctrl+C或者ROS主進程關閉時退出,     */    ros::spin();    return 0;}
3.2 ros::spinOnce()

對於ros::spinOnce()的使用,雖說比ros::spin()更自由,可以出現在程式的各個部位,但是需要注意的因素也更多。比如:

1 對於有些傳輸特別快的訊息,尤其需要注意合理控制訊息池大小和ros::spinOnce()執行頻率; 比如訊息送達頻率為10Hz, ros::spinOnce()的調用頻率為5Hz,那麼訊息池的大小就一定要大於2,才能保證資料不丟失,無延遲。接收端:
123456789101112131415161718192021222324 #include "ros/ros.h"#include "std_msgs/String.h"  void chatterCallback(const std_msgs::String::ConstPtr& msg){    /*...TODO...*/ }  int main(int argc, char **argv){    ros::init(argc, argv, "listener");    ros::NodeHandle n;    ros::Subscriber sub = n.subscribe("chatter", 2, chatterCallback);      ros::Rate loop_rate(5);    while (ros::ok())    {        /*...TODO...*/          ros::spinOnce();        loop_rate.sleep();    }    return 0;}

 

2 ros::spinOnce()用法很靈活,也很廣泛,具體情況需要具體分析。但是對於使用者自訂的周期性的函數,最好和ros::spinOnce並列執行,不太建議放在回呼函數中;

 

1234567891011 /*...TODO...*/ros::Rate loop_rate(100);  while (ros::ok()){    /*...TODO...*/    user_handle_events_timeout(...);     ros::spinOnce();                     loop_rate.sleep();}

【轉】ros::spin() 和 ros::spinOnce() 區別及詳解

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.