概述
日常开发中,常常需要对速度、温度等物理量进行稳态控制,而在目前的自动化控制原理中,使用最为广泛的方法就是PID控制算法。本文简要整理分享PID控制器的使用。
正文
PID控制器,即比例-积分-微分控制器。它是一个不依赖系统模型,仅依赖系统输出即可进行控制的负反馈控制器。PID控制器通过直观地观测当前误差(比例作用)、过去的误差(积分作用)、误差的变化趋势(微分作用) 来进行系统控制。
PID控制器的数学公式可以写成: u = K p ∗ e + K i ∗ ∫ e d t + K d ∗ d e d t u=K_p*e+K_i*\int{e}dt+K_d*\frac{de}{dt} u=Kp∗e+Ki∗∫edt+Kd∗dtde
其中:
e e e是当前误差
K p K_p Kp是比例增益系数
K i K_i Ki是积分增益系数
K d K_d Kd是微分增益系数
所以,从上述公式可以看出,PID控制器对系统的控制作用是比例项、积分项、微分项的加权和。
其次,衡量一个系统的状态,可以从稳定性、准确性、快速性来衡量。其中,
P和I降低系统稳定性,D提高系统稳定性。
P和I减小静态误差,D无作用。
P和D提高响应速度,I降低响应速度。
PID调参方法
(1)整定比例项
方法:先将积分、微分作用去除,设置目标值为系统最大控制量的70%。然后,逐渐加大比例作用,直到系统发生震荡。观察控制量波形,若波形的波峰由大变小,且最终稳定在某个值,且第一个波峰与第二个波峰之间数值比约为4:1。那么可以把当前 K p K_p Kp固定。
(2)整定积分项
方法:逐渐减小积分时间,使得积分项作用增强,观察控制量波形。若控制量静差为0,则可以把当前 T i T_i Ti固定下来。
(3)整定微分项
方法:逐渐增加微分时间,使得微分项作用增强,观察控制量波形。若控制量波形震荡减小至基本无震荡,则可以把当前 T d T_d Td固定下来。
(4)微调参数
方法:若发现粗调后,系统稳定性不足(震荡多),则稍稍加大 T d T_d Td;若准确性不足,则稍稍减小 T i T_i Ti;循环往复观察对比,调整 T i T_i Ti和 T d T_d Td,直到满足系统要求为止。
对于联级PID的调参方法与单环PID调参方法一样,只是联级PID调参时,需要先整定内环,再整定外环(即先将外环作用去除)
使用matlab simulink简单测试调参方法
参数及效果如下:
代码实现
PID控制器分为位置式PID和增量式PID。
位置式PID公式: u ( k ) = K p ∗ e ( k ) + K p ∗ T T i ∗ ∑ i = 1 k e ( i ) + K p ∗ T d T ∗ [ e ( k ) − e ( k − 1 ) ] u(k)=K_p*e(k)+\frac{K_p*T}{T_i}*{\sum_{i=1}^{k}e(i)}+\frac{K_p*T_d}{T}*\left[e(k)-e(k-1)\right] u(k)=Kp∗e(k)+TiKp∗T∗∑i=1ke(i)+TKp∗Td∗[e(k)−e(k−1)]
由于基于误差的微分方程存在微分冲击的缺陷,所以微分项可以改进为: − K p ∗ T d T [ P v ( k ) − P v ( k − 1 ) ] -\frac{K_p*T_d}{T}\left[Pv(k)-Pv(k-1)\right] −TKp∗Td[Pv(k)−Pv(k−1)]
所以C代码如下:
void pid_calc(pid_t *pid)
{
float DelPv;
float ti,ki;
float td;
float kd;
float out;
pid->Ek = pid->Sv - pid->Pv; //得到当前偏差值
pid->Pout = pid->Kp * pid->Ek; //比例输出
//抗积分饱和
if(pid->OUT >= pid->pwmcycle)
{
if(pid->Ek < 0)
pid->SEk += pid->Ek;
}
else if(pid-OUT <= pid->OUT0)
{
if(pid->Ek > 0)
pid->SEk += pid->Ek;
}
else
pid->SEk += pid->Ek;
// pid->SEk += pid->Ek; //历史偏差总和
ti = pid->T / pid->Ti;
ki = ti * pid->Kp;
pid->Iout = ki * pid->SEk; //积分输出
DelPv = pid->Pv - pid->Pv_1;
td = pid->Td / pid->T;
kd = pid->Kp * td;
pid->Dout = kd * DelPv; //微分输出
out = pid->Pout + pid->Iout - pid->Dout;
//输出限幅
if(out > pid->pwmcycle)
{
pid->OUT = pid->pwmcycle;
}
else if(out < 0)
{
pid->OUT = pid->OUT0;
}
else
{
pid->OUT = out;
}
pid->Pv_1 = pid->Pv;
}
增量式PID公式: Δ u = K p ∗ [ e ( k ) − e ( k − 1 ) ] + K p ∗ T T i ∗ e ( k ) + K p ∗ T d T ∗ [ e ( k ) − 2 ∗ e ( k − 1 ) + e ( k − 2 ) ] \Delta{u}=K_p*\left[e(k)-e(k-1)\right]+\frac{K_p*T}{T_i}*e(k)+\frac{K_p*T_d}{T}*\left[e(k)-2*e(k-1)+e(k-2)\right] Δu=Kp∗[e(k)−e(k−1)]+TiKp∗T∗e(k)+TKp∗Td∗[e(k)−2∗e(k−1)+e(k−2)]
同样的,可以改进式子以消除微分冲击:
− K p ∗ T d T [ P v ( k ) − 2 ∗ P v ( k − 1 ) + P v ( k − 2 ) ] -\frac{K_p*T_d}{T}\left[Pv(k)-2*Pv(k-1)+Pv(k-2)\right] −TKp∗Td[Pv(k)−2∗Pv(k−1)+Pv(k−2)]
所以C代码如下:
void incremental_pid_calc(pid_t *pid)
{
float DelPv;
float ti,ki;
float td,kd;
float beta;
float out;
pid->Ek = pid->Sv - pid->Pv; //当前误差
//积分分离
if(fabs(pid->Ek) <= 100) //偏差较大时,不加入积分作用
beta = 1;
else
beta = 0;
//比例项输出
pid->Pout = pid->Kp * (pid->Ek - pid->Ek_1);
//积分项输出
ti = pid->T / pid->Ti;
ki = ti * pid->Kp;
pid->Iout = beta * ki * pid->Ek;
//微分项输出
DelPv = pid->Pv - (2 * pid->Pv_1 ) + pid->Pv_2;//抗微分冲击
td = pid->Td / pid->T;
kd = td * pid->Kp;
pid->Dout = kd * DelPv;
out = pid->Pout + pid->Iout - pid->Dout;
//输出限幅
if(out > pid->pwmcycle)
pid->OUT = pid->pwmcycle;
else if(out < 0)
pid->OUT = pid->OUT0;
else
pid->OUT = out;
//死区限定
if(fabs(pid->Ek) <= 10)
pid->OUT = pid->OUT0;
pid->Ek_1 = pid->Ek;
pid->Pv_2 = pid->Pv_1;
pid->Pv_1 = pid->Pv;
}
总结
这样就可以移植和使用PID控制了。实际开发中,经典PID控制器基本不适用,所以常常需要对PID控制器进行一下改进,如加入积分分离、微分先行、死区控制等方式优化。所以,虽然PID控制原理很简单,但是调参及优化才是比较花时间的地方。熟能生巧,用多了,自然就会了。关于PID的整理分享就到这儿,说得不好的地方请大佬们指教。