ROS学习笔记-ros::spin()和spinonce()

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_36396941/article/details/83448130

在写作业过程中,需要订阅一个话题,结果无论如何尝试都无法进入回调函数,原因是因为没有使用ros::spin()。如果写的程序使用了消息订阅函数,千万千万不要忘了在相应位置加ros::spin()或ros::spinonec(),具体情况看要怎么使用。

关于ros消息发布器和订阅器的教程: http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber(c++)

http://wiki.ros.org/ROS/Tutorials (ROS官方基础教程)

消息发布器在一个while里面一直循环发送“hello world”到话题(topic)chatter上。消息订阅器一旦知道chatter上面有data,就会将这data作为参数传入callback函数中,但是此时还没有执行callback函数,而是把callback函数放到了一个回调函数队列中。所以当发布器不断发送data到chatter上面时,就会有相应的callback函数进入队列中,它们函数名一样,只是实参不一样。

那么什么时候才会执行callback函数呢?

就是ros::spin()和ros::spinOnce()的事了。

当spinOnce函数被调用时,spinOnce就会调用回调函数队列中第一个callback函数,此时callback函数才被执行,然后等到下次spinOnce函数又被调用时,回调函数队列中第二个callback函数就会被调用,以此类推。

所以,这会有一个问题。因为回调函数队列的长度是有限的,如果发布器发送数据的速度太快,spinOnce函数调用的频率太少,就会导致队列溢出,一些callback函数就会被挤掉,导致没被执行到。

而对于spin函数,一旦进入spin函数,它就不会返回了,相当于它在自己的函数里面死循环了。只要回调函数队列里面有callback函数在,它就会马上去执行callback函数。如果没有的话,它就会阻塞,不会占用CPU。

1.ros::spin()

ros::spin()函数用起来比较简单,一般都在主程序的最后,加入该语句就可。例子如下:

#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.ros::spinonce()

对于ros::spinOnce()的使用,虽说比ros::spin()更自由,可以出现在程序的各个部位,但是需要注意的因素也更多。比如:

1 对于有些传输特别快的消息,尤其需要注意合理控制消息池大小和ros::spinOnce()执行频率; 比如消息送达频率为10Hz, ros::spinOnce()的调用频率为5Hz,那么消息池的大小就一定要大于2,才能保证数据不丢失,无延迟

/**接收端**/
#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();
}

————————————————
版权声明:本文为CSDN博主「Yeah2333」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_36396941/article/details/83448130

你可能感兴趣的:(ROS学习笔记-ros::spin()和spinonce())