ROS发布与订阅处理顺序以及多线程使用

本文探讨了ROS系统中发布者与订阅者的处理顺序,以及在单线程和多线程环境下的行为。通过测试,展示了单线程时数据处理的同步特性,而多线程能有效防止数据丢失。总结了ROS话题发布的基本流程和订阅者处理速度对订阅频率的影响。

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一、前言

记录ROS发布与订阅处理顺序以及多线程使用,由于情况很多,所以不一一细讲,有需要的可以自己尝试。这里简单讲解两个话题以及两个订阅者的情况。


二、发布者

发布方发布两个话题:
//参数1:队列长度
talker发布两个话题,然后每个话题都各自开辟自己的队列(有一些人说之开辟一个队列,个人觉得不严谨,只是因为话题处理是单线程,所以和简化成一个队列类似。这里可以去了解以下话题通讯协议)。如何队列被占满,就会丢弃旧的信息。
可以修改参数:
1、话题1的队列长度
2、话题2的队列长度
3、话题1的发布频率
4、话题2的发布频率

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>

int main(int argc, char **argv) {
   
   
  ros::init(argc, argv, "talker");
  ros::NodeHandle n;

  ros::Publisher message_a_pub = n.advertise<std_msgs::String>("MessageA", 1000);//参数1:队列A长度
  ros::Publisher message_b_pub = n.advertise<std_msgs::String>("MessageB", 1000);//参数2:队列B长度

  int message_a_count = 0;
  int message_b_count = 0;

  while (0 == message_a_pub.getNumSubscribers() || 0 == message_b_pub.getNumSubscribers()) {
   
   
    ROS_INFO("Waiting for subscribers to connect");
    ros::Duration(0.1).sleep();
  }

  ros::Timer timer_a = n.createTimer(ros::Duration(0.1), [&](const ros::TimerEvent&) {
   
   
    std_msgs::String msg;
    std::stringstream ss;
    ss << "Messages A: " << message_a_count;
    msg.data = ss.str();
    ROS_INFO("%s", msg.data.
<think>好的,我现在需要帮助用户了解在ROS1的topic通信中使用多线程的方法,包括示例和教程。首,我应该回忆一下ROS1中的多线程机制。ROS1默认情况下使用的是单线程的spinner,也就是所有的回调函数都是在一个线程中顺序执行的。如果用户需要处理多个回调函数同时运行,或者有高频率的数据需要处理,这时候就需要使用多线程处理,避免阻塞。 根据用户提供的引用[1],里面提到了使用ros::SubscribeOptions和ros::MultiThreadedSpinner来实现并发回调执行。这说明在ROS1中,可以通过这两个类来配置多线程。我需要详细说明这两个类的用法,并给出一个具体的示例代码。 首ros::SubscribeOptions允许用户自定义订阅选项,包括指定回调队列。默认情况下,回调会被放入全局队列,但通过设置不同的队列,可以配合多线程spinner来处理。然后,ros::MultiThreadedSpinner可以创建多个线程来处理回调,每个线程都会从队列中取出回调执行。 接下来,我需要构建一个示例。比如,创建一个节点,订阅两个话题,每个话题的回调函数在不同的线程中运行。在代码中,需要初始化节点句柄,创建两个订阅者,每个订阅使用不同的回调队列。然后,使用MultiThreadedSpinner启动多个线程,处理这些回调。 同时,需要注意线程安全和资源竞争的问题。如果多个回调函数访问共享数据,需要使用互斥锁等机制来保护数据。在示例中可能不需要涉及复杂的数据共享,但用户在实际应用中需要注意这一点。 用户还可能需要了解如何调整线程数量,比如MultiThreadedSpinner的参数设置,以及如何管理不同的回调队列。另外,引用[2]中提到ROS2中使用MultiThreadedExecutor,但用户询问的是ROS1,所以重点应放在ROS1的MultiThreadedSpinner上。 总结步骤: 1. 创建节点并初始化订阅者,每个订阅使用不同的回调队列。 2. 使用MultiThreadedSpinner指定线程数,启动多线程处理回调。 3. 示例代码展示如何实现这一点。 4. 提醒线程安全和资源管理的问题。 现在需要将这些步骤转化为结构化的回答,并确保符合用户给出的格式要求,比如使用中文、正确的LaTeX格式、生成相关问题等。同时,检查引用是否正确,在回答末尾添加相关的问题,并确保引用标识符对应。</think>### ROS1 Topic多线程使用方法及示例 在ROS1中实现Topic通信的多线程处理,主要通过`ros::MultiThreadedSpinner`和回调队列管理实现,可提升高并发场景下的消息处理效率。以下为具体实现步骤及示例: --- #### 一、核心机制说明 1. **默认单线程模型** ROS1默认使用`ros::spin()`单线程处理回调函数,所有订阅的Topic回调按顺序执行,可能导致高延迟[^1]。 2. **多线程Spinner** `ros::MultiThreadedSpinner`可创建多个工作线程,并行处理回调任务。例如:指定线程数为2时,两个回调可同时执行。 3. **回调队列隔离** 通过`ros::SubscribeOptions`为不同订阅器分配独立回调队列,避免线程竞争。例如:两个订阅器分别绑定到独立的队列,由不同线程处理。 --- #### 二、代码示例 ```cpp #include <ros/ros.h> #include <std_msgs/String.h> // 回调函数1:处理topic1数据 void callback1(const std_msgs::String::ConstPtr& msg) { ROS_INFO("Callback1 [%s] in thread %ld", msg->data.c_str(), (long)syscall(SYS_gettid)); } // 回调函数2:处理topic2数据 void callback2(const std_msgs::String::ConstPtr& msg) { ROS_INFO("Callback2 [%s] in thread %ld", msg->data.c_str(), (long)syscall(SYS_gettid)); } int main(int argc, char** argv) { ros::init(argc, argv, "multi_threaded_node"); ros::NodeHandle nh; // 创建订阅选项对象,分配独立回调队列 ros::SubscribeOptions ops1 = ros::SubscribeOptions::create<std_msgs::String>( "topic1", 10, &callback1, ros::VoidPtr(), &nh.getCallbackQueue() ); ros::SubscribeOptions ops2 = ros::SubscribeOptions::create<std_msgs::String>( "topic2", 10, &callback2, ros::VoidPtr(), &nh.getCallbackQueue() ); // 创建订阅ros::Subscriber sub1 = nh.subscribe(ops1); ros::Subscriber sub2 = nh.subscribe(ops2); // 启动多线程Spinner(线程数=2) ros::MultiThreadedSpinner spinner(2); spinner.spin(); return 0; } ``` --- #### 三、关键配置解析 1. **`ros::SubscribeOptions`配置** - 第5个参数指定回调队列,此处使用节点的默认队列`nh.getCallbackQueue()` - 若需完全隔离,可为每个订阅器创建独立的`ros::CallbackQueue`对象 2. **线程数设置** `ros::MultiThreadedSpinner(2)`表示启动2个工作线程,通常根据CPU核心数调整 3. **线程安全注意事项** - 若多个回调访问共享数据,需使用`boost::mutex`等锁机制 - 避免在回调中执行阻塞操作,以免影响其他线程任务 --- #### 四、验证方法 1. **查看线程ID** 示例代码中通过`syscall(SYS_gettid)`打印线程ID,若不同回调输出不同ID,则表明多线程生效 2. **性能对比** 对比单线程多线程模型在高频率消息(如>100Hz)下的CPU占用率和延迟差异 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值