1. 程式人生 > 其它 >ROS中spin()和spinOnce()區別與詳解

ROS中spin()和spinOnce()區別與詳解

一.函式意義

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

其實訊息回撥處理函式的原理非常簡單。我們都知道,ROS存在訊息釋出訂閱機制,可以去:http://wiki.ros.org/ROS/Tutorials(ROS官方基礎教程)瞅瞅。

好,我們繼續,如果你的程式寫了相關的訊息訂閱函式,那麼程式在執行過程中,除了主程式以外,ROS還會自動在後臺按照你規定的格式,接受訂閱的訊息,但是所接到的訊息並不是立刻就被處理,而是必須

要等到ros::spin()或ros::spinOnce()執行的時候才被呼叫,這就是訊息回到函式的原理.

二.區別

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

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

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

特別強調一下:如果你寫了相關的訊息訂閱函式,千萬不要忘了在相應的位置加上ros::spin()或者ros::spinOnce()函式,

不然你永遠得不到另一邊發來的資料。

三.例程

1.spin()函式用法簡單,一般在主程式最後加上該語句就可以了。

傳送端

#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; }

接收端

#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;
}

2.spinOnce()函式

對於ros::spinOnce的使用,比ros::spin()更加靈活,可以放在程式的任何位置下,但是需要考慮一下因素。

注意:對於有些傳輸特別快的訊息,尤其需要注意合理的控制訊息池大小和ros::spinOnce()執行頻率,比如訊息傳送的頻率為

10HZ,ros::spinOnce的呼叫頻率為5hz,那麼訊息池的大小一定要大於2,才能保證資料不丟失,無延遲。

傳送端

#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;
}

接受端

/**接收端**/

#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; }

感謝原博主:

http://www.cnblogs.com/liu-fa/p/5925381.html