4、增量式PID实现
增量式PID,这个名字听起来挺唬人。其实说白了,它跟位置式PID是亲兄弟,只是算账的方式不一样。我个人习惯在电机控制、步进驱动这类场景里用增量式,因为它算得快,而且不容易出大乱子。
4.1 增量式PID公式推导
我们先回忆一下位置式PID的公式:
u(k) = Kp * e(k) + Ki * Σe(i) + Kd * [e(k) - e(k-1)]
这个公式里有个累加项 Σe(i),它记录了从启动到现在的所有误差。你想想看,如果系统跑了一天,这个累加值会变得非常大。万一哪天积分项溢出了,输出直接飞掉,电机就乱转了。
增量式PID的思路很简单——我不算总输出,我只算这次比上次多了多少。
推导过程是这样的:
u(k) = Kp * e(k) + Ki * Σe(i) + Kd * [e(k) - e(k-1)]
u(k-1) = Kp * e(k-1) + Ki * Σe(i-1) + Kd * [e(k-1) - e(k-2)]
Δu(k) = u(k) - u(k-1)
= Kp * [e(k) - e(k-1)] + Ki * e(k) + Kd * [e(k) - 2*e(k-1) + e(k-2)]
嗯,这里要注意:增量式PID的输出是Δu(k),不是u(k)。最终的控制量是 u(k) = u(k-1) + Δu(k)。
核心要点:增量式PID只需要保存最近三次的误差值 e(k)、e(k-1)、e(k-2),不需要累加历史误差。这意味着它天然没有积分饱和的问题。
4.2 与位置式PID对比
我在项目里经常被问到:「到底该用增量式还是位置式?」我的回答是:看你的执行机构。
| 对比项 | 位置式PID | 增量式PID |
|---|---|---|
| 输出形式 | 直接输出控制量 u(k) | 输出增量 Δu(k) |
| 积分处理 | 需要防积分饱和 | 天然无积分饱和 |
| 存储需求 | 需保存所有历史误差 | 只需保存3个误差值 |
| 故障影响 | 输出突变,可能损坏设备 | 输出平滑变化 |
| 适用场景 | 伺服电机、温度控制 | 步进电机、阀门控制 |
举个例子。我曾经调试一个阀门开度控制系统,用的是位置式PID。结果有一次传感器突然跳变,积分项瞬间累积了一个巨大的值,阀门直接全开,差点把管道冲爆。后来换成增量式,同样的故障发生时,输出只变化了一点点,系统稳稳的。
避坑指南:我曾经在伺服电机位置环里硬套增量式PID,结果发现电机永远到不了目标位置。为什么?因为增量式没有积分项的直接累加,稳态误差消不掉。后来我加了个死区处理,才解决了这个问题。
4.3 C语言代码实现
直接上代码。这是我个人常用的增量式PID结构体,简洁实用:
typedef struct {
float Kp; // 比例系数
float Ki; // 积分系数
float Kd; // 微分系数
float e_k; // e(k)
float e_k_1; // e(k-1)
float e_k_2; // e(k-2)
float u_k_1; // u(k-1)
float out_max; // 输出限幅
float out_min; // 输出下限
} IncrementalPID_t;
float IncrementalPID_Calc(IncrementalPID_t *pid, float target, float feedback) {
float delta_u;
// 更新误差
pid->e_k_2 = pid->e_k_1;
pid->e_k_1 = pid->e_k;
pid->e_k = target - feedback;
// 计算增量
delta_u = pid->Kp * (pid->e_k - pid->e_k_1)
+ pid->Ki * pid->e_k
+ pid->Kd * (pid->e_k - 2*pid->e_k_1 + pid->e_k_2);
// 累加得到当前输出
pid->u_k_1 += delta_u;
// 输出限幅
if(pid->u_k_1 > pid->out_max) pid->u_k_1 = pid->out_max;
if(pid->u_k_1 < pid->out_min) pid->u_k_1 = pid->out_min;
return pid->u_k_1;
}
小技巧:初始化时记得把 e_k、e_k_1、e_k_2 都清零,u_k_1 设为0。我见过有人忘了初始化,结果第一次调用时微分项算出一个巨大的值,系统直接震荡。
4.4 应用场景分析
增量式PID最适合以下场景:
- 步进电机控制:每次只发一个脉冲增量,不会因为积分饱和导致电机丢步
- 阀门/舵机控制:执行机构有记忆效应,断电后保持当前位置
- 需要平滑启动的场景:增量式天然有软启动效果,不会一开机就猛冲
不适合的场景:
- 位置伺服控制:需要精确到达目标位置,增量式缺少积分累加,会有静差
- 积分作用要求强的系统:比如温度控制,增量式的积分效果偏弱
我做过一个项目,用增量式PID控制直流电机转速。刚开始效果不错,但负载变化时转速波动很大。后来我加了个前馈补偿,把负载变化量直接加到输出上,效果立竿见影。
下面这张图展示了增量式PID的核心逻辑:
总结一下:增量式PID不是万能的,但在合适的场景下,它比位置式PID更稳定、更安全。我个人建议,凡是执行机构有记忆效应(比如步进电机、阀门),优先考虑增量式。凡是需要精确位置控制(比如伺服电机),还是老老实实用位置式。
嗯,这一章就到这里。代码可以直接拿去用,但记得根据你的实际系统调参。
公众号:蓝海资料掘金营,微信deep3321