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不支持复制构造和复制…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...
CTF show 数学不及格
拿到题目先查一下壳,看一下信息 发现是一个ELF文件,64位的 用IDA Pro 64 打开这个文件 然后点击F5进行伪代码转换 可以看到有五个if判断,第一个argc ! 5这个判断并没有起太大作用,主要是下面四个if判断 根据题目…...
41道Django高频题整理(附答案背诵版)
解释一下 Django 和 Tornado 的关系? Django和Tornado都是Python的web框架,但它们的设计哲学和应用场景有所不同。 Django是一个高级的Python Web框架,鼓励快速开发和干净、实用的设计。它遵循MVC设计,并强调代码复用。Django有…...
