AC_PID_2D.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /// @file AC_PID_2D.cpp
  2. /// @brief Generic PID algorithm
  3. #include <AP_Math/AP_Math.h>
  4. #include "AC_PID_2D.h"
  5. #define AC_PID_2D_FILT_HZ_DEFAULT 20.0f // default input filter frequency
  6. #define AC_PID_2D_FILT_HZ_MIN 0.01f // minimum input filter frequency
  7. #define AC_PID_2D_FILT_D_HZ_DEFAULT 10.0f // default input filter frequency
  8. #define AC_PID_2D_FILT_D_HZ_MIN 0.005f // minimum input filter frequency
  9. const AP_Param::GroupInfo AC_PID_2D::var_info[] = {
  10. // @Param: P
  11. // @DisplayName: PID Proportional Gain
  12. // @Description: P Gain which produces an output value that is proportional to the current error value
  13. AP_GROUPINFO("P", 0, AC_PID_2D, _kp, 0),
  14. // @Param: I
  15. // @DisplayName: PID Integral Gain
  16. // @Description: I Gain which produces an output that is proportional to both the magnitude and the duration of the error
  17. AP_GROUPINFO("I", 1, AC_PID_2D, _ki, 0),
  18. // @Param: IMAX
  19. // @DisplayName: PID Integral Maximum
  20. // @Description: The maximum/minimum value that the I term can output
  21. AP_GROUPINFO("IMAX", 2, AC_PID_2D, _imax, 0),
  22. // @Param: FILT
  23. // @DisplayName: PID Input filter frequency in Hz
  24. // @Description: Input filter frequency in Hz
  25. // @Units: Hz
  26. AP_GROUPINFO("FILT", 3, AC_PID_2D, _filt_hz, AC_PID_2D_FILT_HZ_DEFAULT),
  27. // @Param: D
  28. // @DisplayName: PID Derivative Gain
  29. // @Description: D Gain which produces an output that is proportional to the rate of change of the error
  30. AP_GROUPINFO("D", 4, AC_PID_2D, _kd, 0),
  31. // @Param: D_FILT
  32. // @DisplayName: D term filter frequency in Hz
  33. // @Description: D term filter frequency in Hz
  34. // @Units: Hz
  35. AP_GROUPINFO("D_FILT", 5, AC_PID_2D, _filt_d_hz, AC_PID_2D_FILT_D_HZ_DEFAULT),
  36. AP_GROUPEND
  37. };
  38. // Constructor
  39. AC_PID_2D::AC_PID_2D(float initial_p, float initial_i, float initial_d, float initial_imax, float initial_filt_hz, float initial_filt_d_hz, float dt) :
  40. _dt(dt)
  41. {
  42. // load parameter values from eeprom
  43. AP_Param::setup_object_defaults(this, var_info);
  44. _kp = initial_p;
  45. _ki = initial_i;
  46. _kd = initial_d;
  47. _imax = fabsf(initial_imax);
  48. filt_hz(initial_filt_hz);
  49. filt_d_hz(initial_filt_d_hz);
  50. // reset input filter to first value received and derivitive to zero
  51. reset_filter();
  52. }
  53. // set_dt - set time step in seconds
  54. void AC_PID_2D::set_dt(float dt)
  55. {
  56. // set dt and calculate the input filter alpha
  57. _dt = dt;
  58. calc_filt_alpha();
  59. calc_filt_alpha_d();
  60. }
  61. // filt_hz - set input filter hz
  62. void AC_PID_2D::filt_hz(float hz)
  63. {
  64. _filt_hz.set(fabsf(hz));
  65. // sanity check _filt_hz
  66. _filt_hz = MAX(_filt_hz, AC_PID_2D_FILT_HZ_MIN);
  67. // calculate the input filter alpha
  68. calc_filt_alpha();
  69. }
  70. // filt_d_hz - set input filter hz
  71. void AC_PID_2D::filt_d_hz(float hz)
  72. {
  73. _filt_d_hz.set(fabsf(hz));
  74. // sanity check _filt_hz
  75. _filt_d_hz = MAX(_filt_d_hz, AC_PID_2D_FILT_D_HZ_MIN);
  76. // calculate the input filter alpha
  77. calc_filt_alpha_d();
  78. }
  79. // set_input - set input to PID controller
  80. // input is filtered before the PID controllers are run
  81. // this should be called before any other calls to get_p, get_i or get_d
  82. void AC_PID_2D::set_input(const Vector2f &input)
  83. {
  84. // don't process inf or NaN
  85. if (!isfinite(input.x) || !isfinite(input.y)) {
  86. return;
  87. }
  88. // reset input filter to value received
  89. if (_flags._reset_filter) {
  90. _flags._reset_filter = false;
  91. _input = input;
  92. }
  93. // update filter and calculate derivative
  94. const Vector2f input_delta = (input - _input) * _filt_alpha;
  95. _input += input_delta;
  96. set_input_filter_d(input_delta);
  97. }
  98. // set_input_filter_d - set input to PID controller
  99. // only input to the D portion of the controller is filtered
  100. // this should be called before any other calls to get_p, get_i or get_d
  101. void AC_PID_2D::set_input_filter_d(const Vector2f& input_delta)
  102. {
  103. // don't process inf or NaN
  104. if (!isfinite(input_delta.x) && !isfinite(input_delta.y)) {
  105. return;
  106. }
  107. // update filter and calculate derivative
  108. if (is_positive(_dt)) {
  109. const Vector2f derivative = input_delta / _dt;
  110. const Vector2f delta_derivative = (derivative - _derivative) * _filt_alpha_d;
  111. _derivative += delta_derivative;
  112. }
  113. }
  114. Vector2f AC_PID_2D::get_p() const
  115. {
  116. return (_input * _kp);
  117. }
  118. Vector2f AC_PID_2D::get_i()
  119. {
  120. if (!is_zero(_ki) && !is_zero(_dt)) {
  121. _integrator += (_input * _ki) * _dt;
  122. const float integrator_length = _integrator.length();
  123. if ((integrator_length > _imax) && is_positive(integrator_length)) {
  124. _integrator *= (_imax / integrator_length);
  125. }
  126. return _integrator;
  127. }
  128. return Vector2f();
  129. }
  130. // get_i_shrink - get_i but do not allow integrator to grow in length (it may shrink)
  131. Vector2f AC_PID_2D::get_i_shrink()
  132. {
  133. if (!is_zero(_ki) && !is_zero(_dt)) {
  134. const float integrator_length_orig = MIN(_integrator.length(), _imax);
  135. _integrator += (_input * _ki) * _dt;
  136. const float integrator_length_new = _integrator.length();
  137. if ((integrator_length_new > integrator_length_orig) && is_positive(integrator_length_new)) {
  138. _integrator *= (integrator_length_orig / integrator_length_new);
  139. }
  140. return _integrator;
  141. }
  142. return Vector2f();
  143. }
  144. Vector2f AC_PID_2D::get_d()
  145. {
  146. // derivative component
  147. return Vector2f(_kd * _derivative.x, _kd * _derivative.y);
  148. }
  149. Vector2f AC_PID_2D::get_pid()
  150. {
  151. return get_p() + get_i() + get_d();
  152. }
  153. void AC_PID_2D::reset_I()
  154. {
  155. _integrator.zero();
  156. }
  157. void AC_PID_2D::reset_filter()
  158. {
  159. _flags._reset_filter = true;
  160. _derivative.x = 0.0f;
  161. _derivative.y = 0.0f;
  162. _integrator.zero();
  163. }
  164. void AC_PID_2D::load_gains()
  165. {
  166. _kp.load();
  167. _ki.load();
  168. _kd.load();
  169. _imax.load();
  170. _imax = fabsf(_imax);
  171. _filt_hz.load();
  172. _filt_d_hz.load();
  173. // calculate the input filter alpha
  174. calc_filt_alpha();
  175. calc_filt_alpha_d();
  176. }
  177. // save_gains - save gains to eeprom
  178. void AC_PID_2D::save_gains()
  179. {
  180. _kp.save();
  181. _ki.save();
  182. _kd.save();
  183. _imax.save();
  184. _filt_hz.save();
  185. _filt_d_hz.save();
  186. }
  187. // calc_filt_alpha - recalculate the input filter alpha
  188. void AC_PID_2D::calc_filt_alpha()
  189. {
  190. if (is_zero(_filt_hz)) {
  191. _filt_alpha = 1.0f;
  192. return;
  193. }
  194. // calculate alpha
  195. const float rc = 1/(M_2PI*_filt_hz);
  196. _filt_alpha = _dt / (_dt + rc);
  197. }
  198. // calc_filt_alpha - recalculate the input filter alpha
  199. void AC_PID_2D::calc_filt_alpha_d()
  200. {
  201. if (is_zero(_filt_d_hz)) {
  202. _filt_alpha_d = 1.0f;
  203. return;
  204. }
  205. // calculate alpha
  206. const float rc = 1/(M_2PI*_filt_d_hz);
  207. _filt_alpha_d = _dt / (_dt + rc);
  208. }