基于 STM32U535 + ICM42688 的九轴 IMU 模块

项目定位:一块 25 × 30 mm 的 MCU + IMU 外设模块板,可配合其他主控使用,为整体系统提供角度与加速度感知,并参与闭环控制。项目在软件侧沉淀出一套可跨 MCU 移植的嵌入式框架,后续多个项目复用在此之上。

硬件设计

九轴 IMU 模块板

九轴 IMU 模块细节

以 STM32U535 为主控,集成 ICM42688(六轴)与 LIS2MDLTR(磁力计)构成九轴 IMU,通过 CH9102 实现 USB 转串口,负责模块初始化配置与数据上报。

软件架构

采用面向对象与分层解耦设计,将硬件抽象、核心接口、设备驱动、板级适配、业务封装与应用逻辑逐层分离,使同一套业务代码能够跨 MCU 移植、按需扩展外设。

Bootloader 与可靠性

实现基于串口的 Bootloader 与双 App 分区方案,支持分块下载、CRC32 校验、向非活动分区更新、试启动确认,以及未确认时自动回退;配合独立 watchdog 监测应用运行状态,让固件升级过程具备可恢复性。

姿态解算

融合层 imu_fusion 是统一入口:校准 → 低通 → 按配置选择算法。主要配置了 Mahony 互补滤波与 EKF。

传感器标定(三种都实现)

  • 陀螺仪:静止采样求均值与方差,方差超限即判定处于运动中并拒绝本次标定;成功后只重置在线零偏估计,已收敛姿态不受影响。
  • 加速度计:六面法——自动识别 ±X/±Y/±Z 六个朝向,每面要求至少 100 个连续稳定样本,不要求固定摆放顺序,六面齐全后解出逐轴偏置与比例。
  • 磁力计:采集极值求硬磁偏置与对角软磁比例,附带三维覆盖度检查,跨度不足或近共面直接判失败。

校准参数可持久化到 Flash,序列化与 CRC 由上层负责。

EKF 的核心设计

状态量不直接用四元数,而是 6 维误差状态:

$$\delta x = [,\delta\theta \in \mathbb{R}^3,\ \ \delta b \in \mathbb{R}^3,]$$

$\delta\theta$ 为右乘的局部角误差,$\delta b$ 为陀螺残余零偏。用误差状态而非直接对四元数做 EKF 的原因:四元数 4 个参数表示 3 个自由度,协方差矩阵会奇异;误差状态只有 3 维旋转向量,且名义四元数能始终保持严格单位长度。

协方差为 6×6 行优先数组,初值 $\mathrm{diag}(0.04,0.04,0.04,\ 0.0025,0.0025,0.0025)$,对应角误差标准差 0.2 rad、零偏 0.05 rad/s。

  • 预测:状态转移采用 SO(3) 指数与积分形式,含 $dt^3$ 的零偏–姿态交叉项;高转速时自动子步进(steps = ceil(max(dt/0.01, |ω|·dt/0.1)))保证积分精度。
  • 更新:重力方向与磁北方向都建模为三维单位向量观测,$H = [,\mathrm{skew}(\hat z),\ 0,]$,用 Cholesky 分解求 3×3 逆矩阵,协方差用 Joseph 形式更新,再用右 Jacobian 把协方差重置到误差注入后的新切空间。

初始对齐与磁重获

首次可靠重力用最短旋转对齐倾角(倒置情形特判为绕 X 轴旋转 180°,避免反向向量退化);首次可靠磁场锁定磁倾角,并且只绕世界重力轴对齐航向。磁丢失时退化六轴运行,累计缺失 ≥ 2 s 且重力可靠时重新捕获并对齐航向。

门限 判据 拦截对象
模长 加速度 0.81.2 g、磁场 10100 uT 剧烈运动、传感器异常
方向角差 $\langle \hat m, \hat z\rangle < 0.5$(≈60°) 姿态严重失配时的野值
NIS $\chi^2_3$ 的 0.001 分位 16.27 统计上不可能的创新
磁倾角一致性 与锁定参考的 $z$ 分量偏差 > 0.35 rad(≈20°) 局部磁干扰 / 硬铁异常

磁观测另需水平分量 $\ge 0.1$ 且水平场强 $\ge 2$ uT——倾角接近 90° 时航向本就不可观,此时拒绝磁观测而不是让它污染状态。

稳态协方差

静止、100 Hz、1000 s、磁倾角 40°、场强 50 uT:

状态 方差 标准差
roll 7.14e-5 rad² 0.484°
pitch 6.26e-5 rad² 0.453°
yaw 1.67e-4 rad² 0.741°(磁)
零偏 x/y/z 1.50e-6 (rad/s)² 1.23e-3 rad/s

姿态约 300 s 收敛、零偏约 500 s,700 s 后不再变化。场强从 15 到 90 uT 结果完全相同——因为只观测方向而非矢量。

  • yaw 方差是 roll 的 2.3 倍,主导因素不是噪声比而是几何。 $R_{mag}/R_{acc}=1.6$ 只解释一小部分;真正的原因在磁倾角——航向只由磁场的水平分量约束,而水平分量 $\propto\cos(\text{dip})$:
磁倾角 0° 20° 40° 60° 75°
yaw/roll 方差比 1.61 1.77 2.34 3.99 8.35

误差预算与一致性分析(蒙特卡洛仿真)

仿真条件:静止、100 Hz、磁倾角 40°、场强 50 uT。

① 噪声假设与器件实际规格的差距

参数 滤波器配置 ICM42688 / MMC5983 规格 配置保守倍数
gyro_noise 0.015 rad/s/√Hz 0.0028 dps/√Hz 307×
accel_noise 0.05(归一化) 70 µg/√Hz 51×
mag_noise 0.08(归一化) 0.5 mG 113×

配置值刻意保守,但这也意味着表观精度主要反映的是假设而非器件能力。

② 一致性检验(注入噪声 = 配置假设)

轴 实际 RMS 误差 自报 σ 实际/自报
roll 0.421° 0.484° 0.87
pitch 0.547° 0.454° 0.77
yaw 0.664° 0.735° 0.90

roll/yaw 比值接近 1,滤波器自洽;pitch 实际误差是自报值的约 3 倍——物理上 pitch 本应最准(skew(gravity) 对 roll/pitch 灵敏度相同,而 skew(mag) 对 pitch 最灵敏),出现倒挂说明存在模型缺陷。

③ 根因定位

align_heading() 用单帧含噪样本锁定磁参考:

1
ctx->mag_reference[2] = world[2];   /* 该帧磁倾角噪声被永久写进参考 */

紧接着 initial_p(ctx) 把协方差重置回初值,等于宣称「参考是精确的」——参考自身的误差从此不进入 P。对照实验(仅改变参考锁定方式):

参考锁定方式 pitch 实际 自报 比值
单帧含噪样本(现状) 1.35° / 1.01°(两次独立种子) 0.454° 2.97 / 2.23
无噪样本 0.387° / 0.387° 0.454° 0.85 ✓

方向可复现(含噪锁定必然抬高 pitch),幅度随那一帧噪声波动;roll/yaw 基本不受影响。改用多帧平均锁定参考即可把该误差降一个量级。

④ 噪声受限地板

器件实际噪声比配置低 51~307 倍,按线性外推受限地板 < 0.02°,低于本实现 float32 的分辨率——蒙特卡洛在 k≤0.03 时已崩塌(误差直接归零),即该地板已无法用本仿真观测。

⑤ 磁干扰敏感性(决定 yaw)

误差源 仿真中 真机典型量级
传感器白噪声 ✅ 已建模 < 0.02°(非瓶颈)
加计标定残差 ❌ 不存在 0.1~0.5°
磁环境残余 ❌ 不存在 1~3°
零偏不稳定性 ⚠️ 仅随机游走 分钟级主导

验证

  • 无零偏轨迹:最差姿态误差 0.0275°
  • 注入零偏后:最差 0.3474°,零偏估计误差 < 0.004 rad/s
  • 四元数模长 1 ± 2e-5;协方差对称性 < 1e-6
  • 协方差全程保持正定(最小特征值 1.50e-6 > 0)——这是滤波器不发散的前提,而朴素实现最容易丢掉它
  • 零偏估计无虚报:输入零偏为 0 时稳态估计收敛到 0,不会因姿态残差而「编造」出零偏

调试与工具链

使用 CMake + DAPLink + OpenOCD 搭建 GDB MCP Server,让 AI Agent 规范化参与到 MCU 的 Debug 流程中——该工具链后续复用到电赛车载平衡系统中。

技术栈

STM32U535 · ICM42688 · LIS2MDLTR · 误差状态 EKF · Mahony · CMSIS-DSP · Bootloader · CH9102 · 嘉立创 EDA · CMake / OpenOCD

仓库:IMU