ros::spin()和ros::spinOnce()

ros::spin()和ros::spinOnce()的作用

ROS monitor socket负责接受所有订阅的消息。当一个新消息到来,ROS将其对应的回调函数放到队列中。ROS不会立即调用这些回调函数,而是等到ros::spinOnce()到来时才会处理。

很少有应用场景适合直接采用ros::spinOnce(),下面的特殊情况需要特殊处理。

  1. 以一定间隔处理回调

    一般而言,你很少会希望ROS回调函数只在固定的时间间隔被调用。比如一个消息的频率为100HZ,而ros::spinOnce()仅仅5HZ,而同时queue_size为1,那么你将丢失95/100的消息。

    这种情况下,使用ROS::Timer是一个更好的选择。

  2. 存在ROS以外的其他回调函数

    比如使用另一个需要处理异步消息的库,你就需要将这个库中类似于spinOnce()的函数同spinOnce()一起放到主循环函数中。

    1
    2
    3
    4
    5
    6
    7
    ros::Rate r(100);
    while (ros::ok())
    {
    libusb_handle_events_timeout(...); // Handle USB events
    ros::spinOnce(); // Handle ROS events
    r.sleep();
    }
  3. 将ROS集成到其他框架中

    例如在使用OpenGL和GLUT时,一种集成ROS的方法是告诉GLUT的主循环,每10ms就调用以下ros::spinOnce():

    1
    2
    3
    4
    void timerCb(int value) { ros::spinOnce(); }

    glutTimerFunc(10, timerCb, 0);
    glutMainLoop(); // Never returns

ros::spin()和ros::spinOnce()的区别

ros::spin()再调用之后不会返回,因此主程序不会继续执行,所以循环没有意义。而ros::spinOnce()在调用之后会返回,继续执行后面的程序。

ros::spin()函数一般不会出现在循环中,因为程序执行到spin()后就不调用其他语句了,也就是说该循环没有任何意义,还有就是spin()函数后面一定不能有其他语句(return 0 除外),有也是白搭,不会执行的。ros::spinOnce()的用法相对来说很灵活,但往往需要考虑调用消息的时机,调用频率,以及消息池的大小,这些都要根据现实情况协调好,不然会造成数据丢包或者延迟的错误。

参考文献

https://answers.ros.org/question/11887/significance-of-rosspinonce/

[http://wiki.ros.org/roscpp/Overview/Callbacks%20and%20Spinning](http://wiki.ros.org/roscpp/Overview/Callbacks and Spinning)

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