AC_PI_2D.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /// @file AC_PI_2D.cpp
  2. /// @brief Generic PID algorithm
  3. #include <AP_Math/AP_Math.h>
  4. #include "AC_PI_2D.h"
  5. const AP_Param::GroupInfo AC_PI_2D::var_info[] = {
  6. // @Param: P
  7. // @DisplayName: PID Proportional Gain
  8. // @Description: P Gain which produces an output value that is proportional to the current error value
  9. AP_GROUPINFO("P", 0, AC_PI_2D, _kp, 0),
  10. // @Param: I
  11. // @DisplayName: PID Integral Gain
  12. // @Description: I Gain which produces an output that is proportional to both the magnitude and the duration of the error
  13. AP_GROUPINFO("I", 1, AC_PI_2D, _ki, 0),
  14. // @Param: IMAX
  15. // @DisplayName: PID Integral Maximum
  16. // @Description: The maximum/minimum value that the I term can output
  17. AP_GROUPINFO("IMAX", 2, AC_PI_2D, _imax, 0),
  18. // @Param: FILT_HZ
  19. // @DisplayName: PID Input filter frequency in Hz
  20. // @Description: Input filter frequency in Hz
  21. // @Units: Hz
  22. AP_GROUPINFO("FILT_HZ", 3, AC_PI_2D, _filt_hz, AC_PI_2D_FILT_HZ_DEFAULT),
  23. AP_GROUPEND
  24. };
  25. // Constructor
  26. AC_PI_2D::AC_PI_2D(float initial_p, float initial_i, float initial_imax, float initial_filt_hz, float dt) :
  27. _dt(dt)
  28. {
  29. // load parameter values from eeprom
  30. AP_Param::setup_object_defaults(this, var_info);
  31. _kp = initial_p;
  32. _ki = initial_i;
  33. _imax = fabsf(initial_imax);
  34. filt_hz(initial_filt_hz);
  35. // reset input filter to first value received
  36. _flags._reset_filter = true;
  37. }
  38. // set_dt - set time step in seconds
  39. void AC_PI_2D::set_dt(float dt)
  40. {
  41. // set dt and calculate the input filter alpha
  42. _dt = dt;
  43. calc_filt_alpha();
  44. }
  45. // filt_hz - set input filter hz
  46. void AC_PI_2D::filt_hz(float hz)
  47. {
  48. _filt_hz.set(fabsf(hz));
  49. // sanity check _filt_hz
  50. _filt_hz = MAX(_filt_hz, AC_PI_2D_FILT_HZ_MIN);
  51. // calculate the input filter alpha
  52. calc_filt_alpha();
  53. }
  54. // set_input - set input to PID controller
  55. // input is filtered before the PID controllers are run
  56. // this should be called before any other calls to get_p, get_i or get_d
  57. void AC_PI_2D::set_input(const Vector2f &input)
  58. {
  59. // don't process inf or NaN
  60. if (!isfinite(input.x) || !isfinite(input.y)) {
  61. return;
  62. }
  63. // reset input filter to value received
  64. if (_flags._reset_filter) {
  65. _flags._reset_filter = false;
  66. _input = input;
  67. }
  68. // update filter and calculate derivative
  69. Vector2f input_filt_change = (input - _input) * _filt_alpha;
  70. _input = _input + input_filt_change;
  71. }
  72. Vector2f AC_PI_2D::get_p() const
  73. {
  74. return (_input * _kp);
  75. }
  76. Vector2f AC_PI_2D::get_i()
  77. {
  78. if (!is_zero(_ki) && !is_zero(_dt)) {
  79. _integrator += (_input * _ki) * _dt;
  80. const float integrator_length = _integrator.length();
  81. if ((integrator_length > _imax) && (is_positive(integrator_length))) {
  82. _integrator *= (_imax / integrator_length);
  83. }
  84. return _integrator;
  85. }
  86. return Vector2f();
  87. }
  88. // get_i_shrink - get_i but do not allow integrator to grow in length (it may shrink)
  89. Vector2f AC_PI_2D::get_i_shrink()
  90. {
  91. if (!is_zero(_ki) && !is_zero(_dt)) {
  92. const float integrator_length_orig = MIN(_integrator.length(),_imax);
  93. _integrator += (_input * _ki) * _dt;
  94. const float integrator_length_new = _integrator.length();
  95. if ((integrator_length_new > integrator_length_orig) && is_positive(integrator_length_new)) {
  96. _integrator *= (integrator_length_orig / integrator_length_new);
  97. }
  98. return _integrator;
  99. }
  100. return Vector2f();
  101. }
  102. Vector2f AC_PI_2D::get_pi()
  103. {
  104. return get_p() + get_i();
  105. }
  106. void AC_PI_2D::reset_I()
  107. {
  108. _integrator.zero();
  109. }
  110. void AC_PI_2D::load_gains()
  111. {
  112. _kp.load();
  113. _ki.load();
  114. _imax.load();
  115. _imax = fabsf(_imax);
  116. _filt_hz.load();
  117. // calculate the input filter alpha
  118. calc_filt_alpha();
  119. }
  120. // save_gains - save gains to eeprom
  121. void AC_PI_2D::save_gains()
  122. {
  123. _kp.save();
  124. _ki.save();
  125. _imax.save();
  126. _filt_hz.save();
  127. }
  128. /// Overload the function call operator to permit easy initialisation
  129. void AC_PI_2D::operator() (float p, float i, float imaxval, float input_filt_hz, float dt)
  130. {
  131. _kp = p;
  132. _ki = i;
  133. _imax = fabsf(imaxval);
  134. _filt_hz = input_filt_hz;
  135. _dt = dt;
  136. // calculate the input filter alpha
  137. calc_filt_alpha();
  138. }
  139. // calc_filt_alpha - recalculate the input filter alpha
  140. void AC_PI_2D::calc_filt_alpha()
  141. {
  142. if (is_zero(_filt_hz)) {
  143. _filt_alpha = 1.0f;
  144. return;
  145. }
  146. // calculate alpha
  147. const float rc = 1/(M_2PI*_filt_hz);
  148. _filt_alpha = _dt / (_dt + rc);
  149. }