在话题发布和订阅中,消息订阅器一旦知道话题上面有消息发布,就会将消息的值作为参数传入回调函数中,把回调函数放到了一个回调函数队列中,它们的函数名一样,只是实参不一样,这就是subscribe函数的作用。但是此时还没有执行callback函数,当spinOnce函数被调用时,spinOnce就会调用回调函数队列中第一个callback函数,此时回调函数才被执行,然后等到下次spinOnce函数又被调用时,回调函数队列中第二个回调函数就会被调用,以此类推。
注意:因为回调函数队列的长度是有限的,如果发布数据的速度太快,spinOnce函数调用的频率太少,就会导致队列溢出,一些回调函数就会被挤掉,导致没被执行。
对于spin函数,一旦进入spin函数,它就不会返回了,相当于它在自己的函数里阻塞。只要回调函数队列里面有回调函数在,它就会马上去执行。如果没有的话,它就会阻塞,不会占用CPU。
spin()的目的是启动一个新的线程去获取队列中的回调函数并调用它,而回调函数本身不是线程 ,有单线程,同步多线程和异步多线程等情况,这些都有内置的语句。所有用户的调用程序将从 ros::spin()
开始调用,只到节点关闭,ros::spin()
才有返回值。
ros::spin
其实就相当于1
2
3
4
5while(ros::ok())
{
// Do Something
ros::spinOnce();
}
发布和订阅话题都不一定要使用spinOnce()
,如果仅仅只是响应topic,就用ros::spin()
,当程序中除了响应回调函数还有其他重复性工作的时候,那就在循环中做那些工作,然后调用ros::spinOnce()
spinOnece的注意事项
我仔细试验了这几个参数,没有发现缺失回调函数的情况,一般不需要太注意ros::spinOnce()的用法相对来说很灵活,但往往需要考虑调用消息的时机,调用频率,以及消息池的大小。
比如下面的程序,消息送达频率为10Hz,ros::spinOnce()
的调用频率为5Hz,那么消息池的大小就一定要大于2,才能保证数据不丢失,无延迟,跟这里的发布消息池容量无关
1 | //发送频率为10Hz(1秒发10次) 消息池最大容量1000。 |
看一下源码:1
2
3
4void spinOnce()
{
g_global_queue->callAvailable(ros::WallDuration());
}
调用队列中的所有回调函数,如果一个回调还没有准备好调用,再推回队列