学飞控、做平衡车,第一个绕不开的算法就是互补滤波。别被名字吓到,它其实就是“哥俩好,互相拉一把”的加权平均。
1. 痛点:为什么一个传感器搞不定?
假设你要做一个自平衡小车,或者无人机飞控,首先得知道当前倾斜了多少度(角度)。
通常我们会用两种传感器来测角度:
- 陀螺仪(测角速度):反应极快,你一动它就知道。但它有个致命缺点——零漂。静止时它也可能输出微小的值,积分久了,角度会不受控制地飘走(1 分钟飘出几十度)。
- 加速度计(测重力分量):绝对稳定,静止时能靠重力算出精准角度。但它极度怕震动,电机一启动,噪声全来了,角度跳得像心电图。
结论:陀螺仪是“短期靠谱,长期跑偏”;加速度计是“长期准确,短期跳脚”。
2. 互补滤波的核心思想(高频与低频的分工)
互补滤波的思路极其简单、优雅:
既然陀螺仪动态好(高频信号准),加速度计静态好(低频信号准),那我们就把它们通过滤波器组合起来:
- 陀螺仪的数据通过高通滤波器(相信突变,不信缓慢漂移);
- 加速度计的数据通过低通滤波器(相信缓慢变化,不信突跳噪声);
两者相加,正好互补成全频带都准确的角度。
用人话讲:角度绝大部分时间跟着陀螺仪快速跑,但每隔一刹那,偷偷用加速度计的角度往回拽一点点,把漂移拉回来。
3. 最经典的数学公式(一看就懂)
离散化的一阶互补滤波公式只有一行:
a n g l e = α × ( a n g l e − 1 + g y r o × d t ) + ( 1 − α ) × a c c A n g l e angle = \alpha \times (angle_{-1} + gyro \times dt) + (1 - \alpha) \times accAngleangle=α×(angle−1+gyro×dt)+(1−α)×accAngle
参数拆解(每个都很重要):
| 符号 | 含义 | 单位 |
|---|---|---|
| a n g l e \mathrm{angle}angle | 当前融合后的角度(你要的结果) | deg / rad |
| a n g l e − 1 \mathrm{angle}_{-1}angle−1 | 上一时刻融合的角度 | deg / rad |
| g y r o \mathrm{gyro}gyro | 陀螺仪测得的角速度 | ∘ / s ^\circ/\mathrm{s}∘/s |
| d t dtdt | 程序循环时间(采样周期) | s \mathrm{s}s |
| a c c A n g l e \mathrm{accAngle}accAngle | 加速度计计算出的瞬时倾角 | deg |
| α \alphaα | 滤波系数(核心!) | 0 ∼ 1 0 \sim 10∼1 |
4. 核心系数α \alphaα到底怎么调?(附时间常数)
α \alphaα决定了你“更信谁”:
- 当α = 0.98 \alpha = 0.98α=0.98:意味着 98% 信任陀螺仪积分,2% 信任加速度计。漂移修正很慢,但抗震动极好。
- 当α = 0.60 \alpha = 0.60α=0.60:两者权重接近,角度响应变慢,且容易引入噪声。
实际工程中,α \alphaα通常取0.90 ∼ 0.999 0.90 \sim 0.9990.90∼0.999。
更专业的调参方式是看时间常数τ \tauτ:
τ = α × d t 1 − α \tau = \frac{\alpha \times \mathrm{d}t}{1 - \alpha}τ=1−αα×dt
- 如果想在 0.1秒内修正漂移,算出的α \alphaα就小一点;
- 如果电机震动大,想让修正慢一点,α \alphaα就无限趋近于 1。
5. 一个超形象的“开车类比”
把互补滤波想象成开车回家:
- 陀螺仪 =车速表。告诉你当前瞬时速度,反应灵敏,但车轮打滑或磨损时,里程表(积分)会慢慢不准。
- 加速度计 =路边偶尔出现的里程牌。绝对准确,但不是时时刻刻都有。
互补滤波就是:平时按车速表跑,每当路过一个里程牌,就悄悄地微调一下里程表读数,不让误差累积太大。
6. 保姆级 C 语言代码(复制即用)
对于 STM32、Arduino 或任何单片机,你只需这么几行:
// 定义结构体方便管理typedefstruct{floatangle;// 融合后的角度floatdt;// 采样时间 (s)floatalpha;// 滤波系数 (0.9~0.999)}ComplementaryFilter_t;// 初始化voidComplementary_Init(ComplementaryFilter_t*f,floatdt,floatalpha){f->angle=0.0;f->dt=dt;f->alpha=alpha;}// 更新函数(传入陀螺仪角速度和加速度计计算的角度)floatComplementary_Update(ComplementaryFilter_t*f,floatgyro,floataccAngle){// 陀螺仪积分预测floatpredict=f->angle+gyro*f->dt;// 互补融合f->angle=f->alpha*predict+(1.0f-f->alpha)*accAngle;returnf->angle;}// ---------- 主程序调用示例 ----------// 假设加速度计算出俯仰角为 5.2°,陀螺仪 Z 轴角速度为 0.5°/s,dt=0.01sfloatpitch=Complementary_Update(&filter,0.5,5.2);// pitch 结果 ≈ 0.98*(前一角度+0.005) + 0.02*5.27. 进阶避坑指南(写给新手)
加速度计计算角度时,记得加低通滤波:如果电机震动大,建议先对a c c A n g l e \mathrm{accAngle}accAngle滑动平均或二阶低通,再喂给互补滤波。
陀螺仪要去零偏:上电静止时,取前100次陀螺仪平均值作为零偏,之后每次读值都减去它,否则漂移修不回来。
d t dtdt要实时计算:不要用固定死值,最好用定时器时间戳计算d t dtdt,否则α \alphaα的有效时间常数会变,导致动作忽软忽硬。
8. 互补滤波 vs 卡尔曼滤波(横向对比)
经常有人问:为啥不用高大上的卡尔曼?
| 对比项 | 互补滤波 | 卡尔曼滤波 |
|---|---|---|
| 计算量 | 极小(加减乘除) | 较大(矩阵求逆) |
| 调参难度 | 调一个 α 就行 | 调 Q 和 R 矩阵,很难 |
| 适用场景 | 资源紧张的 MCU、入门项目 | 高精度、高动态、有 GPS 等复杂场景 |
| 效果 | 够用,有轻微滞后 | 理论最优,但调不好不如互补 |
对于平衡车、飞控入门、舵机稳定,互补滤波绝对 YYDS(永远的神)。
结语
互补滤波就像一位聪明的和事佬,让暴躁的陀螺仪和安静的加速度计握手言和。它不需要复杂的线性代数,短短几行代码就能让你的设备获得稳定、低延迟的姿态信息。
你的第一个平衡车、自稳云台、四轴飞行器,都可以从这一行公式开始。赶紧去试试吧!
如果你觉得有帮助,欢迎点赞、收藏、评论,让更多人看到!