ROS中的多线程使用

2023-05-16

目录:

    • 单线程
    • 多线程
      • 订阅多个Topic,多个Spinner threads
      • 订阅一个Topic,多个Spinner threads
      • 订阅多个Topic,每个Subscriber一个Callback queue

ROS里面每个节点都是用默认的单线程来处理任务,以前很多时候都没有注意使用多线程的方式来处理回调函数,今天在这里总结一下。实际上ROS中提供了多线程接口,因为单线程在很多时候不能保证时效性,所以我们往往还会使用到多线程。为了文章的完整性,下面将讨论单线程和多线程下的情况。

单线程

image-20221005204110888

在只有一个Spinner thread的情况下,callback queue只能顺序执行。假设场景:一个发布节点 publisher 向两个话题(/topic/Atopic/b )以1Hz速度发布消息,另外一个节点 subscriber 接收两个话题上的消息,以回调函数的方式处理消息内容,其中 CallbackA 在打印接收到的消息以外还会sleep 2s,CallbackB 只打印接收到的消息。代码如下

publisher.cpp

#include "ros/ros.h" 
#include "std_msgs/String.h"   
#include <sstream>   
 
int main(int argc, char **argv)
{
  ros::init(argc, argv, "publisher");  
  ros::NodeHandle n;   
  ros::Publisher pub_a = n.advertise<std_msgs::String>("/topic/A", 1000);
  ros::Publisher pub_b = n.advertise<std_msgs::String>("/topic/B", 1000);   
  ros::Rate loop_rate(1);
  std_msgs::String msg;   
  int count = 0;
  while (ros::ok())
  {
    std::stringstream msg_a;
    msg_a << "msg_a " << count;
    msg.data = msg_a.str();
    ROS_INFO("%s", msg.data.c_str());  
    pub_a.publish(msg);
      
    std::stringstream msg_b;
    msg_b << "msg_b " << count;
    msg.data = msg_b.str();
    ROS_INFO("%s", msg.data.c_str());  
    pub_b.publish(msg);
      
    ros::spinOnce();
    loop_rate.sleep();
    ++count;
  }
  return 0;
}

subscriber.cpp

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

void CallbackA(const std_msgs::String::ConstPtr& msg)  
{
  ROS_INFO("A heard: [%s]", msg->data.c_str());
  std::this_thread::sleep_for(std::chrono::seconds(2));
}

void CallbackB(const std_msgs::String::ConstPtr& msg)  
{
  ROS_INFO("B heard: [%s]", msg->data.c_str());
}
 
int main(int argc, char **argv)
{
  ros::init(argc, argv, "subscriber");
  ros::NodeHandle n;
  ros::Subscriber sub_a = n.subscribe("/topic/A", 1000, CallbackA);
  ros::Subscriber sub_b = n.subscribe("/topic/B", 1000, CallbackB);
  ros::spin();
  return 0;
}

输出结果

image-20221005193446564

从执行效果中可以看到,不管有多少个Subscriber,节点都只能顺序执行回调,在对实时性要求比较高的场景中,这种方式会使得系统性能大打折扣,因此需要使用多线程的方式

多线程

订阅多个Topic,多个Spinner threads

image-20221005204326576

在刚刚的 subscriber.cpp 代码中增加如下两行即可

image-20221005195124035

输出结果

image-20221005195200435

可以看到,A和B两个回调函数现在分别在两个不同的线程中进行处理,B回调不会因为A线程的sleep而被阻塞了。

订阅一个Topic,多个Spinner threads

image-20221005204359764

假设只有一个Topic, 发布端的频率比较高,但我们希望尽可能多地响应消息,这时可以把回调任务分发给多个线程处理

修改 subscriber.cpp

image-20221005200954186

输出结果如下

image-20221005200908064

可以看到,回调A的处理频率和发布频率一致,都是1Hz。如果是单线程处理回调,那么回调的频率应该是0.5Hz,因为CallbackA()中sleep 2s

订阅多个Topic,每个Subscriber一个Callback queue

image-20221005204429264

上面提到的两种情况都是只有一个回调队列,这种情况会导致在处理回调B的时候无法处理回调A。ROS里面还提供了给每个回调创建一个回调消息队列,这样可以实现真正的多线程回调

修改 subscriber.cpp 如下:

image-20221005203113228

输出结果:

image-20221005203212443

给每一个subscriber创建一个单独的callback queue,这样就解决了即使用了MultiThreadedSpinner但所有的callback依然在同一个queue执行的问题,此方法用来解决subscriber的优先级问题。

参考:https://zhuanlan.zhihu.com/p/375418691

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

ROS中的多线程使用 的相关文章

随机推荐

  • PASCAL VOC数据集

    一 简介 PASCAL pattern analysis statistical modelling and computational learning VOC visual object classes 该挑战赛的竞赛项目主要包括 图像
  • ubuntu python 通过奥比中光摄像头获取深度图片和彩色图片

    1 依赖 安装Openni Openni下载Openni添加至环境 xff08 要通过全局变量找到Openni头文件和库 xff09 安装primesense和openni pip install primesense pip instal
  • ROS tf使用报错:ImportError: dynamic module does not define module export function (PyInit__tf2)

    1 报错内容 Traceback span class token punctuation span most recent call last span class token punctuation span File span cla
  • ubuntu cuda cudnn tensorRT的卸载和安装

    1 安装显卡驱动 显卡安装教程 查看N卡驱动支持的最高cuda版本 nvidia smi 2 卸载 span class token function sudo span span class token function apt get
  • 初识VSCode

    Visual Studio Code xff08 以下简称vscode xff09 是一个轻量且强大的代码编辑器 xff0c 跨平台支持Windows xff0c Mac OS X和Linux 内置JavaScript TypeScript
  • Modbus通信及数据存储读取

    1 存储区代号 代码号功能1区输入线圈0区输出线圈3区输入寄存器4区输出寄存器 2 功能码 代码功能0x01读取输出线圈0x02读取输入线圈0x03读取输出寄存器0x04读取输入寄存器0x05写入单个线圈0x06写入单个寄存器0x0F写入多
  • 着色器语言 GLSL (opengl-shader-language)入门大全

    GLSL 中文手册 基本类型 类型说明void空类型 即不返回任何值bool布尔类型 true falseint带符号的整数 signed integerfloat带符号的浮点数 floating scalarvec2 vec3 vec4n
  • Data structure alignment (数据结构对齐 / 内存对齐)

    开篇的话 在比较老的编译器里 xff0c 如果没有对变量取地址的操作 xff0c 那么有些局部变量是通过寄存器保存的 xff0c 不占栈上内存 xff0c 根本不存在内存中如何排列的问题 xff0c 比如TurboC 2 0这种 在一些较新
  • C++primer plus和C++ primer的读书心得

    C 43 43 两本巨著primer plus和primer太过于经典 xff0c 以至于读过多次 xff0c 每次阅读仍然有新的收获 xff0c 所以将一些零碎的知识点整理在这里 xff0c 与大家共同进步 1 i 43 43 与 43
  • VINS 外参在线标定

    在VINS中相机的外参 R i c R ic R i c 是可以在线动态标定的 xff0c 实现函数为 xff1a 6
  • A-LOAM源码阅读

    LOAM 论文地址 xff1a https www ri cmu edu pub files 2014 7 Ji LidarMapping RSS2014 v8 pdf A LOAM地址 xff1a https github com HKU
  • LeGo-LOAM 跑通与源码学习

    论文链接 xff1a https www researchgate net LeGO LOAM 源码仓库 xff1a https github com RobustFieldAutonomyLab LeGO LOAM 本人注释 xff1a
  • SLAM中evo评估工具(用自己的数据集评估vinsFusion)

    目录 xff1a 配置标题文件修改源码修改第一处第二处第三处重新编译工程 安装evo1 安装命令2 常用指令 运行vinsFusion生成位姿估计文件使用evo评估轨迹 配置标题文件修改 主要根据自己的设备 xff0c 修改自己传感器的RO
  • Ubuntu中USB端口与外设绑定,ROS读取IMU模块数据

    目录 xff1a 1 根据设备ID绑定1 1 查看ID1 2 编写USB规则文件1 3 查看绑定结果 2 根据电脑USB口绑定2 1 找到USB端口名称2 2 编写绑定规则 3 通过ROS读数据 1 根据设备ID绑定 方法原理 xff1a
  • 实现外网Ping通WSL(网卡桥接方式实现)

    目录 xff1a 前言 xff1a 实现原理 xff1a 实现步骤1 开启hyper v2 编写桥接网络powershell脚本3 编写网络配置脚本 实现结果取消桥接最后 前言 xff1a 在我们经常和机器人打交道的这群人中有一个需求 xf
  • 如何在markdown中插入表情包

    我们平时经常使用markdown完成一些诸如博客的文档写作 xff0c 但是有时像我这种语言比较乏力的急需要在文档写作过程中插入表情包来完整的表达我想要表达的意思 xff0c 所以我去网上查了一下 xff0c 还真有 比如我想要表达开心即s
  • ROS多设备组网(WSL+miniPC+Nv Orin)

    目录 xff1a 前言硬件连接组网配置1 获取hostname和IP2 在主机添加从机的host信息3 在从机1中配置4 在从机2中配置 测试test1 话题订阅test2 rqt plot可视化传感器信息 最后 前言 实验室最近购买了两台
  • ZED 2i 双目-IMU标定

    目录 xff1a 前言IMU标定1 编译标定工具2 准备数据集3 标定 Camera IMU标定1 安装依赖2 编译Kaibr3 制作标定板下载标定板生成标定板target yaml文件 4 数据采集5 相机标定标定中遇到的问题问题1 xf
  • gazebo中给机器人添加16线激光雷达跑LIO-SAM

    目录 xff1a 前言1 下载雷达仿真包2 添加雷达支架描述文件3 添加雷达描述文件4 启动仿真5 添加IMU模块6 添加RGB D相机7 LIO SAM仿真安装依赖安装GTSAM编译LIO SAM运行 8 源码 遇到的问题1 error
  • ROS中的多线程使用

    目录 xff1a 单线程多线程订阅多个Topic xff0c 多个Spinner threads订阅一个Topic xff0c 多个Spinner threads订阅多个Topic xff0c 每个Subscriber一个Callback