1. 无人机软件架构选型的十字路口
搞无人机软件开发的人,这两年几乎都绕不开一个话题:新项目到底该上 ROS1 还是 ROS2。我自己从 2018 年前后开始用 ROS1 做飞控外围和视觉感知模块,到 2021 年逐步把几个在研项目迁移到 ROS2,中间踩过的坑、熬过的夜、推翻重来的架构设计,攒了不少真实体会。这篇文章不打算写成官方文档的复述,而是想以一个一线开发者的视角,把“为什么我更推崇 ROS2”这件事讲透,顺带把迁移过程中那些文档里不会写的细节摊开来说。
先说清楚这篇文章适合谁看。如果你正在做无人机相关的软件开发,涉及飞控通信、视觉感知、路径规划、集群协同这些方向,并且正在纠结技术栈选型,那这篇内容应该能帮你省下不少试错时间。如果你刚接触 ROS,还在看 ros2 菜鸟教程、ros2 入门教程这类材料,也可以先了解一下两个版本的本质差异,避免一开始就走上一条后期要推倒重来的路。文章会涉及 ROS1、ROS2、DDS、micro-ROS 这些核心概念,也会聊到实际项目中的通信机制、实时性、部署方式等工程问题。
我推崇 ROS2 不是因为它“新”,而是因为它在无人机这个特定场景下,解决了一批 ROS1 时代靠打补丁才能勉强应付的问题。下面我从架构设计、核心机制、实操落地、问题排查几个维度,把这件事掰开揉碎讲清楚。
2. 为什么无人机项目对通信架构如此敏感
2.1 无人机软件系统的真实构成
一架稍微像样的无人机,软件层面从来不是“一个程序跑到底”。它至少包含这几块:飞控固件(跑在 STM32 这类 MCU 上)、机载计算单元(树莓派、Jetson、RK3588 等)、地面站软件、以及可能存在的云端调度服务。机载计算单元上又要同时跑视觉感知、路径规划、状态估计、任务调度等多个模块。这些模块之间需要频繁交换数据:IMU 姿态、GNSS 定位、图像帧、点云、控制指令、航点信息。
问题就出在这里。ROS1 时代,节点间通信走的是自定义的 TCPROS/UDPROS 协议,底层依赖一个叫 roscore 的中心节点。所有节点启动时都要先向 master 注册,通信时先问 master 要对方的地址,然后再建立连接。这个设计在实验室里跑 demo 没问题,但放到无人机上,麻烦就来了。
我印象很深的一次,是做一个多机协同的编队项目。地面站和几架无人机之间需要同步状态,结果 roscore 一挂,整个系统全瘫。更头疼的是,WiFi 链路抖动的时候,TCPROS 的重连逻辑会让某些话题的延迟突然飙到几百毫秒,对于需要实时响应的控制回路来说,这是致命的。
2.2 ROS1 架构在无人机场景下的三个硬伤
第一个硬伤是单点故障。roscore 是全局唯一的,它一旦崩溃或者网络分区,所有节点之间的通信都会中断。无人机在天上飞,你不可能说“等我重启一下 master”。虽然可以用多 master 方案或者一些第三方工具来缓解,但本质上都是在跟架构设计对抗。
第二个硬伤是实时性无法保证。ROS1 的通信层没有 QoS 概念,所有消息都是“尽力而为”或者“可靠传输”二选一,没法针对不同话题做差异化配置。但无人机上不同数据的实时性要求天差地别:IMU 数据要求高频低延迟,丢几帧无所谓;而控制指令丢了可能直接导致炸机。ROS1 没法在通信层面区分这些需求。
第三个硬伤是对嵌入式端支持差。无人机上大量使用 STM32、ESP32 这类 MCU,ROS1 基本没法直接跑上去,只能通过串口桥接,写一堆自定义协议。这不仅增加开发量,还让整个系统的可维护性变差。热词里出现的 stm32 micro-ros、esp32 无人机 开源这些方向,其实都是在解决这个问题,而这些方案几乎都是围绕 ROS2 生态展开的。
2.3 ROS2 带来的架构性改变
ROS2 最根本的变化,是去掉了中心化的 master,改用 DDS 作为通信中间件。DDS 本身就是为分布式实时系统设计的,自带服务发现、QoS 策略、多播通信这些能力。节点之间直接通过 DDS 发现彼此,不需要一个“中间人”。这意味着任何一个节点挂掉,都不会影响其他节点之间的通信。
这个改变对无人机来说意义重大。你可以把视觉节点、规划节点、控制节点分别部署在不同的计算单元上,它们通过 DDS 自动发现并建立通信,整个系统没有单点。而且 DDS 的 QoS 机制允许你针对每个话题单独配置可靠性、持久性、 deadline、延迟预算等参数,真正做到“重要数据可靠传,高频数据快速传”。
3. ROS1 与 ROS2 核心机制对比拆解
3.1 通信模型:从 TCPROS 到 DDS
ROS1 的通信模型可以类比成“打电话先查黄页”。你要给某个节点发消息,得先去 master 那里查它的地址,然后建立连接。这个过程中 master 是必经之路,而且连接建立后是点对点的 TCP 或 UDP。
ROS2 的 DDS 模型更像“对讲机群聊”。每个节点加入一个 domain,通过多播或者单播的方式自动发现同一 domain 内的其他节点。发现之后,数据的传输是节点之间直接进行的,不经过任何中心。DDS 还支持多种传输方式,包括共享内存、UDP、TCP,可以根据场景自动选择。
这里要特别提一下Fast DDS,这是 ROS2 默认的 DDS 实现之一,也是目前用得最广的。它的特点是性能好、配置灵活,支持零拷贝传输。对于无人机上的图像和点云这类大数据量话题,零拷贝能显著降低 CPU 占用和延迟。热词里 fast dds 详解 被频繁搜索,说明大家确实在关注这块的底层机制。
3.2 QoS 策略:无人机场景下的关键差异
QoS 是 ROS2 相比 ROS1 最实用的改进之一。我拿几个无人机上的典型话题来说明。
| 话题类型 | 数据特征 | ROS1 处理方式 | ROS2 QoS 建议配置 |
|---|---|---|---|
| IMU 姿态 | 高频、可丢帧 | 默认可靠传输,易堆积 | Best Effort,Keep Last 1 |
| 控制指令 | 低频、不可丢 | 可靠传输,但无优先级 | Reliable,Keep Last 1,Deadline 监控 |
| 图像帧 | 高频、大流量 | 容易阻塞其他话题 | Best Effort,Keep Last 1,限制带宽 |
| 航点信息 | 低频、需持久 | 无持久化机制 | Reliable,Transient Local |
| 状态告警 | 事件型、需可靠 | 可靠传输 | Reliable,Keep All |
这张表是我在实际项目中反复调整后总结出来的。ROS1 时代,你没法针对话题做这种差异化配置,只能全局调参数,结果就是要么牺牲实时性,要么牺牲可靠性。ROS2 的 QoS 让你可以“因材施教”,这是架构层面的进步。
3.3 实时性与确定性:控制回路的关键
无人机的控制回路对实时性要求极高。从传感器采样到控制输出,整个链路的延迟必须稳定且可预测。ROS1 的通信层没有 deadline 概念,你没法知道一条消息是否在预期时间内到达。ROS2 的 DDS 支持Deadline和Latency Budget等 QoS 策略,可以监控通信是否满足实时性要求,超时还能触发回调。
另外,ROS2 支持实时内核和实时执行器,配合 PREEMPT_RT 补丁,可以把控制回路的抖动控制在微秒级。这对于做高精度姿态控制或者高速避障的团队来说,是 ROS1 完全给不了的能力。
3.4 嵌入式端支持:micro-ROS 的价值
micro-ROS 是 ROS2 生态里专门为 MCU 设计的轻量级实现。它让 STM32、ESP32 这类资源受限的芯片可以直接作为 ROS2 节点参与通信,而不需要额外的桥接程序。热词里 stm32h7 结合 dmamux 双缓冲与 dds 技术实现高精度波生成、stm32 micro-ros、esp32 无人机 开源 这些内容,反映的正是这个趋势。
我自己的一个项目里,用 STM32H7 跑 micro-ROS,直接发布 IMU 数据和接收控制指令,省掉了一颗专门做协议转换的芯片。整个系统的节点数量减少了,故障点也少了。micro-ROS 底层同样走 DDS,所以它和机载 Linux 上的 ROS2 节点是无缝通信的,不需要任何自定义协议。
4. 无人机项目迁移到 ROS2 的实操路径
4.1 环境搭建:从零到可运行
先说安装。ROS2 的安装比 ROS1 友好很多,官方提供了一键脚本和二进制包。以 Ubuntu 22.04 为例,安装 ROS2 Humble 的步骤大致如下:
# 设置 locale sudo apt update && sudo apt install locales sudo locale-gen en_US en_US.UTF-8 sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 # 添加 ROS2 软件源 sudo apt install software-properties-common sudo add-apt-repository universe sudo apt update && sudo apt install curl -y sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null # 安装 ROS2 Humble sudo apt update sudo apt install ros-humble-desktop sudo apt install ros-dev-tools # 配置环境变量 echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc source ~/.bashrc装完之后,可以用ros2 run demo_nodes_cpp talker和ros2 run demo_nodes_cpp listener验证通信是否正常。如果能看到消息收发,说明 DDS 层工作正常。
注意:如果你之前装过 ROS1,环境变量可能会冲突。建议在 .bashrc 里用条件判断区分,或者干脆用 Docker 隔离两个环境。我见过太多人因为 source 顺序问题导致 ros2 command not found,排查半天才发现是 ROS1 的环境变量覆盖了。
4.2 飞控通信接口的重新设计
ROS1 时代,和飞控通信通常用 mavros 或者自己写串口驱动。ROS2 下 mavros 也有对应版本,但更推荐的做法是用 micro-ROS 直接让飞控作为 ROS2 节点,或者用 DDS 桥接。
以 PX4 为例,ROS2 下可以用px4_ros_com和micro-ROS-agent配合,让 PX4 跑 micro-ROS 客户端,直接发布 uORB 消息到 ROS2 话题。这样飞控和机载计算机之间的通信就走 DDS,不需要额外的 mavlink 转换层。
配置 micro-ROS-agent 的典型命令:
# 启动 micro-ROS agent,监听串口 ros2 run micro_ros_agent micro_ros_agent serial --dev /dev/ttyACM0 -b 921600飞控端需要集成 micro-ROS 客户端库,配置好 topic 映射和 QoS。这里有个经验:串口波特率尽量拉高,921600 是起步,能上 2M 更好。因为 IMU 数据频率高,波特率不够会导致消息堆积。
4.3 视觉感知模块的迁移要点
无人机视觉感知通常涉及图像采集、目标检测、跟踪、深度估计等模块。ROS1 下常用 usb_cam、cv_bridge、image_transport 这些包。ROS2 下都有对应版本,但 API 有变化。
迁移时最容易踩的坑是cv_bridge 的编码格式。ROS1 和 ROS2 在图像消息的 encoding 字段处理上有差异,直接移植代码可能出现颜色通道错乱。建议在转换时显式指定编码:
from cv_bridge import CvBridge bridge = CvBridge() # ROS2 下建议显式指定 desired_encoding cv_image = bridge.imgmsg_to_cv2(msg, desired_encoding='bgr8')另一个坑是图像话题的 QoS。默认的 QoS 是 Reliable,对于高帧率图像来说会导致发送端阻塞。一定要改成 Best Effort:
from rclpy.qos import QoSProfile, ReliabilityPolicy, HistoryPolicy qos = QoSProfile( reliability=ReliabilityPolicy.BEST_EFFORT, history=HistoryPolicy.KEEP_LAST, depth=1 ) self.create_subscription(Image, '/camera/image_raw', self.callback, qos)4.4 路径规划与导航栈的适配
ROS1 的 navigation 栈在 ROS2 下对应的是 Nav2。八叉树地图导航在 ROS2 下用 octomap_server2 或者直接集成到 Nav2 的 costmap 插件里。热词里 ros2 八叉树地图导航 被搜索,说明这是很多人的实际需求。
Nav2 的配置比 ROS1 的 move_base 复杂,但灵活性更高。核心配置文件包括:
nav2_params.yaml:全局和局部代价地图、规划器、控制器参数behavior_trees:行为树定义,控制导航流程map_server:地图加载
我建议先用默认配置跑通,再逐步调参。特别是无人机的三维导航,需要把 costmap 配置成 3D 的,或者用 octomap 做障碍物表示。
5. 实操中的典型问题与排查实录
5.1 DDS 发现失败:节点互相看不见
这是 ROS2 新手最常见的问题。两个节点明明在同一台机器上,就是发现不了对方。排查思路如下:
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| 同机节点发现不了 | ROS_DOMAIN_ID 不一致 | 统一 export ROS_DOMAIN_ID=42 |
| 跨机发现不了 | 多播被禁用 | 配置单播发现或检查防火墙 |
| 部分节点可见 | 网卡选择错误 | 设置 ROS_LOCALHOST_ONLY 或指定网卡 |
| 发现延迟大 | DDS 配置问题 | 调整发现协议参数或换 DDS 实现 |
我遇到过一次,是因为开发机上装了 Docker,DDS 默认绑到了 docker0 网卡上,导致和外部节点发现不了。解决办法是设置ROS_LOCALHOST_ONLY=1或者显式指定网卡。
5.2 消息延迟抖动:QoS 配置不当
有次做视觉伺服,发现图像话题的延迟忽高忽低,控制回路跟着抖。查了半天,发现是图像话题用了默认的 Reliable QoS,发送端在等接收端确认,接收端处理不过来就堆积。改成 Best Effort 之后,延迟立刻稳定了。
经验:高频传感器数据一律用 Best Effort,控制指令和状态告警用 Reliable。这个原则能解决 80% 的延迟问题。
5.3 micro-ROS 连接不稳定
micro-ROS 跑在 MCU 上,资源有限,连接不稳定是常见问题。排查要点:
- 串口波特率是否足够,建议 921600 以上
- MCU 端的内存池是否够用,默认配置可能偏小
- micro-ROS-agent 的版本是否和客户端库匹配
- 是否有其他程序占用了串口
我自己的项目里,把 STM32 的 micro-ROS 内存池从默认的 4KB 调到 16KB 之后,连接稳定性明显提升。
5.4 编译与依赖问题
ROS2 用 colcon 替代了 catkin,编译命令变成colcon build。常见问题包括:
ros2 command not found:环境变量没 source,或者 ROS1 和 ROS2 冲突- 包找不到:检查
AMENT_PREFIX_PATH和COLCON_PREFIX_PATH - Python 版本问题:ROS2 Humble 默认用 Python 3.10,虚拟环境里要注意
建议用--symlink-install参数编译,方便调试:
colcon build --symlink-install --packages-select your_package6. 工具链与生态的长期考量
6.1 仿真环境
ROS2 下 Gazebo 的集成比 ROS1 更紧密,Ignition Gazebo(现在叫 Gazebo Sim)原生支持 ROS2。无人机仿真可以用gz配合ros_gz_bridge,把仿真中的传感器数据桥接到 ROS2 话题。相比 ROS1 时代的 gazebo_ros_pkgs,配置更清晰,性能也更好。
6.2 可视化工具
RViz2 是 ROS2 的可视化工具,功能上比 RViz 更现代,支持更多插件。安装和使用:
sudo apt install ros-humble-rviz2 ros2 run rviz2 rviz2对于无人机,常用的可视化包括:TF 树、点云、图像、路径、marker 等。RViz2 的配置可以保存为 .rviz 文件,方便团队共享。
6.3 集群通信
无人机集群是 ROS2 的强项。DDS 天然支持多节点发现和通信,配合 ROS_DOMAIN_ID 可以隔离不同集群。对于大规模集群,可以用 DDS 的 partition 功能做进一步隔离。
我做过一个 5 机编队的项目,每架无人机跑一个 ROS2 节点,通过 DDS 自动发现,地面站作为监控节点加入同一 domain。整个系统没有中心节点,任何一架失联都不影响其他无人机。
6.4 长期维护与社区趋势
ROS1 的 Noetic 是最后一个版本,2025 年 5 月已经停止维护。ROS2 的 Humble 是 LTS 版本,支持到 2027 年,后续还有 Iron、Jazzy 等版本。从社区活跃度看,新功能、新工具几乎都只在 ROS2 上开发。现在入局无人机软件开发,选 ROS2 是顺势而为。
7. 我个人的迁移体会与建议
如果你手头有 ROS1 的老项目,不建议一次性全量迁移。我的做法是新模块直接用 ROS2 写,老模块通过 ros1_bridge 逐步替换。ros1_bridge 可以让 ROS1 和 ROS2 节点互相通信,给迁移留出缓冲期。
对于新项目,直接上 ROS2,别犹豫。学习曲线确实比 ROS1 陡一点,主要是 DDS 和 QoS 的概念需要时间消化,但一旦理解,你会发现很多在 ROS1 里需要绕弯解决的问题,在 ROS2 里是原生支持的。
最后分享一个我踩过的坑:别在无人机上跑默认的 DDS 配置。默认配置是为通用场景设计的,资源占用和发现行为不一定适合无人机。花时间调一下 DDS 的发现协议、线程池、内存池参数,对系统稳定性提升很大。Fast DDS 的 XML 配置文件可以精细控制这些行为,值得深入研究。
至于 micro-ROS,如果你的飞控是 STM32H7 或者 ESP32,强烈建议试试。它能让你的飞控直接成为 ROS2 网络的一部分,省掉一层协议转换,整个系统的架构会清爽很多。