mavros2 CPU 消耗过大原因在这扫码关注我的wx同一个 MAVROS、同一套插件、同样的流率配置从 ROS 1 迁到 ROS 2 后 CPU 占用直接翻了 4 倍——这不是玄学是架构和中间件的锅。本文基于 mavlink/mavros#2031 的完整讨论整理。背景2025 年 4 月开始ArduPilot 的 Ryan Friedman 在 mavros 仓库报告了一个issue同样的插件集合24 个插件和流率配置下mavros ROS 2 (Jazzy FastDDS) 的 CPU 占用是 ROS 1 的 4 倍。小舒GitHub: shupx也深度参与了这场讨论在 Humble FastDDS 环境下复现了问题通过实测定位到两大根因——模拟时间下的/clock订阅冗余、FastDDS 发现机制开销并提出了换用 CycloneDDS 等行之有效的解决办法。本文即基于该 issue 的完整讨论整理。现象一ROS 2 比 ROS 1 慢 4 倍插件开得越多越明显原始报告同一台机器、同样的插件和话题流率ROS 2 版 MAVROS 的 CPU 占用是 ROS 1 版的4 倍。更夸张的实测数据小舒在 Humble 上的复现FastDDS 10 个 MAVROS 实例UDP 连接飞控Intel i9 24 核直接被打满 100%同一条件下切到CycloneDDS只占 20%。而且这不止是 mavros 的问题——只要 ROS 2 节点数量多50FastDDS 在启动阶段的 CPU 开销就明显高于 CycloneDDSmavros 只是更容易踩中因为一个 mavros 进程里就有 10 个节点。现象二SITL 模拟时间下开销翻倍同一个 mavros_node小舒在 SITL 下实测两种时间模式差别巨大模式CPU 占用use_sim_timetrue/clock 以 200Hz 发布~20%use_sim_timefalse墙钟时间~4%模拟时间模式下 CPU 开销大约是真实时间的 5 倍。如果你在 SITL 里开发调试觉得机器发烫先查这个。原因分析根因 1每个插件一个独立节点ROS 2 版 mavros 的架构是每个 plugin 创建一个独立 ROS 节点一个进程里塞了 10 个节点从 issue 里贴的插件列表就能看到十几个/mavros/xxx节点。节点多带来两个连锁反应/clock订阅冗余ROS 2 里当use_sim_timetrue时每个节点都会订阅/clock来同步自己的 ROS 时间——哪怕是同一个进程里的多个节点也一样。10 个插件节点 10 份/clock回调处理纯属重复劳动。DDS 发现机制开销放大每个节点都要参与 DDS 的发现discovery流程节点越多发现相关的状态维护和网络流量越大。FastDDS 的发现机制开销尤其高。根因 2FastDDS 的发现机制开销大同样是节点多FastDDS 和 CycloneDDS 表现差异巨大这也是小舒在实测中观察到的。启动 50 节点的场景下FastDDS 启动阶段 CPU 极高换 CycloneDDS 明显缓解用 FastDDS 的 Discovery Server 也改善有限。这是 FastDDS 发现机制本身的开销问题不是 mavros 独有。根因 3执行器Executor选择不当mavros ROS 2 版默认用MultiThreadedExecutor。社区测试发现换成EventsExecutorROS 2 Jazzy 引入能大幅降低 CPU但 mavros 里部分插件的回调函数内有锁在事件执行器下可能挂死导致 service 调用失败——所以至少需要 2 个线程兜底另外还有一个独立的小 bugsys_time插件的参数回调里用了rclcpp::WallRate而不是标准计时方式白白浪费 CPU对应 PR #2212修复后能显著降耗。小结开销来自两个层面按 issue 里的结论总结mavros2 的 CPU 开销主要来自启动开销节点数量越多启动阶段 CPU 消耗越高FastDDS 的发现机制进一步放大。模拟时间开销use_sim_time开启时节点越多 →/clock订阅越多 → 时钟回调处理越多。一句话每个插件一个节点的架构 FastDDS 模拟时间三重 buff 叠满。解决办法按见效快 → 治本排序1. 换 RMWFastDDS → CycloneDDS效果最立竿见影sudoaptinstallros-${ROS_DISTRO}-rmw-cyclonedds-cppexportRMW_IMPLEMENTATIONrmw_cyclonedds_cpp# 或写进 ~/.bashrc 永久生效小舒的实测数据同条件下 FastDDS 启动50节点时打满 24 核 → CycloneDDS 只占 20%。节点多的场景下 CycloneDDS 的发现机制明显更省。当然还有一个方法是每个节点延迟启动会降低cpu消耗但总启动时间延长很多。2. 关掉模拟时间SITL 场景如果不需要仿真时间同步把use_sim_time设为false用墙钟时间。实测 mavros_node 从 ~20% 降到 ~4%。3. 换执行器Jazzy 及以上mavros 2.15 提供了执行器类型开关exportMAVROS_EXECUTOR_TYPEevents或用 PR #2189 的线程数覆盖把 UAS 执行器限制为 2 个工作线程低风险不用全局切换执行器exportMAVROS_UAS_EXECUTOR_THREADS2注意EventsExecutor 在Humble 不可用Jazzy 才引入mavros 部分回调有锁纯事件执行器可能引发 service 失败至少保留 2 个线程cm_executors的CBGEventsExecutor已 backport 到 Jazzy社区实测效果很好。4. 砍插件数量只加载真正用到的插件。mavros 是插件化架构MAVROS_PLUGINLIST里没用的插件直接不加载节点少了启动和运行开销都会降。5. 期待治本架构回归共享节点issue 讨论的最终建议像 ROS 1 版那样让每个插件复用同一个节点而不是各建各的。这能从根本上减少节点数量同时降低启动时间和/clock开销。mavros 后续版本已经在朝减少线程数、合并节点的方向改2.15 就有大量相关改动。总结mavros2 CPU 占用高的本质是插件级节点架构放大了 ROS 2 中间件的固有开销。短期最有效的三板斧换 CycloneDDS收益最大SITL 下关use_sim_timeJazzy 换 events 执行器或限制线程数。如果这些还不够那就得等 mavros 的架构重构了——或者自己动手把多余节点合并掉。参考mavlink/mavros Issue #2031 — CPU usage 4x higher in ROS 2 than ROS 1、PR #2189、PR #2212