KA_IX

  • 3485 主题
  • 3537 帖子
  • 11048 积分
  • 身份:LV7 中级工程师
  • 论坛新秀 灌水之王 突出贡献
  • E币:3585

PID算法简介及实例完整代码

2021-2-8 11:58:28 显示全部楼层

PID算法简介要想让智能车根据赛道不断变化灵活的行进,PID算法的采用很有意义。
控制器公式 为:
320500015d0600c80640?from=pc.jpg
31ea0001b2b688043898?from=pc.jpg
  • 比例(P)控制

比例控制是一种最简单的控制方式。其控制器的输出与输入误差信号成比例关系。当仅有比例控制时系统输出存在稳态误差(Steady-state error)。
  • 积分(I)控制

在积分控制中,控制器的输出与输入误差信号的积分成正比关系。对一个自动控制系统,如果在进入稳态后存在稳态误差,则称这个控制系统是有稳态误差的或简称有差系统(System with Steady-state Error)。为了消除稳态误差,在控制器中必须引入“积分项”。积分项对误差取决于时间的积分,随着时间的增加,积分项会增大。这样,即便误差很小,积分项也会随着时间的增加而加大,它推动控制器的输出增大使稳态误差进一步减小,直到等于零。因此,比例+积分(PI)控制器,可以使系统在进入稳态后无稳态误差。
  • 微分(D)控制

在微分控制中,控制器的输出与输入误差信号的微分(即误差的变化率)成正比关系。自动控制系统在克服误差的调节过程中可能会出现振荡甚至失稳。其原因是由于存在有较大惯性组件(环节)或有滞后(delay)组件,具有抑制误差的作用,其变化总是落后于误差的变化。解决的办法是使抑制误差的作用的变化“超前”,即在误差接近零时,抑制误差的作用就应该是零。这就是说,在控制器中仅引入“比例”项往往是不够的,比例项的作用仅是放大误差的幅值,而目前需要增加的是“微分项”,它能预测误差变化的趋势,这样,具有比例+微分的控制器,就能够提前使抑制误差的控制作用等于零,甚至为负值,从而避免了被控量的严重超调。所以对有较大惯性或滞后的被控对象,比例+微分(PD)控制器能改善系统在调节过程中的动态特性。
320500015abdb7dfe4a6?from=pc.jpg
PID控制器的参数整定 PID调试一般原则
a. 在输出不振荡时,增大比例增益P。
b. 在输出不振荡时,减小积分时间常数Ti。
c. 输出不振荡时,增大微分时间常数Td。
PID控制器的参数整定是控制系统设计的核心内容。它是根据被控过程的特性确定PID控制器的比例系数、积分时间和微分时间的大小。PID控制器参数整定的方法很多,概括起来有两大类:一是理论计算整定法。它主要是依据系统的数学模型,经过理论计算确定控制器参数。这种方法所得到的计算数据未必可以直接用,还必须通过工程实际进行调整和修改。二是工程整定方法,它主要依赖工程经验,直接在控制系统的试验中进行,且方法简单、易于掌握,在工程实际中被广泛采用。PID控制器参数的工程整定方法,主要有临界比例法、反应曲线法和衰减法。三种方法各有其特点,其共同点都是通过试验,然后按照工程经验公式对控制器参数进行整定。但无论采用哪一种方法所得到的控制器参数,都需要在实际运行中进行最后调整与完善。现在一般采用的是临界比例法。利用该方法进行PID控制器参数的整定步骤如下:

(1)首先预选择一个足够短的采样周期让系统工作﹔
(2)仅加入比例控制环节,直到系统对输入的阶跃响应出现临界振荡,记下这时的比例放大系数和临界振荡周期﹔
(3)在一定的控制度下通过公式计算得到PID控制器的参数。
PID参数的设定:是靠经验及工艺的熟悉,参考测量值跟踪与设定值曲线,从而调整P\I\D的大小。
PID控制器参数的工程整定,各种调节系统中P.I.D参数经验数据以下可参照:
温度T: P=20~60%,T=180~600s,D=3-180s
压3-18P=30~70%,T=24~180s,
液位L: P=20~80%,T=60~300s,
流量L: P=40~100%,T=6~60s。
书上的常用口诀:
参数整定找最佳,从小到大顺序查
先是比例后积分,最后再把微分加
曲线振荡很频繁,比例度盘要放大
曲线漂浮绕大湾,比例度盘往小扳
曲线偏离回复慢,积分时间往下降
曲线波动周期长,积分时间再加长
曲线振荡频率快,先把微分降下来
动差大来波动慢。微分时间应加长
理想曲线两个波,前高后低4比1
一看二调多分析,调节质量不会低
320500015b1db9bb2ab1?from=pc.jpg
这里介绍一种经验法。这种方法实质上是一种试凑法,它是在生产实践中总结出来的行之有效的方法,并在现场中得到了广泛的应用。
这种方法的基本程序是先根据运行经验,确定一组调节器参数,并将系统投入闭环运行,然后人为地加入阶跃扰动(如改变调节器的给定值),观察被调量或调节器输出的阶跃响应曲线。若认为控制质量不满意,则根据各整定参数对控制过程的影响改变调节器参数。这样反复试验,直到满意为止。
经验法简单可靠,但需要有一定现场运行经验,整定时易带有主观片面性。当采用PID调节器时,有多个整定参数,反复试凑的次数增多,不易得到最佳整定参数。
下面以PID调节器为例,具体说明经验法的整定步骤:
⑴让调节器参数积分系数S0=0,实际微分系数k=0,控制系统投入闭环运行,由小到大改变比例系数S1,让扰动信号作阶跃变化,观察控制过程,直到获得满意的控制过程为止。
⑵取比例系数S1为当前的值乘以0.83,由小到大增加积分系数S0,同样让扰动信号作阶跃变化,直至求得满意的控制过程。
(3)积分系数S0保持不变,改变比例系数S1,观察控制过程有无改善,如有改善则继续调整,直到满意为止。否则,将原比例系数S1增大一些,再调整积分系数S0,力求改善控制过程。如此反复试凑,直到找到满意的比例系数S1和积分系数S0为止。
⑷引入适当的实际微分系数k和实际微分时间TD,此时可适当增大比例系数S1和积分系数S0。和前述步骤相同,微分时间的整定也需反复调整,直到控制过程满意为止。
注意:仿真系统所采用的PID调节器与传统的工业 PID调节器有所不同,各个参数之间相互隔离,互不影响,因而用其观察调节规律十分方便。
31ef00023f0ae0d0c32b?from=pc.jpg
PID参数是根据控制对象的惯量来确定的。大惯量如:大烘房的温度控制,一般P可在10以上,I=3-10,D=1左右。小惯量如:一个小电机带
一水泵进行压力闭环控制,一般只用PI控制。P=1-10,I=0.1-1,D=0,这些要在现场调试时进行修正的。
提供一种增量式PID供参考
△U(k)=Ae(k)-Be(k-1)+Ce(k-2)
A=Kp(1+T/Ti+Td/T)
B=Kp(1+2Td/T)
C=KpTd/T
T采样周期 Td微分时间 Ti积分时间
用上面的算法可以构造自己的PID算法。
U(K)=U(K-1)+△U(K)
320500015b40a8146671?from=pc.jpg
对于PID算法,采样周期是相当重要的,特别是当被控制物体的运动速度较高时,若采样周期跟不上,PID算法的输出滞后严重.但若执行部件有较大滞后时PID的功效将会大打折扣,不改进执行部件的响应速度,将是PID发挥其优异控制性能最大的瓶颈.
PID算法的定义:
P:比例控制项. I:积分控制项. D:微分控制项.
设当前输出量为U,我们的期望值或是设定值为U0,则可得当前时刻误差:E=U-U0;
PID算法即是对误差量E及E的历史进行某种线性组合得到控制量的算法.
一般形式:
Up=P*E;
Ui=i*(E+E_1+E_2+...) E_n为之前的第n次误差.
Ud=i*(E-E_1)
U=Up+Ui+Ud; U为PID控制输出量.
上式中Ui的计算不太方便,长时间单方向的累加将可能出现溢出,于是将上式改为如下所示的增量形式:
  1. Up=p*(E-E_1) 比例项增量

  2. Ui=i*(E-2*E_1+E_2) 微分项增量

  3. Ud=i*E 积分项增量

  4. U=Uout_1+Up+Ui+Ud U为PID控制输出量,Uout_1为前次PID输出值

  5. Uout=U 保存本次值

  6. 对于上面的公式或理论,便可得到相应的C语言程序:

  7. //======================定义PID结构=========================

  8. static float MinValue; //最大值限制

  9. static float MaxValue; //最小值限制

  10. static float CurrentValue; //当前采样值

  11. static struct PID{

  12. float Ki; //定义积分常数

  13. float Kp; //定义比例常数

  14. float Kd; //定义微分常数

  15. float E_2; //存储前前次误差

  16. float E_1; //存诸前次误差

  17. float E; //存储本次误差

  18. float OutPut; //本次输出量

  19. float ValueSet; //设定值或期望值

  20. }Control;

  21. //===========================PID计算函数=====================

  22. void PidWork() {

  23. float Up,Ud,Ui;

  24. Control.E=CurrentValue-Control.ValueSet; //得到本次误差

  25. Up =Control.Kp*(Control.E-Control.E_1); //得到比例项

  26. Ud=Control.Kd*(Control.E-2*Control.E_1+Control.E_2); //得到微分项

  27. Ui=Control.Ki*Control.E; //得到积分项

  28. Control.E_2=Control.E_1; //历史存储

  29. Control.E_1=Control.E;

  30. Control.OutPut+=Up+Ud+Ui; //计算增量和

  31. if(Control.OutPut<MinValue)Control.OutPut=MinValue; //值域限制

  32. else if(Control.OutPut>MaxValue)Control.OutPut=MaxValue;

  33. }

  34. //==========================初始化速度=========================

  35. void PidInit() {

  36. MinValue=0;

  37. MaxValue=1000;

  38. CurrentValue=0;

  39. Control.Kp=-6;

  40. Control.Ki=-1.5;

  41. Control.Kd=-0.5;

  42. Control.E=0;

  43. Control.E_2=0;

  44. Control.E_1=0;

  45. Control.ValueSet=100;

  46. Control.OutPut=0;

  47. }
以上三个函数为PID的主体函数,也是万用PID函数.代码量已经相当精简了.注意上面的PID初始化函数中有Kp,Ki,Kd的符号一定要正确,否则输出量方向相反,后果不堪设想!!!

附上一段完整代码:
  1. #include <stdio.h>

  2. struct _pid {

  3. int pv; /*integer that contains the process value*/

  4. int sp; /*integer that contains the set point*/

  5. float integral;

  6. float pgain;

  7. float igain;

  8. float dgain;

  9. int deadband;

  10. int last_error;

  11. };

  12. struct _pid warm,*pid;

  13. int process_point, set_point,dead_band;

  14. float p_gain, i_gain, d_gain, integral_val,new_integ;;

  15. /*------------------------------------------------------------------------

  16. pid_init

  17. DESCRIPTION This function initializes the pointers in the _pid structure

  18. to the process variable and the setpoint. *pv and *sp are

  19. integer pointers.

  20. ------------------------------------------------------------------------*/

  21. void pid_init(struct _pid *warm, int process_point, int set_point)

  22. {

  23. struct _pid *pid;

  24. pid = warm;

  25. pid->pv = process_point;

  26. pid->sp = set_point;

  27. }

  28. /*------------------------------------------------------------------------

  29. pid_tune

  30. DESCRIPTION Sets the proportional gain (p_gain), integral gain (i_gain),

  31. derivitive gain (d_gain), and the dead band (dead_band) of

  32. a pid control structure _pid.

  33. ------------------------------------------------------------------------*/

  34. void pid_tune(struct _pid *pid, float p_gain, float i_gain, float d_gain, int dead_band)

  35. {

  36. pid->pgain = p_gain;

  37. pid->igain = i_gain;

  38. pid->dgain = d_gain;

  39. pid->deadband = dead_band;

  40. pid->integral= integral_val;

  41. pid->last_error=0;

  42. }

  43. /*------------------------------------------------------------------------

  44. pid_setinteg

  45. DESCRIPTION Set a new value for the integral term of the pid equation.

  46. This is useful for setting the initial output of the

  47. pid controller at start up.

  48. ------------------------------------------------------------------------*/

  49. void pid_setinteg(struct _pid *pid,float new_integ)

  50. {

  51. pid->integral = new_integ;

  52. pid->last_error = 0;

  53. }

  54. /*------------------------------------------------------------------------

  55. pid_bumpless

  56. DESCRIPTION Bumpless transfer algorithim. When suddenly changing

  57. setpoints, or when restarting the PID equation after an

  58. extended pause, the derivative of the equation can cause

  59. a bump in the controller output. This function will help

  60. smooth out that bump. The process value in *pv should

  61. be the updated just before this function is used.

  62. ------------------------------------------------------------------------*/

  63. void pid_bumpless(struct _pid *pid)

  64. {

  65. pid->last_error = (pid->sp)-(pid->pv);

  66. }

  67. /*------------------------------------------------------------------------

  68. pid_calc

  69. DESCRIPTION Performs PID calculations for the _pid structure *a. This function uses the positional form of the pid equation, and incorporates an integral windup prevention algorithim. Rectangular integration is used, so this function must be repeated on a consistent time basis for accurate control.

  70. RETURN VALUE The new output value for the pid loop.

  71. USAGE #include "control.h"*/

  72. float pid_calc(struct _pid *pid)

  73. {

  74. int err;

  75. float pterm, dterm, result, ferror;

  76. err = (pid->sp) - (pid->pv);

  77. if (abs(err) > pid->deadband)

  78. {

  79. ferror = (float) err; /*do integer to float conversion only once*/

  80. pterm = pid->pgain * ferror;

  81. if (pterm > 100 || pterm < -100)

  82. {

  83. pid->integral = 0.0;

  84. }

  85. else

  86. {

  87. pid->integral += pid->igain * ferror;

  88. if (pid->integral > 100.0)

  89. {

  90. pid->integral = 100.0;

  91. }

  92. else if (pid->integral < 0.0) pid->integral = 0.0;

  93. }

  94. dterm = ((float)(err - pid->last_error)) * pid->dgain;

  95. result = pterm + pid->integral + dterm;

  96. }

  97. else result = pid->integral;

  98. pid->last_error = err;

  99. return (result);

  100. }

  101. void main(void)

  102. {

  103. float display_value;

  104. int count=0;

  105. pid = &warm;

  106. // printf("Enter the values of Process point, Set point, P gain, I gain, D gain \n");

  107. // scanf("%d%d%f%f%f", &process_point, &set_point, &p_gain, &i_gain, &d_gain);

  108. process_point = 30;

  109. set_point = 40;

  110. p_gain = (float)(5.2);

  111. i_gain = (float)(0.77);

  112. d_gain = (float)(0.18);

  113. dead_band = 2;

  114. integral_val =(float)(0.01);

  115. printf("The values of Process point, Set point, P gain, I gain, D gain \n");

  116. printf(" %6d %6d %4f %4f %4f\n", process_point, set_point, p_gain, i_gain, d_gain);

  117. printf("Enter the values of Process point\n");

  118. while(count<=20)

  119. {

  120. scanf("%d",&process_point);

  121. pid_init(&warm, process_point, set_point);

  122. pid_tune(&warm, p_gain,i_gain,d_gain,dead_band);

  123. pid_setinteg(&warm,0.0); //pid_setinteg(&warm,30.0);

  124. //Get input value for process point

  125. pid_bumpless(&warm);

  126. // how to display output

  127. display_value = pid_calc(&warm);

  128. printf("%f\n", display_value);

  129. //printf("\n%f%f%f%f",warm.pv,warm.sp,warm.igain,warm.dgain);

  130. count++;

  131. }

  132. }


来源:头条号 小锋学长


您需要登录后才可以评论 登录 | 立即注册

最新评论

楼层直达:
快速回复
0
5
1
2
3
4
5
6
7
8
9
0
广告
关闭 热点推荐上一条 /2 下一条
快速回复 返回列表