4、姿态解算算法(一):互补滤波原理、Mahony算法详解、代码实现。

各位同学,欢迎来到姿态解算的第一讲。

飞控里什么最核心?我个人觉得,姿态解算排第一。你想想看,如果连飞机当前是正着还是歪着都搞不清楚,那后面的PID控制、位置估算全白搭。今天咱们就啃这块硬骨头——互补滤波和Mahony算法。

4.1 为什么需要姿态解算?

说白了,飞控就是个“盲人”。它没有眼睛,只能靠传感器去“摸”世界。陀螺仪告诉它转得有多快,加速度计告诉它重力朝哪边,磁力计告诉它北在哪。

但问题是,每个传感器都有毛病:

  • 陀螺仪:短时间准,但时间一长就飘。我做过一个测试,让IMU静止不动,纯积分陀螺仪数据,10分钟后姿态偏了快30度。
  • 加速度计:长时间稳,但一有震动就炸。飞机电机一转,加速度计读数全是噪声。
  • 磁力计:能定航向,但容易被电机磁场干扰。

所以,我们需要一个“聪明”的算法,把这三个传感器的优点结合起来,缺点互相抵消。这就是姿态解算的核心思想——数据融合。

核心观点:姿态解算不是选一个最好的传感器,而是让所有传感器“投票”,取一个最靠谱的结果。

4.2 互补滤波原理——直觉上的理解

互补滤波这个名字听起来挺唬人,其实道理很简单。

陀螺仪的高频数据(快速变化)很准,但低频(缓慢漂移)不准。加速度计和磁力计正好反过来:低频稳,高频噪。互补滤波就是做一个“频率分工”:

  • 陀螺仪负责快速响应——飞机突然转一下,全靠它。
  • 加速度计/磁力计负责长期修正——把陀螺仪慢慢拉回正确位置。

数学上就是一个加权平均:

最终姿态 = α × (陀螺仪积分) + (1 - α) × (加速度计/磁力计估算)

这里的α通常取0.98或0.99。为什么?因为陀螺仪更可信,权重就大一点。

我的经验:α值不是死的。如果你用的陀螺仪噪声大,α可以降到0.95;如果加速度计特别烂(比如廉价的MEMS),α可以升到0.995。我一般在调试时先设0.98,然后看悬停时的姿态波动,再微调。

4.3 Mahony算法详解——从理论到实现

Mahony算法是互补滤波的一种经典实现。它不直接融合角度,而是融合四元数。为什么用四元数?因为避免了欧拉角的万向锁问题,计算量也小。

4.3.1 算法流程

Mahony的核心就三步:

  1. 预测:用陀螺仪数据更新四元数(积分)。
  2. 观测:用加速度计和磁力计数据,算出当前姿态的“误差”。
  3. 修正:用这个误差去补偿陀螺仪的漂移,然后重复。

下面这张图把整个流程串起来了:

Mahony 互补滤波姿态解算流程 陀螺仪 (ω) 加速度计 (a) 磁力计 (m) 四元数积分 误差计算 (叉积) PI 补偿器 输出四元数 关键说明: 1. 陀螺仪做短时预测(高频),加速度计/磁力计做长时修正(低频)。 2. 误差 = 测量方向 × 预测方向(叉积),误差越大说明漂移越严重。 3. PI补偿器把误差转换成陀螺仪偏置修正量,反馈回积分环节。

4.3.2 误差到底怎么算?

这里有个关键点——叉积。我刚开始学的时候也懵,为什么两个向量叉一下就是误差?

你想想看,加速度计测出来的重力方向(在机体坐标系下)是 [ax, ay, az]。同时,我们根据当前四元数,也能算出一个“预测的重力方向”。如果两个方向完全一致,叉积为0,说明没误差。如果它们有夹角,叉积的大小正比于夹角的正弦值,方向就是旋转轴。

这个叉积,就是陀螺仪的“漂移指示器”。

注意:叉积只在角度偏差较小时近似线性。如果飞机倒置(偏差接近180度),叉积会变小甚至为0,导致修正失效。所以Mahony算法在初始化时,一定要保证飞机大致水平。

4.4 代码实现——手写一个Mahony

光说不练假把式。下面是我在实际项目中用过的Mahony核心代码,去掉了工程冗余,保留了最精华的部分。

// Mahony 互补滤波核心函数
// gx, gy, gz: 陀螺仪数据 (rad/s)
// ax, ay, az: 加速度计数据 (归一化后)
// mx, my, mz: 磁力计数据 (归一化后)
// dt: 采样时间 (s)

void MahonyAHRSupdate(float gx, float gy, float gz,
                      float ax, float ay, float az,
                      float mx, float my, float mz, float dt)
{
    float recipNorm;
    float q0q0, q0q1, q0q2, q0q3;
    float q1q1, q1q2, q1q3;
    float q2q2, q2q3;
    float q3q3;
    
    // 1. 加速度计归一化
    recipNorm = invSqrt(ax*ax + ay*ay + az*az);
    ax *= recipNorm;
    ay *= recipNorm;
    az *= recipNorm;
    
    // 2. 磁力计归一化
    recipNorm = invSqrt(mx*mx + my*my + mz*mz);
    mx *= recipNorm;
    my *= recipNorm;
    mz *= recipNorm;
    
    // 3. 用当前四元数计算预测的重力方向
    q0q0 = q0 * q0;
    q0q1 = q0 * q1;
    q0q2 = q0 * q2;
    q0q3 = q0 * q3;
    q1q1 = q1 * q1;
    q1q2 = q1 * q2;
    q1q3 = q1 * q3;
    q2q2 = q2 * q2;
    q2q3 = q2 * q3;
    q3q3 = q3 * q3;
    
    // 预测重力向量 (在机体坐标系下)
    float halfvx = q1q3 - q0q2;
    float halfvy = q0q1 + q2q3;
    float halfvz = q0q0 - 0.5f + q3q3;
    
    // 4. 计算误差 (叉积)
    float ex = (ay * halfvz - az * halfvy);
    float ey = (az * halfvx - ax * halfvz);
    float ez = (ax * halfvy - ay * halfvx);
    
    // 5. PI补偿器
    integralFBx += Ki * ex * dt;
    integralFBy += Ki * ey * dt;
    integralFBz += Ki * ez * dt;
    
    gx += Kp * ex + integralFBx;
    gy += Kp * ey + integralFBy;
    gz += Kp * ez + integralFBz;
    
    // 6. 四元数积分 (一阶龙格-库塔)
    q0 += (-q1*gx - q2*gy - q3*gz) * 0.5f * dt;
    q1 += ( q0*gx + q2*gz - q3*gy) * 0.5f * dt;
    q2 += ( q0*gy - q1*gz + q3*gx) * 0.5f * dt;
    q3 += ( q0*gz + q1*gy - q2*gx) * 0.5f * dt;
    
    // 7. 归一化四元数
    recipNorm = invSqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3);
    q0 *= recipNorm;
    q1 *= recipNorm;
    q2 *= recipNorm;
    q3 *= recipNorm;
}

4.4.1 关键参数说明

参数 作用 典型值 我的建议
Kp 比例增益,决定误差修正的强度 0.5 ~ 2.0 先设1.0,如果姿态震荡就减小
Ki 积分增益,消除稳态误差 0.001 ~ 0.05 我一般设0.005,太大容易低频振荡
dt 采样周期,必须准确 0.001 ~ 0.005 用定时器测量,不要用延时估算

避坑指南:我曾经在Ki上吃过亏。有一次为了快速收敛,把Ki设到了0.1,结果飞机悬停时像“点头”一样周期性晃动。后来才明白,Ki太大相当于给陀螺仪偏置一个错误的修正,反而引入了低频振荡。记住:Ki宁小勿大。

4.5 实际调试中的几个坑

代码写完了,不代表就能跑。我总结几个实际项目中容易踩的坑:

  • 传感器坐标系不一致:陀螺仪和加速度计的坐标系可能反了。我见过有人把X轴和Y轴搞反,结果飞机一推油门就翻。上电后先手动旋转,看数据变化方向对不对。
  • 归一化不能省:加速度计和磁力计数据必须归一化。如果不归一化,叉积的大小会受加速度幅值影响,导致修正强度不稳定。
  • 四元数归一化:积分步长累积误差会让四元数模长偏离1,必须每步都归一化。否则姿态会慢慢“缩”成一个点。
  • 磁力计干扰:电机大电流时磁场畸变严重。我一般只在起飞前用磁力计做一次航向初始化,起飞后就只用陀螺仪积分航向,靠加速度计修正俯仰和横滚。

警告:不要在电机高速旋转时依赖磁力计做航向修正。我曾经在测试时没注意这个,飞机在空中突然“甩头”90度,差点炸机。后来加了磁力计置信度判断,当电机油门超过30%时,降低磁力计权重。

4.6 小结

好了,这一讲的内容就到这。互补滤波和Mahony算法,说白了就是“陀螺仪做主角,加速度计和磁力计做配角”。主角负责动作戏,配角负责把跑偏的主角拉回来。