百科不全书之ROS函数解析

本文详细介绍了ROS中的回调函数,包括ros::spin()和ros::spinOnce()的使用,以及多线程回调处理。同时,讨论了ROS订阅(Subscribe)和发布(Publisher)的机制,强调了设置队列大小和缓冲区大小对于处理最新消息的重要性。此外,还解释了Publisher和Subscriber消息队列的作用,以及为何两者都需要消息队列。
摘要由CSDN通过智能技术生成

1. ROS的回调函数

/************单线程***************/
ros::spin()  单线程回调函数
ros::spin()在节点关闭或ros::shutdown()或按下Ctrl-C才会返回。
ros::spinOnce() 单线程回调函数
ros::spinOnce()在那个时间点,会调用所有的回调函数。

/************多线程***************/
// 类似于ros::spin(),在构造过程中可以指定它所用线程数,但如果不指定线程数或者线程数设置为0,它将在每个cpu内核开辟一个线程。
ros::MultiThreadedSpinner spinner(4); 

AsyncSpinner比MultiThreadedSpinner更优,它有start() 和stop() 函数,并且在销毁的时候会自动停止。
ros::AsyncSpinner spinner(4); // Use 4 threads
spinner.start();
spinner.stop();
ros::waitForShutdown();

// CallbackQueue  创建回调队列   CallbackQueue 有两种方法调用回调函数: callAvailable() 和callOne()
// callAvailable()调用队列里所有的。 callone()只会调用回调在队列最旧的。

#include <ros/callback_queue.h>
ros::CallbackQueue my_queue;

2. ROS中的订阅(Subscribe)和发布(Publisher)

参考链接:CSDN博主「西涯先生」link

ros::Publisher pub_ = n.advertise<std_msgs::String>("char", 1000);
ros::Subscriber sub = nh_.subscribe<uhf_rfid_api::UhfRfid>("messageepc", 0, rfid_callback) ; //正常用
ros::Subscriber sub_= nh_.subscribe<std_msgs::String>("char", 1, &Recognition::cloudCallBack, this);  // 类中用

// 如果想要给回调函数传参数可以用C++ 的boost库中的boost::bind() 函数  这里,boost::bind中的第一个参数是回调函数名,第二个 _1 是一个占位符,因为回调函数image_callback的第一个参数是msg,要给它留位置。第三个,就是传的一个参数。以此扩展,如果想要传两个参数,这样:boost::bind(image_callback, _1, &pub_vt, &pub_odo),不要把_1当做参数个数哈
ros::Subscriber sub = nh_.subscribe("/camera/image", 0, boost::bind(image_callback, _1, &pub_vt));


在ROS的回调函数中,遇到运算很费时的操作时,因为这些操作的运算速度达不到消息发布的速度,所以,我们需要每次回调函数都处理当前时刻最新的一个消息。
要达到这个目标有三点,第一点是要设置Publisher的queue_size等于1;第二点是要设置Subscriber的queue_size(消息队列大小)等于1;第三点非常重要,要设置Subscriber的buff_size(缓冲区大小)足够大,大于一个消息的大小。像这样:

pcdpub = rospy.Publisher("lidardata", PointCloud, queue_size=1)
rospy.Subscriber("lidardata", PointCloud, self.pcd_resolve_callback,queue_size=1,buff_size=52428800)

Subscriber和Publisher的消息队列起什么作用,队列的大小有什么影响?

简单描述一下,Publisher的消息队列是为了缓存发布节点发布的消息,一旦队列中消息的数量超过了queue_size,那么最先进入队列的(最老的)消息被舍弃。Subscriber的消息队列是为了缓存节点接收到的信息,一旦自己处理的速度过慢,接收到的消息数量超过了queue_size,那么最先进入队列的(最老的)消息会被舍弃。所以,我们想只处理最新的消息,实际上只需要把两个queue_size都设置成1,那么系统不会缓存数据,自然处理的就是最新的消息。

Subscriber有消息队列缓存消息了,为什么Publisher还要有消息队列?

在我看来,Publisher的消息队列是一定要有的,因为ROS中发布节点往外发送消息是基于Topic发送,而不是直接向Subscriber订阅者发送,所以必须要有一个消息队列来存放发布的消息,以供订阅者来获取。而且这个消息队列的好处是在网络差、带宽小、延时高的时候,保证数据不容易丢失。
既然Publisher有消息队列了,为什么Subscriber还要有消息队列?

这个问题比较难一点。我的理解是,由于ROS毕竟是分布式系统,Publisher和Subscriber不一定在同一台主机上,因此消息需要通过网络来交换。但是网络的性能时好时坏,如果Subscriber没有消息队列,那么每次运行Callback函数前都要先通过网络取回消息,然后才能处理。当网络很差时,就会让系统堵塞。而有消息队列的话,Subscriber就可以一边处理队列中的消息,一边通过网络缓存新的消息,而不用每次处理消息前都要临时去读一个回来。这样就增加了系统的可靠性。

为什么要设置缓冲区的大小?

这个缓冲区的大小是指消息队列使用的缓冲区物理内存空间大小。如果这个空间小于一个消息所需要的空间,比如消息是一副图片或者一帧点云,数据量超过了缓冲区的大小。这个时候为了保证通信不发生错误,就会触发网络通信的保护机制,TCP的Buffer会为你缓存消息。这种机制就会导致每一帧消息都被完整的缓存下来,没有消息被丢弃,感觉上就像queue_size被设置成了无穷大。详细说明请参考:

3. ddd

  1. ddd
  2. fff
  3. ddd
  4. ddfff
  5. fff
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值