理解ROS Topic 通信频率背后的机制

这篇具有很好参考价值的文章主要介绍了理解ROS Topic 通信频率背后的机制。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Topic是ROS的三种通信方式中最为基本、也是常用的一种。本文对于ROS的Topic通信背后的数据吞吐机制做一个较为详细、深入的介绍。

Publisher

ROS中发布一个topic的函数是这样的

ros::Publisher advertise(const std::string& topic, uint32_t queue_size, bool latch = false);
Parameters:
topic:	Topic to advertise on
queue_size:	Maximum number of outgoing messages to be queued for delivery to subscribers
latch:	(optional) If true, the last message published on this topic will be saved and sent to new subscribers when they connect

有三个参数:topic就是我们要发布的话题,queue_size是publisher队列中可以存储的消息数量, latch是锁存,比如停止publish后保存最后一条message,如果有新的subscriber订阅的话,把之前保存的消息发给新的subscriber。
下面讲一讲和queue_size相关的,关系到我们发送的数据能否按照期望频率传输,会不会丢帧等。

案例分析

ros::init(argc, argv, "talker");
ros::NodeHandle handle;
ros::Publisher chatter_pub = handle.advertise<std_msgs::String>("chatter", 10);
ros::Rate loop_rate(100);
int count = 0;
std::stringstream ss;
std_msgs::String msg;
while (ros::ok())
{
    ss<<"Message ["<<count<<"]";
    msg.data = ss.str();
    ROS_INFO("%s", msg.data.c_str());
    chatter_pub.publish(msg);
    loop_rate.sleep();
    ++count;
    // ss.str("");
}

比如上面这个例子,我设置了publish()的循环频率为100Hz ,但是使用rostopic hz <topic> 查看这个topic的发布频率是不到100Hz的(下图),出现了实际发布频率和设置频率不一致的情况。

理解ROS Topic 通信频率背后的机制

这是因为我用的stringstream没有清零,而是逐渐累积,字符串越来越长,所以发布的消息是越来越复杂的,publisher thread处理耗时越来越多,所以发布频率也在逐渐降低。但是如果发布的消息很简单的话,还是可以跟上的,一般而言发布频率和publish()频率是几乎相等的。

那么这种频率错位的背后是什么导致的呢?

Publisher 背后

理解ROS Topic 通信频率背后的机制

The publisher queue is another queue like callback queue, but the queue is for queuing published message which is filled every time publish() function is called.
There is a separate thread (publisher thread) that is responsible for taking the message from the publisher queue and send it to subscribers of the topic if there are any. If you are calling the publish()more quickly than the publisher thread can send the messages, the messages start piling up in the publisher queue and if it reaches over the specified queue size (in this case 1000), the old message starts to get overwritten by new messages.

每调用一次publish()都会往 publisher message queue (以下简称PMQ) 当中放入一个message,然后有个单独的线程publisher thread 从PMQ当中取出message并真正发布。

我们叫publish()的循环频率为 期望发布频率,publisher thread处理的频率为 实际发布频率

一般而言,publisher thread的处理频率要比我们调用publish()的频率高,所以表现出来发布消息的频率就是我们publish()的循环速率。但是如果publish()的循环频率过高,以至于超过了publisher thread处理的速度(或者说publisher thread处理的速度低于publish()的速度)消息就会在PMQ中积累,超过了queue_size的话旧的消息便会丢失。

所以说如果发布的消息比较复杂,且publish()频率较高的话,最好将queue_size设置得大一点,要不然会丢失数据。当然也要看你应用的场景,有些场景丢帧也无所谓,反而是需要更新的数据。

Subscriber

ROS中订阅一个话题的函数如下

ros::Subscriber subscribe(const std::string& topic, uint32_t queue_size, <callback, which may involve multiple arguments>, const ros::TransportHints& transport_hints = ros::TransportHints());

topic还是很好理解,就是我们要订阅的话题。下面讲一讲callbackqueue_size

Callback

subscriber初始化的时候指明了回调函数callback,这就是回调函数的注册。

那么什么叫回调函数的注册呢?我的理解是下面这样,熟悉的小伙伴可以跳过。

回调就是告诉调用方你应该调用哪个回调函数,其实就是将这个函数的函数指针传给调用方,比如我们这里subscribe(callback),就是将callback的指针通过subscribe这个函数传给了subscriber。

打个日常生活的比方:好比你(回调函数)刚来一个单位,你跟上级(调用方)说“有事您叫我”,这个露脸的过程就是 回调函数的注册。然后领导有事真的找了你,就是调用了你这个回调函数。

理解ROS Topic 通信频率背后的机制

ROS中与回调处理相关的有两类对象:callback queues,spinners 。

subscriber节点初始化之时,它就创建了一个用于接收消息的线程 (receiver thread),每个subscriber都有一个接收消息的队列 subscriber message queue (SMQ)。同样地还有一个callback queue用于存放回调函数。每当subscriber接收一个消息,就有一个callback放入callback queue当中。

A spinner is an object that has the ability to call the callbacks contained in a callback queue. A callback queue is the object in which each subscriber will add an element each time a message is received by resolving which kind of message should call which callbacks (and with which arguments).
Callback queues/spinning do not have any effect on the internal network communication in roscpp. They only affect when user callbacks occur. They will have an effect on the subscription queue, since how fast you process your callbacks and how quickly messages are arriving determines whether or not messages will be dropped.

roscpp支持三种回调

  1. function

    void callback(const std_msgs::StringConstPtr& str)
    {	}
    ros::Subscriber sub = nh.subscribe("my_topic", 1, callback);
    
  2. class methods

    void Foo::callback(const std_msgs::StringConstPtr& message)
    {	}
    
    Foo foo_object;
    ros::Subscriber sub = nh.subscribe("my_topic", 1, &Foo::callback, &foo_object);
    
  3. functor objects,这里就不做介绍了。

SMQ中的回调处理是由Spinner实现的

spinner

ros::spin()

ros::spin() 创建了一个单独的线程 spinner thread 不停循环地、依次将callback从队列中取出并执行 。

虽然主程序当中没有循环,但是ros::spin()里有个循环。subscriber接收到消息并向callback queue当中放入一个回调函数,但是真正执行是在spin()里执行的。跟上面publisher thread类似, spinner thread处理回调的速度是根据回调函数的复杂程度决定的。

ros:spin() 是一个单独的线程,这个线程是循环处理回调函数的,一次处理一个回调函数。具体循环时间要依据callback而决定,这个跟receiver接收信息的频率一般是不一致的。如果比receiver接收信息要快,callback queue可以设置得很小;如果spinner处理回调的速度比receiver接收信息要慢,那么callback queue当中就开始累积callbacks,这时候queue_size最好设置地比较大一点。

有时候spinner thread实在处理不过来怎么办呢?我们可以让spinner thread开影分身——使用多线程spinner,并行处理callbacks。

总共有三种实现spinner的方式,可以参考Three implementations of spinners

Multi-threaded spinning

多线程的有两种ros::MultiThreadedSpinner()ros::AsyncSpinner()。一般用AsyncSpinner()

Multi spinner thread

ros::MultiThreadedSpinner spinner(2); 	// 开两个spinner并行处理
spinner.spin();

Instead of a blocking spin() call, it has start() and stop() calls, and will automatically stop when it is destroyed. An equivalent use of AsyncSpinner to the MultiThreadedSpinner example above, is:

ros::AsyncSpinner spinner(4); // Use 4 threads
spinner.start();
ros::waitForShutdown();

Reference

ROS Spinning, Threading, Queuing文章来源地址https://www.toymoban.com/news/detail-480811.html

到了这里,关于理解ROS Topic 通信频率背后的机制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ROS学习——通信机制(话题通信③—注意事项)

    2.1.2 话题通信基本操作A(C++) · Autolabor-ROS机器人入门课程《ROS理论与实践》零基础教程   043话题通信(C++)4_注意事项_Chapter2-ROS通信机制_哔哩哔哩_bilibili 1. int main(int argc, char const *argv[]){} vscode 中的 main 函数 声明 int main(int argc, char const *argv[]){},默认生成 argv 被 const 修饰,需要

    2024年02月08日
    浏览(36)
  • ROS学习笔记(六)---服务通信机制

    在ROS中,服务通信机制是一种点对点的通信方式,用于节点之间的请求和响应。它允许一个节点(服务请求方)向另一个节点(服务提供方)发送请求,并等待响应。 服务通信机制在ROS中使用以下两个概念: 服务(Service):服务是一种在ROS中定义的一对相关消息类型,包括

    2024年02月07日
    浏览(34)
  • 初识FreeRTOS入门,对FreeRTOS简介、任务调度、内存管理、通信机制以及IO操作,控制两个led不同频率闪烁

    当代嵌入式系统的开发越来越复杂,实时性要求也越来越高。为了满足这些需求,开发者需要使用实时操作系统(RTOS),其中一个流行的选择是FreeRTOS(Free Real-Time Operating System)。本篇博客将详细介绍FreeRTOS的特性、任务调度、内存管理、通信机制以及一些示例代码。 FreeR

    2024年02月14日
    浏览(26)
  • ROS2从入门到精通1-2:详解ROS2服务通信机制与自定义服务

    本专栏旨在通过对ROS2的系统学习,掌握ROS2底层基本分布式原理,并具有机器人建模和应用ROS2进行实际项目的开发和调试的工程能力。 🚀详情:《ROS2从入门到精通》 服务 是 ROS 图中节点之间的另一种通信方法。服务基于 服务器-客户端 模型,不同于话题的 发布者-订阅者

    2024年04月09日
    浏览(29)
  • ROS通信机制之话题(Topics)的发布与订阅以及自定义消息的实现

    我们知道在 ROS 中,由很多互不相干的节点组成了一个复杂的系统,单个的节点看起来是没起什么作用,但是节点之间进行了通信之后,相互之间能够交互信息和数据的时候,就变得很有意思了。 节点之间进行通信的一个常用方法就是使用 话题(topic) ,话题表示的是一个定义

    2024年02月11日
    浏览(28)
  • 深入探讨进程间通信的重要性:理解不同的通信机制(下)

    在上一篇文章中,我们探讨了进程间通信的三种常见机制:管道、消息队列和共享内存。我们了解到,这些机制各有其特点和适用场景,可以根据实际需求选择合适的机制进行进程间通信。然而,进程间通信并不仅限于这三种方式。 在本文中,我们将继续探索进程间通信的知

    2024年02月10日
    浏览(32)
  • 深入探讨进程间通信的重要性:理解不同的通信机制(上)

    在操作系统中,进程间通信是指不同进程之间进行信息共享、数据传输和消息通知等交互的过程。每个进程在创建时都有自己独立的虚拟地址空间,但它们共享内核空间。因此,要实现进程间的通信,必须通过内核来进行中介,如下图所示: 在Linux系统中,提供了多种进程间

    2024年02月10日
    浏览(32)
  • ROS2之topic

    查看topic输出: ros2 topic echo topic_name 查看topic频率: ros2 topic hz topic_name 查看有哪些topic: ros2 topic list 查看每个topic及其message type: ros2 topic list -t 在某个topic上使用命令行pub数据: 按默认周期发送: ros2 topic pub topic_name msg_type \\\'args\\\' 注意,args要使用yaml格式 只发送一次: ros2

    2024年02月11日
    浏览(26)
  • ROS2学习笔记三:话题Topic

    目录 前言 1 话题简介 2 常用指令 3 RCLCPP实现实现话题 3.1 创建工作空间 3.2 代码编写 3.2.1 发布端编写 3.2.2 发布端编写 ROS2中的一个重要概念是话题(Topic)。话题是一种通过发布者和订阅者之间进行异步通信的机制。发布者(Publisher)将消息发布到特定的话题上,而订阅者(

    2024年01月20日
    浏览(33)
  • kafka删除topic消息的三种方式

    kafka删除topic消息的三种方式 方法一:快速配置删除法(确保topic数据不要了) 1.kafka启动之前,在server.properties配置delete.topic.enable=true 2.执行命令bin/kafka-topics.sh --delete --topic test --zookeeper zk:2181或者使用kafka-manager集群管理工具删除 注意:如果kafka启动之前没有配置delete.topic.e

    2024年02月16日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包