C语言PID算法

摘自:https://blog.csdn.net/u014100311/article/details/81204208

额外参考:http://www.stmcu.org.cn/module/forum/thread-600738-1-1.html

https://www.cnblogs.com/steed/p/7808303.html

1. PID算法原理

 

 

  • 如果偏差为0,则比例环节不起作用;
  • 积分环节主要是用来消除静差,即系统稳定后输出值和设定值之间的差值;
  • 微分环节则反映了偏差信号的变化规律,根据偏差信号的变化趋势来进行超前调节,从而增加系统快速性。

 

 

2. 不同类型PID算法

2.1 位置式PID:

2.2 增量式PID:

2.3 积分分离PID:

        普通PID中,引入积分环节的目的主要是为了消除静差,提高控制精度,但是在启动、结束或大幅增减设定时,短时间内系统输出有很大的偏差,会造成PID运算的积分积累,可能导致控制量超过执行机构允许的极限控制量,从而引起较大的超调甚至振荡。

        为了克服这一问题,引入了积分分离的概念,其基本思路是当被控量与设定值偏差较大时,取消积分作用;当控制量接近给定值时,引入积分控制以消除静差,提高精度。

2.4 抗积分饱和PID:

        积分饱和现象是指如果系统存在一个方向的偏差,PID控制器的输出由于积分作用不断累加而加大,从而导致执行机构达到极限位置,若控制器输出继续增大,执行器开度不可能再增大,此时计算机输出控制量超过了正常运行范围而进入饱和区。一旦系统出现反向偏差,u(k)逐渐从饱和区退出。进入饱和区越深则退出饱和区时间越长,在这段时间里,执行机构仍停留在极限位置而不随偏差反向而立即做出相应改变,系统就像失控一样,造成控制系统恶化。

        防止积分饱和的方法之一就是抗积分饱和法,该方法思路是在计算u(k)时,先判断上一时刻控制量u(k-1)是否超过了极限,如果是,则只累加反向偏差,从而避免控制量长时间停留在饱和区。

3. C语言实现

 

 
  1. #include "stdio.h"

  2. #include<stdlib.h>

  3.  
  4. //定义PID结构体

  5. struct _pid{

  6. float SetSpeed;

  7. float ActualSpeed;

  8. float err;

  9. float err_last;

  10. float Kp,Ki,Kd;

  11. //位置式pid

  12. float voltage;

  13. float integral;

  14. //增量式pid

  15. float err_next;

  16. //抗积分饱和PID

  17. float umax;

  18. float umin;

  19. }pid;

  20.  
  21. //初始化变量(基于位置式PID)

  22. void PID_init() {

  23. printf("PID_init begin\n");

  24. pid.SetSpeed = 0.0;

  25. pid.ActualSpeed = 0.0;

  26. pid.err = 0.0;

  27. pid.err_last = 0.0;

  28. pid.voltage = 0.0;

  29. pid.integral = 0.0;

  30. pid.Kp = 0.2;

  31. pid.Ki = 0.015;

  32. pid.Kd = 0.2;

  33. printf("PID_init end \n");

  34. }

  35.  
  36. //编写控制算法

  37. //位置式PID

  38. float positional_PID_realize(float speed) {

  39. pid.SetSpeed = speed;

  40. pid.err = pid.SetSpeed - pid.ActualSpeed;

  41. pid.integral += pid.err;

  42. pid.voltage = pid.Kp*pid.err + pid.Ki*pid.integral + pid.Kd*(pid.err - pid.err_last);

  43. pid.err_last = pid.err;

  44. pid.ActualSpeed = pid.voltage*1.0;

  45. return pid.ActualSpeed;

  46. }

  47.  
  48. //增量式PID

  49. float incremental_PID_realize(float speed) {

  50. pid.err_next = 0.0;

  51.  
  52. pid.SetSpeed = speed;

  53. pid.err = pid.SetSpeed - pid.ActualSpeed;

  54. float incrementSpeed = pid.Kp*(pid.err - pid.err_next) + pid.Ki*pid.err + pid.Kd*(pid.err - 2 * pid.err_next + pid.err_last);

  55. pid.ActualSpeed += incrementSpeed;

  56. pid.err_last = pid.err_next;

  57. pid.err_next = pid.err;

  58. return pid.ActualSpeed;

  59. }

  60.  
  61. //积分分离PID

  62. float IntegralSeparatio_PID_realize(float speed) {

  63. int index;

  64. pid.Kp = 0.2;

  65. pid.Ki = 0.04;

  66. pid.Kd = 0.2;

  67.  
  68. pid.SetSpeed = speed;

  69. pid.err = pid.SetSpeed - pid.ActualSpeed;

  70. if (abs(pid.err) > 200) {

  71. index = 0;

  72. }

  73. else {

  74. index = 1;

  75. pid.integral += pid.err;

  76. }

  77. pid.voltage = pid.Kp*pid.err + index*pid.Ki*pid.integral + pid.Kd*(pid.err - pid.err_last);

  78. pid.err_last = pid.err;

  79. pid.ActualSpeed = pid.voltage*1.0;

  80. return pid.ActualSpeed;

  81. }

  82.  
  83. //抗饱和PID

  84. float anti_windup_PID_realize(float speed) {

  85. pid.Kp = 0.2;

  86. pid.Ki = 0.1;

  87. pid.Kd = 0.2;

  88. pid.umax = 400;

  89. pid.umin = -200;

  90. int index;

  91. pid.SetSpeed = speed;

  92. pid.err = pid.SetSpeed - pid.ActualSpeed;

  93. if (pid.ActualSpeed > pid.umax) {

  94. if (abs(pid.err) > 200)

  95. {

  96. index = 0;

  97. }

  98. else {

  99. index = 1;

  100. if (pid.err < 0)

  101. {

  102. pid.integral += pid.err;

  103. }

  104. }

  105. }

  106. else if (pid.ActualSpeed < pid.umin) {

  107. if (abs(pid.err) > 200)

  108. {

  109. index = 0;

  110. }

  111. else {

  112. index = 1;

  113. if (pid.err > 0)

  114. {

  115. pid.integral += pid.err;

  116. }

  117. }

  118. }

  119. else {

  120. if (abs(pid.err) > 200)

  121. {

  122. index = 0;

  123. }

  124. else {

  125. index = 1;

  126. pid.integral += pid.err;

  127. }

  128. }

  129. pid.voltage = pid.Kp*pid.err + index*pid.Ki*pid.integral + pid.Kd*(pid.err - pid.err_last);

  130. pid.err_last = pid.err;

  131. pid.ActualSpeed = pid.voltage*1.0;

  132. return pid.ActualSpeed;

  133.  
  134. }

  135.  
  136. //测试代码

  137. int main() {

  138. printf("system begin\n");

  139. PID_init();

  140. int count = 0;

  141. while (count < 500)

  142. {

  143. float speed = anti_windup_PID_realize(200.0);

  144. printf("%f\n", speed);

  145. count++;

  146. }

  147. system("pause");

  148. return 0;

  149. }

  • 1

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值