2. PX4飞控基础
在把 Zenoh 与 ROS 2 接入 PX4 之前,必须先理解 PX4 自身的运行骨架。PX4 并不是一个“大循环”程序,而是由多个模块(Module)组成的实时系统:传感器驱动、姿态估计、控制器、导航、通信等模块各自运行,通过 uORB 消息总线交换数据。外部通信(MAVLink、Zenoh、ROS 2)本质上都是“把内部 uORB 话题翻译成外部协议,或把外部指令翻译回 uORB 话题”的桥接过程。理解这条链路,才能判断数据从哪里来、延迟发生在哪、以及为什么某些话题无法直接桥接。
一、PX4 架构:模块化 + 发布/订阅
PX4 的固件可分为四层:最底层是 NuttX 实时操作系统(或 Linux 仿真目标),其上是驱动与板级支持,再上是飞行控制核心模块(如 ekf2、mc_att_control、navigator),最上层是通信与外部接口(mavlink、uxrce_dds、zenoh 等)。各模块之间不直接调用函数,而是通过 uORB 发布和订阅话题,这种松耦合让模块可以独立启停、替换和调试。
PX4 的启动由启动脚本(rcS)完成,它按顺序启动传感器、估计器、控制器和通信模块。你可以通过 MAVLink 控制台或 QGroundControl 的 MAVLink Shell 查看模块状态:
px4> uorb top
px4> listener sensor_combined
px4> mavlink status
px4> work_queue status
其中 uorb top 显示各话题的发布频率,是排查“数据是否在流动”的第一工具;listener 可以打印某个话题的实时内容,用于确认字段含义和数值范围。
二、uORB 消息总线:PX4 的“数据中枢”
uORB 是 PX4 内部的发布/订阅消息总线,每个话题对应一个 .msg 定义文件,编译时生成 C/C++ 结构体。发布者写入数据,订阅者按固定频率读取,支持多发布者、多订阅者,并带有时间戳和队列深度。uORB 的关键特性是:话题名唯一、数据结构固定、发布频率由模块决定。例如 vehicle_attitude 由 ekf2 发布,vehicle_local_position 由 ekf2 发布,vehicle_command 可由 MAVLink 或外部模块发布。
在桥接场景中,uORB 话题是“源数据”。Zenoh 或 ROS 2 桥接模块通常订阅一个或多个 uORB 话题,将其序列化后发送到外部网络;反向则把外部消息反序列化并发布回 uORB。因此,选择哪些话题、以多高频率桥接,直接决定带宽和实时性。
vehicle_attitude 在 ROS 2 中通常映射为 /fmu/out/vehicle_attitude,而 Zenoh 桥接可以自定义键表达式,例如 px4/vehicle_attitude。桥接前必须确认话题名、频率和字段类型。三、MAVLink 协议:PX4 的传统外部通道
MAVLink 是 PX4 与地面站、机载计算机通信的经典协议,采用二进制帧、消息 ID 和校验机制,支持串口、UDP、TCP 等传输方式。PX4 中 MAVLink 模块负责将 uORB 话题打包成 MAVLink 消息(如 ATTITUDE、GLOBAL_POSITION_INT),并解析外部指令(如 COMMAND_LONG、SET_MODE)。MAVLink 的优点是成熟、工具链完善;缺点是消息集固定、扩展性有限,且在高频大数据场景下带宽效率不高。
在 PX4 与 ROS 2 的早期方案中,常用 mavros 作为桥接:mavros 通过 MAVLink 与 PX4 通信,再在 ROS 2 侧发布话题。但 mavros 的延迟和消息映射限制,促使了 uXRCE-DDS 和 Zenoh 等更直接的桥接方式。理解 MAVLink 有助于对比:MAVLink 是“协议翻译”,而 Zenoh 更接近“数据总线直连”。
四、仿真环境与硬件在环基础
PX4 支持软件在环(SITL)和硬件在环(HITL)。SITL 在 Linux 上运行 PX4 仿真固件,配合 Gazebo 或 jMAVSim 提供物理模型和传感器数据;HITL 则把真实飞控板接入仿真器,飞控运行真实固件,传感器数据由仿真注入。两者对桥接开发都很有价值:SITL 便于快速迭代,HITL 能验证真实时序和硬件接口。
启动 SITL 的典型命令如下:
make px4_sitl gazebo-classic
# 或
make px4_sitl gz_x500
启动后,PX4 会监听 UDP 14550 端口用于 MAVLink,QGroundControl 可自动连接。若要在 SITL 中测试 Zenoh 桥接,通常需要额外启动桥接模块,并确认仿真时间与真实时间的关系,避免因时间步长导致消息频率异常。
五、核心链路对比与选型参考
下表对比 PX4 内部与外部通信的关键通道,帮助判断在 Zenoh/ROS 2 工程中应把桥接点放在哪里。
| 通道 | 作用域 | 典型频率 | 优点 | 局限 |
|---|---|---|---|---|
| uORB | PX4 内部模块间 | 1 Hz ~ 1 kHz | 零拷贝、低延迟、类型安全 | 仅限固件内部,不直接对外 |
| MAVLink | 飞控 ↔ 地面站/机载 | 1 Hz ~ 50 Hz | 成熟、工具多、跨平台 | 消息集固定、带宽效率低 |
| uXRCE-DDS | PX4 ↔ ROS 2 | 1 Hz ~ 100 Hz | 直接映射 uORB 到 ROS 2 | 依赖 Micro XRCE-DDS Agent |
| Zenoh | PX4 ↔ ROS 2/云 | 可配置,可达 1 kHz | 低开销、支持广域、键表达式灵活 | 需自行实现桥接与序列化 |
六、案例:从 uORB 到 Zenoh 的最小桥接思路
假设我们要把 vehicle_attitude 通过 Zenoh 发布出去。桥接模块需要做三件事:订阅 uORB 话题、按固定频率读取、序列化后写入 Zenoh 键。伪代码如下:
// 伪代码:uORB -> Zenoh
orb_subscribe(ORB_ID(vehicle_attitude));
while (running) {
orb_copy(ORB_ID(vehicle_attitude), sub, &att);
serialize(att, buf);
zenoh_put("px4/vehicle_attitude", buf, len);
usleep(10000); // 100 Hz
}
反向桥接则订阅 Zenoh 键,反序列化后 orb_publish 到对应 uORB 话题。注意:不是所有 uORB 话题都适合高频桥接,例如 sensor_combined 频率可达 1 kHz,直接桥接会占满带宽;通常只桥接估计器输出和控制指令。
七、复盘:桥接前必须确认的清单
- 目标 uORB 话题是否存在、由哪个模块发布、频率多少。
- 话题字段类型、单位、坐标系是否与外部系统一致。
- 桥接方向:只读(遥测)还是读写(控制),是否需要安全校验。
- 传输层:串口、UDP、共享内存还是 Zenoh 网络,带宽和延迟预算。
- 仿真与真机的差异:SITL 时间步长、HITL 传感器注入方式。
- 调试手段:
uorb top、listener、Zenoh 订阅端日志、ROS 2topic hz。
掌握以上基础后,后续章节中的 Zenoh 桥接、ROS 2 话题映射和端到端延迟分析,都可以回到这条“uORB → 桥接 → 外部网络”的主线上来定位问题。