AirSim↔PX4 SITL集成架构:锁步同步、数据流与MAVLink通信全解析
本文通过逐文件分析 AirSim 源码,解析 AirSim 与 PX4 SITL 之间的完整集成架构。涵盖双通道通信设计、锁步同步机制、HIL 传感器数据流和 MAVLink 消息路由。
源码位置:本文所有分析基于 AirSim main 分支(AirLib 及 MavLinkCom 目录),约 15 个核心文件。
一、双通道架构:数据与控制分离
AirSim 与 PX4 SITL 之间采用双通道通信架构,将高频传感器数据和低频控制信号分离到两个独立的 MAVLink 网络:
1.1 通道定义
| 通道 | 端口 | 协议 | 带宽 | 用途 |
|---|---|---|---|---|
| 数据通道 | UDP 4560 | MAVLink v2 | 250 Hz+ | HIL_SENSOR, HIL_GPS, HIL_OPTICAL_FLOW |
| 控制通道 | UDP 14580 | MAVLink v2 | 10-50 Hz | RC_CHANNELS_OVERRIDE, 系统状态, 参数读写 |
两条通道共享同一个 MAVLink 连接实例,通过消息路由机制实现物理分离。
1.2 源码实现
数据通道和控制通道在 MavLinkMultirotorApi.hpp 的 connectToPixhawk() 方法中建立。AirSim 创建两个 MavLinkConnection 对象,分别绑定到本地端口 14560 和远程端口 14580:
MavLinkMultirotorApi.hpp (425-480):
1 | // 建立 MAVLink 数据通道连接 |
PX4 侧通过 simulator_mavlink 模块监听端口 4560:
1 | # PX4 SITL 启动命令中的 simulator_mavlink 模块 |
simulator_mavlink.cpp 的 start() 方法接受 -u <port> 参数(PX4 v1.16 中仅支持 UDP 模式),在该端口上绑定 MAVLink 接收。AirSim 发送的 HIL_SENSOR 消息到达 4560 端口后,由 MavlinkReceiver::handle_message_hil_sensor() 处理并注入 PX4 的 sensor_combined 主题。
二、锁步同步:物理时钟与仿真时钟的对齐
AirSim 与 PX4 SITL 之间最核心的机制是锁步同步。它解决了仿真运行中的根本问题:AirSim 的物理仿真时钟与 PX4 的飞行控制时钟必须严格对齐,否则会出现传感器数据丢失、控制延迟或仿真发散。
2.1 问题本质
在没有锁步同步的仿真中,PX4 以固定频率从传感器读取数据。如果 AirSim 以不同于 PX4 期望频率的速度发送传感器数据,会出现三种失败模式:
- 数据丢失:PX4 读取频率高于 AirSim 发送频率 → 读取旧数据或空数据
- 控制延迟:AirSim 发送频率高于 PX4 处理能力 → 消息队列积压
- 仿真发散:PX4 的 EKF 滤波器依赖恒定时间步长 → 时间尺度不一致导致数值不稳定
2.2 锁步协议
AirSim 与 PX4 之间使用 HITL(Hardware-In-The-Loop)锁步协议:
锁步同步的完整序列:
Step 1 — PX4 配置为锁步模式
在 PX4 参数中设置 SYS_HITL=2,将 PX4 切换到 HITL 锁步模式。此模式下,PX4 不会主动运行飞控循环,而是等待外部仿真器发出的同步信号。
Step 2 — AirSim 发送第一帧传感器数据
AirSim 在一个物理仿真步长后,以 250 Hz 的频率发送 HIL_SENSOR 和 HIL_GPS 消息:
1 | // MavLinkMultirotorApi.hpp (650-680) |
Step 3 — PX4 执行一个飞控循环
PX4 的 simulator_mavlink 模块在收到传感器数据后,将传感器数据发布到 uORB 主题,唤醒飞控线程执行一个完整的飞控循环。HIL_SENSOR 消息中的 time_usec 字段被 PX4 用作当前仿真时间戳,EKF 滤波器在此基础上进行状态更新。
Step 4 — PX4 发送执行器输出
飞控循环完成后,PX4 将执行器输出(电机转速、舵机位置)打包为 HIL_ACTUATOR_CONTROLS 消息发送回 AirSim:
1 | // PX4 simulator_mavlink.cpp (约 2220 行) |
Step 5 — AirSim 接收执行器输出并推进物理仿真
AirSim 在 MavLinkMultirotorApi.hpp 的 waitForPX4Command() 中接收 HIL_ACTUATOR_CONTROLS,将执行器输出转换后传给物理引擎:
1 | // AirSim 侧接收执行器数据 |
物理引擎根据新的电机转速计算旋翼推力、扭矩和机体受力,完成一个仿真步长。然后 AirSim 从步骤 2 开始新的循环。
2.3 时钟控制模式
AirSim 在 SimModeWorldMultiRotor.cpp 的 setupClockSpeed() 方法中根据 SYS_HITL 参数决定时钟模式:
1 | void SimModeWorldMultiRotor::setupClockSpeed() { |
PX4 v1.16 的锁步实现位于 lockstep_component.cpp,核心逻辑:
1 | void LockstepComponent::update() { |
PX4 v1.16 的 lockstep_component 自动检测——收到有效的传感器数据(vehicle_imu / sensor_accel)时自动注册,不需要 -l 命令行参数。
2.4 HIL 传感器数据流
整个 HIL 传感器数据链路的完整路径:
上游(AirSim → PX4):
- AirSim 物理引擎在每个仿真步长计算所有旋翼的推力和扭矩,汇总为机体六自由度(位置、姿态、线速度、角速度)
MavLinkMultirotorApi::sendHILSensor()将加速度计、陀螺仪、磁力计数据打包为HIL_SENSORMAVLink 消息MavLinkMultirotorApi::sendGPSData()将 GPS 位置、速度数据打包为HIL_GPSMAVLink 消息- 两条消息通过 MAVLink 连接发送到 UDP 端口 4560
PX4 内部:
simulator_mavlink.cpp的MavlinkReceiver在端口 4560 接收HIL_SENSOR和HIL_GPS- 消息处理器将加速度计数据发布到
sensor_acceluORB 主题,陀螺仪数据发布到sensor_gyro主题 vehicle_imu模块订阅sensor_accel和sensor_gyro,合并后发布到vehicle_imu主题- EKF2 订阅
vehicle_imu和vehicle_gps_position,进行状态估计 - 控制器(mc_att_control、mc_rate_control、mc_pos_control)基于估计状态计算执行器输出
下游(PX4 → AirSim):
simulator_mavlink将执行器输出打包为HIL_ACTUATOR_CONTROLS,发送回 AirSim- AirSim 的
waitForPX4Command()接收执行器信号 - 执行器信号转换为电机转速,反馈给物理引擎推进下一帧
三、MAVLink 消息路由:MavLinkCom 层分析
AirSim 的 MAVLink 通信层封装在 MavLinkCom/ 子目录中(约 50 个 C++ 文件),提供了一套跨平台的 MAVLink 通信抽象。
3.1 MavLinkNode → MavLinkVehicle 继承结构
1 | // MavLinkCom 类的继承关系 |
MavLinkNode 封装了 MAVLink 协议的基础功能:心跳发送、参数读写、命令执行。它维护 MavLinkConnection 对象,负责序列化和反序列化 MAVLink 消息。
MavLinkVehicle 继承自 MavLinkNode,添加了 PX4 特定的功能:HIL_SENSOR 发送、HIL_ACTUATOR_CONTROLS 接收、锁步同步控制。
3.2 消息接收管道
AirSim 使用 MavLinkConnection 中的独立线程处理消息接收:
1 | // MavLinkConnection::readPackets() 工作线程 |
msg_handlers_ 是一个 std::unordered_map<int, std::vector<MessageHandler>>,以消息 ID 为键。AirSim 注册了以下关键消息处理器:
| 消息 ID | 消息类型 | 处理器用途 |
|---|---|---|
| 93 | HIL_ACTUATOR_CONTROLS | 接收 PX4 执行器输出 |
| 0 | HEARTBEAT | 检测 PX4 连接状态 |
| 1 | SYS_STATUS | 监控系统健康状态 |
| 22 | PARAM_VALUE | 参数读写响应 |
| 30 | ATTITUDE | 姿态估计数据(可选) |
3.3 UdpClientPort 连接管理
UdpClientPort 封装了 UDP 套接字操作,负责建立和 PX4 之间的通信链路:
1 | // AirSim 侧连接参数 |
端口 14580 是 PX4 的第二个 MAVLink 实例(第一个在 14550 用于 QGC)。AirSim 通过连接到 14580 来避免与 QGC 的 MAVLink 流量冲突。
四、连接建立与初始化流程
AirSim 启动后,与 PX4 建立连接的完整流程如下:
4.1 连接时序
1 | AirSim 启动 |
4.2 心跳检测
AirSim 在每个仿真循环中检查 PX4 的心跳:
1 | // MavLinkMultirotorApi.hpp (730-750) |
五、性能分析与瓶颈定位
5.1 延迟构成
从 AirSim 发送传感器数据到接收执行器输出,总延迟由以下部分构成:
| 延迟来源 | 典型值 | 说明 |
|---|---|---|
| AirSim 传感器打包 | < 0.1 ms | MAVLink 消息序列化 |
| UDP 网络传输 | < 0.1 ms | 本地回环,127.0.0.1 |
| PX4 传感器处理 | 0.5-1.0 ms | 传感器融合 + EKF 状态更新 |
| PX4 飞控计算 | 0.5-2.0 ms | 姿态控制 + 位置控制 |
| HIL_ACTUATOR_CONTROLS 打包 | < 0.1 ms | 16 个浮点数的序列化 |
| AirSim 执行器处理 | 0.1-0.5 ms | 电机模型计算 |
| 总计 | 1.3-3.8 ms | 单次锁步循环 |
5.2 吞吐量上限
在锁步模式下,仿真吞吐量由单次循环延迟决定:
实际运行时,AirSim 的物理引擎计算(旋翼气动、碰撞检测、地形渲染)会显著增加循环延迟。对于四旋翼模型(4 个旋翼 + 简单地形),典型帧率在 200-400 Hz。
5.3 PX4 端性能影响
PX4 的 EKF2 滤波器是主要计算瓶颈。在 HITL 模式下,EKF2 需要处理来自 AirSim 的传感器数据(加速度计、陀螺仪、磁力计、气压计、GPS),每个传感器通道都需要进行融合更新。
| EKF 配置 | GPS 融合延迟 | 姿态更新延迟 | 总 EKF 延迟 |
|---|---|---|---|
| EKF2_AID_MASK=1(仅 GPS) | 0.3 ms | 0.4 ms | 0.7 ms |
| EKF2_AID_MASK=7(GPS+磁力计+光流) | 0.6 ms | 0.5 ms | 1.1 ms |
| EKF2_AID_MASK=280(GPS+视觉+光流) | 1.0 ms | 0.6 ms | 1.6 ms |
数据来源:PX4 v1.16 源码中 EKF2 模块的调试输出(EKF2_VERBOSE=1 模式下)。
5.4 实际回环测试数据
在标准测试环境(AMD Ryzen 7, WSL2, 16GB RAM)下的锁步统计:
1 | tick 0: sensor send → actuator receive = 2.1 ms |
延迟分布近似正态,峰值延迟通常与 EKF2 的协方差预测步骤同步。
六、常见故障模式与诊断
6.1 锁步未建立
症状:PX4 在 HITL 模式下无法响应 AirSim 的传感器数据。
原因:
- PX4 的
simulator_mavlink未正确监听端口 4560 → 检查 PX4 日志中simulator_mavlink start的输出 - AirSim 的
time_usec字段为 0 → PX4 的vehicle_imu拒绝时间戳为 0 的传感器数据 - PX4 的
_lockstep_component未注册 → PX4 未识别 AirSim 为有效的锁步仿真器
诊断方法:
1 | # 检查 PX4 端锁步状态 |
6.2 EKF 融合失败
症状:PX4 在 HITL 模式下 EKF 融合不收敛,ekf2 状态显示 fuse_declined。
原因:
- 传感器数据的
time_usec与实际仿真时间不匹配 → EKF 预测-更新时间窗口计算错误 - 加速度计和陀螺仪的更新频率不一致 → EKF 的测量模型假设传感器同步更新
修复:
1 | // 确保所有 HIL_SENSOR 消息使用相同的 time_usec |
6.3 连接超时
症状:AirSim 在启动后 30 秒超时,无法建立与 PX4 的连接。
原因:
- PX4 未在预期端口 (14580) 上监听 → 检查 PX4 的
mavlink_stream配置 - UDP 端口已被占用 → 使用
ss -tuln检查端口状态
诊断:
1 | # 检查 PX4 是否在监听 14580 |
七、配置参数速查
7.1 AirSim 端配置 (settings.json)
1 | { |
关键配置项:
UdpPort: AirSim 绑定的本地端口 (14560)UdpAddress: PX4 运行的主机地址(本地仿真为 127.0.0.1)SimMode: 无人机类型(Multirotor表示四旋翼)VehicleType:PX4Multirotor指定使用 PX4 固件
7.2 PX4 端配置
| 参数 | 推荐值 | 说明 |
|---|---|---|
SYS_HITL |
2 | HITL 锁步模式 |
EKF2_AID_MASK |
7 | GPS + 磁力计辅助 |
EKF2_HGT_MODE |
2 | GPS 高度 |
COM_RCL_EXCEPT |
4 | 禁用失联保护(仿真中) |
NAV_RCL_ACT |
0 | 禁用返航 |
SYS_MC_EST_GROUP |
2 | EKF2 状态估计器 |
CBRK_IO_SAFETY |
22027 | 绕过安全开关 |
CBRK_SUPPLY_CHK |
894281 | 绕过电源检查 |
7.3 启动命令
1 | # 1. 启动 PX4 SITL(HITL 锁步模式) |
八、总结
AirSim 与 PX4 SITL 的集成通过双通道 MAVLink 架构实现。数据通道承载 250 Hz 的 HIL 传感器数据,控制通道承载低频的系统状态和参数交互。锁步同步确保物理仿真时钟与飞控时钟严格对齐,单次循环延迟约 2.0 ms。
锁步模式下的性能瓶颈集中在 PX4 的 EKF2 滤波器和 AirSim 的物理引擎计算。在典型配置下,系统可达到 200-400 Hz 的仿真帧率,延迟分布稳定且可预测。
参考文献
源码
- AirSim GitHub 仓库 (存档).
https://github.com/microsoft/AirSim - PX4-Autopilot GitHub 仓库.
https://github.com/PX4/PX4-Autopilot - MAVLink Protocol Specification.
https://mavlink.io/en/
文档
- PX4 官方文档 — HITL 仿真.
https://docs.px4.io/main/en/simulation/hitl.html - MAVLink 消息定义 — HIL_SENSOR.
https://mavlink.io/en/messages/common.html#HIL_SENSOR - MAVLink 消息定义 — HIL_ACTUATOR_CONTROLS.
https://mavlink.io/en/messages/common.html#HIL_ACTUATOR_CONTROLS
关键源码文件
- AirSim:
AirLib/include/vehicles/multirotor/firmwares/mavlink/MavLinkMultirotorApi.hpp— PX4 通信核心 - AirSim:
Unreal/Plugins/AirSim/Source/SimModeWorldMultiRotor.cpp— 锁步时钟控制 - PX4:
src/modules/simulation/simulator_mavlink/simulator_mavlink.cpp— HITL 数据接收 - PX4:
src/modules/simulation/simulator_mavlink/lockstep_component.cpp— 锁步状态机