概述
日常开发中,常常需要对速度、温度等物理量进行稳态控制,而在目前的自动化控制原理中,使用最为广泛的方法就是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;
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的整理分享就到这儿,说得不好的地方请大佬们指教。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)