ROS中spin()和spinOnce()区别与详解
一.函數(shù)意義
首先要知道,spin()和spinOnce()叫ROS消息回調(diào)處理函數(shù)。它倆通常會(huì)出現(xiàn)在ROS的主循環(huán)中,程序需要不斷調(diào)用ros::spin()或 ros::spinOnce(),兩者區(qū)別在于前者調(diào)用后不會(huì)再返回,也就是你的主程序到這兒就不往下執(zhí)行了,而后者在調(diào)用后還可以繼續(xù)執(zhí)行之后的程序。
其實(shí)消息回調(diào)處理函數(shù)的原理非常簡(jiǎn)單。我們都知道,ROS存在消息發(fā)布訂閱機(jī)制,可以去:http://wiki.ros.org/ROS/Tutorials(ROS官方基礎(chǔ)教程)瞅瞅。
好,我們繼續(xù),如果你的程序?qū)懥讼嚓P(guān)的消息訂閱函數(shù),那么程序在執(zhí)行過(guò)程中,除了主程序以外,ROS還會(huì)自動(dòng)在后臺(tái)按照你規(guī)定的格式,接受訂閱的消息,但是所接到的消息并不是立刻就被處理,而是必須要等到ros::spin()或ros::spinOnce()執(zhí)行的時(shí)候才被調(diào)用,這就是消息回到函數(shù)的原理.
二.區(qū)別
就像上面說(shuō)的,ros::spin()在調(diào)用后不會(huì)再返回,也就是你的主程序到這兒就不往下執(zhí)行了,而ros::spinOnce()后者在調(diào)用后還可以繼續(xù)執(zhí)行之后的程序。
其實(shí)看函數(shù)名也能理解個(gè)差不多,一個(gè)是一直調(diào)用;另一個(gè)是只調(diào)用一次,如果還想再調(diào)用,就需要加上循環(huán)了。
這里一定要記住,ros::spin()函數(shù)一般不會(huì)出現(xiàn)在循環(huán)中,因?yàn)槌绦驁?zhí)行到spin()后就不調(diào)用其他語(yǔ)句了,也就是說(shuō)該循環(huán)沒(méi)有任何意義,還有就是spin()函數(shù)后面一定不能有其他語(yǔ)句(return 0 除外),有也是白搭,不會(huì)執(zhí)行的。ros::spinOnce()的用法相對(duì)來(lái)說(shuō)很靈活,但往往需要考慮調(diào)用消息的時(shí)機(jī),調(diào)用頻率,以及消息池的大小,這些都要根據(jù)現(xiàn)實(shí)情況協(xié)調(diào)好,不然會(huì)造成數(shù)據(jù)丟包或者延遲的錯(cuò)誤。
特別強(qiáng)調(diào)一下:如果你寫(xiě)了相關(guān)的消息訂閱函數(shù),千萬(wàn)不要忘了在相應(yīng)的位置加上ros::spin()或者ros::spinOnce()函數(shù),
不然你永遠(yuǎn)得不到另一邊發(fā)來(lái)的數(shù)據(jù)。
三.例程
1.spin()函數(shù)用法簡(jiǎn)單,一般在主程序最后加上該語(yǔ)句就可以了。
發(fā)送端
#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 發(fā)送消息, 發(fā)送頻率為10Hz(1秒發(fā)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() 將會(huì)進(jìn)入循環(huán), 一直調(diào)用回調(diào)函數(shù)chatterCallback(),每次調(diào)用1000個(gè)數(shù)據(jù)。
* 當(dāng)用戶輸入Ctrl+C或者ROS主進(jìn)程關(guān)閉時(shí)退出,
*/
ros::spin();
return 0;
}
2.spinOnce()函數(shù)
對(duì)于ros::spinOnce的使用,比ros::spin()更加靈活,可以放在程序的任何位置下,但是需要考慮一下因素。
注意:對(duì)于有些傳輸特別快的消息,尤其需要注意合理的控制消息池大小和ros::spinOnce()執(zhí)行頻率,比如消息發(fā)送的頻率為
10HZ,ros::spinOnce的調(diào)用頻率為5hz,那么消息池的大小一定要大于2,才能保證數(shù)據(jù)不丟失,無(wú)延遲。
發(fā)送端
#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 發(fā)送消息, 發(fā)送頻率為10Hz(1秒發(fā)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
總結(jié)
以上是生活随笔為你收集整理的ROS中spin()和spinOnce()区别与详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Linux 使用 yum 查看安装的软件
- 下一篇: Sqlserver 数据库安全