4、姿态解算入门:互补滤波原理与实现

各位同学,今天我们来聊聊姿态解算里最经典、也最实用的一个方法——互补滤波。

说实话,我刚入行那会儿,面对一堆加速度计、陀螺仪的数据,头都是大的。加速度计噪声大,陀螺仪有漂移,怎么把它们揉到一起?后来师傅丢给我一句话:「互补滤波,就是取长补短。」嗯,这句话我记到现在。

4.1 为什么需要互补滤波?

先想一个问题:

你手里有个陀螺仪,它能测角速度。积分一下,就能得到角度。但陀螺仪有零偏,时间一长,积分出来的角度就飘到姥姥家去了。

你手里还有个加速度计,它能测重力方向。静态时算角度很准,但一有运动,振动、加速度一上来,角度就抖得像筛糠。

你看,一个高频准但低频漂,一个低频稳但高频噪。互补滤波,就是把这两个信号「互补」起来。

核心思想:陀螺仪负责短期动态响应(高通),加速度计负责长期稳态校正(低通)。两者一结合,就得到了一个既响应快、又不漂移的姿态角。

4.2 互补滤波的数学原理

说白了,互补滤波就是一个一阶滤波器组合。公式很简单:

angle = α * (angle + gyro * dt) + (1 - α) * acc_angle

其中:

  • angle:融合后的角度
  • gyro:陀螺仪角速度
  • dt:采样时间间隔
  • acc_angle:加速度计计算出的角度
  • α:权重系数,通常取 0.9~0.99

为什么会这样?

你想想看,α 越接近 1,陀螺仪的权重越大,系统响应快,但长期漂移也大。α 越接近 0,加速度计的权重越大,系统稳定,但动态响应慢。这个 α,就是你要调的「平衡点」。

个人经验:我一般从 α = 0.98 开始调。如果发现角度飘得厉害,就减小一点;如果发现角度跟不上动作,就增大一点。说白了,就是个手感活。

4.3 互补滤波的代码实现

下面是我在实际项目中用过的互补滤波代码。麻雀虽小,五脏俱全。

// 互补滤波结构体
typedef struct {
    float angle;    // 融合后的角度
    float gyro;     // 陀螺仪角速度
    float acc_angle; // 加速度计角度
    float alpha;    // 权重系数
    float dt;       // 采样时间
} ComplementaryFilter_t;

// 初始化
void CF_Init(ComplementaryFilter_t *cf, float alpha, float dt) {
    cf->angle = 0.0f;
    cf->gyro = 0.0f;
    cf->acc_angle = 0.0f;
    cf->alpha = alpha;
    cf->dt = dt;
}

// 更新姿态
void CF_Update(ComplementaryFilter_t *cf, float gyro, float acc_angle) {
    // 陀螺仪积分
    float gyro_angle = cf->angle + gyro * cf->dt;
    
    // 互补融合
    cf->angle = cf->alpha * gyro_angle + (1.0f - cf->alpha) * acc_angle;
    
    // 保存当前值
    cf->gyro = gyro;
    cf->acc_angle = acc_angle;
}

这段代码我用了好几年,从四轴飞行器到平衡小车,基本没出过问题。你直接拿去用就行。

4.4 加速度计角度计算

刚才代码里有个 acc_angle,它是怎么来的?

对于俯仰角(Pitch)和横滚角(Roll),可以用加速度计的三轴数据算出来:

// 从加速度计计算俯仰角
float pitch = atan2(-acc_x, sqrt(acc_y * acc_y + acc_z * acc_z)) * 180.0f / M_PI;

// 从加速度计计算横滚角
float roll = atan2(acc_y, acc_z) * 180.0f / M_PI;

注意:加速度计算不出偏航角(Yaw)!因为偏航角绕着重力方向旋转,加速度计感知不到。所以偏航角通常要靠磁力计来校正。

4.5 互补滤波的优缺点

优点 缺点
计算量极小,适合低性能MCU 精度有限,不如卡尔曼滤波
实现简单,调参直观 对加速度计噪声敏感
响应速度快,适合实时控制 无法处理非线性运动
不需要系统模型 权重系数需要手动调整

我个人觉得,互补滤波最大的优势就是「简单粗暴」。你不需要懂什么协方差矩阵、状态空间,一个公式就能跑起来。对于入门级的飞控、平衡车、云台,完全够用。

4.6 避坑指南

我曾经在一个四轴项目里,发现飞机悬停时角度一直在缓慢漂移。查了半天,发现是 α 设成了 0.999。你想想看,陀螺仪权重这么大,加速度计几乎不起作用,不漂才怪。

后来我把 α 降到 0.98,问题立刻解决。

还有一次,我发现加速度计的角度跳得厉害。一查,原来是低通滤波没做。加速度计的数据直接拿来用,高频噪声全进来了。所以我的建议是:

  • 加速度计数据先做低通滤波(比如滑动平均),再送进互补滤波
  • 陀螺仪数据可以做高通滤波,去掉零偏
  • α 的取值,建议在 0.95 ~ 0.99 之间调试

小技巧:如果你发现调参很麻烦,可以试试自适应互补滤波。让 α 随着运动剧烈程度自动变化——运动剧烈时增大 α(信任陀螺仪),静止时减小 α(信任加速度计)。

4.7 核心逻辑流程图

下面这张图,是我用 SVG 画的互补滤波核心流程。你看一眼就能明白整个数据流。

陀螺仪 (角速度) 加速度计 (加速度) 积分 atan2 计算角度 互补融合 融合角度 高通路径 低通路径

嗯,这张图其实已经说得很清楚了。陀螺仪走高通路径,加速度计走低通路径,最后在互补融合节点汇合,输出一个干净、稳定的角度。

4.8 什么时候用互补滤波?

我个人的建议是:

  • 入门学习:一定要从互补滤波开始。它简单、直观,能帮你理解姿态解算的本质。
  • 资源受限:如果你用的是 STM32F103 这种级别的 MCU,互补滤波是首选。
  • 实时性要求高:互补滤波的计算延迟极低,适合 1kHz 以上的控制循环。
  • 精度要求不高:如果你只需要 ±2° 的精度,互补滤波完全够用。

但如果你要做高精度导航、无人机编队、或者需要抗强振动环境,那还是得上卡尔曼滤波或者 Mahony 滤波。不过那是后面章节的内容了。


好了,互补滤波就讲到这里。代码我给你了,流程图也画了,剩下的就是你自己动手调一调。记住,调参的时候别急,一点一点来,手感会有的。

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