传感器标定与预处理:加速度计、陀螺仪、磁力计标定方法

各位同学,今天我们来聊聊传感器标定。

说实话,飞控系统里最让我头疼的,往往不是控制算法本身,而是传感器数据到底靠不靠谱。你想想看,算法再漂亮,输入的数据是歪的,那输出肯定跑偏。我在项目里见过太多这种情况——飞机悬停时莫名其妙往一边飘,查了半天,最后发现是加速度计零偏没标好。

所以,传感器标定是飞控调试的第一步,也是基本功。今天我把加速度计、陀螺仪、磁力计这三样东西的标定方法,掰开了讲清楚。

为什么传感器需要标定?

说白了,任何传感器出厂时都有误差。温度漂移、安装偏差、器件本身的非线性,都会让读数偏离真实值。你拿一个静止的加速度计,理论上应该读到(0, 0, -g),但实际读出来可能是(0.05, -0.03, -9.72)。

这些误差如果不消除,飞控的姿态解算就会出问题。悬停时飞机歪着,航线飞行时轨迹偏掉,都是标定没做好的后果。

核心思路:标定的本质就是建立「传感器原始读数 → 真实物理量」的映射关系。通常用一个线性模型:

真实值 = 比例因子 × (原始值 - 零偏)

我们需要标定的,就是零偏和比例因子这两个参数。

加速度计标定

加速度计标定,我习惯用六位置法。为什么叫六位置?因为我们需要让加速度计的每个轴,分别朝上和朝下各采集一次数据。

具体步骤:

  1. 将飞控水平放置,Z轴朝上,采集100组数据取平均
  2. 将飞控翻转,Z轴朝下,采集100组数据取平均
  3. 同理,X轴朝上、X轴朝下、Y轴朝上、Y轴朝下,各采集一次
  4. 这样我们得到6组数据,每组包含三轴读数

有了这6组数据,就可以解算出每个轴的零偏和比例因子。公式其实不复杂:

// 以X轴为例
// 当X轴朝上时,理论值应为 +g
// 当X轴朝下时,理论值应为 -g
// 设原始读数为 raw_up 和 raw_down
// 则有:
// scale_x = 2g / (raw_up - raw_down)
// bias_x = (raw_up + raw_down) / 2

// 实际代码实现
float raw_up = 1645;   // 采集到的原始值
float raw_down = 1523;
float g = 9.81;

float scale_x = 2 * g / (raw_up - raw_down);
float bias_x = (raw_up + raw_down) / 2;

// 标定后的值
float calibrated_x = (raw_x - bias_x) * scale_x;

我的经验:六位置法虽然简单,但有个坑——你必须保证每次放置时,飞控是绝对水平的。我曾经用水平仪垫着飞控做标定,结果垫块本身就不平,标出来的参数全是歪的。后来我改用三轴转台,精度一下子就上去了。

陀螺仪标定

陀螺仪标定比加速度计简单。为什么?因为陀螺仪测量的是角速度,静止时理论值应该是0。所以标定只需要采集静止数据,算出零偏就行。

具体做法:

  1. 将飞控静止放置,不要有任何振动
  2. 连续采集1000组陀螺仪数据
  3. 对每个轴分别求平均值,这个平均值就是零偏

代码实现也很直接:

// 陀螺仪零偏标定
float gyro_bias[3] = {0};
int sample_count = 1000;

for(int i = 0; i < sample_count; i++) {
    gyro_bias[0] += raw_gyro_x[i];
    gyro_bias[1] += raw_gyro_y[i];
    gyro_bias[2] += raw_gyro_z[i];
}

gyro_bias[0] /= sample_count;
gyro_bias[1] /= sample_count;
gyro_bias[2] /= sample_count;

// 使用时减去零偏
float calibrated_gyro_x = raw_gyro_x - gyro_bias[0];

注意:陀螺仪零偏会随温度变化。我遇到过最头疼的情况——冬天标定好的参数,夏天飞起来就飘。所以工业级飞控通常会做温度补偿,或者每次上电后先静止几秒,自动重新标定零偏。

磁力计标定

磁力计标定是最麻烦的,也是坑最多的。为什么?因为地磁场很弱,很容易被周围铁磁物质干扰。你拿着手机转一圈,磁力计读数画出来应该是个球,但实际画出来往往是个椭球。

椭球拟合标定法:

我个人习惯用椭球拟合。原理很简单——理想情况下,磁力计在三维空间旋转时,读数应该落在一个球面上。但因为有硬铁干扰和软铁干扰,实际数据会变成一个椭球。

标定的目标,就是把这个椭球拉回球心在原点、半径为1的标准球。

采集数据的方法:

  1. 拿着飞控,在空中画「8」字
  2. 尽量让飞控的每个面都朝向各个方向
  3. 采集至少200组数据,覆盖整个球面

有了数据后,用最小二乘法拟合椭球参数。这里我直接给出常用的代码框架:

// 椭球拟合标定(简化版)
// 输入:raw_mag[3] 原始磁力计数据
// 输出:calibrated_mag[3] 标定后的数据

// 标定参数(由椭球拟合算法计算得到)
float hard_iron[3] = {45.2, -12.7, 23.1};  // 硬铁偏移
float soft_iron[3][3] = {                   // 软铁矩阵
    {1.02, 0.01, -0.03},
    {0.01, 0.98, 0.02},
    {-0.03, 0.02, 1.01}
};

// 标定过程
float temp[3];
for(int i = 0; i < 3; i++) {
    temp[i] = raw_mag[i] - hard_iron[i];
}

// 应用软铁校正
for(int i = 0; i < 3; i++) {
    calibrated_mag[i] = 0;
    for(int j = 0; j < 3; j++) {
        calibrated_mag[i] += soft_iron[i][j] * temp[j];
    }
}

避坑指南:我曾经在无人机上装了个碳纤维管,结果磁力计读数一直不对。查了半天才发现,碳纤维管里有一根细铁丝。所以做磁力计标定时,一定要确保周围没有铁磁物质。另外,电机通电后也会产生磁场干扰,标定时最好把电机断电。

标定流程总结

好了,三种传感器的标定方法都讲完了。我画了一张流程图,帮你理清整个标定流程:

传感器标定流程 开始标定 加速度计标定(六位置法) 采集6个方向的静止数据 → 解算零偏和比例因子 陀螺仪标定(静止采集) 静止采集1000组数据 → 求平均得到零偏 磁力计标定(椭球拟合) 画8字采集数据 → 拟合椭球参数 → 校正 验证标定结果 检查数据是否在合理范围内 标定完成

标定后的数据预处理

标定完参数,还没完。数据还需要做预处理,才能喂给姿态解算算法。

常用的预处理步骤:

  • 低通滤波:传感器数据都有高频噪声,用一阶低通滤波就能去掉大部分。我一般用截止频率20Hz。
  • 异常值剔除:偶尔会出现跳变的数据点,直接扔掉或者用前一帧数据替代。
  • 坐标系对齐:如果传感器安装方向与飞控坐标系不一致,需要做旋转矩阵变换。
// 一阶低通滤波示例
float lowpass_filter(float raw, float prev, float alpha) {
    // alpha 越小,滤波越平滑,但延迟越大
    // 一般取 0.1 ~ 0.3
    return alpha * raw + (1 - alpha) * prev;
}

// 使用示例
float filtered_acc_x = lowpass_filter(raw_acc_x, prev_acc_x, 0.2);

我的习惯:标定参数我会保存到飞控的EEPROM里,每次上电自动加载。但我会留一个「重新标定」的指令,方便现场调试。另外,标定完一定要做验证——把飞控静止放好,看看加速度计读数是不是(0, 0, -g),陀螺仪是不是(0, 0, 0)。

好了,传感器标定这部分就讲到这里。内容不少,但都是实打实的干货。你回去做实验时,记得先把标定做好,后面的控制调试才能事半功倍。


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