ROS 2基础概念#5:执行器(Executor)| ROS 2学习笔记
在ROS 2中,Executor是一个核心概念,负责管理节点(Node)中的回调函数,如订阅消息的回调、服务请求的回调、定时器回调等。Executor决定了何时以及如何执行这些回调,从而在ROS 2系统中实现异步编程。
ROS 2 Executor的工作原理
在ROS 2中,节点是构成系统的基本单元,每个节点可以发布和订阅主题(Topic),提供和使用服务(Service),以及使用定时器(Timer)。Executor是控制节点中回调函数执行的机制。当消息到达或服务请求发生时,这些回调函数需要被调用。Executor负责从节点中收集待处理的回调,并决定执行它们的顺序和时间。
ROS 2 Executor的类型
ROS 2提供了几种不同类型的Executor,每种都有其特定的用途和调度策略:
- SingleThreadedExecutor:这是最简单的Executor,它在单个线程中顺序执行所有回调。这意味着在任意时刻,只有一个回调被执行,直到完成。这种Executor适用于不需要并行处理的简单应用。
- MultiThreadedExecutor:这种Executor允许在多个线程中并行执行回调。它使用一个线程池,回调任务可以在不同的线程中同时运行,适用于需要处理大量并行任务的复杂应用。
- StaticSingleThreadedExecutor:这是对SingleThreadedExecutor的优化,适用于性能要求较高的场景。它在内部缓存了一些信息,以减少每次执行回调时的开销。
通过为每个节点调用 add_node(..) ,所有三个执行器都可以与多个节点一起使用。
rclcpp::Node::SharedPtr node1 = ...
rclcpp::Node::SharedPtr node2 = ...
rclcpp::Node::SharedPtr node3 = ...rclcpp::executors::StaticSingleThreadedExecutor executor;
executor.add_node(node1);
executor.add_node(node2);
executor.add_node(node3);
executor.spin();
尽管基本 API 非常相似,但ROS 2 Executor 类(在 rclcpp 中的 executor.hpp 中、rclpy 中的 executors.py 中或 rclc 中的 executor.h 中)比 ROS 1 中的spin机制提供了更多对执行管理的控制。接下来的内容我们重点关注 C++ 客户端库 rclcpp。
基本使用方法
在最简单的情况下,主线程用于通过调用 rclcpp::spin(..) 来处理 Node 的传入消息和事件,如下所示:
int main(int argc, char* argv[])
{// Some initialization.rclcpp::init(argc, argv);...// Instantiate a node.rclcpp::Node::SharedPtr node = ...// Run the executor.rclcpp::spin(node);// Shutdown and exit....return 0;
}
对 spin(node) 的调用基本上扩展为单线程执行器的实例化和调用,这是最简单的执行器:
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
executor.spin();
通过调用 Executor 实例的 spin(),当前线程开始查询 rcl 和中间件层以获取传入消息和其他事件,并调用相应的回调函数,直到节点关闭。 为了不影响中间件的 QoS 设置,传入消息不会存储在客户端库层的队列中,而是保留在中间件中,直到由回调函数进行处理(这是与 ROS 1 的一个关键区别)。等待集(waitset)用于通知执行器中间件层上的可用消息,每个队列有一个二进制标志。 等待集还用于检测计时器何时到期。
单线程执行器也被组件的容器进程使用,即在没有显式主函数的情况下创建和执行节点的所有情况。
回调(callback)分组
ROS 2 允许按组组织节点的回调。 在 rclcpp 中,可以通过 Node 类的 create_callback_group 函数创建这样的回调组。 在rclpy中,通过调用特定回调组类型的构造函数来完成相同的操作。 回调组必须在节点的整个执行过程中存储(例如作为类成员),否则执行器将无法触发回调。 然后,可以在创建订阅、计时器等时指定该回调组 – 例如通过订阅选项:C++或Python。
my_callback_group = MutuallyExclusiveCallbackGroup()
my_subscription = self.create_subscription(Int32, "/topic", self.callback, qos_profile=1, callback_group=my_callback_group)
所有在没有指定回调组的情况下创建的订阅、计时器等都将分配给默认回调组。 默认回调组可以通过 rclcpp 中的 NodeBaseInterface::get_default_callback_group() 和 rclpy 中的 Node.default_callback_group 查询。
有两种类型的回调组,必须在实例化时指定类型:
- Mutually exclusive: 该组的回调不得并行执行。
- Reentrant: 该组的回调可以并行执行。
不同回调组的回调可能总是并行执行。 多线程执行器使用其线程作为资源池,根据这些条件并行处理尽可能多的回调。 有关如何有效使用回调组的提示,请参阅使用回调组。
自 Galatic 版本以来,rclcpp 中 Executor 基类的接口已通过新函数 add_callback_group(..) 进行了细化。 这允许将回调组分配给不同的执行器。 通过使用操作系统调度程序配置底层线程,特定回调可以优先于其他回调。 例如,控制循环的订阅和定时器可以优先于节点的所有其他订阅和标准服务。 example_rclcpp_cbg_executor 包提供了此机制的演示。
调度语义
如果回调的处理时间短于消息和事件发生的周期,Executor 基本上按照 FIFO 的顺序处理它们。 但是,如果某些回调的处理时间较长,消息和事件将在堆栈的较低层排队。 等待集机制只向执行器报告关于这些队列的很少的信息。 具体来说,它仅报告是否有特定主题的消息。 执行器使用此信息以循环方式处理消息(包括服务和操作),但不是按照 FIFO 顺序。 下面的流程图直观地展示了这种调度语义。
Casini 等人在 ECRTS 2019 上的论文首次描述了这种语义(注意:本文还解释了计时器事件的优先级高于所有其他消息。这种优先级在 Eloquent 版本中已被删除。)
Executor的使用
在ROS 2应用程序中,开发者需要创建一个或多个节点,并将它们添加到Executor。然后,开发者调用Executor的spin
方法来开始循环,等待并执行回调。例如,使用SingleThreadedExecutor的基本用法如下:
import rclpy
from rclpy.executors import SingleThreadedExecutor
from my_package import MyNode
def main(args=None):
rclpy.init(args=args)
node = MyNode()
executor = SingleThreadedExecutor()
executor.add_node(node)
try:executor.spin() # 开始执行回调
finally:executor.remove_node(node)rclpy.shutdown()
if name == 'main':
main()
展望
虽然 rclcpp 的三个执行器适用于大多数应用程序,但它也存在一些问题,使它们不适合实时应用程序,因为实时应用程序需要明确定义的执行时间、确定性以及对执行顺序的自定义控制。 以下是其中一些问题的摘要:
- 复杂且混合的调度语义。 理想情况下,您需要明确定义的调度语义来执行正式的时序分析。
- 回调可能会受到优先级反转的影响。 较高优先级的回调可能会被较低优先级的回调阻止。
- 没有对回调执行顺序的显式控制。
- 没有对特定主题的触发的内置控制。
此外,执行器在 CPU 和内存使用方面的开销也相当大。 静态单线程执行器大大减少了这种开销,但对于某些应用程序来说可能还不够。
这些问题已通过以下开发得到部分解决:
- rclcpp WaitSet:rclcpp 的 WaitSet 类允许直接等待订阅、计时器、服务服务器、操作服务器等,而不是使用 Executor。 它可用于实现确定性的、用户定义的处理序列,可能会一起处理来自不同订阅的多个消息。 example_rclcpp_wait_set 包提供了几个使用此用户级等待设置机制的示例。
- rclc 执行器:来自 C 客户端库 rclc 的执行器,为 micro-ROS 开发,为用户提供了对回调执行顺序的细粒度控制,并允许自定义触发条件来激活回调。 此外,它还实现了逻辑执行时间(LET)语义的思想。
总结
ROS 2的Executor提供了一个灵活且强大的机制来管理和调度节点中的回调函数,使得开发者可以根据应用的需求选择或自定义合适的执行策略。通过合理地使用Executor,可以有效地提高ROS 2应用程序的性能和响应能力。
作者个人Blog ROS 2学习笔记系列文章: ROS 2学习笔记 归档 - HY's Blog
相关文章:

ROS 2基础概念#5:执行器(Executor)| ROS 2学习笔记
在ROS 2中,Executor是一个核心概念,负责管理节点(Node)中的回调函数,如订阅消息的回调、服务请求的回调、定时器回调等。Executor决定了何时以及如何执行这些回调,从而在ROS 2系统中实现异步编程。 ROS 2 …...

Unity 动画(旧版-新版)
旧版 旧版-动画组件:Animation 窗口-动画 动画文件后缀: .anim 将制作后的动画拖动到Animation组件上 旧版的操作 using System.Collections; using System.Collections.Generic; using UnityEngine;public class c1 : MonoBehaviour {// Start is called before…...
Linux和Windows操作系统线程调度策略
本文介绍Linux和Windows操作系统线程调度策略。 不同的操作系统具有不同的线程调度策略,本文针对常见的操作系统(Linux和Windows操作系统)对其线程调度策略作简要说明,并不对其内在运行机制作详细介绍。 1.Linux操作系统线程调度…...

[OpenWrt 22.03] ttylogin添加登录密码与禁止登录的配置
ttylogin 的使用 Openwrt 串口默认是没有密码的。Openwrt启动后,一个默认的密码将被启用去保护ssh登录和页面(http)登录,而串口登录密码却是空缺的。 对于 Openwrt,当内核初始化后,就会启动第一个进程 init,init进程会进行一系列的系统初始化工作,然后会读取 /etc/in…...

RK3568平台 USB数据包的收发格式
一.USB硬件拓扑结构 compound device :多个设备组合起来,通过HUB跟Host相连composite device :一个物理设备有多个逻辑设备(multiple interfaces) 在软件开发过程中,我们可以忽略Hub的存在,硬件拓扑图简化如下&#x…...
Day 8.TCP通信
TCP通信 TCP发端: socket connect send recv close TCP收端: socket bind listen accept send recv close 1.connect int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 功能:发…...

小游戏加固方案已全面适配微信、QQ、抖音、快手、美团、华为、支付宝渠道
2023年,国内移动游戏收入与游戏用户规模双双创下历史新高。其中小游戏异军突起,市场规模达到200亿元,同比增长300%,成了万众瞩目的行业新风口。 小游戏的高速发展带来了更多的活力,产出了多款月流水过亿的热门游戏。行…...

粉色ui微信小程序源码/背景图/头像/壁纸小程序源码带流量主
云开发版粉色UI微信小程序源码,背景图、头像、壁纸小程序源码,带流量主功能。 云开发小程序源码无需服务器和域名即可搭建小程序另外还带有流量主功能噢!微信平台注册小程序就可以了。 这套粉色UI非常的好看,里面保护有背景图、…...

chrome选项页面options page配置
options 页面用以定制Chrome浏览器扩展程序的运行参数。 通过Chrome 浏览器的“工具 ->更多工具->扩展程序”,打开chrome://extensions页面,可以看到有的Google Chrome扩展程序有“选项Options”链接,如下图所示。单击“选项Options”…...

迭代器失效问题(C++)
迭代器失效就是迭代器指向的位置已经不是原来的含义了,或者是指向的位置是非法的。以下是失效的几种情况: 删除元素: 此处发生了迭代器的失效,因为erase返回的是下一个元素的位置的迭代器,所以在删除1这个元素的时候&…...

2-web端管理界面使用rabbitmq
Web管理界面可以直接操作RabbitMQ,下面进行操作并记录步骤 1、添加交换器: Add a new exchange 中,Name是交换器名称,Type是交换器类型,有direce、fanout、heders、topic 4种。 这里先只填Name和选个类型,…...
【华为OD机试】最多购买宝石数目【C卷|100分】
【华为OD机试】-真题 !!点这里!! 【华为OD机试】真题考点分类 !!点这里 !! 题目描述: 橱窗里有一排宝石,不同的宝石对应不同的价格, 宝石的价格标记为gems[i],0<=i<n, n = gems.length 宝石可同时出售0个或多个,如果同时出售多个,则要求出售的宝石编号连续; 例如…...
RK3588 Android 12 源码编译与开发板烧录
前言 开发板型号:RK_EVB7_RK3588_LP4…_V11 获取RK3588源码 解压RK提供的Android 12的tgz,开通权限 your_verify.sh # 身份验证脚本(由RK提供) .repo/repo/repo sync -l # 检出代码 .repo/repo/repo sync -c # 同…...

学习JAVA的第十四天(基础)
目录 Collection集合 迭代器遍历 增强for遍历 Lambda表达式遍历 List集合 遍历 数据结构 栈 队列 数组 链表 前言: 学习JAVA的第十三天 Collection集合 Collection的遍历方式: 迭代器(不依赖索引)遍…...

安捷伦N5182A信号源 AgilentN5182A
描述: 1)信号特性: 250 kHz to 3 or 6 GHz频率范围 (可选低至 100 kHz) 13 dBm 1GHz输出功率 5dBm输出功率时W-CDMA动态范围:单载波 ≤-73 dBc ;4载波≤-66 dBc ≤1.2 ms切换速度在SCPI模式 2)调制与扫描&#x…...

就业班 2401--3.7 Linux Day13--日志轮转+jumpserver堡垒机
一、日志轮转 日志重要性 Linux系统日志对管理员来说,是了解系统运行的主要途径,因此需要对 Linux 日志系统有个详细的了解。 Linux 系统内核和许多程序会产生各种错误信息、告警信息和其他的提示信息,这些各种信息都应该记录到日志文件中&a…...
信息安全概论 习题
用密钥information构造一个Playfair矩阵 Playfair密码是一种替换加密技术,它不像传统的单字母替换密码那样工作,而是将信息分成一对字母(双字母)进行加密。构造Playfair矩阵时,首先需要一个密钥词,然后根据…...

仓储管理系统(WMS) 的研发历程-PRD撰写
题外话:PRD的展现形式有多种,有的人喜欢在axure上直接做产品描述,觉得word较为过时,有的人认为axure不专业,任何展现形式都无可厚非,重要的达到PRD的目的,PRD的目标是让团队知道需求实现细节&am…...

springboot实现多线程开发(使用@Async注解,简单易上手)
根据springboot的核心思想便捷开发,使用多线程也变得简单起来,通过一下几个步骤即可实现。 核心注解 EnableAsync将此注解加在启动类上,使项目支持多线程。 Async 使用我们的Async注解在所需要进行多线程的类上即可实现。 配置线程池 …...
并发支持库(1)-线程
线程允许多个程序任务在统一时间执行,不同的线程可以共享内存空间,每个线程也有自己的栈空间。 线程类 thread 类thread表示单个执行线程。线程在thread构造对象时开始执行。每个thread对象表示唯一的一个线程,thread不支持复制构造和复制…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...

用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...

九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...
Python 高效图像帧提取与视频编码:实战指南
Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...