3. PID控制基础:比例、积分、微分的作用、PID参数对系统的影响、数字PID实现
聊到FOC速度环,绕不开的就是PID。说实话,我见过不少新手一上来就调参数,调得满头大汗,结果电机要么抖得像筛子,要么转都转不起来。其实,搞懂PID这三个字母到底在干什么,比盲目调参重要得多。
这一节,咱们就把PID掰开揉碎了讲。我会结合我在电机驱动项目里踩过的坑,帮你把基础打牢。
3.1 比例控制:最直接的“硬拉”
比例控制,说白了就是“看偏差,给力气”。
你设定目标转速是1000 RPM,现在实际转速是800 RPM。偏差是200 RPM。比例控制器就会把这个偏差乘以一个系数Kp,然后输出一个控制量去拉转速。
公式很简单:
u(t) = Kp * e(t)
其中e(t)就是当前偏差。
Kp大了会怎样?
反应快,但容易过头。我在一个无刷电机项目里,Kp设得太大,电机一启动就“嗡”的一声冲过目标,然后来回震荡,像极了秋千停不下来。这就是典型的超调和震荡。
Kp小了会怎样?
反应慢,而且永远追不上目标。你想想看,偏差越小,输出的力就越小。到最后,偏差小到一定程度,输出的力刚好只够克服摩擦力,电机就停在那里,离目标转速差那么一点点。这就是稳态误差。
核心结论:比例控制能快速响应,但单靠它,系统会有稳态误差,而且容易震荡。
3.2 积分控制:专治“差一口气”
刚才说的稳态误差,怎么消除?积分控制就是干这个的。
积分项会把过去所有的偏差累加起来。只要还有偏差,积分项就会一直增长,输出的控制力就会越来越大,直到把最后那点偏差给“磨掉”。
公式:
u(t) = Ki * ∫e(t) dt
Ki的作用:
Ki越大,积分作用越强,消除稳态误差越快。但Ki太大,积分项会“冲过头”,导致系统震荡,甚至出现“积分饱和”。
避坑指南:我曾经在一个大惯量负载的项目里,Ki设得偏大。电机启动时,积分项疯狂累加,等转速到达目标时,积分项已经积累了一大堆“能量”,导致转速直接冲过目标一大截,然后来回震荡了好几次才稳定下来。这就是积分饱和的典型表现。
解决办法:加积分限幅,或者用抗积分饱和算法。这个后面会细讲。
3.3 微分控制:提前“踩刹车”
比例和积分都是“事后”调节,微分则是“事前”预测。
微分项看的是偏差的变化率。如果偏差正在快速减小(转速正在快速接近目标),微分项就会输出一个反向的力,提前“踩刹车”,防止超调。
公式:
u(t) = Kd * de(t)/dt
Kd的作用:
Kd能抑制震荡,提高系统的稳定性。但Kd对噪声非常敏感。你想想看,如果速度反馈信号里有一点毛刺,微分项就会把它放大,导致控制量剧烈抖动。
我的经验:在FOC速度环里,我一般很少用微分项,或者只用很小的Kd。因为电流采样和速度计算本身就有噪声,微分项容易引入高频抖动。如果非要用,一定要先对速度信号做低通滤波。
3.4 PID参数对系统的影响
为了让你看得更清楚,我整理了一个表格。这是我在项目里反复验证过的经验总结。
| 参数 | 增大后的效果 | 减小后的效果 | 常见问题 |
|---|---|---|---|
| Kp | 响应变快,超调增大,稳态误差减小 | 响应变慢,稳态误差增大 | Kp过大导致震荡 |
| Ki | 消除稳态误差更快,但容易超调 | 消除稳态误差变慢 | Ki过大导致积分饱和 |
| Kd | 抑制超调,提高稳定性 | 系统容易震荡 | Kd过大引入噪声 |
3.5 数字PID的实现
在实际的MCU里,我们用的是离散化的数字PID。说白了,就是把连续的积分和微分,变成累加和差分。
位置式PID:
直接计算当前时刻的控制量。公式如下:
u(k) = Kp * e(k) + Ki * ∑e(i) * T + Kd * (e(k) - e(k-1)) / T
其中T是采样周期。这个公式直接、好理解,但积分项需要一直累加,容易积分饱和。
增量式PID:
计算的是控制量的增量,而不是绝对值。公式如下:
Δu(k) = Kp * (e(k) - e(k-1)) + Ki * e(k) * T + Kd * (e(k) - 2*e(k-1) + e(k-2)) / T
这个公式的好处是:输出的是增量,不会出现积分饱和。而且就算MCU死机重启,控制量也不会突变。我在实际项目中,90%的情况都用增量式PID。
代码示例(增量式PID,C语言):
typedef struct {
float Kp;
float Ki;
float Kd;
float T; // 采样周期
float error_prev; // e(k-1)
float error_pprev;// e(k-2)
float output; // 当前输出
} PID_IncTypeDef;
float PID_Inc_Calc(PID_IncTypeDef *pid, float target, float actual) {
float error = target - actual;
float delta_u;
delta_u = pid->Kp * (error - pid->error_prev)
+ pid->Ki * error * pid->T
+ pid->Kd * (error - 2*pid->error_prev + pid->error_pprev) / pid->T;
pid->output += delta_u;
pid->error_pprev = pid->error_prev;
pid->error_prev = error;
return pid->output;
}
注意:实际使用时,一定要对输出做限幅。不然积分项或者微分项一抽风,输出值能飞到天上去,电机直接就炸了。
3.6 本章知识体系图
下面这张图,是我用SVG画的。它把PID的核心逻辑、参数影响、以及数字实现的关键点都串起来了。你可以把它当作一个速查地图。
嗯,这一节的内容就到这里。PID看起来简单,但真正用好,需要你在项目里反复体会。别急,后面我们会结合FOC速度环,一步步把参数调明白。