DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> 關於JavaScript >> ros::spin() 和 ros::spinOnce()函數的區別及詳解
ros::spin() 和 ros::spinOnce()函數的區別及詳解
編輯:關於JavaScript     

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()函數用起來比較簡單,一般都在主程序的最後,加入該語句就可。例子如下:

發送端:

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

3.2 ros::spinOnce()

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

1 對於有些傳輸特別快的消息,尤其需要注意合理控制消息池大小和ros::spinOnce()執行頻率; 比如消息送達頻率為10Hz, ros::spinOnce()的調用頻率為5Hz,那麼消息池的大小就一定要大於2,才能保證數據不丟失,無延遲。

/**接收端**/<br>#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並列執行,不太建議放在回調函數中;

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

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved