ROS CallBack函数和spinOnce()的触发机制,和消息队列的理解

ROS Subscriber的callback函数的触发条件

当循环到spinOnce()函数时,会调用subscriber的callback函数,此时会检查订阅到的消息队列的大小,
如果此时subscriber的消息队列的size为n,则会执行n次callback

ROS消息队列的理解

主要分以下几种情况,

subscriber的消息队列为1时

sub方的消息队列size为1,callback函数永远只拿到最新的数据

subscriber的消息队列为10(>1)时

sub方的消息队列size为10,callback函数会被触发10次,依次读取缓存收到的所有数据,如果这个消息队列足够大的话,是不会漏掉任何pub方发布的任一帧数据的。

publisher的消息队列为1时

pub方的消息队列size为1,每次publish只会发布此次循环中最新的数据

publisher的消息队列为10(>1)时

publisher的消息队列size大于1的情况会比较tricky,首先得先讲讲publish函数的机制,当pub方调用publish函数时,其实系统并不会阻塞直至消息真正发送出去,而是会将此次要发送的msg存入一个队列(此队列即为publisher的消息队列),然后立即返回,什么时候真正发送消息是由ros说了算。考虑以下代码:

#include <ros/ros.h>
#include <std_msgs/UInt32.h>

int main(int argc, char** argv) {
  ros::init(argc, argv, "pub_node");
  ros::NodeHandle n;
  // ros::Publisher chatter_pub = n.advertise<std_msgs::UInt32>("chatter", 1);
  ros::Publisher chatter_pub = n.advertise<std_msgs::UInt32>("chatter", 20);
  ros::Rate loop_rate(10);
  while (ros::ok()) {
    static int count = 0;
    static std_msgs::UInt32 msg;
    msg.data = count;
    for (int i = 0; i < 10; ++i) {
      chatter_pub.publish(msg);
    }
    loop_rate.sleep();
    ++count;
  }
  return 0;
}

注意到代码中的for循环,for循环执行了10次publish操作,直觉上会认为在一个while循环周期,此publisher发布了10次消息,但根据我们刚才讲的,publish函数并不会阻塞直至消息真正发送,而是将此msg存入一个publish队列,所以如果publish队列很短的话,如1,则很有可能一个while循环周期并不会执行10次publish操作(在我的机器上大概只有2次),因为还没等到ros真正发送消息,队列里的老消息就被新消息顶掉了。但如果我们将这个publish队列设置成20,那么一个while循环周期将会确确实实地执行10次publish操作,因为队列的size是20,大于for循环的10次,所以老消息不会被挤掉。

因此,如果这个publisher消息队列足够大的话,是不会漏发任何一帧本该发送的数据的。

猜你喜欢

转载自blog.csdn.net/zmhzmhzm/article/details/129756448