ROS订阅最新的消息及queue_size和buff_size的理解

本文介绍在ROS中如何通过合理配置消息队列(queue_size)与缓冲区(buff_size)来确保处理最新数据,避免数据堆积,提高系统实时性。详细解释了Publisher与Subscriber消息队列的作用及设置原则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

机器人应用中难免会遇到运算起来很费时间的操作,比如图像的特征提取、点云的匹配等等。有时候,不可避免地,我们需要在ROS的Subscriber的Callback回调函数中进行这些费时的操作。Subscriber所订阅的消息的发布频率可能是很高的,而这些操作的运算速度肯定达不到消息发布的速度。所以,如果我们要是没有取舍的对于每个消息都调用一次回调函数,那么势必会导致计算越来越不实时,很有可能当下在处理的还是几十秒以前的数据。所以,我们希望每次回调函数都处理当前时刻最新的一个消息,这就是我们的目标。
要达到这个目标有三点,第一点是要设置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)

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

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

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

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

3、Publisher有消息队列了,为什么Subscriber还要有消息队列?

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

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

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

#!/usr/bin/env python3 # -*- coding: utf-8 -*- import cv2 import torch import rospy import numpy as np from ultralytics import YOLO from time import time from std_msgs.msg import Header from sensor_msgs.msg import Image from yolov8_ros_msgs.msg import BoundingBox, BoundingBoxes class Yolo_Dect: def __init__(self): # load parameters weight_path = rospy.get_param('~weight_path', '') image_topic = rospy.get_param( '~image_topic', '/camClassera/color/image_raw') pub_topic = rospy.get_param('~pub_topic', '/yolov8/BoundingBoxes') self.camera_frame = rospy.get_param('~camera_frame', '') conf = rospy.get_param('~conf', '0.5') self.visualize = rospy.get_param('~visualize', 'True') # which device will be used if (rospy.get_param('/use_cpu', 'false')): self.device = 'cpu' else: self.device = 'cuda' self.model = YOLO(weight_path) self.model.fuse() self.model.conf = conf self.color_image = Image() self.getImageStatus = False # Load class color self.classes_colors = {} # image subscribe self.color_sub = rospy.Subscriber(image_topic, Image, self.image_callback, queue_size=1, buff_size=52428800) # output publishers self.position_pub = rospy.Publisher( pub_topic, BoundingBoxes, queue_size=1) self.image_pub = rospy.Publisher( '/yolov8/detection_image', Image, queue_size=1) # if no image messages while (not self.getImageStatus): rospy.loginfo("waiting for image.") rospy.sleep(2) def image_callback(self, image): self.boundingBoxes = BoundingBoxes() self.boundingBoxes.header = image.header self.boundingBoxes.image_header = image.header self.getImageStatus = True self.color_image = np.frombuffer(image.data, dtype=np.uint8).reshape( image.height, image.width, -1) self.color_image = cv2.cvtColor(self.color_image, cv2.COLOR_BGR2RGB) results = self.model(self.color_image, show=False, conf=0.3) self.dectshow(results, image.height, image.width) cv2.waitKey(3) def dectshow(self, results, height, width): self.frame = results[0].plot() print(str(results[0].speed['inference'])) fps = 1000.0/ results[0].speed['inference'] cv2.putText(self.frame, f'FPS: {int(fps)}', (20,50), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2, cv2.LINE_AA) for result in results[0].boxes: boundingBox = BoundingBox() boundingBox.xmin = np.int64(result.xyxy[0][0].item()) boundingBox.ymin = np.int64(result.xyxy[0][1].item()) boundingBox.xmax = np.int64(result.xyxy[0][2].item()) boundingBox.ymax = np.int64(result.xyxy[0][3].item()) boundingBox.Class = results[0].names[result.cls.item()] boundingBox.probability = result.conf.item() self.boundingBoxes.bounding_boxes.append(boundingBox) self.position_pub.publish(self.boundingBoxes) self.publish_image(self.frame, height, width) if self.visualize : cv2.imshow('YOLOv8', self.frame) def publish_image(self, imgdata, height, width): image_temp = Image() header = Header(stamp=rospy.Time.now()) header.frame_id = self.camera_frame image_temp.height = height image_temp.width = width image_temp.encoding = 'bgr8' image_temp.data = np.array(imgdata).tobytes() image_temp.header = header image_temp.step = width * 3 self.image_pub.publish(image_temp) def main(): rospy.init_node('yolov8_ros', anonymous=True) yolo_dect = Yolo_Dect() rospy.spin() if __name__ == "__main__": main()检查里面有没有该话题,该话题的功能是把用该功能包检测到的物体名称发布到话题上,如果没有请帮我写,并给我完整代码
最新发布
08-10
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值