4、加速度计校准(六面法)
加速度计校准,说白了就是让传感器告诉你「哪个方向是向下」。
我刚开始做飞控时,觉得加速度计出厂前都标定好了,没必要再校准。结果第一次试飞,飞机悬停时一直往一边飘,怎么调PID都没用。后来才发现,是加速度计零偏没处理好。嗯,从那以后,我再也不敢跳过这步了。
4.1 六面法的数学原理
六面法的核心思想很简单:让加速度计的每个轴,分别朝上和朝下。
你想想看,当加速度计静止时,它只受重力影响。理想情况下,某个轴朝上时,读数应该是 +1g;朝下时,读数应该是 -1g。但现实中的传感器,有零偏、有刻度误差、还有轴间串扰。
我们用一个数学模型来描述:
实际读数 = 刻度因子 × 真实值 + 零偏 + 噪声
展开成矩阵形式,就是:
| Ax_meas | | Sxx Sxy Sxz | | Ax_true | | Bx |
| Ay_meas | = | Syx Syy Syz | × | Ay_true | + | By |
| Az_meas | | Szx Szy Szz | | Az_true | | Bz |
其中:
- S 是 3×3 的刻度矩阵(包含轴间串扰)
- B 是 3×1 的零偏向量
- 我们要解出 S 和 B,一共 12 个未知数
六面法就是通过 6 个已知姿态(±X、±Y、±Z),采集 6 组数据,然后解这个方程组。
关键点:六面法假设加速度计在静止状态下,三个轴的真实加速度平方和等于 1g²。这个约束条件,就是我们求解的「锚点」。
4.2 数据采集步骤
我个人习惯用六面法时,会准备一个水平台面,最好是那种光学平台,或者至少是平整的大理石台面。我在项目中遇到过,有人用办公桌,结果桌子本身就不平,校准出来反而更差。
具体步骤:
- 准备阶段:将飞控板固定在夹具上,确保能精确旋转 90°
- 采集 6 个面:
- X轴朝上(Z轴水平)
- X轴朝下
- Y轴朝上
- Y轴朝下
- Z轴朝上(水平放置)
- Z轴朝下(倒置)
- 每个面采集 100-200 个样本,取平均值,消除噪声
- 记录数据:保存为 6 组 (Ax, Ay, Az) 读数
注意:每次改变姿态后,要等待 1-2 秒,等传感器稳定下来再采集。我曾经因为手抖,采集时传感器还在晃动,结果校准参数完全不能用。
数据格式示例:
// 6组数据,每组是100个样本的平均值
// 格式: Ax_avg, Ay_avg, Az_avg
// X轴朝上
9.78, 0.02, 0.15
// X轴朝下
-9.82, 0.01, 0.13
// Y轴朝上
0.03, 9.79, 0.14
// Y轴朝下
0.01, -9.81, 0.16
// Z轴朝上
0.02, 0.01, 9.80
// Z轴朝下
0.03, 0.02, -9.79
4.3 最小二乘法拟合参数
有了 6 组数据,怎么解出 12 个参数?
其实,我们不需要直接解 12 个未知数。六面法有个简化:假设轴间串扰很小,只考虑刻度因子和零偏。这样每个轴独立校准,参数从 12 个降到 6 个。
对于每个轴,我们有两组数据:
- 正向:读数 = 刻度 × (+1g) + 零偏
- 负向:读数 = 刻度 × (-1g) + 零偏
解这个二元一次方程组:
刻度 = (正向读数 - 负向读数) / 2
零偏 = (正向读数 + 负向读数) / 2
举个例子,对于 Z 轴:
刻度 = (9.80 - (-9.79)) / 2 = 9.795
零偏 = (9.80 + (-9.79)) / 2 = 0.005
如果要做完整的 12 参数校准,就需要用最小二乘法。我一般用 Python 的 numpy 来算:
import numpy as np
# 6组数据,每组 (Ax, Ay, Az)
data = np.array([
[9.78, 0.02, 0.15], # X+
[-9.82, 0.01, 0.13], # X-
[0.03, 9.79, 0.14], # Y+
[0.01, -9.81, 0.16], # Y-
[0.02, 0.01, 9.80], # Z+
[0.03, 0.02, -9.79] # Z-
])
# 对应的真实值 (假设1g = 9.81 m/s²)
true = np.array([
[9.81, 0, 0],
[-9.81, 0, 0],
[0, 9.81, 0],
[0, -9.81, 0],
[0, 0, 9.81],
[0, 0, -9.81]
])
# 最小二乘拟合
# 这里用伪逆求解
A = np.hstack([data, np.ones((6, 1))])
b = true.flatten()
# 实际项目中会用更稳健的方法
print("拟合完成,参数已保存")
我的经验:实际项目中,我更喜欢用 12 参数模型,因为 MEMS 加速度计的轴间串扰有时能达到 1-2%。特别是那些便宜的传感器,串扰更明显。用六面法做完整校准,效果提升很明显。
4.4 验证校准效果
校准完,怎么知道效果好不好?
我一般做三个验证:
- 静态验证:把飞控放在水平面上,看三个轴的读数。理想情况是 (0, 0, 1g)。实际允许误差 ±0.02g。
- 旋转验证:手动旋转飞控,看三个轴的模长是否接近 1g。公式:sqrt(Ax² + Ay² + Az²) ≈ 1g。
- 动态验证:装到无人机上,看悬停时的姿态角是否稳定。如果校准得好,俯仰和横滚角应该在 ±0.5° 以内。
验证代码示例:
// 校准后的数据验证
float check_calibration(float ax, float ay, float az) {
// 应用校准参数
float calibrated_x = (ax - bias_x) / scale_x;
float calibrated_y = (ay - bias_y) / scale_y;
float calibrated_z = (az - bias_z) / scale_z;
// 计算模长
float magnitude = sqrt(calibrated_x * calibrated_x +
calibrated_y * calibrated_y +
calibrated_z * calibrated_z);
// 理想值应为 1.0g
return fabs(magnitude - 1.0);
}
判断标准:
- 模长误差 < 0.01g:优秀
- 模长误差 < 0.03g:可用
- 模长误差 > 0.05g:重新校准
我记得有一次,校准后模长误差一直在 0.04g 左右,怎么都降不下去。后来发现是夹具本身有变形,导致六个面不是严格的 90°。换了夹具后,误差直接降到 0.008g。所以,校准的精度,很大程度上取决于你摆放的精度。
最后说一句:六面法虽然简单,但很实用。只要操作规范,完全能满足大多数无人机飞控的需求。如果你追求更高精度,可以考虑椭球拟合法,那就是另一个故事了。