mavros2 CPU 消耗过大?原因在这

mavros2 CPU 消耗过大?原因在这

同一个 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 节点数量多(50+),FastDDS 在启动阶段的 CPU 开销就明显高于 CycloneDDS,mavros 只是更容易踩中,因为一个 mavros 进程里就有 10+ 个节点

现象二:SITL 模拟时间下开销翻倍

同一个 mavros_node,小舒在 SITL 下实测两种时间模式,差别巨大:

模式CPU 占用
use_sim_time=true(/clock 以 200Hz 发布)~20%
use_sim_time=false(墙钟时间)~4%

模拟时间模式下 CPU 开销大约是真实时间的 5 倍。如果你在 SITL 里开发调试觉得机器发烫,先查这个。

原因分析

根因 1:每个插件一个独立节点

ROS 2 版 mavros 的架构是每个 plugin 创建一个独立 ROS 节点,一个进程里塞了 10+ 个节点(从 issue 里贴的插件列表就能看到十几个 /mavros/xxx 节点)。

节点多带来两个连锁反应:

  1. /clock 订阅冗余:ROS 2 里当 use_sim_time=true 时,每个节点都会订阅 /clock 来同步自己的 ROS 时间——哪怕是同一个进程里的多个节点也一样。10 个插件节点 = 10 份 /clock 回调处理,纯属重复劳动。
  2. DDS 发现机制开销放大:每个节点都要参与 DDS 的发现(discovery)流程,节点越多,发现相关的状态维护和网络流量越大。FastDDS 的发现机制开销尤其高。

根因 2:FastDDS 的发现机制开销大

同样是节点多,FastDDS 和 CycloneDDS 表现差异巨大(这也是小舒在实测中观察到的)。启动 50+ 节点的场景下,FastDDS 启动阶段 CPU 极高,换 CycloneDDS 明显缓解;用 FastDDS 的 Discovery Server 也改善有限。这是 FastDDS 发现机制本身的开销问题,不是 mavros 独有

根因 3:执行器(Executor)选择不当

mavros ROS 2 版默认用 MultiThreadedExecutor。社区测试发现:

  • 换成 EventsExecutor(ROS 2 Jazzy 引入)能大幅降低 CPU;
  • 但 mavros 里部分插件的回调函数内有锁,在事件执行器下可能挂死,导致 service 调用失败——所以至少需要 2 个线程兜底;
  • 另外还有一个独立的小 bug:sys_time 插件的参数回调里用了 rclcpp::WallRate 而不是标准计时方式,白白浪费 CPU(对应 PR #2212,修复后能显著降耗)。

小结:开销来自两个层面

按 issue 里的结论总结,mavros2 的 CPU 开销主要来自:

  1. 启动开销:节点数量越多,启动阶段 CPU 消耗越高;FastDDS 的发现机制进一步放大。
  2. 模拟时间开销use_sim_time 开启时,节点越多 → /clock 订阅越多 → 时钟回调处理越多。

一句话:"每个插件一个节点"的架构 + FastDDS + 模拟时间,三重 buff 叠满。

解决办法

按"见效快 → 治本"排序:

1. 换 RMW:FastDDS → CycloneDDS(效果最立竿见影)

sudo apt install ros-${ROS_DISTRO}-rmw-cyclonedds-cpp
export RMW_IMPLEMENTATION=rmw_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 提供了执行器类型开关:

export MAVROS_EXECUTOR_TYPE=events

或用 PR #2189 的线程数覆盖,把 UAS 执行器限制为 2 个工作线程(低风险,不用全局切换执行器):

export MAVROS_UAS_EXECUTOR_THREADS=2

注意:

  • EventsExecutor 在 Humble 不可用(Jazzy 才引入);
  • mavros 部分回调有锁,纯事件执行器可能引发 service 失败,至少保留 2 个线程
  • cm_executorsCBGEventsExecutor 已 backport 到 Jazzy,社区实测效果很好。

4. 砍插件数量

只加载真正用到的插件。mavros 是插件化架构,MAVROS_PLUGINLIST 里没用的插件直接不加载,节点少了,启动和运行开销都会降。

5. 期待治本:架构回归"共享节点"

issue 讨论的最终建议:像 ROS 1 版那样,让每个插件复用同一个节点,而不是各建各的。这能从根本上减少节点数量,同时降低启动时间和 /clock 开销。mavros 后续版本已经在朝"减少线程数、合并节点"的方向改(2.15 就有大量相关改动)。

总结

mavros2 CPU 占用高的本质是:插件级节点架构放大了 ROS 2 中间件的固有开销。短期最有效的三板斧:

  1. 换 CycloneDDS(收益最大);
  2. SITL 下关 use_sim_time
  3. Jazzy+ 换 events 执行器或限制线程数

如果这些还不够,那就得等 mavros 的架构重构了——或者自己动手,把多余节点合并掉。


参考:mavlink/mavros Issue #2031 — CPU usage 4x higher in ROS 2 than ROS 1PR #2189PR #2212

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值