第4章 PID控制器入门:比例、积分、微分的作用
说实话,我刚入行那会儿,觉得PID这玩意儿挺玄乎的。三个字母,三个参数,调来调去就是调不好。后来带我的老工程师跟我说了一句话,我到现在都记得——「PID没那么复杂,你把它想成三个人在干活就行了。」
嗯,今天我就用这个思路,带你彻底搞懂比例、积分、微分到底在干嘛。
4.1 先问一个问题:为什么要用PID?
你想想看,一个机器人要沿着一条线走。你给它一个目标位置,它得动起来。但怎么动?
- 动得太慢,跟不上轨迹
- 动得太快,冲过头了
- 动得刚刚好?那得有个控制器
PID就是干这个的。它根据「当前误差」来决定「下一步怎么动」。误差大就猛动,误差小就微调。
核心思想: 误差 = 目标值 - 当前值。PID就是对这个误差做三种不同的处理,然后加起来输出。
4.2 比例控制(P)—— 最直接的反应
比例控制,说白了就是「误差越大,输出越大」。你离目标远,我就使劲推你;你离目标近了,我就轻轻推。
数学表达式:
u(t) = Kp * e(t)
其中:
- u(t) 是控制输出
- Kp 是比例增益
- e(t) 是当前误差
我在项目中遇到过一个问题:只用比例控制,机器人永远到不了目标点。为什么?因为当误差很小时,输出也很小,小到不足以克服摩擦力。这就叫「稳态误差」。
我的习惯: 调PID时,先把P调到一个能让系统「动起来但不振荡」的值。别急着加I和D。
4.3 积分控制(I)—— 消除累积误差
比例控制搞不定的稳态误差,积分来搞定。积分看的是「过去所有误差的总和」。只要误差一直存在,积分项就会一直增长,直到把误差消除。
数学表达式:
u(t) = Ki * ∫e(t) dt
这里有个坑,我踩过。积分项太强,系统会「过冲」—— 冲过头了,然后来回振荡。这叫「积分饱和」。
我曾经... 在一个电机控制项目里,积分项设得太大,结果电机一启动就疯狂振荡,差点把减速箱搞坏。后来加了积分限幅才解决。
积分的作用,说白了就是「纠偏」。你一直偏左,我就一直往右推,直到你回到中间。
4.4 微分控制(D)—— 预测未来
比例和积分都是看「过去和现在」。微分不一样,它看的是「误差的变化趋势」。误差在快速增大?微分项会提前输出一个反向力,阻止它继续增大。
数学表达式:
u(t) = Kd * de(t)/dt
微分就像个「刹车」。你想想看,开车时看到前面红灯,你不会等到跟前才刹车吧?你会提前减速。微分干的就是这个事。
但微分有个毛病:它对噪声特别敏感。传感器抖一下,微分项就跳一下。我在做四足机器人时,腿部的加速度计噪声很大,加了微分后反而更抖了。后来我加了低通滤波才搞定。
建议: 如果系统噪声大,微分增益Kd别设太大,或者干脆不用D。很多场合P+I就够了。
4.5 三个合在一起:完整的PID
把三个加起来,就是完整的PID控制器:
u(t) = Kp * e(t) + Ki * ∫e(t) dt + Kd * de(t)/dt
用一张图来理解它们的关系:
4.6 三个参数怎么调?
调参这事儿,没有标准答案。但我可以给你一个我常用的「三板斧」:
- 先调P:从小到大慢慢加,直到系统开始振荡。然后回调一点,让振荡消失。这时候P就差不多了。
- 再加I:如果存在稳态误差(到不了目标点),加一点I。从很小的值开始,慢慢加,直到误差消除。
- 最后加D:如果系统过冲严重或者振荡,加一点D来抑制。注意D别太大,否则噪声会放大。
记住: 不是所有系统都需要三个参数。很多场合P+I就够了。D是锦上添花,不是雪中送炭。
4.7 一个简单的代码示例
下面是一个位置式PID的C语言实现,我在STM32上跑过:
typedef struct {
float Kp;
float Ki;
float Kd;
float integral;
float prev_error;
} PID_Controller;
float PID_Update(PID_Controller *pid, float target, float current) {
float error = target - current;
// 比例项
float p_out = pid->Kp * error;
// 积分项(带限幅)
pid->integral += error;
if (pid->integral > 100.0f) pid->integral = 100.0f;
if (pid->integral < -100.0f) pid->integral = -100.0f;
float i_out = pid->Ki * pid->integral;
// 微分项
float derivative = error - pid->prev_error;
float d_out = pid->Kd * derivative;
// 保存当前误差供下次使用
pid->prev_error = error;
return p_out + i_out + d_out;
}
注意: 积分限幅很重要。不加限幅的话,积分项会一直累积,导致「积分饱和」。我吃过这个亏,现在每次写PID都会加上限幅。
4.8 常见问题与避坑
| 问题 | 原因 | 解决方法 |
|---|---|---|
| 系统振荡 | P太大,或者D太小 | 减小Kp,或者增加Kd |
| 到不了目标点 | P太小,或者没有I | 增加Kp,或者加一点Ki |
| 过冲严重 | I太大,或者没有D | 减小Ki,或者加一点Kd |
| 噪声放大 | D太大 | 减小Kd,或者加低通滤波 |
嗯,PID入门其实就这么点东西。别被那些复杂的公式吓到,说白了就是三个参数的组合游戏。你多调几次,手感就出来了。
我刚开始做轨迹跟踪时,调一个PID花了两天。现在嘛,十分钟搞定。这东西就是个经验活。