4、IMU确定性误差校准:六面法校准加速度计和陀螺仪的零偏与标度因数

各位同学,欢迎来到第四讲。

上一章我们聊了IMU的误差模型,把那些乱七八糟的误差项分成了确定性误差和随机误差。今天咱们就动真格的——手把手把加速度计和陀螺仪的零偏、标度因数给校准了。

说白了,就是让传感器说人话。

4.1 为什么非得做六面法?

你想想看,一个加速度计放在桌上,理论上应该只感受到重力(1g)。但实际读出来可能是1.02g,或者0.98g。这就是零偏和标度因数在捣鬼。

陀螺仪更离谱,静止的时候它应该输出0,但实际可能飘着0.5°/s。这种误差如果不校准,你飞控的姿态解算从一开始就是歪的。

我个人习惯,拿到一个新IMU芯片,第一件事就是做六面法校准。不做这一步,后面什么卡尔曼滤波、什么融合算法,都是空中楼阁。

核心思想: 利用重力加速度作为已知参考,通过旋转IMU到不同姿态,建立方程组求解误差参数。

4.2 六面法的基本原理

六面法,顾名思义,就是把IMU分别朝六个方向放置。每个方向对应一个轴的正负方向与重力对齐。

以加速度计为例,当X轴朝上时,理论上输出应为[+1g, 0, 0];X轴朝下时,输出为[-1g, 0, 0]。但实际读数包含了零偏和标度因数误差。

我们建立如下模型(只考虑零偏和标度因数):

实际输出 = 标度因数 × 理论值 + 零偏

对于加速度计,每个轴需要两个方程:

  • 正方向:A_pos = S × (+1g) + B
  • 负方向:A_neg = S × (-1g) + B

解这个二元一次方程组,就能得到:

  • 标度因数 S = (A_pos - A_neg) / (2g)
  • 零偏 B = (A_pos + A_neg) / 2

陀螺仪的六面法稍微不同。因为陀螺仪测量的是角速度,静止时理论输出为0。所以我们通过旋转台提供已知角速度,或者利用地球自转(但精度要求高,一般用转台)。

我在项目中遇到过,有些同学直接用六面法校准陀螺仪,结果发现零偏校准后还是飘。为什么?因为陀螺仪的零偏对温度极其敏感,六面法只能校准常温下的静态零偏。温度变化后,还得做温补。

4.3 实际操作步骤

好,咱们来走一遍流程。你需要准备:

  • 一个水平台面(越平越好)
  • IMU模块(固定在一个小方块上,方便翻转)
  • 串口助手或数据采集程序

4.3.1 加速度计六面法

六个放置姿态如下:

姿态编号 放置方向 理论加速度 (g)
1 X轴朝上 [+1, 0, 0]
2 X轴朝下 [-1, 0, 0]
3 Y轴朝上 [0, +1, 0]
4 Y轴朝下 [0, -1, 0]
5 Z轴朝上 [0, 0, +1]
6 Z轴朝下 [0, 0, -1]

每个姿态采集100-200个数据点,取平均值。然后按上面的公式计算每个轴的S和B。

小技巧: 采集数据时,等IMU稳定后再开始。我一般会等2-3秒,让数据收敛。另外,每个姿态之间翻转动作要快,但放置后要稳,避免手抖引入额外加速度。

4.3.2 陀螺仪六面法

陀螺仪的六面法其实更简单——因为静止时理论输出就是0。所以六个姿态下,每个轴的理论角速度都是0。

但这里有个坑:陀螺仪的零偏是各向同性的吗?不一定。我曾经遇到过一款IMU,X轴和Z轴的零偏差了一倍。所以必须每个轴单独校准。

操作步骤:

  1. 将IMU静止放置在六个姿态中的任意一个
  2. 采集100个数据点,取平均
  3. 这个平均值就是该轴的零偏(因为理论值为0)
  4. 重复六个姿态,取六个零偏的平均值作为最终零偏

至于标度因数,六面法其实不太适合陀螺仪。因为你需要一个已知的角速度输入。我建议用转台,或者至少用单轴旋转法。如果实在没有条件,可以先用加速度计的标度因数近似,或者查芯片手册。

警告: 陀螺仪的零偏校准一定要在IMU充分预热后进行。冷启动和热机后的零偏可能差好几倍。我习惯上电后等5分钟再开始校准。

4.4 代码实现

下面是我写的一个简单校准函数,用C语言实现。你可以直接移植到嵌入式平台上。

// 加速度计六面法校准
typedef struct {
    float scale[3];   // 标度因数
    float bias[3];    // 零偏
} AccelCalib;

AccelCalib accel_six_face_calib(float data[6][3]) {
    AccelCalib calib;
    // data[0]~data[5] 对应六个姿态的平均值
    // 姿态顺序:X+,X-,Y+,Y-,Z+,Z-
    
    for (int i = 0; i < 3; i++) {
        float pos = data[2*i][i];   // 正方向读数
        float neg = data[2*i+1][i]; // 负方向读数
        calib.scale[i] = (pos - neg) / 2.0f;  // 假设1g=1.0
        calib.bias[i] = (pos + neg) / 2.0f;
    }
    return calib;
}

// 应用校准
void apply_accel_calib(float raw[3], AccelCalib calib, float out[3]) {
    for (int i = 0; i < 3; i++) {
        out[i] = (raw[i] - calib.bias[i]) / calib.scale[i];
    }
}

嗯,这里要注意:上面的代码假设重力加速度归一化为1.0。如果你的IMU输出单位是m/s²,那标度因数算出来就是m/s²/LSB,零偏单位也是m/s²。使用时保持一致就行。

4.5 校准效果验证

校准完了,怎么知道效果好不好?

我个人习惯做两个验证:

  1. 静态验证: 把校准后的IMU放在水平面上,看加速度计模值是否接近1g(9.8m/s²)。偏差应该在0.01g以内。
  2. 翻转验证: 手动翻转IMU,看各轴读数是否在±1g附近,且正负对称。

我曾经遇到一个案例,校准后模值还是偏大0.05g。排查了半天,发现是台面不够水平。后来用水平仪重新调平,问题就解决了。所以,校准环境很重要。

4.6 六面法的局限性

六面法虽然简单,但有几个硬伤:

  • 依赖重力精度: 重力加速度在不同纬度有微小差异,高精度应用需要查表修正。
  • 无法校准交叉耦合: 六面法只处理了对角线元素,轴间耦合误差(比如X轴加速度对Y轴输出的影响)没考虑。
  • 陀螺仪标度因数不准: 前面说了,六面法对陀螺仪标度因数基本无能为力。

如果要做更高精度的校准,需要用到多位置法(比如十二面法)或者转台标定。但作为入门,六面法已经能解决80%的问题了。

总结一下: 六面法校准是飞控系统传感器融合的基石。它用最少的硬件成本(一个水平台面),解决了零偏和标度因数这两个最大的确定性误差。做完这一步,你的IMU数据才算真正可用。
六面法校准核心流程 1. 准备水平台面 2. 六个姿态采集数据 3. 计算零偏与标度因数 4. 验证校准效果 合格? 校准完成 检查环境/重采 返回步骤2 图:六面法校准流程图

好了,这一讲的内容就到这里。六面法虽然基础,但它是后续所有传感器融合工作的前提。下一章我们会讨论更复杂的多位置校准方法,以及如何处理轴间耦合误差。

公众号:蓝海资料掘金营,微信deep3321