2. PX4与传感器生态概览
在开始编写自定义传感器驱动之前,必须先建立一张“系统地图”:PX4 的软件架构长什么样,传感器在系统中处于什么位置,驱动又夹在哪一层之间。只有把这张地图看清楚,后续写 I2C/SPI 探测、注册 uORB 话题、发布 sensor_accel 等操作才不会变成“照抄模板”。本节从架构、传感器类型、驱动位置和典型应用场景四个角度,建立 PX4 传感器生态的整体认知。
一、PX4 的分层架构与传感器所处位置
PX4 采用典型的“分层 + 模块化”架构,自上而下大致可分为四层:应用层(飞行模式、任务、MAVLink 通信)、控制与估计层(姿态/位置控制器、EKF2 状态估计)、传感器抽象层(sensor 模块、uORB 话题)、驱动与总线层(具体驱动、I2C/SPI/UART/CAN 总线)。传感器驱动位于最底层,它负责把物理芯片的寄存器数据翻译成 PX4 内部统一格式的消息。
理解这一点的关键在于:驱动不直接参与控制,它只负责“采集 + 发布”。驱动通过 uORB 发布话题(如 sensor_accel、sensor_gyro、sensor_baro),上层估计与控制模块订阅这些话题。这种解耦让驱动开发变得相对独立——只要话题格式正确,上层无需关心你用的是哪家芯片。
二、PX4 支持的传感器类型
PX4 生态中的传感器种类繁多,但按功能可归为几大类。每类传感器在系统中都有对应的话题和驱动框架,理解分类有助于快速定位自己该写哪类驱动。
| 传感器类别 | 典型芯片/器件 | uORB 话题 | 总线 |
|---|---|---|---|
| 加速度计 | ICM-42688、BMI088 | sensor_accel | SPI / I2C |
| 陀螺仪 | ICM-42688、BMI088 | sensor_gyro | SPI / I2C |
| 磁力计 | IST8310、QMC5883 | sensor_mag | I2C |
| 气压计 | BMP388、MS5611 | sensor_baro | I2C / SPI |
| 测距传感器 | TFmini、超声波 | distance_sensor | UART / I2C |
| 光流/视觉 | PMW3901、光流模块 | optical_flow | SPI / UART |
| GNSS | u-blox M9N | sensor_gps | UART |
三、驱动在系统中的位置与工作流程
一个 PX4 传感器驱动的生命周期可以概括为“探测—初始化—采集—发布”四步。以 I2C 加速度计为例:驱动在启动时通过 probe() 读取 WHO_AM_I 寄存器确认芯片存在;随后配置量程、输出数据率(ODR)和滤波器;接着在定时器或中断驱动下周期性读取原始数据,做单位换算和温度补偿;最后通过 uORB 发布 sensor_accel 话题。
// 驱动核心流程伪代码
probe() → 读 WHO_AM_I,确认芯片 ID
init() → 配置量程、ODR、FIFO、中断
run() → 周期读取原始数据
publish() → 填充 sensor_accel_s 并 uORB 发布
四、常见应用场景
自定义传感器驱动在真实项目中非常常见,典型场景包括:
- 替换停产芯片:原厂 IMU 停产,需要把新芯片接入 PX4,保持话题不变。
- 增加专用传感器:如农业植保需要下视激光测距,物流无人机需要称重传感器。
- 提高采样率:竞速无人机需要更高 ODR 的陀螺仪数据,官方驱动不满足时自行优化。
- 多传感器冗余:在同一总线上挂载多颗同型号 IMU,实现冗余投票。
- 科研定制:实验平台需要接入非标传感器,如气体检测、辐射检测模块。
五、常见误区与复盘
误区二:忽略时间戳。uORB 话题中的
timestamp 必须来自 hrt_absolute_time(),错误的时间戳会导致 EKF 发散。误区三:直接修改官方驱动而不新建模块。建议新建独立驱动模块,避免升级 PX4 时冲突。
误区四:忘记注册到板级配置。驱动需要在
boards/ 对应板的 default.px4board 中启用,否则不会编译进固件。