omniWheel_controller.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. /* Functions and type-defs for PID control.
  2. Taken mostly from Mike Ferguson's ArbotiX code which lives at:
  3. http://vanadium-ros-pkg.googlecode.com/svn/trunk/arbotix/
  4. */
  5. /* PID setpoint info For a Motor */
  6. typedef struct {
  7. double TargetTicksPerFrame; // target speed in ticks per frame
  8. long Encoder; // encoder count
  9. long PrevEnc; // last encoder count
  10. /*
  11. Using previous input (PrevInput) instead of PrevError to avoid derivative kick,
  12. see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-derivative-kick/
  13. */
  14. int PrevInput; // last input
  15. /*
  16. Using integrated term (ITerm) instead of integrated error (Ierror),
  17. to allow tuning changes,
  18. see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
  19. */
  20. int ITerm; //integrated term
  21. long output; //last motor setting
  22. }
  23. SetPointInfo;
  24. SetPointInfo AWheelPID, BWheelPID, CWheelPID;
  25. /*default PID Parameters */
  26. int AWheel_Kp = 11;
  27. int AWheel_Kd = 15;
  28. int AWheel_Ki = 0;
  29. int AWheel_Ko = 50;
  30. int BWheel_Kp = 11;
  31. int BWheel_Kd = 15;
  32. int BWheel_Ki = 0;
  33. int BWheel_Ko = 50;
  34. int CWheel_Kp = 11;
  35. int CWheel_Kd = 16;
  36. int CWheel_Ki = 0;
  37. int CWheel_Ko = 50;
  38. unsigned char moving = 0; // is the base in motion?
  39. /*
  40. Initialize PID variables to zero to prevent startup spikes
  41. when turning PID on to start moving
  42. In particular, assign both Encoder and PrevEnc the current encoder value
  43. See http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-initialization/
  44. Note that the assumption here is that PID is only turned on
  45. when going from stop to moving, that's why we can init everything on zero.
  46. */
  47. void resetPID()
  48. {
  49. AWheelPID.TargetTicksPerFrame = 0.0;
  50. AWheelPID.Encoder = readEncoder(A_WHEEL);
  51. AWheelPID.PrevEnc = AWheelPID.Encoder;
  52. AWheelPID.output = 0;
  53. AWheelPID.PrevInput = 0;
  54. AWheelPID.ITerm = 0;
  55. BWheelPID.TargetTicksPerFrame = 0.0;
  56. BWheelPID.Encoder = readEncoder(B_WHEEL);
  57. BWheelPID.PrevEnc = BWheelPID.Encoder;
  58. BWheelPID.output = 0;
  59. BWheelPID.PrevInput = 0;
  60. BWheelPID.ITerm = 0;
  61. CWheelPID.TargetTicksPerFrame = 0.0;
  62. CWheelPID.Encoder = readEncoder(C_WHEEL);
  63. CWheelPID.PrevEnc = CWheelPID.Encoder;
  64. CWheelPID.output = 0;
  65. CWheelPID.PrevInput = 0;
  66. CWheelPID.ITerm = 0;
  67. }
  68. /* PID routine to compute the next A motor commands */
  69. void doAWheelPID(SetPointInfo *p)
  70. {
  71. long Perror = 0;
  72. long output = 0;
  73. int input = 0;
  74. p->Encoder = readEncoder(A_WHEEL);
  75. input = p->Encoder - p->PrevEnc;
  76. Perror = p->TargetTicksPerFrame - input;
  77. /*
  78. Avoid derivative kick and allow tuning changes,
  79. see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-derivative-kick/
  80. see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
  81. */
  82. output = (AWheel_Kp * Perror - AWheel_Kd * (input - p->PrevInput) + p->ITerm) / AWheel_Ko;
  83. p->PrevEnc = p->Encoder; //save current encoder value to preEncoder
  84. output += p->output;
  85. // Accumulate Integral error *or* Limit output.
  86. // Stop accumulating when output saturates
  87. if (output >= MAX_PWM)
  88. {
  89. output = MAX_PWM;
  90. }
  91. else if (output <= -MAX_PWM)
  92. {
  93. output = -MAX_PWM;
  94. }
  95. else
  96. {
  97. /*
  98. allow turning changes, see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
  99. */
  100. p->ITerm += AWheel_Ki * Perror;
  101. }
  102. p->output = output; //save current pid output for next pid
  103. p->PrevInput = input;
  104. }
  105. /* PID routine to compute the next motor commands */
  106. void doBWheelPID(SetPointInfo * p)
  107. {
  108. long Perror = 0;
  109. long output = 0;
  110. int input = 0;
  111. p->Encoder = readEncoder(B_WHEEL);
  112. input = p->Encoder - p->PrevEnc;
  113. Perror = p->TargetTicksPerFrame - input;
  114. /*
  115. Avoid derivative kick and allow tuning changes,
  116. see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-derivative-kick/
  117. see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
  118. */
  119. output = (BWheel_Kp * Perror - BWheel_Kd * (input - p->PrevInput) + p->ITerm) / BWheel_Ko;
  120. p->PrevEnc = p->Encoder;
  121. output += p->output;
  122. // Accumulate Integral error *or* Limit output.
  123. // Stop accumulating when output saturates
  124. if (output >= MAX_PWM)
  125. {
  126. output = MAX_PWM;
  127. }
  128. else if (output <= -MAX_PWM)
  129. {
  130. output = -MAX_PWM;
  131. }
  132. else
  133. {
  134. /*
  135. allow turning changes, see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
  136. */
  137. p->ITerm += BWheel_Ki * Perror;
  138. }
  139. p->output = output;
  140. p->PrevInput = input;
  141. }
  142. /* PID routine to compute the next motor commands */
  143. void doCWheelPID(SetPointInfo * p)
  144. {
  145. long Perror = 0;
  146. long output = 0;
  147. int input = 0;
  148. p->Encoder = readEncoder(C_WHEEL);
  149. input = p->Encoder - p->PrevEnc;
  150. Perror = p->TargetTicksPerFrame - input;
  151. /*
  152. Avoid derivative kick and allow tuning changes,
  153. see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-derivative-kick/
  154. see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
  155. */
  156. output = (CWheel_Kp * Perror - CWheel_Kd * (input - p->PrevInput) + p->ITerm) / CWheel_Ko;
  157. p->PrevEnc = p->Encoder;
  158. output += p->output;
  159. // Accumulate Integral error *or* Limit output.
  160. // Stop accumulating when output saturates
  161. if (output >= MAX_PWM)
  162. {
  163. output = MAX_PWM;
  164. }
  165. else if (output <= -MAX_PWM)
  166. {
  167. output = -MAX_PWM;
  168. }
  169. else
  170. {
  171. /*
  172. allow turning changes, see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
  173. */
  174. p->ITerm += CWheel_Ki * Perror;
  175. }
  176. p->output = output;
  177. p->PrevInput = input;
  178. }
  179. /* Read the encoder values and call the PID routine */
  180. void updatePID()
  181. {
  182. if (!moving) /* If we're not moving, resetPID() there is nothing more to do */
  183. {
  184. /*
  185. Reset PIDs once, to prevent startup spikes,
  186. see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-initialization/
  187. PrevInput is considered a good proxy to detect whether reset has already happened
  188. */
  189. if (AWheelPID.PrevInput != 0 || BWheelPID.PrevInput != 0 || CWheelPID.PrevInput != 0)
  190. {
  191. resetPID();
  192. }
  193. return;
  194. }
  195. /* Compute PID update for each motor */
  196. doAWheelPID(&AWheelPID);
  197. doBWheelPID(&BWheelPID);
  198. doCWheelPID(&CWheelPID);
  199. /* Set the motor speeds accordingly */
  200. setMotorSpeeds(AWheelPID.output, BWheelPID.output, CWheelPID.output);
  201. }
  202. long readPidIn(int wheel)
  203. {
  204. long pidin = 0;
  205. if (wheel == A_WHEEL)
  206. {
  207. pidin = AWheelPID.PrevInput;
  208. }
  209. else if (wheel == B_WHEEL)
  210. {
  211. pidin = BWheelPID.PrevInput;
  212. }
  213. else
  214. {
  215. pidin = CWheelPID.PrevInput;
  216. }
  217. return pidin;
  218. }
  219. long readPidOut(int wheel)
  220. {
  221. long pidout = 0;
  222. if (wheel == A_WHEEL)
  223. {
  224. pidout = AWheelPID.output;
  225. }
  226. else if (wheel == B_WHEEL)
  227. {
  228. pidout = BWheelPID.output;
  229. }
  230. else
  231. {
  232. pidout = CWheelPID.output;
  233. }
  234. return pidout;
  235. }