一.函數意義
首先要知道,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