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,每种都有其特定的用途和调度策略:

  1. SingleThreadedExecutor:这是最简单的Executor,它在单个线程中顺序执行所有回调。这意味着在任意时刻,只有一个回调被执行,直到完成。这种Executor适用于不需要并行处理的简单应用。
  2. MultiThreadedExecutor:这种Executor允许在多个线程中并行执行回调。它使用一个线程池,回调任务可以在不同的线程中同时运行,适用于需要处理大量并行任务的复杂应用。
  3. 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 的三个执行器适用于大多数应用程序,但它也存在一些问题,使它们不适合实时应用程序,因为实时应用程序需要明确定义的执行时间、确定性以及对执行顺序的自定义控制。 以下是其中一些问题的摘要:

  1. 复杂且混合的调度语义。 理想情况下,您需要明确定义的调度语义来执行正式的时序分析。
  2. 回调可能会受到优先级反转的影响。 较高优先级的回调可能会被较低优先级的回调阻止。
  3. 没有对回调执行顺序的显式控制。
  4. 没有对特定主题的触发的内置控制。

此外,执行器在 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/271007.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ansible 基础入门

2)Ansible 介绍 Ansible 基本概念 Ansible 是一种自动化运维工具,基于 Paramiko 开发的,并且基于模块化工作,Ansible 是一种集成 IT 系统的配置管理、应用部署、执行特定任务的开源平台,它是基于 Python 语言&#xf…

【黑马程序员】C++项目之机房预约管理系统实战

文章目录 需求系统简介身份介绍机房介绍申请简介系统具体需求 实现菜单与退出功能实现功能测试 创建身份类创建角色基类创建学生类创建教师类创建管理员类 登录模块功能描述登录函数封装各个校色具体登录验证管理员操作界面调用流程 管理员模块构造函数实现管理员子菜单显示添加…

数据备份:守护你的数字资产,安全无忧!

一、数据备份:数字时代的“保险箱” 在数字化日益盛行的今天,我们的工作、学习和生活都离不开各种电子设备。无论是电脑中的文档、图片,还是手机里的联系人、短信,都承载着我们的重要信息和回忆。然而,电子设备并非永…

Spring源码:手写AOP

文章目录 一、概念1、AOP是什么?2、相关概念1)目标对象Target2)通知Advice3)连接点Joinpoint4)切点Pointcut5)切面Aspect6)织入Weaving 二、分析三、实现1、实现Advice1)前置通知2&a…

【开源物联网平台】使用MQTT.fx模拟设备接入FastBee物联网平台

​🌈 个人主页:帐篷Li 🔥 系列专栏:FastBee物联网开源项目 💪🏻 专注于简单,易用,可拓展,低成本商业化的AIOT物联网解决方案 目录 一、接入步骤 1.1 创建产品&#xff…

springboot3.x集成SpringDoc Swagger3

近期将springboox2.x升级到了3.x&#xff0c;索性将swagger2也同步升级到swagger3&#xff0c;具体过程如下。 一、添加maven依赖 <dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>…

Mac版2024 CleanMyMac X 4.14.6 核心功能详解以及永久下载和激活入口

CleanMyMac 是 macOS 上久负盛名的系统清理工具&#xff0c;2018 年&#xff0c;里程碑式版本 CleanMyMac X 正式发布。不仅仅是命名上的变化&#xff0c;焕然一新的 UI、流畅的动画也让它显得更加精致。新增的系统优化、软件更新等功能&#xff0c;使得在日常使用 macOS 时有了…

正向代理和反向代理区别

正向代理和反向代理的区别&#xff1a; 特点正向代理反向代理位置位于客户端和目标服务器之间位于目标服务器和客户端之间代理对象代理服务器代表客户端发送请求到目标服务器代理服务器代表目标服务器接收客户端的请求配置客户端需要手动配置代理服务器客户端不需要知道代理服…

TCP收发——计算机网络——day02

今天主要讲了TCP的收发 TCP发端步骤 ①socket ②connect ③send ④closeTCP收端步骤 ①socket ②bind ③listen ④accept ⑤recv ⑥clise其函数主要有 connect int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);功能:发送链接请求参数:sockfd:套接…

【linuxC语言】系统调用IO文件操作

文章目录 前言一、文件描述符介绍二、系统调用IO API介绍2.1 open函数2.2 close函数2.3 read函数2.4 write函数2.5 lseek函数 三、示例代码总结 前言 在Linux系统中&#xff0c;C语言通过系统调用实现对文件的输入输出&#xff08;I/O&#xff09;操作。系统调用提供了访问操作…

一款Mac系统NTFS磁盘读写软件Tuxera NTFS 2023 for Mac

当您获得一台新 Mac 时&#xff0c;它只能读取 Windows NTFS 格式的 USB 驱动器。要将文件添加、保存或写入您的 Mac&#xff0c;您需要一个附加的 NTFS 驱动程序。Tuxera 的 Microsoft NTFS for Mac 2023是一款易于使用的软件&#xff0c;可以在 Mac 上打开、编辑、复制、移动…

sudo command not found

文章目录 一句话Intro其他操作 一句话 sudo 某命令 改成 sudo -i 某命令 试试。 -i 会把当前用户的环境变量带过去&#xff0c;这样在sudo的时候&#xff0c;有更高的权限&#xff0c;有本用户的环境变量(下的程序命令)。 -i, --login run login shell as the target user; a …

Javaweb之Web后端开发总结的详细解析

4. Web后端开发总结 到此基于SpringBoot进行web后端开发的相关知识我们已经学习完毕了。下面我们一起针对这段web课程做一个总结。 我们来回顾一下关于web后端开发&#xff0c;我们都学习了哪些内容&#xff0c;以及每一块知识&#xff0c;具体是属于哪个框架的。 web后端开…

MySQL 使用 pt-archiver 删除数据

文章目录 前言1. 环境准备1.1 模拟造数1.2 工具安装 2. 删除数据2.1 批次删除表2.2 原理解析2.3 批处理思路 后记 前言 在线核心业务都会有日志表&#xff0c;随着业务持续运行&#xff0c;日志表每天都在增大&#xff0c;最后超过阈值触发空间使用率告警。DBA 处理空间告警时…

调用Mybatis plus中的saveBatch方法报找不到表的问题

1.问题现象 在用Mybatis plus开发的项目中&#xff0c;用自带的API批量保存的方法saveBatch操作时&#xff0c;发现报没有找到表的错误。 错误日志截图如下&#xff1a; 表实际是存在的&#xff0c;且发现其他的方法都没有问题&#xff0c;包括save、update等单个的方法&…

第十五届蓝桥杯青少组STEMA测评SPIKE初级真题试卷 2024年1月

第十五届蓝桥杯青少组STEMA测评SPIKE初级真题试卷 2024年1月 ​​​​​​​ 来自&#xff1a;6547网 http://www.6547.cn/doc/vywur8eics

数智化转型的新篇章:企业如何在「数据飞轮」理念中寻求增长?_光点科技

在当今的数字化浪潮中&#xff0c;企业对数据的渴求与日俱增。数据不再仅是辅助决策的工具&#xff0c;而是成为推动业务增长的核心动力。自从「数据中台」概念降温后&#xff0c;企业纷纷探寻新的数智化路径。在这个过程中&#xff0c;「数据飞轮」作为一种新兴的理念&#xf…

鸿蒙NEXT实战开发:【截屏】

展示全屏截图和屏幕局部截图。通过[screenshot]模块实现屏幕截图 &#xff0c;通过[window]模块实现隐私窗口切换&#xff0c;通过[display]模块查询当前隐私窗口。 效果预览 全屏截图局部截图选择区域局部截图 使用说明&#xff1a; 点击右上角图标打开弹窗&#xff0c;选…

【笔记】Android 漫游定制SPN定制有关字段

一、SPN模块简介 【笔记】SPN和PLMN 运营商网络名称显示 Android U 配置 WiFiCalling 场景下PLMN/SPN 显示的代码逻辑介绍 【笔记】Android Telephony 漫游SPN显示定制&#xff08;Roaming Alpha Tag&#xff09; 二、相关配置字段 non_roaming_operator_string_array 是否…

Linux系统——Keepalive群集部署及认识

目录 一、Keepalive的认识 1.Keepalive基础——VRRP 2.Keepalived工具介绍 2.1Keepalived介绍 2.2Keepalived架构 2.2.1用户空间核心组件 2.2.2WatchDog&#xff1a;监控进程&#xff08;整个架构是否有问题&#xff09; 二、安装Keepalived及相关配置文件详解 1.安装…