基本原理

image.png

模糊规则表

image.png

代码实现

  • 模块化设计
  • 需要配合C620C610电机群模块实现具体功能

    Math_FuzzyPID.h

    ```c /*
    • Copyright (c) 2020 - ~, HIT_HERO Team *
    • FUZZYPID MODULE HEAD FILE
    • Used in RT-Thread Operate System *
    • Change Logs:
    • Date Author Notes Mail
    • 2020-08-20 WangXi first version WangXi_chn@foxmail.com
    • Note: */

      ifndef MATH_FUZZYPID_H

      define MATH_FUZZYPID_H

include

include

include

enum fuzztab { NB = 0, NM = 1, NS = 2, ZO = 3, PS = 4, PM = 5, PB = 6, };

struct _MATH_FUZZYPID { / Property / float Property_Kp; float Property_Ki; float Property_Kd;

  1. float Property_dt;
  2. float Property_integralMax;
  3. float Property_AimMax;
  4. float Property_OutputMax;
  5. float Value_errRange[7];
  6. float Value_errDotRange[7];
  7. float Value_deltaKpRange[7];
  8. float Value_deltaKiRange[7];
  9. float Value_deltaKdRange[7];
  10. /* Value */
  11. float Value_Aim;
  12. float Value_Actual;
  13. float Value_err;
  14. float Value_errDot;
  15. float Value_err_last;
  16. float Value_integral;
  17. float Value_output;
  18. rt_uint8_t Value_errBelongStage[2];
  19. float Value_errBelongValue[2];
  20. rt_uint8_t Value_errDotBelongStage[2];
  21. float Value_errDotBelongValue[2];
  22. float Value_deltaKp;
  23. float Value_deltaKi;
  24. float Value_deltaKd;
  25. /* Method */
  26. void (*Method_Init)(struct _MATH_FUZZYPID *module);
  27. void (*Method_Update)(struct _MATH_FUZZYPID *module,float Aim, float Feedback);

}; typedef struct _MATH_FUZZYPID MATH_FUZZYPID;

rt_err_t Module_FuzzyPID_Config(MATH_FUZZYPID *module);

endif

  1. <a name="H4nEk"></a>
  2. ## Math_FuzzyPID.c
  3. ```c
  4. /*
  5. * Copyright (c) 2020 - ~, HIT_HERO Team
  6. *
  7. * FUZZYPID MODULE SOUCE FILE
  8. * Used in RT-Thread Operate System
  9. *
  10. * Change Logs:
  11. * Date Author Notes Mail
  12. * 2020-08-20 WangXi first version WangXi_chn@foxmail.com
  13. *
  14. * Note:
  15. *
  16. */
  17. #include "Math_FuzzyPID.h"
  18. #include <math.h>
  19. #define FUZZYPID
  20. enum fuzztab KPTAB[7][7] =
  21. {
  22. PB,PB,PM,PM,PS,ZO,ZO,
  23. PB,PB,PM,PS,PS,ZO,NS,
  24. PM,PM,PM,PS,ZO,NS,NS,
  25. PM,PM,PS,ZO,NS,NM,NM,
  26. PS,PS,ZO,NS,NS,NM,NM,
  27. PS,ZO,NS,NM,NM,NM,NB,
  28. ZO,ZO,NM,NM,NM,NB,NB
  29. };
  30. enum fuzztab KITAB[7][7] =
  31. {
  32. NB,NB,NM,NM,NS,ZO,ZO,
  33. NB,NB,NM,NS,NS,ZO,ZO,
  34. NB,NM,NS,NS,ZO,PS,PS,
  35. NM,NM,NS,ZO,PS,PM,PM,
  36. NM,NS,ZO,PS,PS,PM,PB,
  37. ZO,ZO,PS,PS,PM,PB,PB,
  38. ZO,ZO,PS,PM,PM,PB,PB
  39. };
  40. enum fuzztab KDTAB[7][7] =
  41. {
  42. PS,NS,NB,NB,NB,NM,PS,
  43. PS,NS,NB,NM,NM,NS,ZO,
  44. ZO,NS,NM,NM,NS,NS,ZO,
  45. ZO,NS,NS,NS,NS,NS,ZO,
  46. ZO,ZO,ZO,ZO,ZO,ZO,ZO,
  47. PB,NS,PS,PS,PS,PS,PB,
  48. PB,PM,PM,PM,PS,PS,PB
  49. };
  50. static void Module_FuzzyPIDInit(MATH_FUZZYPID *module);
  51. static void Module_FuzzyPIDUpdate(MATH_FUZZYPID *module,float Aim, float Feedback);
  52. static void fuzziFication(MATH_FUZZYPID *module);
  53. static void defuzzify(MATH_FUZZYPID *module);
  54. rt_err_t Module_FuzzyPID_Config(MATH_FUZZYPID *module)
  55. {
  56. if( module->Method_Init ==NULL &&
  57. module->Method_Update ==NULL
  58. ){
  59. /* Link the Method */
  60. module->Method_Init = Module_FuzzyPIDInit;
  61. module->Method_Update = Module_FuzzyPIDUpdate;
  62. }
  63. else{
  64. rt_kprintf("Warning: Module Fuzzy PID is Configed twice\n");
  65. return RT_ERROR;
  66. }
  67. /* Device Init */
  68. module->Method_Init(module);
  69. return RT_EOK;
  70. }
  71. static void Module_FuzzyPIDInit(MATH_FUZZYPID *module)
  72. {
  73. module->Value_Actual = 0;
  74. module->Value_Aim = 0;
  75. module->Value_err = 0;
  76. module->Value_err_last = 0;
  77. module->Value_integral = 0;
  78. module->Value_output = 0;
  79. }
  80. static void Module_FuzzyPIDUpdate(MATH_FUZZYPID *module,float Aim, float Feedback)
  81. {
  82. float P,I,D;
  83. module->Value_Aim = Aim;
  84. module->Value_Actual = Feedback;
  85. /* Culculate P */
  86. if(module->Value_Aim > module->Property_AimMax)
  87. module->Value_Aim = module->Property_AimMax;
  88. else if(module->Value_Aim < -module->Property_AimMax)
  89. module->Value_Aim = -module->Property_AimMax;
  90. module->Value_err = module->Value_Aim - module->Value_Actual;
  91. module->Value_errDot = module->Value_err - module->Value_err_last;
  92. module->Value_err_last = module->Value_err;
  93. #ifdef FUZZYPID
  94. /* Fuzzy PID Used */
  95. fuzziFication(module);
  96. defuzzify(module);
  97. module->Property_Kp += module->Value_deltaKp;
  98. module->Property_Ki += module->Value_deltaKi;
  99. //module->Property_Kd += module->Value_deltaKd;
  100. #endif
  101. P = module->Value_err * module->Property_Kp;
  102. /* Culculate I */
  103. if(fabs(module->Value_err) < 500)
  104. {
  105. module->Value_integral += module->Value_err * module->Property_Ki * module->Property_dt;
  106. if(module->Value_integral > module->Property_integralMax)
  107. module->Value_integral = module->Property_integralMax;
  108. else if(module->Value_integral < -module->Property_integralMax)
  109. module->Value_integral = -module->Property_integralMax;
  110. I = module->Value_integral;
  111. }
  112. /* Culculate D */
  113. D = module->Property_Kd * (module->Value_err - module->Value_err_last) / module->Property_dt;
  114. /* Culculate Output */
  115. module->Value_output = P + I + D;
  116. if(module->Value_output > module->Property_OutputMax)
  117. module->Value_output = module->Property_OutputMax;
  118. else if(module->Value_output < -module->Property_OutputMax)
  119. module->Value_output = -module->Property_OutputMax;
  120. }
  121. static void fuzziFication(MATH_FUZZYPID *module)
  122. {
  123. /* get err fuzzy */
  124. if(module->Value_err > module->Value_errRange[6])
  125. {
  126. module->Value_errBelongStage[0] = PB;
  127. module->Value_errBelongStage[1] = PB;
  128. module->Value_errBelongValue[0] = 1;
  129. module->Value_errBelongValue[1] = 0;
  130. }
  131. else if(module->Value_err < module->Value_errRange[0])
  132. {
  133. module->Value_errBelongStage[1] = NB;
  134. module->Value_errBelongStage[0] = NB;
  135. module->Value_errBelongValue[0] = 0;
  136. module->Value_errBelongValue[1] = 1;
  137. }
  138. else
  139. {
  140. for(rt_uint8_t i = 0;i<5;i++)
  141. {
  142. if(module->Value_err == module->Value_errRange[i])
  143. {
  144. module->Value_errBelongStage[1] = i;
  145. module->Value_errBelongStage[0] = i;
  146. module->Value_errBelongValue[0] = 0;
  147. module->Value_errBelongValue[1] = 1;
  148. }
  149. else if((module->Value_err>module->Value_errRange[i])&&(module->Value_err<module->Value_errRange[i+1]))
  150. {
  151. float step = fabs(module->Value_errRange[1]-module->Value_errRange[0]);
  152. module->Value_errBelongStage[0] = i;
  153. module->Value_errBelongStage[1] = i+1;
  154. module->Value_errBelongValue[0] =
  155. fabs((module->Value_err-module->Value_errRange[i])/step);
  156. module->Value_errBelongValue[1] = 1-module->Value_errBelongValue[0];
  157. break;
  158. }
  159. }
  160. }
  161. /* get err last fuzzy */
  162. if(module->Value_errDot > module->Value_errDotRange[6])
  163. {
  164. module->Value_errDotBelongStage[0] = PB;
  165. module->Value_errDotBelongStage[1] = PB;
  166. module->Value_errDotBelongValue[0] = 1;
  167. module->Value_errDotBelongValue[1] = 0;
  168. }
  169. else if(module->Value_errDot < module->Value_errDotRange[0])
  170. {
  171. module->Value_errDotBelongStage[1] = NB;
  172. module->Value_errDotBelongStage[0] = NB;
  173. module->Value_errDotBelongValue[0] = 0;
  174. module->Value_errDotBelongValue[1] = 1;
  175. }
  176. else
  177. {
  178. for(rt_uint8_t i = 0;i<5;i++)
  179. {
  180. if(module->Value_errDot == module->Value_errDotRange[i])
  181. {
  182. module->Value_errDotBelongStage[1] = i;
  183. module->Value_errDotBelongStage[0] = i;
  184. module->Value_errDotBelongValue[0] = 0;
  185. module->Value_errDotBelongValue[1] = 1;
  186. }
  187. else if((module->Value_errDot>module->Value_errDotRange[i])&&(module->Value_errDot<module->Value_errDotRange[i+1]))
  188. {
  189. float step = fabs(module->Value_errDotRange[1]-module->Value_errDotRange[0]);
  190. module->Value_errDotBelongStage[0] = i;
  191. module->Value_errDotBelongStage[1] = i+1;
  192. module->Value_errDotBelongValue[0] =
  193. fabs((module->Value_err-module->Value_errRange[i])/step);
  194. module->Value_errDotBelongValue[1] = 1-module->Value_errDotBelongValue[0];
  195. break;
  196. }
  197. }
  198. }
  199. }
  200. static void defuzzify(MATH_FUZZYPID *module)
  201. {
  202. module->Value_deltaKp =
  203. module->Value_deltaKpRange[KPTAB[module->Value_errBelongStage[0]][module->Value_errDotBelongStage[0]]]
  204. *module->Value_errBelongValue[0]*module->Value_errDotBelongValue[0]+
  205. module->Value_deltaKpRange[KPTAB[module->Value_errBelongStage[0]][module->Value_errDotBelongStage[1]]]
  206. *module->Value_errBelongValue[0]*module->Value_errDotBelongValue[1]+
  207. module->Value_deltaKpRange[KPTAB[module->Value_errBelongStage[1]][module->Value_errDotBelongStage[0]]]
  208. *module->Value_errBelongValue[1]*module->Value_errDotBelongValue[0]+
  209. module->Value_deltaKpRange[KPTAB[module->Value_errBelongStage[1]][module->Value_errDotBelongStage[1]]]
  210. *module->Value_errBelongValue[1]*module->Value_errDotBelongValue[1];
  211. module->Value_deltaKi =
  212. module->Value_deltaKiRange[KITAB[module->Value_errBelongStage[0]][module->Value_errDotBelongStage[0]]]
  213. *module->Value_errBelongValue[0]*module->Value_errDotBelongValue[0]+
  214. module->Value_deltaKiRange[KITAB[module->Value_errBelongStage[0]][module->Value_errDotBelongStage[1]]]
  215. *module->Value_errBelongValue[0]*module->Value_errDotBelongValue[1]+
  216. module->Value_deltaKiRange[KITAB[module->Value_errBelongStage[1]][module->Value_errDotBelongStage[0]]]
  217. *module->Value_errBelongValue[1]*module->Value_errDotBelongValue[0]+
  218. module->Value_deltaKiRange[KITAB[module->Value_errBelongStage[1]][module->Value_errDotBelongStage[1]]]
  219. *module->Value_errBelongValue[1]*module->Value_errDotBelongValue[1];
  220. module->Value_deltaKd =
  221. module->Value_deltaKdRange[KDTAB[module->Value_errBelongStage[0]][module->Value_errDotBelongStage[0]]]
  222. *module->Value_errBelongValue[0]*module->Value_errDotBelongValue[0]+
  223. module->Value_deltaKdRange[KDTAB[module->Value_errBelongStage[0]][module->Value_errDotBelongStage[1]]]
  224. *module->Value_errBelongValue[0]*module->Value_errDotBelongValue[1]+
  225. module->Value_deltaKdRange[KDTAB[module->Value_errBelongStage[1]][module->Value_errDotBelongStage[0]]]
  226. *module->Value_errBelongValue[1]*module->Value_errDotBelongValue[0]+
  227. module->Value_deltaKdRange[KDTAB[module->Value_errBelongStage[1]][module->Value_errDotBelongStage[1]]]
  228. *module->Value_errBelongValue[1]*module->Value_errDotBelongValue[1];
  229. }

Module_DjiC610C620Group.h

  1. 修改电机的PID成员为模糊PID
  2. struct _MODULE_DjiC610620
  3. {
  4. /* Property */
  5. rt_uint8_t Enable;
  6. rt_uint8_t Mode;
  7. MATH_FUZZYPID PID_Speed;
  8. MATH_FUZZYPID PID_Angle;

Module_DjiC610C620Group.c

  1. 在电机群的电机成员初始化时,把原来对普通PID的初始化修改为对模糊PID的初始化
  2. /* Module PID controler Init */
  3. if(Dev_DjiC610620->Mode == DjiC610620MODE_SPEED)
  4. {
  5. Module_FuzzyPID_Config(&(Dev_DjiC610620->PID_Speed));
  6. }
  7. else if(Dev_DjiC610620->Mode == DjiC610620MODE_ANGLE)
  8. {
  9. Module_FuzzyPID_Config(&(Dev_DjiC610620->PID_Speed));
  10. Module_FuzzyPID_Config(&(Dev_DjiC610620->PID_Angle));
  11. }

因为PID参数更新的方法没有改变绑定关系,因此无需变动

main.c

和原来相比在main中电机群模块的初始化多了对模糊PID参数的初始化,主要是模糊范围

  1. MODULE_DjiC610620GROUP dev_DjiC610620group =
  2. {
  3. .Property_CanDevName = "can1",
  4. .Value_module_DjiC610620[DjiC610620ID_1] =
  5. {
  6. .Enable = 1,
  7. .Mode = DjiC610620MODE_SPEED,
  8. .PID_Speed =
  9. {
  10. .Property_Kp = 6, .Property_Ki = 2, .Property_Kd = 0,
  11. .Value_errRange = {-6750, -4500, -2250, 0, 2250, 4500, 6750},
  12. .Value_errDotRange = {-13500, -9000, -4500, 0, 4500, 9000, 13500},
  13. .Value_deltaKpRange = {-0.015, -0.01, -0.005, 0, 0.005, 0.01, 0.015},
  14. .Value_deltaKiRange = {-0.003, -0.002, -0.001, 0, 0.001, 0.002, 0.003},
  15. .Value_deltaKdRange = {-0.015, -0.01, -0.005, 0, 0.005, 0.01, 0.015},
  16. .Property_dt = 0.005,
  17. .Property_integralMax = 500, .Property_AimMax = 9000, .Property_OutputMax =16300
  18. }
  19. },
  20. };

实际效果

  • 电机的PID控制器中Kp、Ki可以实现闭环调整,在速度环运行过程中自动寻找Kp、Ki的最佳值
  • 表现形式是电机在加速过程中Kp逐渐上升,直至电机抖动,然后Kp自动回落,电机平稳,往复进行
  • 据此猜测模糊PID的适用场合
    • 模糊PID和传统PID的优点在于无需给定明确的参数值,只需给定一个增量的调整范围
    • 可以实现参数的自适应,此时的PID更像是一个学习过程
    • 因为是学习过程,因此存在学习时间,可能不适合应用在实时性要求严格的场合
    • 可以用来寻找系统的最佳的参数,从而成为一个工具