2. PX4与ArduPilot架构对比

PX4 与 ArduPilot 都是开源飞控软件栈,二者都能在 Pixhawk 系列硬件上运行,也都支持硬件在环(HIL)仿真,但它们的内部组织方式、驱动模型、通信机制和 HIL 接入路径存在明显差异。理解这些差异,直接决定你在做 HIL 时该从哪里接入仿真器、该改哪一层、该看哪条数据链。本节不泛泛比较“谁更好”,而是从飞控栈组成、传感器驱动、通信协议和 HIL 支持四个维度,把两者的结构关系讲清楚。

一、飞控栈组成:分层方式不同

PX4 采用“模块化中间件 + 独立任务”的结构。底层是 NuttX 实时操作系统(Pixhawk 系列)或 Linux(部分伴飞场景),其上运行 uORB 发布/订阅消息总线。传感器驱动、姿态估计(EKF2)、位置控制、姿态控制、导航、commander 状态机、mavlink 模块等,都是独立模块,通过 uORB 主题交换数据。例如 sensor_combined、vehicle_attitude、vehicle_local_position、actuator_controls_0 都是 uORB 主题。模块之间不直接调用,而是发布和订阅,因此替换或旁路某一层相对容易。

ArduPilot 采用“库 + 主循环调度”的结构。核心是 AP_Vehicle 派生出的 ArduCopter、ArduPlane、ArduRover 等机型类,传感器、EKF、控制律、MAVLink 等以库(library)形式被链接进同一个固件。主循环按固定频率调度 update(),各库通过 AP_HAL 硬件抽象层访问底层。相比 PX4 的“消息总线 + 模块”,ArduPilot 更接近“单体固件 + 库调用”,模块边界由 C++ 类接口体现,而不是运行时的消息主题。

这一差异对 HIL 的影响很直接:PX4 可以在 uORB 层注入仿真传感器数据,也可以整体替换 simulator 模块;ArduPilot 则通常通过 AP_HAL 的 SIM 后端或 SITL 编译选项,把传感器读取和电机输出重定向到仿真器。

PX4 与 ArduPilot 飞控栈结构对比 PX4:uORB 消息总线 + 独立模块 应用层:commander / navigator / mavlink 控制层:mc_pos_control / mc_att_control 估计层:EKF2 / sensors 模块 uORB 发布/订阅消息总线 驱动层:spi / i2c / pwm_out 驱动 NuttX / Linux + HAL HIL 接入点:simulator 模块 经 uORB 注入 sensor_combined / 读取 actuator ArduPilot:库调用 + 主循环调度 机型层:ArduCopter / ArduPlane / Rover 控制库:AC_AttitudeControl / AP_Motors 估计库:AP_NavEKF3 / AP_AHRS 主循环 scheduler(固定频率 update) 传感器库:AP_InertialSensor / AP_Baro AP_HAL(ChibiOS / Linux / SITL) HIL 接入点:AP_HAL_SITL 重定向传感器读取与电机输出到仿真器 对比

二、传感器驱动:注册模型与 HAL 抽象

PX4 的传感器驱动通常以独立模块存在,例如 mpu6000、icm20689、ms5611、ist8310。驱动启动后向 sensors 模块注册,由 sensors 统一做校准、滤波和发布,最终形成 sensor_combined、vehicle_imu 等主题。也就是说,PX4 的驱动与数据发布之间隔了一层 sensors 聚合模块,HIL 时可以用 simulator 模块直接发布这些主题,绕过真实 SPI/I2C 驱动。

ArduPilot 的传感器驱动以 AP_InertialSensor 后端形式组织,例如 AP_InertialSensor_MPU6000、AP_InertialSensor_ICM20689。驱动通过 AP_HAL::SPIDevice 或 I2CDevice 访问总线,采样后交给 AP_InertialSensor 前端做统一处理和发布。HIL 时,ArduPilot 使用 AP_InertialSensor_SITL 等 SITL 后端,从仿真器接收 IMU 数据,而不是从真实总线读取。因此,ArduPilot 的 HIL 接入更靠近 HAL 层,PX4 的 HIL 接入更靠近 uORB 消息层。

三、通信协议:MAVLink 是共同语言,但内部链路不同

两者对外都使用 MAVLink 与地面站通信,也都支持 MAVLink 2。区别在于内部:PX4 的 mavlink 模块订阅 uORB 主题,把 vehicle_attitude、vehicle_global_position 等转成 MAVLink 消息;ArduPilot 的 GCS_MAVLink 库则从各库直接取数据组包。对 HIL 而言,这意味着 PX4 的 HIL 数据流通常表现为“仿真器 → simulator 模块 → uORB → mavlink 模块 → 地面站”,而 ArduPilot 是“仿真器 → AP_HAL_SITL → 各库 → GCS_MAVLink → 地面站”。

此外,PX4 还支持 uXRCE-DDS、RTPS 等与伴飞计算机通信;ArduPilot 则常用 MAVLink 转发、AP_DDS(较新版本)或直接串口协议。做 HIL 时,如果你要注入外部导航数据,PX4 更倾向通过 uORB 主题或 MAVLink 消息,ArduPilot 更倾向通过 MAVLink 或 HAL 层重定向。

四、HIL 支持差异与共同点

共同点很明确:两者都支持 SITL/HIL 仿真,都能与 Gazebo、jMAVSim(PX4 侧)、JSBSim(ArduPilot 侧)等仿真器联动,都通过 MAVLink 的 HIL 相关消息(如 HIL_SENSOR、HIL_GPS、HIL_STATE_QUATERNION)或自定义 UDP 包交换数据,都能在无真实硬件的情况下验证姿态估计、控制律和任务逻辑。

差异在于接入层次和配置方式。PX4 的 HIL 通常通过 make px4_sitl 或 simulator 模块启动,仿真器与飞控之间用 UDP 交换 HIL_SENSOR 等消息,飞控内部走 uORB。ArduPilot 的 HIL 通常通过 sim_vehicle.py 启动 SITL,使用 AP_HAL_SITL 把传感器和输出重定向到仿真器,飞控内部走库调用。PX4 更强调“消息级替换”,ArduPilot 更强调“HAL 级替换”。

实践提示:做 HIL 联调时,先确认你面对的是哪一层。PX4 侧优先检查 uorb top 中 sensor_combined、vehicle_attitude 是否更新;ArduPilot 侧优先检查 SIM 后端是否被编译进来、AP_HAL_SITL 是否收到仿真数据。两者都用 MAVLink 看 ATTITUDE、GLOBAL_POSITION_INT 是否合理。

五、对比速查表

维度 PX4 ArduPilot
飞控栈组织 uORB 消息总线 + 独立模块 库调用 + 主循环调度
传感器驱动 独立驱动模块,经 sensors 聚合发布 uORB 主题 AP_InertialSensor 等后端,经 AP_HAL 访问总线
内部通信 uORB 发布/订阅 C++ 类接口直接调用
对外协议 MAVLink、uXRCE-DDS、RTPS MAVLink、AP_DDS(新版本)
HIL 接入层 simulator 模块 + uORB 主题注入 AP_HAL_SITL + 传感器/输出重定向
常用仿真器 Gazebo、jMAVSim Gazebo、JSBSim
HIL 消息 HIL_SENSOR、HIL_GPS 等 MAVLink 消息 HIL_SENSOR、HIL_GPS 等 MAVLink 消息

总结来看,PX4 与 ArduPilot 在 HIL 上的共同点是“都用 MAVLink 交换仿真数据、都能脱离真实硬件验证飞控逻辑”,差异在于“PX4 从消息层接入、ArduPilot 从 HAL 层接入”。掌握这一点,你在搭建 HIL 环境时就能快速判断该改哪个模块、该看哪条数据、该在哪里注入故障,而不是盲目试错。