ROS 搞懂多话题回调机制以及消息队列 |
您所在的位置:网站首页 › ros订阅话题 › ROS 搞懂多话题回调机制以及消息队列 |
ROS 消息队列的运行机制
下面只是自己的理解,如果有误望大家指正! 问:ROS中,publisher和subscriber都有一个消息队列用于数据收发时候的缓存,那么它们的作用分别是什么? 答:ROS话题的通信是异步的,也就是publisher只管不停的发但不管是否被接收,publisher是向Topic的消息队列发布信息,而不是publisher直接push给subscriber,publisher发送数据后,订阅该topic的subscriber则会过来读取,系统会通过位置指针管理不同subscriber读取消息队列的位置,因此可以支持任意多个subscriber对话题进行读取,每个subscriber读取到数据后,会将数据放置到自己的缓存队列上,然后触发注册的回调函数进行处理… 综上所述,publisher不停将消息发布到消息队列上,直到队列占满,然后新到的消息把最老的消息挤出队列,因此,publisher消息队列的作用就是,缓存一定数量的历史信息,让不能及时订阅的subscriber能读取到之前发布的信息。如果没这个需求或是想让subscriber读取到最新的消息,那么让消息队列长度设为1 。 而subscriber的消息队列的作用是,将回调函数来不及处理的信息及时的缓存,这样不至于因为回调函数执行或调用过慢,导致数据的丢失。 多话题回调机制 ros::spinOnce()和spin()spinOnce()的主要用法是: ros::Rate r(rate); while (ros::ok()) { ros::spinOnce(); r.sleep(); }当一个节点订阅了多个话题时,每调用一次ros::spinOnce(),每个接收到消息的subscriber都去执行它的回调函数,那么问题来了,每个subscriber执行回调函数的次数是多少呢?难道每次每个subscriber就调用一次回调函数? 还有多个subscriber的回调函数的执行顺序是什么样呢? 上一节讲到了,subscriber的消息队列用于缓存来不及处理的消息,那么每次调用ros::spinOnce()时,如果各个subscriber只是执行一次回调函数,那么消息队列估计很长时间都不会清0, 所以, 应该说每次调用ros::spinOnce()都会执行与消息队列中缓存的信息数量相同次数的回调函数,只要回调函数执行够快的话,就能清空队列。 另外, 当多个subscriber都需要调用回调函数时,则按顺序依次执行各个subscriber的回调函数。 如下例(非完整): /*****************************订阅部分*********************************/ void chatterCallback1(const std_msgs::String::ConstPtr& msg) { int i=0; ROS_INFO("I heard: [%s]", msg->data.c_str()); // sleep(1); } void chatterCallback2(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); sleep(1); } void main() { chatter1_sub = nh.subscribe("/chatter1", 5, chatterCallback1 ); chatter2_sub = nh.subscribe("/chatter2", 3, chatterCallback2 ); ros::Rate r(0.1); while (ros::ok()) { ros::spinOnce(); r.sleep(); } } /******************************发布部分*********************************/ void send1() { static int t=0; std_msgs::String msg; std::stringstream ss; ss chatter1_pub = nh.advertise("/chatter1", 1); chatter2_pub = nh.advertise("/chatter2", 1); ros::Rate r(10); while (ros::ok()) { send1(); send2(); ros::spinOnce(); r.sleep(); } }发布器以10HZ的速度发布信息到chatter1,chatter2话题。 接收器,以0.1HZ的速度调用ros::spinOnce(),订阅的消息队列长度分别为5和3,那么以0.1hz即10s的间隔调用ros::spinOnce()时,两个Topic的消息队列都满了,这时一共会调用8次回调函数,且前6次为交替调用 。 有一点要注意,在回调函数里执行的时间也是会算在r.sleep()中的,如上例中,执行chatterCallback2()需要一秒,那么spinOnce()后一共要花3秒在回调函数中,然后的r.sleep()就只会执行7秒的延时,那么可想而知,如果在回调函数中执行的时间大于r.sleep()需要延时的时间,那么回调函数就一直执行下去。 MultiThreadedSpinner的用法是: ros::MultiThreadedSpinner spinner(4); // 数字表示调用的线程数 spinner.spin(); // spin() will not return until the node has been shutdown通过MultiThreadedSpinner调用的回调函数就不再是串行执行的了,而是多线程 并行执行! 总结: 1、spinOnce()/spin()调用时是串行执行所有的回调函数,并且是各个话题按顺序执行的,执行的次数与调用spinOnce()时消息队列的元素个数相同。 2、MultiThreadedSpinner调用的回调函数就不再是串行执行的了,而是多线程 并行执行。 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |