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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章