【ROS进阶】一文搞懂ROS话题通信机制与消息队列

2023-05-16

文章目录

    • 一、话题通信机制解析
      • 1、话题通信机制简介
      • 2、消息队列分析
      • 3、使用技巧
    • 二、实验验证
      • (一)subscriber队列长度对数据传输影响
      • (二)数据传输时间延迟
    • 三、总结

一、话题通信机制解析

在这里插入图片描述

1、话题通信机制简介

(1)首先,发布节点把消息发布,消息进入Publisher的消息队列,同时通知订阅了该话题消息的Subscriber来取消息。
(2)其次,Subscriber来Publisher的消息队列里取消息,但取走的也是最老的消息,因为毕竟这是先入先出的队列。
(3)最后,被取走的消息存放入了Subscriber的消息队列中,等待被Callback执行。如果Callback执行很慢,消息越堆越多,最老的消息会逐渐被顶替。

2、消息队列分析

Publisher和Subscriber设置消息队列,都可以从两点进行分析:

  • 话题通信属于异步通信,队列可以存储一定量的历史数据
  • 网络传输异常的时候,队列可以预先进行缓存

(1)为什么需要设置Publisher的消息队列?

  • 话题通信属于异步通信,publisher节点发布消息,有多个Subscriber节点进行订阅,因此需要有一个地方对消息进行缓存。
  • 网络传输差、延时突然高的时候,可以把消息放在Publisher的队列中进行暂存。

(2)为什么要设置Subscriber消息队列?

  • Subscriber消息队列提供一边处理数据一边缓存新消息的机制。Publisher和Subscriber不一定在同一台主机上,但是网络的性能时好时坏,如果Subscriber没有消息队列。如果没有Subscriber消息队列,那么程序每次运行Callback函数前都要先通过网络取回消息,然后才能处理,当网络很差的时候就会造成系统的阻塞。

3、使用技巧

(1)队列长度queue_size参数选择

参考:http://wiki.ros.org/rospy/Overview/Publishers%20and%20Subscribers#Choosing_a_good_queue_size

  • 当queue_size=0,即ROS消息队列为0时,表示为无限队列长度,内存使用量可以无限增长,因此不推荐使用。
  • 当两个queue_size=1时,那么系统不会缓存数据,自然处理的就是最新的消息。
  • 当queue_size设置为10或者更多时候,用户更不容易错过发布的消息,适用于与人交互的用户界面的数据展示。

(2)ros::spinOnce机制

  • 一次 ros::spinOnce()会获取完所有Subscriber队列中的消息

二、实验验证

实验过程比较繁杂,可以直接看第三部分:总结

(一)subscriber队列长度对数据传输影响

1、实验目的

测试什么状态下队列会溢出

2、实验结论

结论一:
当回调函数处理时长小于数据发布的时间间隔,数据可以完整地传输。
结论二:
subscriber队列可以对接收数据进行缓存,spinonce每次进入回调函数,会取出Subscriber队列中最新的数据

3、详细实验过程
测试一:
1)条件设置

  • 数据发布为5Hz
  • 回调函数执行时间为0.19s

2)测试代码:

#include<ros/ros.h>
#include<ros/time.h>
#include"std_msgs/Int8.h"

int main(int argc,char **argv)
{
	ros::init(argc,argv,"test_publisher");
	ros::NodeHandle node;
	//控制队列长度
	ros::Publisher num_pub = node.advertise<std_msgs::Int8>("num",1);
	//控制Publisher发送频率
	ros::Rate loop_rate(5);
	int count=0;
	while(ros::ok())
	{
		std_msgs::Int8 msg;
		msg.data=count;
		num_pub.publish(msg);
		std::cout<<"I send:"<<count<<"   "<<"Time:"<<ros::Time::now()<<std::endl;
		count++;
		ros::spinOnce();
		loop_rate.sleep();
		
	}

}
#include"ros/ros.h"
#include<ros/time.h>
#include <ros/duration.h>
#include"std_msgs/Int8.h"

void numcallback(const std_msgs::Int8::ConstPtr& msg)
{
	ROS_INFO("I heard:[%d]",msg->data);
	std::cout<<"Time:"<<ros::Time::now()<<std::endl;
	ros::Duration(0.19).sleep();
	
		
}


int main(int argc,char **argv)
{
	ros::init(argc,argv,"test_subscriber");
	ros::NodeHandle node;
	ros::Subscriber sub=node.subscribe("num", 5, numcallback);
	
	//subscriber节点数据订阅频率
	while(ros::ok())
	{
		ros::spinOnce();
			
	}
}

3)测试结果:

I send:0   Time:1651218272.909345283
I send:1   Time:1651218273.109455274
I send:2   Time:1651218273.309404860
I send:3   Time:1651218273.509534306
I send:4   Time:1651218273.709532966
I send:5   Time:1651218273.909548481
I send:6   Time:1651218274.109474975
I send:7   Time:1651218274.309555626
I send:8   Time:1651218274.509553033
I send:9   Time:1651218274.709557666
I send:10   Time:1651218274.909548771
I send:11   Time:1651218275.109466288
I send:12   Time:1651218275.309543458
I send:13   Time:1651218275.509558336
I send:14   Time:1651218275.709546293

[ INFO] [1651218273.309568749]: I heard:[2]
Time:1651218273.310396018
[ INFO] [1651218273.509881431]: I heard:[3]
Time:1651218273.509977833
[ INFO] [1651218273.709862283]: I heard:[4]
Time:1651218273.709933310
[ INFO] [1651218273.909996336]: I heard:[5]
Time:1651218273.910075954
[ INFO] [1651218274.109691506]: I heard:[6]
Time:1651218274.109723500
[ INFO] [1651218274.309999529]: I heard:[7]
Time:1651218274.310088643
[ INFO] [1651218274.509997999]: I heard:[8]
Time:1651218274.510090090
[ INFO] [1651218274.709979046]: I heard:[9]
Time:1651218274.710068361
[ INFO] [1651218274.909994015]: I heard:[10]
Time:1651218274.910081014
[ INFO] [1651218275.109661000]: I heard:[11]
Time:1651218275.109693420
[ INFO] [1651218275.309972661]: I heard:[12]
Time:1651218275.310058529
[ INFO] [1651218275.509988978]: I heard:[13]
Time:1651218275.510075436
[ INFO] [1651218275.709965890]: I heard:[14]
Time:1651218275.710054172

测试二:
1)测试条件

  • 数据发布为5Hz
  • 回调函数执行时间为1s

2)测试代码:
同测试一代码,ros::Duration(0.19).sleep();修改为ros::Duration(1).sleep();
3)测试结果:

I send:0   Time:1651218738.926879714
I send:1   Time:1651218739.126986022
I send:2   Time:1651218739.326976590
I send:3   Time:1651218739.527334121
I send:4   Time:1651218739.727314856
I send:5   Time:1651218739.927253191
I send:6   Time:1651218740.127338630
I send:7   Time:1651218740.327119437
I send:8   Time:1651218740.527310282
I send:9   Time:1651218740.727320096
I send:10   Time:1651218740.927319061
I send:11   Time:1651218741.127077520
I send:12   Time:1651218741.327314284
I send:13   Time:1651218741.527084625
I send:14   Time:1651218741.727320603
I send:15   Time:1651218741.927310977
I send:16   Time:1651218742.127316121
I send:17   Time:1651218742.327314879
I send:18   Time:1651218742.527084705
I send:19   Time:1651218742.727317344
I send:20   Time:1651218742.927309793
I send:21   Time:1651218743.127181334
I send:22   Time:1651218743.327346438
I send:23   Time:1651218743.526975577
I send:24   Time:1651218743.727310035
I send:25   Time:1651218743.926981510
I send:26   Time:1651218744.127081416
I send:27   Time:1651218744.327057619
[ INFO] [1651218739.327222543]: I heard:[2]
Time:1651218739.328122020
[ INFO] [1651218740.328379711]: I heard:[3]
Time:1651218740.328493901
[ INFO] [1651218741.328750504]: I heard:[8]
Time:1651218741.328841823
[ INFO] [1651218742.329083810]: I heard:[13]
Time:1651218742.329179718
[ INFO] [1651218743.329413185]: I heard:[18]
Time:1651218743.329527079
[ INFO] [1651218744.329811444]: I heard:[23]
Time:1651218744.329907939
[ INFO] [1651218745.330186229]: I heard:[24]
Time:1651218745.330278204
[ INFO] [1651218746.330738718]: I heard:[25]
Time:1651218746.330852786
[ INFO] [1651218747.331349463]: I heard:[26]
Time:1651218747.331466039
[ INFO] [1651218748.331944456]: I heard:[27]
Time:1651218748.332064212

(二)数据传输时间延迟

1、实验目的

测试同一平台下,节点发布订阅之间的延迟

2、实验结论

1)同一平台上,发布与订阅节点之间存在延迟时间:大概为0.2ms
2)先运行订阅者节点,后运行发布者节点也会存在数据丢失,说明:订阅者与发布者刚建立连接时需要大致0.5s的时间

3、详细实验过程

//测试
publisher节点:5HZ发送数据
subscriber节点:循环无延迟接收
publisher队列长度:1
subscriber队列长度:1

订阅者节点程序:

#include"ros/ros.h"
#include<ros/time.h>
#include"std_msgs/Int8.h"

void numcallback(const std_msgs::Int8::ConstPtr& msg)
{
	ROS_INFO("I heard:[%d]",msg->data);
	std::cout<<"Time:"<<ros::Time::now()<<std::endl;	
}


int main(int argc,char **argv)
{
	ros::init(argc,argv,"test_subscriber");
	ros::NodeHandle node;
	ros::Subscriber sub=node.subscribe("num", 1 , numcallback);
	
	//subscriber节点数据订阅频率
	//ros::Rate loop_rate(1);
	while(ros::ok())
	{
		ros::spinOnce();
	//	loop_rate.sleep();	
	}
}
I send:0   Time:1651205837.321564955
I send:1   Time:1651205837.521682618
I send:2   Time:1651205837.721703296
I send:3   Time:1651205837.921677835
I send:4   Time:1651205838.121677621
I send:5   Time:1651205838.321678661
I send:6   Time:1651205838.521629560
I send:7   Time:1651205838.721682315
I send:8   Time:1651205838.921686516
I send:9   Time:1651205839.121680353
I send:10   Time:1651205839.321681521
I send:11   Time:1651205839.521680580
I send:12   Time:1651205839.721678035
I send:13   Time:1651205839.921678646
I send:14   Time:1651205840.121678181
I send:15   Time:1651205840.321680872
I send:16   Time:1651205840.521679562
I send:17   Time:1651205840.721690948
I send:18   Time:1651205840.921680647
I send:19   Time:1651205841.121677714
I send:20   Time:1651205841.321677517
I send:21   Time:1651205841.521679494
I send:22   Time:1651205841.721680698
I send:23   Time:1651205841.921687221
[ INFO] [1651205837.721951989]: I heard:[2]
Time:1651205837.722832444
[ INFO] [1651205837.921802016]: I heard:[3]
Time:1651205837.921839834
[ INFO] [1651205838.121838956]: I heard:[4]
Time:1651205838.121857432
[ INFO] [1651205838.321856591]: I heard:[5]
Time:1651205838.321874992
[ INFO] [1651205838.521779574]: I heard:[6]
Time:1651205838.521797385
[ INFO] [1651205838.721839387]: I heard:[7]
Time:1651205838.721876415
[ INFO] [1651205838.921855876]: I heard:[8]
Time:1651205838.921891244
[ INFO] [1651205839.121832170]: I heard:[9]
Time:1651205839.121883353
[ INFO] [1651205839.321850889]: I heard:[10]
Time:1651205839.321871226
[ INFO] [1651205839.521831303]: I heard:[11]
Time:1651205839.521865618
[ INFO] [1651205839.721848060]: I heard:[12]
Time:1651205839.721867795
[ INFO] [1651205839.921843985]: I heard:[13]
Time:1651205839.921864013
[ INFO] [1651205840.121845232]: I heard:[14]
Time:1651205840.121864557
[ INFO] [1651205840.321851113]: I heard:[15]
Time:1651205840.321871289
[ INFO] [1651205840.521843675]: I heard:[16]
Time:1651205840.521862573
[ INFO] [1651205840.721814996]: I heard:[17]
Time:1651205840.721868193
[ INFO] [1651205840.921852729]: I heard:[18]
Time:1651205840.921871924
[ INFO] [1651205841.121849661]: I heard:[19]
Time:1651205841.121867539
[ INFO] [1651205841.321848846]: I heard:[20]
Time:1651205841.321866561
[ INFO] [1651205841.521847632]: I heard:[21]
Time:1651205841.521864884
[ INFO] [1651205841.721849989]: I heard:[22]
Time:1651205841.721867769
[ INFO] [1651205841.921830872]: I heard:[23]
Time:1651205841.921847805

三、总结

1、数据发布到缓存到订阅者队列的时间是很短的,大约为0.5ms,如果对数据实时性要求比较高,发布者和订阅者的队列长度均需要设置为1;
2、回调函数处理数据时间过长,subscriber队列数据堆积,并可能导致数据丢失。每次执行回调函数时,会从subscriber队列选取最老的数据。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【ROS进阶】一文搞懂ROS话题通信机制与消息队列 的相关文章

随机推荐

  • vs2010 webapi开发http请求以及website中如何实现http请求

    一 vs2010 webapi开发 第一步 xff1a 创建 第二步 xff1a 离线安装NuGet 1 复制链接到浏览器打开 xff1a http visualstudiogallery msdn microsoft com 27077b
  • 字节和bit的大小端简介

    C语言的位域虽然很多人强烈建议不要使用 xff0c 但现有系统里还广泛存在位域的使用 xff0c 所以还是很有必要理清楚的 对big endian和little endian的区别 xff0c 很多人认为是对多字节数据类型而言 其实 xff
  • C++ 数字与char*的转换

    目录 1 数字转char 1 1 sprintf1 2 itoa1 3 ltoa ultoa 2 char 转数字2 1 atoi2 2 atol2 3 atof2 4 strtol2 5 strtoul2 6 strtod 1 数字转ch
  • 【C语言】printf输出16进制: %x %02x %#x

    x即按十六进制输出 xff0c 英文字母小写 xff0c 右对齐 02X有以下变化 xff1a 英文字母变大写 xff0c 如果输出字符不足两位的 xff0c 输出两位宽度 xff0c 右对齐 xff0c 空的一位补0 超过两位的 xff0
  • 【c语言】结构体初始化4中方法

    今天在6轴传感器的驱动代码源文件中看到结构体没见过的写法 xff1a typedef struct uint8 t xlda 1 uint8 t gda 1 uint8 t tda 1 uint8 t not used 01 5 lsm6d
  • 【debug】stm32 指针奇数地址问题导致HardFault

    很久很久没有记录过debug了 xff0c 今天有空就正好记录一下 嵌入式开发 xff0c stm32F407的MCU的开发板 遇到如下问题 xff1a 变量的地址竟然为奇数 xff01 xff01 xff01 导致程序运行到写入该地址的数
  • 【Autosar】学习总结-BSW层

    一 简介 AUTOSAR AUTomotive Open Systems ARchitecture xff0c 汽车开放系统架构 1 优势 xff1a 有利于提高软件复用度 xff0c 尤其是跨平台的复用度 xff1b 便于软件的交换与更新
  • 【PWM】从stm32到pwm到OLED屏幕调光到晚上不要玩手机

    一 前言 最近做项目 xff0c 配置了单片机中PWM波形输出 xff0c 配置单片机中的一个引脚输出PWM波 xff0c 示波器查看这个波形 xff0c 做了实践操作 xff0c 有一些感想 xff0c 将一些了解过的知识和常识结合 xf
  • 算法提高 高精度加法

    1051 算法提高 高精度加法 时间限制 1 Sec 内存限制 256 MB 提交 5 解决 2 提交 状态 讨论版 题目描述 在C C 43 43 语言中 xff0c 整型所能表示的范围一般为 231到231 xff08 大约21亿 xf
  • 【Autosar】学习总结-MCAL

    一 简介 MCAL xff1a 微控制器抽象层 xff1b 位于BSW层中的最下层 xff1b MCAL细分 xff0c 可将驱动分为 xff1a 微控制器驱动 存储器驱动 通信驱动 IO驱动 xff1a 二 MCAL的配置 xff08 E
  • 【2022】年度总结

    一 月报 xff1a 1 一月 二月 初入新公司 xff0c 还在试用期 xff1b 进的外包安卓手机升级项目 xff0c 是一个短期的项目 xff0c 3 4个月左右 xff1b 第一次了解到外包项目原来是这种模式 xff1a 建立黄区
  • 【笔试总结 网络】IP地址分类 划分子网 子网掩码 (相关例题分析)

    xff08 最近做了很多春招公司笔试卷子 xff0c 发现很多是学过的东西 xff0c 看着很熟悉 xff0c 就是不会 很多学过的概念模棱两可 xff0c 这在笔试中很吃亏 说不会吧会点 xff0c 说会吧 xff0c 做不出来 就比如关
  • 网页登录时密码如何传输?

    今天突发奇想想看下一般网站登录时密码是如何传输的 首先是QQMail xff0c gmail xff0c 各大网上银行等对于我非常重要的登录网站 xff1a https https的安全性自然是很高 其次是通常的腾讯微博以及其他腾讯常用的网
  • C/C++中简单数据结构的对齐

    这里只讨论简单的数据结构 xff0c 从MSDN上的例子开始 struct x char a 1 byte int b 4 bytes short c 2 bytes char d 1 byte 在没有对齐的情况下 xff0c x 中的所有
  • yolo数据增强以及批量修改图片和xml名

    记录下打完标签对数据集进行扩增 xff0c 数据增强后的图片及标签名字进行修改 xff0c 重点在代码只需更改文件名就可使用 无论数据增强还是修改名称 xff0c 标签框位置都会跟着改变 xff01 xff01 xff01 前人之鉴 xff
  • 利用select实现服务器和客户端的随时收发

    服务器代码实现 xff1a include lt stdio h gt include lt sys types h gt include lt sys socket h gt include lt arpa inet h gt inclu
  • 采集温度数据,用串口传输到上位机

    这里写目录标题 一 实验要求二 I2C总线通信协议 xff08 一 xff09 概念 xff08 二 xff09 I2C总线特征 xff08 三 xff09 I2C总线协议 xff08 四 xff09 I2C的两种方式 硬件I2C和软件I2
  • rflysim基于simulink控制3.4:硬件在环仿真-e0-1实验

    一 实验1 xff1a Simulink代码自动烧录 要求 xff1a 将设计好的simulink模型 xff0c 生成固件烧录到Pixhawk中 步骤 xff1a 1 设计控制器 例程参考 xff1a e0 2 PSPOfficialEx
  • 如果参数是指针,且仅作输入用,则应在类型前加 const,以防止该 指针在函数体内被意外修改...

    如果参数是指针 xff0c 且仅作输入用 xff0c 则应在类型前加 const xff0c 以防止该 指针在函数体内被意外修改 1 include lt iostream gt 2 3 run this program using the
  • 【ROS进阶】一文搞懂ROS话题通信机制与消息队列

    文章目录 一 话题通信机制解析1 话题通信机制简介2 消息队列分析3 使用技巧 二 实验验证 xff08 一 xff09 subscriber队列长度对数据传输影响 xff08 二 xff09 数据传输时间延迟 三 总结 一 话题通信机制解