<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Topics tagged with executor]]></title><description><![CDATA[A list of topics that have been tagged with executor]]></description><link>https://fishros.org.cn/forum/tags/executor</link><generator>RSS for Node</generator><lastBuildDate>Wed, 26 Aug 2026 18:14:59 GMT</lastBuildDate><atom:link href="https://fishros.org.cn/forum/tags/executor.rss" rel="self" type="application/rss+xml"/><pubDate>Invalid Date</pubDate><ttl>60</ttl><item><title><![CDATA[microros中执行器管理]]></title><description><![CDATA[<h1>执行器管理</h1>
<p dir="auto">本文是对官网文章个人的总结概括，有意读者可阅读官网文章：<a href="https://micro.ros.org/docs/concepts/client_library/execution_management/" target="_blank" rel="noopener noreferrer nofollow ugc">https://micro.ros.org/docs/concepts/client_library/execution_management/</a></p>
<h2>介绍</h2>
<p dir="auto">​    节点是ROS框架的根基，节点内的回调函数更是灵魂。ROS中通信机制有很多，话题，服务，动作等等，所以对节点的回调函数的执行处理是一个很重要的问题。</p>
<p dir="auto">​    ROS1中网络线程接收到的所有消息均放在FIFO队列中，回调也是以FIFO的方式调用，没有执行管理。在ROS2中，随着DDS（数据分发服务）的引入，executor（执行器）的概念也被创建来支持执行管理。大致流程是<strong>查询-&gt;获取-&gt;执行</strong>：</p>
<ul>
<li>ROS2中消息被缓冲在DDS中，executor 会收集它所管理的所有节点中的句柄，配置一个等待集(wait set)并发给rcl层，并阻塞。</li>
<li>rcl层返回一个就绪集（ready set），列出哪些句柄此刻有消息。</li>
<li>Executor 遍历就绪集，从中提取数据，调用相应回调函数。</li>
</ul>
<p dir="auto">​    但ROS2标准rclcpp执行器具有局限性。例如定时器优先于所有其他 DDS 句柄，非定时器句柄采用非抢占式轮询调度，以及每个句柄仅考虑一个输入数据（即使可能有多个输入数据可用），ROS也没有机制来强制节点内回调函数的执行顺序。这些特点致使其难以保证执行器的<strong>确定性和实时性。</strong></p>
<p dir="auto">​    鉴于以上问题，在开发microros的执行器时，官方开发了高级执行管理机制，并将其用于ROS中，改进了标准ROS2的rclcpp库。</p>
<h2>rclcpp标准执行器分析</h2>
<h3>体系结构</h3>
<ul>
<li>弱引用管理：<strong>执行器实例只维护指向节点的弱指针（weak po1inter）</strong>。弱指针是c++中的一个概念。通俗理解就是通过一个中间人去访问对象。执行器访问节点时会判断节点是否存在，如果节点已销毁，执行器就会跳过，而不会强行访问导致bug。所以我们可以安全地销毁节点，而无需通知Executor。</li>
<li>依赖DDS队列：执行器自己不维护回调队列，而是依赖DDS来缓冲消息。它只是需要了，从中提取数据。</li>
<li>缺乏优先级：执行器内部层次，在一个任务中，不对回调进行优先级排序或分类。</li>
<li>非实时感知：执行器与操作系统层次，没有利用底层操作系统调度器的实时特性来更好地控制执行顺序。可以理解为没有配置任务优先级。</li>
</ul>
<h3>不太好的特性</h3>
<ul>
<li>计时器优先级最高。执行器总是先处理定时器。如果定时器任务太多（过载），DDS 里的普通消息（如传感器数据）可能永远轮不到处理。</li>
<li>非定时器句柄采用非抢占式循环调度。</li>
<li>每一句柄只考虑一条消息。会严重加剧延迟。</li>
</ul>
<h2>处理模式的分析</h2>
<p dir="auto">​    这一大部分文章主要分析了<strong>移动机器人和实时嵌入式系统的处理模式</strong>，由此分析推导出<code>microros</code>中执行器应具有的特点.</p>
<p dir="auto"><strong>移动机器人：</strong></p>
<ul>
<li>机器人的感知-规划-行动流水线</li>
<li>多速率传感器同步</li>
<li>高优先级处理路径</li>
</ul>
<p dir="auto"><strong>实时嵌入式系统</strong></p>
<ul>
<li>时间触发轮询</li>
<li>逻辑执行时间 （LET）</li>
</ul>
<h2>rclc执行器</h2>
<h3>特征</h3>
<p dir="auto">rclc执行器支持所有事件类型：</p>
<ul>
<li>订阅</li>
<li>计时器</li>
<li>服务</li>
<li>客户</li>
<li>警戒条件</li>
<li>行动</li>
<li>生命周期</li>
</ul>
<p dir="auto">还提供了如下新功能：</p>
<ul>
<li>触发执行</li>
<li>用户自定义顺序执行</li>
<li>多线程和调度配置</li>
<li>用于周期性进程调度数据同步的<strong>LET语义</strong></li>
</ul>
<h3>顺序执行</h3>
<ul>
<li>配置过程中，用户可定义句柄的顺序：即添加顺序，先添加，先检查先执行。</li>
<li>在配置时，用户可以定义句柄是仅在有新数据可用时调用（ON_NEW_DATA）还是始终调用回调（ALWAYS）。<code>rclc_executor_add_subscription(&amp;exe_sense, &amp;sense_IMU, &amp;my_sub_cb2, ON_NEW_DATA);</code></li>
<li>运行时，所有句柄均按照用户定义的顺序进行处理。
<ul>
<li>如果句柄配置为 <strong>ON_NEW_DATA</strong>，则仅当<strong>有新数据可用时</strong>才会调用相应的回调函数。</li>
<li>如果句柄的配置为 <strong>ALWAYS</strong>，则相应的回调函数也始终为 ALWAYS。如果没有数据可用，则回调函数将<strong>不带任何数据（例如，空指针）被调用</strong>。</li>
<li>辨析：执行器被触发和回调被调用是两个概念。</li>
</ul>
</li>
</ul>
<h3>触发条件</h3>
<ul>
<li>给定一组句柄，触发条件（基于这些句柄的输入数据是否可用）决定<strong>何时开始处理所有回调</strong>。</li>
<li>可选方案：
<ul>
<li>ALL:当所有句柄都有输入数据时触发。</li>
<li>ANY:当至少一个句柄有输入数据可用时触发。</li>
<li>ONE:当用户指定的句柄有输入数据时触发。</li>
<li>User-defined： 用户自定义复杂的触发逻辑，甚至可以包含硬件中断。可以满足更个性化的需求。</li>
</ul>
</li>
</ul>
<h3>逻辑执行时间（LET语义）</h3>
<p dir="auto">LET语义的核心是通过<strong>固定时间读取，固定时间写入</strong>的策略，保证实时系统中**数据的一致性。**具体流程如下，在一个周期中：</p>
<ul>
<li>
<p dir="auto">周期开始（读输入）：<br />
周期开始时执行器会读取所有相关的输入数据，并保存为一份<strong>本地副本</strong>。</p>
</li>
<li>
<p dir="auto">周期进行中（处理计算）：</p>
<p dir="auto">执行器拿着本地副本中的数据，按预定顺序执行回调函数。关键在于，执行期间，<strong>即使DDS收到了新的数据，执行器也不会使用</strong>，从而保证本周期内数据的一致性。</p>
</li>
<li>
<p dir="auto">周期结束（写输出）：</p>
<p dir="auto">周期结束时，统一将结果发布，即使有的结果早就算出，也要等到最后统一发布。</p>
</li>
</ul>
<blockquote>
<p dir="auto">逻辑执行是一个特殊情况，正常情况下，执行器触发后，对数据是<strong>即取即用</strong>，对逐一读取句柄时，在执行该回调函数之前，才会从DDS队列中请求新数据。</p>
</blockquote>
<h3>多线程和调度配置</h3>
<p dir="auto">这个特点支持用户可以创建多个<code>executor</code>，把优先级高,低的<code>callback</code>分配给不同的<code>executor</code>，然后创建不同优先级的任务，让<code>executor</code>在不同任务中运行。</p>
<p dir="auto"><strong>注意</strong>：</p>
<ul>
<li>
<p dir="auto">通过将回调分配给不同的 Executor 实例，可以避免标准 ROS 2 执行器中“一个慢任务阻塞所有任务”的现象。</p>
</li>
<li>
<p dir="auto"><strong>危险性：</strong></p>
<blockquote>
<p dir="auto">if Executors are running in multiple threads, publishing needs to be atomic</p>
</blockquote>
</li>
</ul>
<p dir="auto">​</p>
<p dir="auto">当执行器在多线程中运行时，<strong>发布操作一定要是原子性的</strong>。microros现在库尚未提供这种线程安全的保护，所以需要用户手动实现。</p>
<pre><code class="language-c">void motor_callback(const void * msgin) {
    
    // 在发布前获取锁
    if (xSemaphoreTake(pub_mutex, portMAX_DELAY) == pdTRUE) {
        // 【原子操作区】此时没人能打断发布过程
        rcl_publish(&amp;shared_publisher, &amp;tx_msg, NULL);
        
        // 发布完立即释放锁
        xSemaphoreGive(pub_mutex);
    }
}
</code></pre>
<h3>执行器常用API</h3>
<h4>配置阶段</h4>
<ol>
<li>初始化参数  ：
<ul>
<li>回调总数</li>
<li>回调顺序</li>
<li>触发条件（可选，默认值：ANY）</li>
<li>数据通信语义（可选，默认为 ROS2）</li>
</ul>
</li>
<li>执行顺序与逻辑
<ul>
<li>顺序定义： 代码中添加句柄（Handle）的顺序，直接决定了运行时回调的 <strong>顺序处理顺序</strong>。</li>
<li>回调执行条件：
<ul>
<li><code>ON_NEW_DATA</code></li>
<li><code>ALWAYS</code></li>
</ul>
</li>
<li>执行器触发条件：
<ul>
<li><code>trigger_any</code> (默认)：任意一个回调有新数据就触发（兼容标准 ROS 2 行为）。</li>
<li><code>trigger_all</code>：所有回调都有新数据时才触发。</li>
<li><code>trigger_one</code>：指定某个特定句柄收到数据时触发。</li>
<li><code>user_defined_function</code>：用户自定义复杂逻辑。</li>
</ul>
</li>
<li>通信语义设置：
<ul>
<li>ROS2 (默认)</li>
<li>LET(逻辑执行时间)</li>
</ul>
</li>
</ul>
</li>
</ol>
<h4>执行阶段</h4>
<p dir="auto">可用的旋转函数：</p>
<ul>
<li>
<p dir="auto"><code>spin_some</code>：运行一次。<code>rclc_executor_spin_some(&amp;executor, 1000);</code>在1000ns内等待执行，<strong>只执行一次，就立即返回</strong>，1000ns是最大等待时间。</p>
</li>
<li>
<p dir="auto"><code>spin_period</code>：按固定周期运行。<strong>不会返回</strong>，在1000周期内执行一次，然后休眠；该周期结束，开始下一次周期。</p>
</li>
<li>
<p dir="auto"><code>spin</code>：无限循环运行。</p>
</li>
</ul>
]]></description><link>https://fishros.org.cn/forum/topic/4661/microros中执行器管理</link><guid isPermaLink="true">https://fishros.org.cn/forum/topic/4661/microros中执行器管理</guid><dc:creator><![CDATA[没文化青年]]></dc:creator><pubDate>Invalid Date</pubDate></item></channel></rss>