SRV_Channel.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. This program is free software: you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation, either version 3 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program. If not, see <http://www.gnu.org/licenses/>.
  12. */
  13. /*
  14. SRV_Channel.cpp - object to separate input and output channel
  15. ranges, trim and reversal
  16. */
  17. #include <AP_HAL/AP_HAL.h>
  18. #include <AP_Math/AP_Math.h>
  19. #include <AP_Vehicle/AP_Vehicle.h>
  20. #include <AP_Math/AP_Math.h>
  21. #include "SRV_Channel.h"
  22. extern const AP_HAL::HAL& hal;
  23. SRV_Channel::servo_mask_t SRV_Channel::have_pwm_mask;
  24. const AP_Param::GroupInfo SRV_Channel::var_info[] = {
  25. // @Param: MIN
  26. // @DisplayName: Minimum PWM
  27. // @Description: minimum PWM pulse width in microseconds. Typically 1000 is lower limit, 1500 is neutral and 2000 is upper limit.
  28. // @Units: PWM
  29. // @Range: 500 2200
  30. // @Increment: 1
  31. // @User: Standard
  32. AP_GROUPINFO("MIN", 1, SRV_Channel, servo_min, 1000),
  33. // @Param: MAX
  34. // @DisplayName: Maximum PWM
  35. // @Description: maximum PWM pulse width in microseconds. Typically 1000 is lower limit, 1500 is neutral and 2000 is upper limit.
  36. // @Units: PWM
  37. // @Range: 800 2200
  38. // @Increment: 1
  39. // @User: Standard
  40. AP_GROUPINFO("MAX", 2, SRV_Channel, servo_max, 2000),
  41. // @Param: TRIM
  42. // @DisplayName: Trim PWM
  43. // @Description: Trim PWM pulse width in microseconds. Typically 1000 is lower limit, 1500 is neutral and 2000 is upper limit.
  44. // @Units: PWM
  45. // @Range: 800 2200
  46. // @Increment: 1
  47. // @User: Standard
  48. AP_GROUPINFO("TRIM", 3, SRV_Channel, servo_trim, 1500),
  49. // @Param: REVERSED
  50. // @DisplayName: Servo reverse
  51. // @Description: Reverse servo operation. Set to 0 for normal operation. Set to 1 to reverse this output channel.
  52. // @Values: 0:Normal,1:Reversed
  53. // @User: Standard
  54. AP_GROUPINFO("REVERSED", 4, SRV_Channel, reversed, 0),
  55. // @Param: FUNCTION
  56. // @DisplayName: Servo output function
  57. // @Description: Function assigned to this servo. Seeing this to Disabled(0) will setup this output for control by auto missions or MAVLink servo set commands. any other value will enable the corresponding function
  58. // @Values: 0:Disabled,1:RCPassThru,2:Flap,3:Flap_auto,4:Aileron,6:mount_pan,7:mount_tilt,8:mount_roll,9:mount_open,10:camera_trigger,11:release,12:mount2_pan,13:mount2_tilt,14:mount2_roll,15:mount2_open,16:DifferentialSpoilerLeft1,17:DifferentialSpoilerRight1,19:Elevator,21:Rudder,24:FlaperonLeft,25:FlaperonRight,26:GroundSteering,27:Parachute,28:EPM,29:LandingGear,30:EngineRunEnable,31:HeliRSC,32:HeliTailRSC,33:Motor1,34:Motor2,35:Motor3,36:Motor4,37:Motor5,38:Motor6,39:Motor7,40:Motor8,41:MotorTilt,51:RCIN1,52:RCIN2,53:RCIN3,54:RCIN4,55:RCIN5,56:RCIN6,57:RCIN7,58:RCIN8,59:RCIN9,60:RCIN10,61:RCIN11,62:RCIN12,63:RCIN13,64:RCIN14,65:RCIN15,66:RCIN16,67:Ignition,68:Choke,69:Starter,70:Throttle,71:TrackerYaw,72:TrackerPitch,73:ThrottleLeft,74:ThrottleRight,75:tiltMotorLeft,76:tiltMotorRight,77:ElevonLeft,78:ElevonRight,79:VTailLeft,80:VTailRight,81:BoostThrottle,82:Motor9,83:Motor10,84:Motor11,85:Motor12,86:DifferentialSpoilerLeft2,87:DifferentialSpoilerRight2,88:Winch,89:Main Sail,90:Camera ISO,91:Camera Focus,92:Camera Shutter Speed,94:Script 1,95:Script 2,96:Script 3,97:Script 4,98:Script 5,99:Script 6,100:Script 7,101:Script 8,102:Script 9,103:Script 10,104:Script 11,105:Script 12,106:Script 13,107:Script 14,108:Script 15,109:Script 16
  59. // @User: Standard
  60. AP_GROUPINFO("FUNCTION", 5, SRV_Channel, function, 0),
  61. AP_GROUPEND
  62. };
  63. SRV_Channel::SRV_Channel(void)
  64. {
  65. AP_Param::setup_object_defaults(this, var_info);
  66. // start with all pwm at zero
  67. have_pwm_mask = ~uint16_t(0);
  68. }
  69. // convert a 0..range_max to a pwm
  70. uint16_t SRV_Channel::pwm_from_range(int16_t scaled_value) const
  71. {
  72. if (servo_max <= servo_min || high_out == 0) {
  73. return servo_min;
  74. }
  75. scaled_value = constrain_int16(scaled_value, 0, high_out);
  76. if (reversed) {
  77. scaled_value = high_out - scaled_value;
  78. }
  79. return servo_min + ((int32_t)scaled_value * (int32_t)(servo_max - servo_min)) / (int32_t)high_out;
  80. }
  81. // convert a -angle_max..angle_max to a pwm
  82. uint16_t SRV_Channel::pwm_from_angle(int16_t scaled_value) const
  83. {
  84. if (reversed) {
  85. scaled_value = -scaled_value;
  86. }
  87. scaled_value = constrain_int16(scaled_value, -high_out, high_out);
  88. if (scaled_value > 0) {
  89. return servo_trim + ((int32_t)scaled_value * (int32_t)(servo_max - servo_trim)) / (int32_t)high_out;
  90. } else {
  91. return servo_trim - (-(int32_t)scaled_value * (int32_t)(servo_trim - servo_min)) / (int32_t)high_out;
  92. }
  93. }
  94. void SRV_Channel::calc_pwm(int16_t output_scaled)
  95. {
  96. if (have_pwm_mask & (1U<<ch_num)) {
  97. return;
  98. }
  99. // check for E - stop
  100. if (SRV_Channel::should_e_stop(get_function()) && SRV_Channels::emergency_stop) {
  101. output_scaled = 0;
  102. }
  103. uint16_t pwm;
  104. if (type_angle) {
  105. pwm = pwm_from_angle(output_scaled);
  106. } else {
  107. pwm = pwm_from_range(output_scaled);
  108. }
  109. set_output_pwm(pwm);
  110. }
  111. void SRV_Channel::set_output_pwm(uint16_t pwm)
  112. {
  113. output_pwm = pwm;
  114. have_pwm_mask |= (1U<<ch_num);
  115. }
  116. // set angular range of scaled output
  117. void SRV_Channel::set_angle(int16_t angle)
  118. {
  119. type_angle = true;
  120. high_out = angle;
  121. type_setup = true;
  122. }
  123. // set range of scaled output
  124. void SRV_Channel::set_range(uint16_t high)
  125. {
  126. type_angle = false;
  127. high_out = high;
  128. type_setup = true;
  129. }
  130. /*
  131. get normalised output from -1 to 1, assuming 0 at mid point of servo_min/servo_max
  132. */
  133. float SRV_Channel::get_output_norm(void)
  134. {
  135. uint16_t mid = (servo_max + servo_min) / 2;
  136. float ret;
  137. if (mid <= servo_min) {
  138. return 0;
  139. }
  140. if (output_pwm < mid) {
  141. ret = (float)(output_pwm - mid) / (float)(mid - servo_min);
  142. } else if (output_pwm > mid) {
  143. ret = (float)(output_pwm - mid) / (float)(servo_max - mid);
  144. } else {
  145. ret = 0;
  146. }
  147. if (get_reversed()) {
  148. ret = -ret;
  149. }
  150. return ret;
  151. }
  152. uint16_t SRV_Channel::get_limit_pwm(LimitValue limit) const
  153. {
  154. switch (limit) {
  155. case SRV_CHANNEL_LIMIT_TRIM:
  156. return servo_trim;
  157. case SRV_CHANNEL_LIMIT_MIN:
  158. return reversed?servo_max:servo_min;
  159. case SRV_CHANNEL_LIMIT_MAX:
  160. return reversed?servo_min:servo_max;
  161. case SRV_CHANNEL_LIMIT_ZERO_PWM:
  162. default:
  163. return 0;
  164. }
  165. }
  166. // return true if function is for a multicopter motor
  167. bool SRV_Channel::is_motor(SRV_Channel::Aux_servo_function_t function)
  168. {
  169. return ((function >= SRV_Channel::k_motor1 && function <= SRV_Channel::k_motor8) ||
  170. (function >= SRV_Channel::k_motor9 && function <= SRV_Channel::k_motor12));
  171. }
  172. // return true if function is for anything that should be stopped in a e-stop situation, ie is dangerous
  173. bool SRV_Channel::should_e_stop(SRV_Channel::Aux_servo_function_t function)
  174. {
  175. return ((function >= SRV_Channel::k_heli_rsc && function <= SRV_Channel::k_motor8) ||
  176. function == SRV_Channel::k_starter || function == SRV_Channel::k_throttle ||
  177. function == SRV_Channel::k_throttleLeft || function == SRV_Channel::k_throttleRight ||
  178. (function >= SRV_Channel::k_boost_throttle && function <= SRV_Channel::k_motor12) ||
  179. function == k_engine_run_enable);
  180. }