📚 本文是 「从 0 到 1 带你打电赛 · 小车电控篇」 系列(共 12 篇)第 9 篇。
到了这一篇,你手里应该已经有一辆能跑的车了:电机听话转、编码器能测速、串级 PID 调好以后能稳稳跟线、过弯也不冲出去。这时候很多同学会开始心痒——网上铺天盖地的”模糊 PID””卡尔曼滤波””前馈控制””自抗扰 ADRC”,名字一个比一个唬人,是不是把这些都堆上去,车就能从”能跑”变成”封神”?
先把话撂在这儿:90% 的省赛小车,把基础 PID 加串级双环调扎实,就足够拿奖了。 这一篇要讲的进阶算法,定位是”锦上添花 + 报告亮点”,不是”不上就完蛋”的必需品。本篇的真正价值,不是教你把每个算法都写一遍,而是帮你判断:哪个算法解决什么问题、什么时候才值得上、性价比到底高不高——免得你把宝贵的四天三夜耗在调一个收益微薄的高级算法上,最后基础反而没跑稳。
❗ 一句话定调
进阶算法是”装修”,基础 PID 是”地基”。地基没夯实就急着装修,房子只会塌得更难看。先把机械中值、编码器测速、PWM 频率、控制周期、串级 PID 这些做扎实,再按需逐级往上加——每加一个,都留一份对比数据。
先认清这条”逐级升级”的路线
进阶算法不是平行摆在货架上让你随便挑的,它们有明显的”性价比梯度”:越往后,调试成本越高、边际收益越小。一个稳妥的升级顺序长这样:

为什么是这个顺序?因为越靠左的,改动小、收益直接、不容易引入新 bug;越靠右的(尤其模糊 PID、卡尔曼),自由度多、调试耗时,稍有不慎反而把好不容易调稳的车搞乱。省赛时间紧,跑不稳就果断回退到上一级。 下面我们一个一个拆。
📝 一句话交代前置
这一篇默认你已经把单环 PID、串级双环和那一套”工程补丁”调通了——位置式/增量式怎么选、方向环为什么用 PD、抗积分饱和怎么做,分别在《PID 入门》《PID 进阶》两篇里讲过;具体怎么看波形对症下药,见《PID 调参实战》。这里只聊”在基础之上还能再加什么”。
变速积分 / 积分分离:性价比最高,优先上
这是进阶项里性价比最高的一个:简单、收益直接,建议第一个上。
普通 PID 的积分系数是恒定的,全程积分增量都一样。但实际需求是矛盾的——误差大的时候,积分项疯狂累加,等误差快归零时这股劲儿泄不掉,造成严重超调;误差小的时候又需要积分稳稳消掉静差。
💡 攒钱补差距的比喻
把积分想象成攒钱补差距。离目标还远(误差大)时先别急着存钱,免得攒过头冲出去;快到目标(误差小)了,再慢慢攒,把最后那一点点差距精确补平。
最直接的办法是三段式积分分离:
| 误差大小 | 积分系数 | 含义 |
|---|---|---|
| $\lvert e\rvert > 50$ | 0 | 误差大,切断积分 |
| $30 < \lvert e\rvert < 50$ | 0.6 | 过渡区,弱化积分 |
| $\lvert e\rvert < 30$ | 1.0 | 误差小,全额积分 |
但阶跃式分段在临界点会有突变。更平滑的是变速积分,用一个线性过渡系数:
if (pid->errABS > lErr) { // 误差大: 不积分
kiIndex = 0.000f;
} else if (pid->errABS < sErr) { // 误差小: 全额积分
kiIndex = 1.000f;
} else { // 中间: 线性过渡
kiIndex = (lErr - pid->errABS) / (lErr - sErr);
}
pid->outPut = pid->outPutP + pid->outPutI * kiIndex + pid->outPutD;
经验取值 lErr ≈ 50、sErr ≈ 30。
⚠️ 这些阈值不是普适常数
50/30 这组数字是某位作者在他那套车上的具体工程取值(来源见 智能车常规 PID 及改进式 PID)。一旦你换了被控量的量纲/单位,这两个阈值就得重新定。能照抄的是”误差大弱化、误差小全额”这个思想,不是这两个数。
怎么选? 匀速车选变速积分(积分主导稳态精度,平滑过渡最好);有明显加减速的车,更该重视下面这个”遇限削弱积分”。
❗ 补一句:抗积分饱和是底线,不是进阶
积分饱和(输出顶到限幅了积分还在傻傻累加,反向时半天泄不掉,造成大超调甚至震荡)是 PID 翻车的头号杀手。”遇限削弱积分 + 积分限幅 + 输出限幅 + 模式切换清零积分”这一套,属于基础工程补丁,《PID 进阶》一篇已经讲透,这里不重复——只强调一点:它比上面任何进阶算法都更必须做。 顺带提一个工业上更平滑的进阶玩法叫 back-calculation(反算抗饱和):把饱和被砍掉的那部分输出,按一个增益回灌到积分器里,退饱和比简单的”条件积分”更柔和。省赛用条件积分够了,这个留作了解。
Bang-Bang + PID:电机弱的车靠它”榨提速”
思路:大误差全力冲,小误差精细停
Bang-Bang(起停 / 砰砰控制)让输出在两个极端之间切换——要么全速,要么全刹。控制理论里有个结论:当哈密顿量对控制量是线性的时候,Bang-Bang 就是最短时间最优解。说人话就是:想在最短时间内从 A 跑到 B,”地板油加速 + 急刹”往往就是最快的。
但纯 Bang-Bang 在目标附近会疯狂抖动,所以智能车里用的是组合拳——用 Bang-Bang 控力度、用 PID 控精度:
if (e > eps) u = Umax; // 大正偏差: 全速
else if (e < -eps) u = -Umax; // 大负偏差: 全刹/反向
else u = PID(e); // 阈值内: 切 PID 精调
// eps(阈值)务必带迟滞, 避免阈值附近来回抖动(chattering)
🧩 油门到底冲 + 到点轻踩
离目标速度还远,就一脚地板油(全速)把动态榨出来;快到了,松开油门、踩点刹车,交给 PID 精细停准。电机扭矩不足的车型,靠这”一脚地板油”能明显提速。
💡 选电机阶段就该量化测试
有支飞思卡尔队伍的 C 车模电机偏弱,他们用恒流源逐一测对应电压下的电流和转速来选电机,再用”Bang-Bang 控力度 + PID 控精度”的组合榨出加速性能(飞思卡尔智能车电机 PID)。电机弱的时候别死磕 PID 调速:Bang-Bang 负责大误差段全速冲、PID 负责小误差精调,是性价比极高的提速手段。
它的坑:抖动(chattering)
Bang-Bang 最大的毛病是切换不连续。如果阈值 $\varepsilon$ 不带迟滞,误差在阈值附近来回时,输出就在两个极值之间高频跳变——既伤电机,又让车发抖。
解决办法是给阈值加一个迟滞带(施密特触发器的思路):进入用一个阈值、退出用另一个略小的阈值,中间留一段缓冲。
📝 理论上的"瞬时全速/全刹"做不到
补一句严谨的:纯 Bang-Bang 的”最短时间最优”建立在”控制能瞬时切换”上,而且对一个 $n$ 阶线性系统,切换次数不超过系统阶数(二阶系统最多切一次)。但实际电机有电气时间常数、执行器有带宽,全速 / 全刹不可能一瞬间完成。这也正是为什么一定要带 PID 精调段 + 迟滞,而不是指望纯 Bang-Bang 一招鲜。
前馈控制:从”亡羊补牢”到”未雨绸缪”
它到底解决什么问题
PID 是典型的反馈控制——它盯着”已经发生的偏差”去纠正。问题是,等偏差出现了你才动作,永远慢半拍。高速过弯的时候,等你看到车已经偏出赛道(误差变大)才猛打方向,往往已经来不及了。
前馈(feedforward)反过来:它不等误差出现,而是根据已知的扰动或模型提前补偿。
🧩 老司机过弯的比喻
反馈 PID = 亡羊补牢:羊跑了(偏差出现)才去补圈。 前馈 = 未雨绸缪:老司机看到前方是个弯(已知曲率),方向盘提前就开始打了,根本不等车冲出去。 实战里两者一定是搭配用的——前馈预判、反馈兜底。前馈把大头先补上,剩下模型不准、路面打滑这些没料到的误差,交给 PID 收尾。
它的威力在于:在扰动影响输出之前就预补偿,响应能快很多,动态误差明显减小,能耗和磨损也更低。但它有三个硬性前提:
- 必须有一个比较准的被控对象模型(前馈控制器本质上就是被控对象模型的”倒数”);
- 扰动必须可测 / 可预知——对没料到的扰动它无能为力;
- 每个系统的前馈控制器都不一样,是专用的,换车、换赛道就得重算。
所以前馈不能单用,铁律是和 PID 复合:
$$U(k) = U_{pid}(k) + U_{ff}(k)$$
⚠️ 前馈滥用是个坑
前馈只补”可测扰动”,而且依赖较准的模型。模型不准的前馈反而帮倒忙——你以为提前打了正确的舵,结果模型错了,等于主动把车往沟里带。所以宁可前馈量保守一点、让反馈多兜底,也别让一个不靠谱的模型主导输出。
智能车里前馈的两个典型落地
第一个:曲率前馈打舵。 侧向控制量 = 前馈 + 反馈。前馈那一份由参考路径的曲率和车辆动力学模型直接算出来(舵机转角公式里含轮距 $L$、曲率 $\rho$、不足转向梯度)。曲率怎么求?一个实用做法是用赛道上连续三个点:曲率等于这三点外接圆半径的倒数,而拐向用三点的叉乘面积判——右拐为负、左拐为正。高速时舵机响应慢,在输出里提前加入这个”路径趋势分量”,舵机就能预先打舵,而不是等偏差累积。
第二个:速度突变前馈 PWM。 速度环里,当目标速度突然变化(比如起步、出弯加速)时,光靠 PID 慢慢追会有明显滞后。这时候直接前馈一段 PWM,电机响应立刻跟上。一个常见的离散前馈实现,是对设定值做一阶 + 二阶差分加权:
前馈输出: result = α*(rin - lastRin) + β*(rin - 2*lastRin + prevRin)
其中 α = A/(B*T), β = 1/(B*T^2) (A、B 为对象模型参数, T 为采样周期)
复合控制: U(k) = Upid(k) + Uff(k) // 位置式或增量式 PID 都行
第一项是”速度前馈”(设定值变化的快慢),第二项是”加速度前馈”(设定值变化的变化)。$\alpha$、$\beta$ 由你的电机模型参数和采样周期决定,没有万能值,得自己标。
死区补偿:一个不起眼但特别实用的小补丁
这个严格说属于《PID 进阶》里的”工程补丁”,但太常用、又特别容易被漏掉,这里单独点一下。
直流电机有个”死区电压”:大约是额定的 10%~15%(比如一个 12V 电机,低于约 1.5~2V 根本不转)。PID 算出来的小 PWM 如果落在死区里,电机纹丝不动——结果就是低速爬行、静差死活消不掉、起步迟滞。
解决办法很简单,输出非零时叠加一个死区偏置,把电机直接推出静摩擦区:
// 输出不为零时, 补一个死区偏置, 把电机踹出死区
if (pwm_out > 0) pwm_out += PWM_DEADZONE;
else if (pwm_out < 0) pwm_out -= PWM_DEADZONE;
📝 别和"死区时间"搞混
这里说的”死区补偿”是补电机的死区电压。它和 H 桥 PWM 互补输出里的”死区时间(dead-time,防上下桥臂直通烧管子)”是完全不同的两个概念,名字像但别混。
模糊 PID:报告里的”高级感”,赛场上的”性价比陷阱”
它解决”一套参数不够用”
普通 PID 全程就一套 Kp/Ki/Kd。但智能车是个时变、非线性的系统——高速时需要一套参数,低速时需要另一套,直道和急弯的需求完全不同。一套死参数顾此失彼。
模糊 PID 的做法是:输入当前偏差 $e$ 和偏差变化率 $ec$,经过模糊化(量化因子 $K_e = N/e_{max}$ 把 $e$ 映射到论域)→ 查一张 7×7 的模糊规则表(模糊子集 NB/NM/NS/ZO/PS/PM/PB)→ 模糊推理 → 解模糊(缩放因子 $K_u = u_{max}/N$)→ 在线输出 $\Delta K_p / \Delta K_i / \Delta K_d$,实时微调 PID 三个参数。
🧩 请了个老师傅在旁边随时拧旋钮
你给老师傅看:现在差多少($e$)、差距是在变快还是变慢($ec$)。他凭经验(规则表)实时帮你把 Kp/Ki/Kd 拧大拧小,而不是让你全程守着一套死参数。本质上是”模仿熟练驾驶员的推理”去协调横向偏角和纵向速度。
残酷的现实:省赛性价比偏低
模糊 PID 听起来很美,但它的调试自由度多得吓人——规则表、隶属度函数、量化因子、缩放因子,每一个都要调。
⚠️ 花两天调模糊 PID,可能还不如认真调好的串级 PID
这是社区里相当普遍的反馈。模糊 PID 的实测收益常常不如把串级 PID 老老实实调扎实,但它会实实在在地吃掉你两天时间,容易拖垮整体进度。
那它的价值在哪?报告和答辩的创新点。 在论文里能体现”仿照熟练驾驶员推理、协调横向偏角与纵向速度”,这是实打实的加分项。
所以建议很明确:车先用普通 / 串级 PID 跑稳,确实有余力了再上模糊 PID,并且一定要在报告里给出对比曲线——”加了模糊 PID 之后,过弯误差从 X 降到 Y”,这种带数据的论证,比光堆一个”我们用了模糊 PID”的名词强一百倍。想找现成起点的话,FlameAlpha/fuzzy-pid(纯 C 实现)和 the-fenrir/Fuzzy-PID(直接面向 STM32 电机控制)都可以拿来改。
卡尔曼 vs 互补滤波:姿态融合该选哪个
这一节主要是给做直立车 / 平衡车的同学——姿态解算是直立车的命根子。四轮循迹车其实多数时候用陀螺 Z 轴 + 简单滤波锁航向就够了。
为什么要融合
MPU6050 这类 6 轴 IMU 有两个传感器,各有各的毛病:
- 加速度计算出的 Pitch/Roll 是绝对的(长期不漂),但噪声大、一晃就乱跳;
- 陀螺仪积分出的角度平滑(短期准),但会随时间漂移。
🧩 两个证人互相补台
陀螺仪:短期说得准,但时间一长爱吹牛(漂移)。加速度计:长期靠谱,但一受震动就慌(噪声)。各取所长——短期信陀螺仪、长期信加速度计,拼出真相。
一阶互补滤波的公式和代码,《感知:灰度/电磁/编码器/IMU》一篇已经给过($angle = a\cdot(angle + gyro\cdot dt) + (1-a)\cdot acc$,$a$ 取 0.98)。这里不重复推导,只把”两条路线怎么选”讲清楚。
互补滤波:简单、够用,省赛首选
互补滤波就一行核心公式,优点是计算量小、易于嵌入式实现,平衡车直立环完全够用。它的两个系数 $a$ 与 $1-a$ 之和必须等于 1,$a$ 的物理含义是 $a = \tau/(\tau+dt)$,$\tau$ 越大越信陀螺仪、跟随越慢。
💡 几个能直接用的数
- 100Hz($dt=0.01$s)、$a=0.98$ 时,时间常数 $\tau = a\cdot dt/(1-a) = 0.49$s。
- 控制周期 5ms、想要 $\tau=1$s 时,$a \approx 0.995$。
- 调参从 $a=0.98$ 起步,这是社区验证过的安全起点。$a$ 越大越平滑但跟随慢,越小越跟手但越抖。
它的局限是对陀螺仪零漂的抑制有限、初始收敛慢。
卡尔曼滤波:精度更高,但要交”学费”
卡尔曼把陀螺仪角速度(当先验/预测)和加速度计倾角(当观测)做最优融合,还能在线估计陀螺零偏,精度比互补滤波更高。代价是:计算量大、要懂点统计、还得调那两个噪声参数 $Q$ 和 $R$。
🧩 会算概率的精明法官
卡尔曼不只听两个证人,还根据各自”平时多靠谱”($Q$/$R$ 噪声)动态决定这一刻该多信谁。判得更准,但你得先摸清两个证人的脾气(调 $Q$/$R$),挺费脑子。其实卡尔曼可以理解成”增益会自适应的互补滤波”。
$Q$/$R$ 这两个参数的方向特别容易记反,这里给准确说法:
- $Q$(过程噪声):越小越信模型/预测,越大越信测量。
- $R$(测量噪声):越大响应越慢、越信预测;越小收敛越快,但过小会震荡。
调法:$R$ 的初值可以这样估——让陀螺仪静止采一段数据(近似正态分布),按 $3\sigma$ 原则取 $(3\sigma)^2$ 作 $R$ 初值;然后 $Q$ 由小到大、$R$ 由大到小慢慢试。平衡车常用的一套经典参数(TKJ 版)是 Q_angle=0.001, Q_bias=0.003, R_measure=0.03, dt=0.005~0.01。
🔥 $Q$/$R$ 乱调是无底洞
$R$ 太大响应变慢、$R$ 太小震荡,$Q$/$R$ 不匹配会让滤波结果要么保留运动噪声、要么受零漂影响。没有方法地瞎试,能浪费掉你一整天。 有方法地按上面的套路逼近。
结论:省赛优先互补,精度敏感再上卡尔曼
✅ 一句话决策
多位做姿态融合的开发者都直言”卡尔曼太复杂了”,转头选了互补滤波(互补滤波概述)。省赛优先用互补滤波把车站稳,别为了”高级”硬上卡尔曼把时间耗在调 $Q$/$R$ 上;真到了对漂移/精度敏感的程度,再升级。 MPU6050 内置的 DMP 也是个省事选项(硬件直接输出姿态、不占主控算力),缺点是灵活性差、移植驱动繁琐。
如果你做的是多轴/全姿态(不只直立环单轴),还有两条比手写卡尔曼更省心的路:带零偏在线估计的二阶互补滤波(专治一阶互补”零漂抑制有限”的毛病),以及无人机/AHRS 圈广泛用的 Madgwick/Mahony 四元数互补滤波(计算量介于一阶互补和卡尔曼之间)。想直接抄卡尔曼的,Mattral/Kalman-Filter-mpu6050 是即拿即用的姿态卡尔曼实现。
一张表:到底什么时候该上什么
把上面这些拢成一张决策表,照着对号入座就行:
| 算法 | 解决什么 | 何时值得上 | 性价比 | 调试成本 |
|---|---|---|---|---|
| 变速积分/积分分离 | 积分饱和、超调 | 匀速车,几乎都该上 | 很高 | 低 |
| 抗积分饱和(遇限削弱) | 饱和退不掉→大超调 | 凡带积分的环必做 | 很高 | 低 |
| 死区补偿 | 低速爬行、静差消不掉 | 电机有明显死区 | 高 | 很低 |
| Bang-Bang+PID | 电机弱、想提速 | 扭矩不足、追用时 | 高 | 中 |
| 前馈 | 响应慢半拍、动态误差 | 高速过弯、目标突变 | 中高 | 中(要模型) |
| 模糊 PID | 一套参数不够用 | 余力 + 想要报告亮点 | 低(赛场)/高(报告) | 高 |
| 卡尔曼 | 姿态精度/漂移 | 直立车且互补不够 | 中 | 高 |
几条压箱底的忠告
进阶算法这块,翻车的往往不是”算法没学会”,而是”用错了地方”。最后几条,记牢:
- 别本末倒置。 机械中值没找准、编码器测速不稳、PWM 频率/控制周期没固定,就急着堆模糊 PID/卡尔曼——地基不稳,高级算法只会放大问题、引入更多 bug。
- 控制周期必须固定且已知。 Ki、Kd、互补滤波的 $a$、卡尔曼的 $Q$/$R$,全都隐含依赖采样周期 $T$。一定要用硬件定时器中断跑控制环来保证周期恒定,把打印、无线发送这些放低优先级或降频。有队伍踩过坑:调 PID 时发现效果不只受 PID 数值影响,还明显受无线发数间隔、编码器测速间隔的影响——控制周期不稳是隐形杀手。
- 逐级加、留对比数据。 先用基础/串级 PID 跑稳跑完整圈,再按”变速积分 → Bang-Bang → 前馈 → 模糊 PID”逐级加,每加一个都留一份对比曲线。这既是科学的工程方法,也是答辩时最有说服力的素材。
- 报告别只堆名词。 论文/答辩里只写”我们用了模糊 PID/卡尔曼”却不讲”为什么需要 + 对比数据”,反而显得为用而用。把一个算法讲透 + 给曲线,远比罗列一堆名词加分。
✅ 收个尾
这一篇你不用全记住,记住一个判断标准就够了:这个算法解决的痛点,是不是我的车现在真正卡住的地方? 是,就上,并且用数据证明它有用;不是,就先放着——把时间还给基础。90% 的省赛车,赢在”基础调得比别人扎实”,而不是”算法堆得比别人多”。
讲到这里,电控的”控制”部分基本拼齐了。但小车要真正变聪明——看得懂赛道、认得出数字和色块、和主控对得上话——还差一双”眼睛”。下一篇我们就来聊 K230 视觉模块怎么用、怎么设计一套稳的通信协议,把视觉结论稳稳喂给主控。
📚 本文是 「从 0 到 1 带你打电赛 · 小车电控篇」 系列(共 12 篇)第 9 篇。




