LCOV - code coverage report
Current view: top level - APM_Control - AR_AttitudeControl.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 204 235 86.8 %
Date: 2026-09-09 11:02:08 Functions: 20 23 87.0 %

          Line data    Source code
       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             : 
       7             :    This program is distributed in the hope that it will be useful,
       8             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
       9             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      10             :    GNU General Public License for more details.
      11             : 
      12             :    You should have received a copy of the GNU General Public License
      13             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      14             :  */
      15             : 
      16             : #include <AP_AHRS/AP_AHRS.h>
      17             : #include <AP_Math/AP_Math.h>
      18             : #include <AP_HAL/AP_HAL.h>
      19             : #include "AR_AttitudeControl.h"
      20             : #include <AP_GPS/AP_GPS.h>
      21             : 
      22             : // attitude control default definition
      23             : #define AR_ATTCONTROL_STEER_ANG_P       2.00f
      24             : #define AR_ATTCONTROL_STEER_RATE_FF     0.20f
      25             : #define AR_ATTCONTROL_STEER_RATE_P      0.20f
      26             : #define AR_ATTCONTROL_STEER_RATE_I      0.20f
      27             : #define AR_ATTCONTROL_STEER_RATE_IMAX   1.00f
      28             : #define AR_ATTCONTROL_STEER_RATE_D      0.00f
      29             : #define AR_ATTCONTROL_STEER_RATE_FILT   10.00f
      30             : #define AR_ATTCONTROL_STEER_RATE_MAX    120.0f
      31             : #define AR_ATTCONTROL_STEER_ACCEL_MAX   120.0f
      32             : #define AR_ATTCONTROL_STEER_DECEL_MAX   0.0f
      33             : #define AR_ATTCONTROL_THR_SPEED_P       0.20f
      34             : #define AR_ATTCONTROL_THR_SPEED_I       0.20f
      35             : #define AR_ATTCONTROL_THR_SPEED_IMAX    1.00f
      36             : #define AR_ATTCONTROL_THR_SPEED_D       0.00f
      37             : #define AR_ATTCONTROL_THR_SPEED_FILT    10.00f
      38             : #define AR_ATTCONTROL_PITCH_THR_P       1.80f
      39             : #define AR_ATTCONTROL_PITCH_THR_I       1.50f
      40             : #define AR_ATTCONTROL_PITCH_THR_D       0.03f
      41             : #define AR_ATTCONTROL_PITCH_THR_IMAX    1.0f
      42             : #define AR_ATTCONTROL_PITCH_THR_FILT    10.0f
      43             : #define AR_ATTCONTROL_BAL_PITCH_FF      0.4f
      44             : #define AR_ATTCONTROL_PITCH_LIM_TC      0.5f        // pitch limit default time constant
      45             : #define AR_ATTCONTROL_PITCH_RELAX_RATIO 0.5f        // pitch limit relaxed 2x slower than it is limited
      46             : #define AR_ATTCONTROL_PITCH_LIM_THR_THRESH  0.60    // pitch limiting starts if throttle exceeds 60%
      47             : #define AR_ATTCONTROL_DT                0.02f
      48             : #define AR_ATTCONTROL_TIMEOUT_MS        200
      49             : #define AR_ATTCONTROL_HEEL_SAIL_P       1.0f
      50             : #define AR_ATTCONTROL_HEEL_SAIL_I       0.1f
      51             : #define AR_ATTCONTROL_HEEL_SAIL_D       0.0f
      52             : #define AR_ATTCONTROL_HEEL_SAIL_IMAX    1.0f
      53             : #define AR_ATTCONTROL_HEEL_SAIL_FILT    10.0f
      54             : #define AR_ATTCONTROL_DT                0.02f
      55             : 
      56             : // throttle/speed control maximum acceleration/deceleration (in m/s) (_ACCEL_MAX parameter default)
      57             : #define AR_ATTCONTROL_THR_ACCEL_MAX     1.00f
      58             : 
      59             : // minimum speed in m/s
      60             : #define AR_ATTCONTROL_STEER_SPEED_MIN   1.0f
      61             : 
      62             : // speed (in m/s) at or below which vehicle is considered stopped (_STOP_SPEED parameter default)
      63             : #define AR_ATTCONTROL_STOP_SPEED_DEFAULT    0.1f
      64             : 
      65             : extern const AP_HAL::HAL& hal;
      66             : 
      67             : AR_AttitudeControl *AR_AttitudeControl::_singleton;
      68             : 
      69             : const AP_Param::GroupInfo AR_AttitudeControl::var_info[] = {
      70             : 
      71             :     // @Param: _STR_RAT_P
      72             :     // @DisplayName: Steering control rate P gain
      73             :     // @Description: Steering control rate P gain.  Converts the turn rate error (in radians/sec) to a steering control output (in the range -1 to +1)
      74             :     // @Range: 0.000 2.000
      75             :     // @Increment: 0.001
      76             :     // @User: Standard
      77             : 
      78             :     // @Param: _STR_RAT_I
      79             :     // @DisplayName: Steering control I gain
      80             :     // @Description: Steering control I gain.  Corrects long term error between the desired turn rate (in rad/s) and actual
      81             :     // @Range: 0.000 2.000
      82             :     // @Increment: 0.001
      83             :     // @User: Standard
      84             : 
      85             :     // @Param: _STR_RAT_IMAX
      86             :     // @DisplayName: Steering control I gain maximum
      87             :     // @Description: Steering control I gain maximum.  Constrains the steering output (range -1 to +1) that the I term will generate
      88             :     // @Range: 0.000 1.000
      89             :     // @Increment: 0.01
      90             :     // @User: Standard
      91             : 
      92             :     // @Param: _STR_RAT_D
      93             :     // @DisplayName: Steering control D gain
      94             :     // @Description: Steering control D gain.  Compensates for short-term change in desired turn rate vs actual
      95             :     // @Range: 0.000 0.400
      96             :     // @Increment: 0.001
      97             :     // @User: Standard
      98             : 
      99             :     // @Param: _STR_RAT_FF
     100             :     // @DisplayName: Steering control feed forward
     101             :     // @Description: Steering control feed forward
     102             :     // @Range: 0.000 3.000
     103             :     // @Increment: 0.001
     104             :     // @User: Standard
     105             : 
     106             :     // @Param: _STR_RAT_FILT
     107             :     // @DisplayName: Steering control filter frequency
     108             :     // @Description: Steering control input filter.  Lower values reduce noise but add delay.
     109             :     // @Range: 0.000 100.000
     110             :     // @Increment: 0.1
     111             :     // @Units: Hz
     112             :     // @User: Standard
     113             : 
     114             :     // @Param: _STR_RAT_FLTT
     115             :     // @DisplayName: Steering control Target filter frequency in Hz
     116             :     // @Description: Target filter frequency in Hz
     117             :     // @Range: 0.000 100.000
     118             :     // @Increment: 0.1
     119             :     // @Units: Hz
     120             :     // @User: Standard
     121             : 
     122             :     // @Param: _STR_RAT_FLTE
     123             :     // @DisplayName: Steering control Error filter frequency in Hz
     124             :     // @Description: Error filter frequency in Hz
     125             :     // @Range: 0.000 100.000
     126             :     // @Increment: 0.1
     127             :     // @Units: Hz
     128             :     // @User: Standard
     129             : 
     130             :     // @Param: _STR_RAT_FLTD
     131             :     // @DisplayName: Steering control Derivative term filter frequency in Hz
     132             :     // @Description: Derivative filter frequency in Hz
     133             :     // @Range: 0.000 100.000
     134             :     // @Increment: 0.1
     135             :     // @Units: Hz
     136             :     // @User: Standard
     137             : 
     138             :     // @Param: _STR_RAT_SMAX
     139             :     // @DisplayName: Steering slew rate limit
     140             :     // @Description: Sets an upper limit on the slew rate produced by the combined P and D gains. If the amplitude of the control action produced by the rate feedback exceeds this value, then the D+P gain is reduced to respect the limit. This limits the amplitude of high frequency oscillations caused by an excessive gain. The limit should be set to no more than 25% of the actuators maximum slew rate to allow for load effects. Note: The gain will not be reduced to less than 10% of the nominal value. A value of zero will disable this feature.
     141             :     // @Range: 0 200
     142             :     // @Increment: 0.5
     143             :     // @User: Advanced
     144             : 
     145             :     // @Param: _STR_RAT_PDMX
     146             :     // @DisplayName: Steering control PD sum maximum
     147             :     // @Description: Steering control PD sum maximum.  The maximum/minimum value that the sum of the P and D term can output
     148             :     // @Range: 0.000 1.000
     149             :     // @Increment: 0.01
     150             : 
     151             :     // @Param: _STR_RAT_D_FF
     152             :     // @DisplayName: Steering control Derivative FeedForward Gain
     153             :     // @Description: FF D Gain which produces an output that is proportional to the rate of change of the target
     154             :     // @Range: 0 0.03
     155             :     // @Increment: 0.001
     156             :     // @User: Advanced
     157             : 
     158             :     // @Param: _STR_RAT_NTF
     159             :     // @DisplayName: Steering control Target notch filter index
     160             :     // @Description: Steering control Target notch filter index, zero disables
     161             :     // @Range: 0 8
     162             :     // @User: Advanced
     163             : 
     164             :     // @Param: _STR_RAT_NEF
     165             :     // @DisplayName: Steering control Error notch filter index
     166             :     // @Description: Steering control Error notch filter index, zero disables
     167             :     // @Range: 0 8
     168             :     // @User: Advanced
     169             : 
     170             :     AP_SUBGROUPINFO(_steer_rate_pid, "_STR_RAT_", 1, AR_AttitudeControl, AC_PID),
     171             : 
     172             :     // @Param: _SPEED_P
     173             :     // @DisplayName: Speed control P gain
     174             :     // @Description: Speed control P gain.  Converts the error between the desired speed (in m/s) and actual speed to a motor output (in the range -1 to +1)
     175             :     // @Range: 0.010 2.000
     176             :     // @Increment: 0.01
     177             :     // @User: Standard
     178             : 
     179             :     // @Param: _SPEED_I
     180             :     // @DisplayName: Speed control I gain
     181             :     // @Description: Speed control I gain.  Corrects long term error between the desired speed (in m/s) and actual speed
     182             :     // @Range: 0.000 2.000
     183             :     // @Increment: 0.01
     184             :     // @User: Standard
     185             : 
     186             :     // @Param: _SPEED_IMAX
     187             :     // @DisplayName: Speed control I gain maximum
     188             :     // @Description: Speed control I gain maximum.  Constrains the maximum motor output (range -1 to +1) that the I term will generate
     189             :     // @Range: 0.000 1.000
     190             :     // @Increment: 0.01
     191             :     // @User: Standard
     192             : 
     193             :     // @Param: _SPEED_D
     194             :     // @DisplayName: Speed control D gain
     195             :     // @Description: Speed control D gain.  Compensates for short-term change in desired speed vs actual
     196             :     // @Range: 0.000 0.400
     197             :     // @Increment: 0.001
     198             :     // @User: Standard
     199             : 
     200             :     // @Param: _SPEED_FF
     201             :     // @DisplayName: Speed control feed forward
     202             :     // @Description: Speed control feed forward
     203             :     // @Range: 0.000 0.500
     204             :     // @Increment: 0.001
     205             :     // @User: Standard
     206             : 
     207             :     // @Param: _SPEED_FILT
     208             :     // @DisplayName: Speed control filter frequency
     209             :     // @Description: Speed control input filter.  Lower values reduce noise but add delay.
     210             :     // @Range: 0.000 100.000
     211             :     // @Increment: 0.1
     212             :     // @Units: Hz
     213             :     // @User: Standard
     214             : 
     215             :     // @Param: _SPEED_FLTT
     216             :     // @DisplayName: Speed control Target filter frequency in Hz
     217             :     // @Description: Target filter frequency in Hz
     218             :     // @Range: 0.000 100.000
     219             :     // @Increment: 0.1
     220             :     // @Units: Hz
     221             :     // @User: Standard
     222             : 
     223             :     // @Param: _SPEED_FLTE
     224             :     // @DisplayName: Speed control Error filter frequency in Hz
     225             :     // @Description: Error filter frequency in Hz
     226             :     // @Range: 0.000 100.000
     227             :     // @Increment: 0.1
     228             :     // @Units: Hz
     229             :     // @User: Standard
     230             : 
     231             :     // @Param: _SPEED_FLTD
     232             :     // @DisplayName: Speed control Derivative term filter frequency in Hz
     233             :     // @Description: Derivative filter frequency in Hz
     234             :     // @Range: 0.000 100.000
     235             :     // @Increment: 0.1
     236             :     // @Units: Hz
     237             :     // @User: Standard
     238             : 
     239             :     // @Param: _SPEED_SMAX
     240             :     // @DisplayName: Speed control slew rate limit
     241             :     // @Description: Sets an upper limit on the slew rate produced by the combined P and D gains. If the amplitude of the control action produced by the rate feedback exceeds this value, then the D+P gain is reduced to respect the limit. This limits the amplitude of high frequency oscillations caused by an excessive gain. The limit should be set to no more than 25% of the actuators maximum slew rate to allow for load effects. Note: The gain will not be reduced to less than 10% of the nominal value. A value of zero will disable this feature.
     242             :     // @Range: 0 200
     243             :     // @Increment: 0.5
     244             :     // @User: Advanced
     245             : 
     246             :     // @Param: _SPEED_PDMX
     247             :     // @DisplayName: Speed control PD sum maximum
     248             :     // @Description: Speed control PD sum maximum.  The maximum/minimum value that the sum of the P and D term can output
     249             :     // @Range: 0.000 1.000
     250             :     // @Increment: 0.01
     251             : 
     252             :     // @Param: _SPEED_D_FF
     253             :     // @DisplayName: Speed control Derivative FeedForward Gain
     254             :     // @Description: FF D Gain which produces an output that is proportional to the rate of change of the target
     255             :     // @Range: 0 0.03
     256             :     // @Increment: 0.001
     257             :     // @User: Advanced
     258             : 
     259             :     // @Param: _SPEED_NTF
     260             :     // @DisplayName: Speed control Target notch filter index
     261             :     // @Description: Speed control Target notch filter index, zero disables
     262             :     // @Range: 0 8
     263             :     // @User: Advanced
     264             : 
     265             :     // @Param: _SPEED_NEF
     266             :     // @DisplayName: Speed control Error notch filter index
     267             :     // @Description: Speed control Error notch filter index, zero disables
     268             :     // @Range: 0 8
     269             :     // @User: Advanced
     270             : 
     271             :     AP_SUBGROUPINFO(_throttle_speed_pid, "_SPEED_", 2, AR_AttitudeControl, AC_PID),
     272             : 
     273             :     // @Param: _ACCEL_MAX
     274             :     // @DisplayName: Speed control acceleration (and deceleration) maximum in m/s/s
     275             :     // @Description: Speed control acceleration (and deceleration) maximum in m/s/s.  0 to disable acceleration limiting
     276             :     // @Range: 0.0 10.0
     277             :     // @Increment: 0.1
     278             :     // @Units: m/s/s
     279             :     // @User: Standard
     280             :     AP_GROUPINFO("_ACCEL_MAX", 3, AR_AttitudeControl, _throttle_accel_max, AR_ATTCONTROL_THR_ACCEL_MAX),
     281             : 
     282             :     // @Param: _BRAKE
     283             :     // @DisplayName: Speed control brake enable/disable
     284             :     // @Description: Speed control brake enable/disable. Allows sending a reversed output to the motors to slow the vehicle.
     285             :     // @Values: 0:Disable,1:Enable
     286             :     // @User: Standard
     287             :     AP_GROUPINFO("_BRAKE", 4, AR_AttitudeControl, _brake_enable, 1),
     288             : 
     289             :     // @Param: _STOP_SPEED
     290             :     // @DisplayName: Speed control stop speed
     291             :     // @Description: Speed control stop speed.  Motor outputs to zero once vehicle speed falls below this value
     292             :     // @Range: 0.00 0.50
     293             :     // @Increment: 0.01
     294             :     // @Units: m/s
     295             :     // @User: Standard
     296             :     AP_GROUPINFO("_STOP_SPEED", 5, AR_AttitudeControl, _stop_speed, AR_ATTCONTROL_STOP_SPEED_DEFAULT),
     297             : 
     298             :     // @Param: _STR_ANG_P
     299             :     // @DisplayName: Steering control angle P gain
     300             :     // @Description: Steering control angle P gain.  Converts the error between the desired heading/yaw (in radians) and actual heading/yaw to a desired turn rate (in rad/sec)
     301             :     // @Range: 1.000 10.000
     302             :     // @Increment: 0.1
     303             :     // @User: Standard
     304             :     AP_SUBGROUPINFO(_steer_angle_p, "_STR_ANG_", 6, AR_AttitudeControl, AC_P),
     305             : 
     306             :     // @Param: _STR_ACC_MAX
     307             :     // @DisplayName: Steering control angular acceleration maximum
     308             :     // @Description: Steering control angular acceleration maximum (in deg/s/s).  0 to disable acceleration limiting
     309             :     // @Range: 0 1000
     310             :     // @Increment: 0.1
     311             :     // @Units: deg/s/s
     312             :     // @User: Standard
     313             :     AP_GROUPINFO("_STR_ACC_MAX", 7, AR_AttitudeControl, _steer_accel_max, AR_ATTCONTROL_STEER_ACCEL_MAX),
     314             : 
     315             :     // @Param: _STR_RAT_MAX
     316             :     // @DisplayName: Steering control rotation rate maximum
     317             :     // @Description: Steering control rotation rate maximum in deg/s.  0 to remove rate limiting
     318             :     // @Range: 0 1000
     319             :     // @Increment: 0.1
     320             :     // @Units: deg/s
     321             :     // @User: Standard
     322             :     AP_GROUPINFO("_STR_RAT_MAX", 8, AR_AttitudeControl, _steer_rate_max, AR_ATTCONTROL_STEER_RATE_MAX),
     323             : 
     324             :     // @Param: _DECEL_MAX
     325             :     // @DisplayName: Speed control deceleration maximum in m/s/s
     326             :     // @Description: Speed control and deceleration maximum in m/s/s.  0 to use ATC_ACCEL_MAX for deceleration
     327             :     // @Range: 0.0 10.0
     328             :     // @Increment: 0.1
     329             :     // @Units: m/s/s
     330             :     // @User: Standard
     331             :     AP_GROUPINFO("_DECEL_MAX", 9, AR_AttitudeControl, _throttle_decel_max, 0.00f),
     332             : 
     333             :     // @Param: _BAL_P
     334             :     // @DisplayName: Pitch control P gain
     335             :     // @Description: Pitch control P gain for BalanceBots.  Converts the error between the desired pitch (in radians) and actual pitch to a motor output (in the range -1 to +1)
     336             :     // @Range: 0.000 2.000
     337             :     // @Increment: 0.01
     338             :     // @User: Standard
     339             : 
     340             :     // @Param: _BAL_I
     341             :     // @DisplayName: Pitch control I gain
     342             :     // @Description: Pitch control I gain for BalanceBots.  Corrects long term error between the desired pitch (in radians) and actual pitch
     343             :     // @Range: 0.000 2.000
     344             :     // @Increment: 0.01
     345             :     // @User: Standard
     346             : 
     347             :     // @Param: _BAL_IMAX
     348             :     // @DisplayName: Pitch control I gain maximum
     349             :     // @Description: Pitch control I gain maximum.  Constrains the maximum motor output (range -1 to +1) that the I term will generate
     350             :     // @Range: 0.000 1.000
     351             :     // @Increment: 0.01
     352             :     // @User: Standard
     353             : 
     354             :     // @Param: _BAL_D
     355             :     // @DisplayName: Pitch control D gain
     356             :     // @Description: Pitch control D gain.  Compensates for short-term change in desired pitch vs actual
     357             :     // @Range: 0.000 0.100
     358             :     // @Increment: 0.001
     359             :     // @User: Standard
     360             : 
     361             :     // @Param: _BAL_FF
     362             :     // @DisplayName: Pitch control feed forward
     363             :     // @Description: Pitch control feed forward
     364             :     // @Range: 0.000 0.500
     365             :     // @Increment: 0.001
     366             :     // @User: Standard
     367             : 
     368             :     // @Param: _BAL_FILT
     369             :     // @DisplayName: Pitch control filter frequency
     370             :     // @Description: Pitch control input filter.  Lower values reduce noise but add delay.
     371             :     // @Range: 0.000 100.000
     372             :     // @Increment: 0.1
     373             :     // @Units: Hz
     374             :     // @User: Standard
     375             : 
     376             :     // @Param: _BAL_FLTT
     377             :     // @DisplayName: Pitch control Target filter frequency in Hz
     378             :     // @Description: Pitch control Target filter frequency in Hz
     379             :     // @Range: 0.000 100.000
     380             :     // @Increment: 0.1
     381             :     // @Units: Hz
     382             :     // @User: Standard
     383             : 
     384             :     // @Param: _BAL_FLTE
     385             :     // @DisplayName: Pitch control Error filter frequency in Hz
     386             :     // @Description: Pitch control Error filter frequency in Hz
     387             :     // @Range: 0.000 100.000
     388             :     // @Increment: 0.1
     389             :     // @Units: Hz
     390             :     // @User: Standard
     391             : 
     392             :     // @Param: _BAL_FLTD
     393             :     // @DisplayName: Pitch control Derivative term filter frequency in Hz
     394             :     // @Description: Pitch control Derivative filter frequency in Hz
     395             :     // @Range: 0.000 100.000
     396             :     // @Increment: 0.1
     397             :     // @Units: Hz
     398             :     // @User: Standard
     399             : 
     400             :     // @Param: _BAL_SMAX
     401             :     // @DisplayName: Pitch control slew rate limit
     402             :     // @Description: Pitch control upper limit on the slew rate produced by the combined P and D gains. If the amplitude of the control action produced by the rate feedback exceeds this value, then the D+P gain is reduced to respect the limit. This limits the amplitude of high frequency oscillations caused by an excessive gain. The limit should be set to no more than 25% of the actuators maximum slew rate to allow for load effects. Note: The gain will not be reduced to less than 10% of the nominal value. A value of zero will disable this feature.
     403             :     // @Range: 0 200
     404             :     // @Increment: 0.5
     405             :     // @User: Advanced
     406             : 
     407             :     // @Param: _BAL_PDMX
     408             :     // @DisplayName: Pitch control PD sum maximum
     409             :     // @Description: Pitch control PD sum maximum.  The maximum/minimum value that the sum of the P and D term can output
     410             :     // @Range: 0.000 1.000
     411             :     // @Increment: 0.01
     412             : 
     413             :     // @Param: _BAL_D_FF
     414             :     // @DisplayName: Pitch control Derivative FeedForward Gain
     415             :     // @Description: FF D Gain which produces an output that is proportional to the rate of change of the target
     416             :     // @Range: 0 0.03
     417             :     // @Increment: 0.001
     418             :     // @User: Advanced
     419             : 
     420             :     // @Param: _BAL_NTF
     421             :     // @DisplayName: Pitch control Target notch filter index
     422             :     // @Description: Pitch control Target notch filter index, zero disables
     423             :     // @Range: 0 8
     424             :     // @User: Advanced
     425             : 
     426             :     // @Param: _BAL_NEF
     427             :     // @DisplayName: Pitch control Error notch filter index
     428             :     // @Description: Pitch control Error notch filter index, zero disables
     429             :     // @Range: 0 8
     430             :     // @User: Advanced
     431             : 
     432             :     AP_SUBGROUPINFO(_pitch_to_throttle_pid, "_BAL_", 10, AR_AttitudeControl, AC_PID),
     433             : 
     434             :     // @Param: _BAL_PIT_FF
     435             :     // @DisplayName: Pitch control feed forward from current pitch angle
     436             :     // @Description: Pitch control feed forward from current pitch angle
     437             :     // @Range: 0.0 1.0
     438             :     // @Increment: 0.01
     439             :     // @User: Standard
     440             :     AP_GROUPINFO("_BAL_PIT_FF", 11, AR_AttitudeControl, _pitch_to_throttle_ff, AR_ATTCONTROL_BAL_PITCH_FF),
     441             : 
     442             :     // @Param: _SAIL_P
     443             :     // @DisplayName: Sail Heel control P gain
     444             :     // @Description: Sail Heel control P gain for sailboats.  Converts the error between the desired heel angle (in radians) and actual heel to a main sail output (in the range -1 to +1)
     445             :     // @Range: 0.000 2.000
     446             :     // @Increment: 0.01
     447             :     // @User: Standard
     448             : 
     449             :     // @Param: _SAIL_I
     450             :     // @DisplayName: Sail Heel control I gain
     451             :     // @Description: Sail Heel control I gain for sailboats.  Corrects long term error between the desired heel angle (in radians) and actual
     452             :     // @Range: 0.000 2.000
     453             :     // @Increment: 0.01
     454             :     // @User: Standard
     455             : 
     456             :     // @Param: _SAIL_IMAX
     457             :     // @DisplayName: Sail Heel control I gain maximum
     458             :     // @Description: Sail Heel control I gain maximum.  Constrains the maximum I term contribution to the main sail output (range -1 to +1)
     459             :     // @Range: 0.000 1.000
     460             :     // @Increment: 0.01
     461             :     // @User: Standard
     462             : 
     463             :     // @Param: _SAIL_D
     464             :     // @DisplayName: Sail Heel control D gain
     465             :     // @Description: Sail Heel control D gain.  Compensates for short-term change in desired heel angle vs actual
     466             :     // @Range: 0.000 0.100
     467             :     // @Increment: 0.001
     468             :     // @User: Standard
     469             : 
     470             :     // @Param: _SAIL_FF
     471             :     // @DisplayName: Sail Heel control feed forward
     472             :     // @Description: Sail Heel control feed forward
     473             :     // @Range: 0.000 0.500
     474             :     // @Increment: 0.001
     475             :     // @User: Standard
     476             : 
     477             :     // @Param: _SAIL_FILT
     478             :     // @DisplayName: Sail Heel control filter frequency
     479             :     // @Description: Sail Heel control input filter.  Lower values reduce noise but add delay.
     480             :     // @Range: 0.000 100.000
     481             :     // @Increment: 0.1
     482             :     // @Units: Hz
     483             :     // @User: Standard
     484             : 
     485             :     // @Param: _SAIL_FLTT
     486             :     // @DisplayName: Sail Heel Target filter frequency in Hz
     487             :     // @Description: Target filter frequency in Hz
     488             :     // @Range: 0.000 100.000
     489             :     // @Increment: 0.1
     490             :     // @Units: Hz
     491             :     // @User: Standard
     492             : 
     493             :     // @Param: _SAIL_FLTE
     494             :     // @DisplayName: Sail Heel Error filter frequency in Hz
     495             :     // @Description: Error filter frequency in Hz
     496             :     // @Range: 0.000 100.000
     497             :     // @Increment: 0.1
     498             :     // @Units: Hz
     499             :     // @User: Standard
     500             : 
     501             :     // @Param: _SAIL_FLTD
     502             :     // @DisplayName: Sail Heel Derivative term filter frequency in Hz
     503             :     // @Description: Derivative filter frequency in Hz
     504             :     // @Range: 0.000 100.000
     505             :     // @Increment: 0.1
     506             :     // @Units: Hz
     507             :     // @User: Standard
     508             : 
     509             :     // @Param: _SAIL_SMAX
     510             :     // @DisplayName: Sail heel slew rate limit
     511             :     // @Description: Sets an upper limit on the slew rate produced by the combined P and D gains. If the amplitude of the control action produced by the rate feedback exceeds this value, then the D+P gain is reduced to respect the limit. This limits the amplitude of high frequency oscillations caused by an excessive gain. The limit should be set to no more than 25% of the actuators maximum slew rate to allow for load effects. Note: The gain will not be reduced to less than 10% of the nominal value. A value of zero will disable this feature.
     512             :     // @Range: 0 200
     513             :     // @Increment: 0.5
     514             :     // @User: Advanced
     515             : 
     516             :     // @Param: _SAIL_PDMX
     517             :     // @DisplayName: Sail Heel control PD sum maximum
     518             :     // @Description: Sail Heel control PD sum maximum.  The maximum/minimum value that the sum of the P and D term can output
     519             :     // @Range: 0.000 1.000
     520             :     // @Increment: 0.01
     521             : 
     522             :     // @Param: _SAIL_D_FF
     523             :     // @DisplayName: Sail Heel Derivative FeedForward Gain
     524             :     // @Description: FF D Gain which produces an output that is proportional to the rate of change of the target
     525             :     // @Range: 0 0.03
     526             :     // @Increment: 0.001
     527             :     // @User: Advanced
     528             : 
     529             :     // @Param: _SAIL_NTF
     530             :     // @DisplayName: Sail Heel Target notch filter index
     531             :     // @Description: Sail Heel Target notch filter index, zero disables
     532             :     // @Range: 0 8
     533             :     // @User: Advanced
     534             : 
     535             :     // @Param: _SAIL_NEF
     536             :     // @DisplayName: Sail Heel Error notch filter index
     537             :     // @Description: Sail Heel Error notch filter index, zero disables
     538             :     // @Range: 0 8
     539             :     // @User: Advanced
     540             : 
     541             :     AP_SUBGROUPINFO(_sailboat_heel_pid, "_SAIL_", 12, AR_AttitudeControl, AC_PID),
     542             : 
     543             :     // @Param: _TURN_MAX_G
     544             :     // @DisplayName: Turning maximum G force
     545             :     // @Description: The maximum turning acceleration (in units of gravities) that the rover can handle while remaining stable. The navigation code will keep the lateral acceleration below this level to avoid rolling over or slipping the wheels in turns
     546             :     // @Units: gravities
     547             :     // @Range: 0.1 10
     548             :     // @Increment: 0.01
     549             :     // @User: Standard
     550             :     AP_GROUPINFO("_TURN_MAX_G", 13, AR_AttitudeControl, _turn_lateral_G_max, 0.6f),
     551             : 
     552             :     // @Param: _BAL_LIM_TC
     553             :     // @DisplayName: Pitch control limit time constant
     554             :     // @Description: Pitch control limit time constant to protect against falling.  Lower values limit pitch more quickly, higher values limit more slowly.  Set to 0 to disable
     555             :     // @Range: 0.0 5.0
     556             :     // @Increment: 0.01
     557             :     // @User: Standard
     558             :     AP_GROUPINFO("_BAL_LIM_TC", 14, AR_AttitudeControl, _pitch_limit_tc, AR_ATTCONTROL_PITCH_LIM_TC),
     559             : 
     560             :     // @Param: _BAL_LIM_THR
     561             :     // @DisplayName: Pitch control limit throttle threshold
     562             :     // @Description: Pitch control limit throttle threshold.  Pitch angle will be limited if throttle crosses this threshold (from 0 to 1)
     563             :     // @Range: 0.0 1.0
     564             :     // @Increment: 0.01
     565             :     // @User: Standard
     566             :     AP_GROUPINFO("_BAL_LIM_THR", 15, AR_AttitudeControl, _pitch_limit_throttle_thresh, AR_ATTCONTROL_PITCH_LIM_THR_THRESH),
     567             : 
     568             :     // @Param: _STR_DEC_MAX
     569             :     // @DisplayName: Steering control angular deceleration maximum
     570             :     // @Description: Steering control angular deceleration maximum (in deg/s/s).  0 to disable deceleration limiting
     571             :     // @Range: 0 1000
     572             :     // @Increment: 0.1
     573             :     // @Units: deg/s/s
     574             :     // @User: Standard
     575             :     AP_GROUPINFO("_STR_DEC_MAX", 16, AR_AttitudeControl, _steer_decel_max, AR_ATTCONTROL_STEER_DECEL_MAX),
     576             : 
     577             :     AP_GROUPEND
     578             : };
     579             : 
     580         285 : AR_AttitudeControl::AR_AttitudeControl() :
     581         285 :     _steer_angle_p(AR_ATTCONTROL_STEER_ANG_P),
     582         285 :     _steer_rate_pid(AR_ATTCONTROL_STEER_RATE_P, AR_ATTCONTROL_STEER_RATE_I, AR_ATTCONTROL_STEER_RATE_D, AR_ATTCONTROL_STEER_RATE_FF, AR_ATTCONTROL_STEER_RATE_IMAX, 0.0f, AR_ATTCONTROL_STEER_RATE_FILT, 0.0f),
     583         285 :     _throttle_speed_pid(AR_ATTCONTROL_THR_SPEED_P, AR_ATTCONTROL_THR_SPEED_I, AR_ATTCONTROL_THR_SPEED_D, 0.0f, AR_ATTCONTROL_THR_SPEED_IMAX, 0.0f, AR_ATTCONTROL_THR_SPEED_FILT, 0.0f),
     584         285 :     _pitch_to_throttle_pid(AR_ATTCONTROL_PITCH_THR_P, AR_ATTCONTROL_PITCH_THR_I, AR_ATTCONTROL_PITCH_THR_D, 0.0f, AR_ATTCONTROL_PITCH_THR_IMAX, 0.0f, AR_ATTCONTROL_PITCH_THR_FILT, 0.0f),
     585         285 :     _sailboat_heel_pid(AR_ATTCONTROL_HEEL_SAIL_P, AR_ATTCONTROL_HEEL_SAIL_I, AR_ATTCONTROL_HEEL_SAIL_D, 0.0f, AR_ATTCONTROL_HEEL_SAIL_IMAX, 0.0f, AR_ATTCONTROL_HEEL_SAIL_FILT, 0.0f)
     586             : {
     587         285 :     _singleton = this;
     588         285 :     AP_Param::setup_object_defaults(this, var_info);
     589         285 : }
     590             : 
     591             : // return a steering servo output from -1.0 to +1.0 given a desired lateral acceleration rate in m/s/s.
     592             : // positive lateral acceleration is to the right.
     593        3598 : float AR_AttitudeControl::get_steering_out_lat_accel(float desired_accel, bool motor_limit_left, bool motor_limit_right, float dt)
     594             : {
     595             :     // record desired accel for reporting purposes
     596        3598 :     _steer_lat_accel_last_ms = AP_HAL::millis();
     597        3598 :     _desired_lat_accel = desired_accel;
     598             : 
     599             :     // get speed forward
     600             :     float speed;
     601        3598 :     if (!get_forward_speed(speed)) {
     602             :         // we expect caller will not try to control heading using rate control without a valid speed estimate
     603             :         // on failure to get speed we do not attempt to steer
     604           0 :         return 0.0f;
     605             :     }
     606             : 
     607        3598 :     const float desired_rate = get_turn_rate_from_lat_accel(desired_accel, speed);
     608             : 
     609        3598 :     return get_steering_out_rate(desired_rate, motor_limit_left, motor_limit_right, dt);
     610             : }
     611             : 
     612             : // return a steering servo output from -1 to +1 given a heading in radians
     613             : // set rate_max_rads to a non-zero number to apply a limit on the desired turn rate
     614             : // return value is normally in range -1.0 to +1.0 but can be higher or lower
     615       23820 : float AR_AttitudeControl::get_steering_out_heading(float heading_rad, float rate_max_rads, bool motor_limit_left, bool motor_limit_right, float dt)
     616             : {
     617             :     // calculate the desired turn rate (in radians) from the angle error (also in radians)
     618       23820 :     float desired_rate = get_turn_rate_from_heading(heading_rad, rate_max_rads);
     619             : 
     620       23820 :     return get_steering_out_rate(desired_rate, motor_limit_left, motor_limit_right, dt);
     621             : }
     622             : 
     623             : // return a desired turn-rate given a desired heading in radians
     624       23820 : float AR_AttitudeControl::get_turn_rate_from_heading(float heading_rad, float rate_max_rads) const
     625             : {
     626       23820 :     const float yaw_error = wrap_PI(heading_rad - AP::ahrs().get_yaw_rad());
     627             : 
     628             :     // Calculate the desired turn rate (in radians) from the angle error (also in radians)
     629       23820 :     float desired_rate = _steer_angle_p.get_p(yaw_error);
     630             : 
     631             :     // limit desired_rate if a custom pivot turn rate is selected, otherwise use ATC_STR_RAT_MAX
     632       23820 :     if (is_positive(rate_max_rads)) {
     633         786 :         desired_rate = constrain_float(desired_rate, -rate_max_rads, rate_max_rads);
     634             :     }
     635             : 
     636             :     // if deceleration limit is provided, ensure rate can be slowed to zero in time to stop at heading_rad (i.e. avoid overshoot)
     637       23820 :     if (is_positive(_steer_decel_max)) {
     638           0 :         const float steer_decel_rate_max_rads = safe_sqrt(2.0 * fabsf(yaw_error) * radians(_steer_decel_max));
     639           0 :         desired_rate = constrain_float(desired_rate, -steer_decel_rate_max_rads, steer_decel_rate_max_rads);
     640       23820 :     } else if (is_positive(_steer_accel_max)) {
     641             :         // if no deceleration limit, use acceleration limit
     642       23820 :         const float steer_accel_rate_max_rads = safe_sqrt(2.0 * fabsf(yaw_error) * radians(_steer_accel_max));
     643       23820 :         desired_rate = constrain_float(desired_rate, -steer_accel_rate_max_rads, steer_accel_rate_max_rads);
     644             :     }
     645             : 
     646       23820 :     return desired_rate;
     647             : }
     648             : 
     649             : // return a steering servo output given a desired yaw rate in radians/sec.
     650             : // positive yaw is to the right
     651             : // return value is normally in range -1.0 to +1.0 but can be higher or lower
     652             : // also sets steering_limit_left and steering_limit_right flags
     653      220275 : float AR_AttitudeControl::get_steering_out_rate(float desired_rate, bool motor_limit_left, bool motor_limit_right, float dt)
     654             : {
     655             :     // sanity check dt
     656      220275 :     dt = constrain_float(dt, 0.0f, 1.0f);
     657             : 
     658             :     // update steering limit flags used by higher level controllers (e.g. position controller)
     659      220275 :     _steering_limit_left = motor_limit_left;
     660      220275 :     _steering_limit_right = motor_limit_right;
     661             : 
     662             :     // if not called recently, reset input filter and desired turn rate to actual turn rate (used for accel limiting)
     663      220275 :     const uint32_t now = AP_HAL::millis();
     664      220275 :     if ((_steer_turn_last_ms == 0) || ((now - _steer_turn_last_ms) > AR_ATTCONTROL_TIMEOUT_MS)) {
     665          88 :         _steer_rate_pid.reset_filter();
     666          88 :         _steer_rate_pid.reset_I();
     667          88 :         _desired_turn_rate = AP::ahrs().get_yaw_rate_earth();
     668             :     }
     669      220275 :     _steer_turn_last_ms = now;
     670             : 
     671             :     // acceleration limit desired turn rate
     672      220275 :     if (is_positive(_steer_accel_max)) {
     673      220275 :         const float change_max = radians(_steer_accel_max) * dt;
     674      220275 :         if (desired_rate <= _desired_turn_rate - change_max) {
     675        2445 :             _steering_limit_left = true;
     676             :         }
     677      220275 :         if (desired_rate >= _desired_turn_rate + change_max) {
     678        4849 :             _steering_limit_right = true;
     679             :         }
     680      220275 :         desired_rate = constrain_float(desired_rate, _desired_turn_rate - change_max, _desired_turn_rate + change_max);
     681             :     }
     682      220275 :     _desired_turn_rate = desired_rate;
     683             : 
     684             :     // rate limit desired turn rate
     685      220275 :     if (is_positive(_steer_rate_max)) {
     686      220275 :         const float steer_rate_max_rad = radians(_steer_rate_max);
     687      220275 :         if (_desired_turn_rate <= -steer_rate_max_rad) {
     688         465 :             _steering_limit_left = true;
     689             :         }
     690      220275 :         if (_desired_turn_rate >= steer_rate_max_rad) {
     691        2504 :             _steering_limit_right = true;
     692             :         }
     693      220275 :         _desired_turn_rate = constrain_float(_desired_turn_rate, -steer_rate_max_rad, steer_rate_max_rad);
     694             :     }
     695             : 
     696             :     // G limit based on speed
     697             :     float speed;
     698      220275 :     if (get_forward_speed(speed)) {
     699             :         // do not limit to less than 1 deg/s
     700      220090 :         const float turn_rate_max = MAX(get_turn_rate_from_lat_accel(get_turn_lat_accel_max(), fabsf(speed)), radians(1.0f));
     701      220090 :         if (_desired_turn_rate <= -turn_rate_max) {
     702          16 :             _steering_limit_left = true;
     703             :         }
     704      220090 :         if (_desired_turn_rate >= turn_rate_max) {
     705         263 :             _steering_limit_right = true;
     706             :         }
     707      220090 :         _desired_turn_rate = constrain_float(_desired_turn_rate, -turn_rate_max, turn_rate_max);
     708             :     }
     709             : 
     710             :     // update pid to calculate output to motors
     711      220275 :     float output = _steer_rate_pid.update_all(_desired_turn_rate, AP::ahrs().get_yaw_rate_earth(), dt, (motor_limit_left || motor_limit_right));
     712      220275 :     output += _steer_rate_pid.get_ff();
     713             :     // constrain and return final output
     714      220275 :     return output;
     715             : }
     716             : 
     717             : // get latest desired turn rate in rad/sec (recorded during calls to get_steering_out_rate)
     718      119840 : float AR_AttitudeControl::get_desired_turn_rate() const
     719             : {
     720             :     // return zero if no recent calls to turn rate controller
     721      119840 :     if ((_steer_turn_last_ms == 0) || ((AP_HAL::millis() - _steer_turn_last_ms) > AR_ATTCONTROL_TIMEOUT_MS)) {
     722       75630 :         return 0.0f;
     723             :     }
     724       44210 :     return _desired_turn_rate;
     725             : }
     726             : 
     727             : // get latest desired lateral acceleration in m/s/s (recorded during calls to get_steering_out_lat_accel)
     728           0 : float AR_AttitudeControl::get_desired_lat_accel() const
     729             : {
     730             :     // return zero if no recent calls to lateral acceleration controller
     731           0 :     if ((_steer_lat_accel_last_ms == 0) || ((AP_HAL::millis() - _steer_lat_accel_last_ms) > AR_ATTCONTROL_TIMEOUT_MS)) {
     732           0 :         return 0.0f;
     733             :     }
     734           0 :     return _desired_lat_accel;
     735             : }
     736             : 
     737             : // get actual lateral acceleration in m/s/s.  returns true on success
     738      119840 : bool AR_AttitudeControl::get_lat_accel(float &lat_accel) const
     739             : {
     740             :     float speed;
     741      119840 :     if (!get_forward_speed(speed)) {
     742        7235 :         return false;
     743             :     }
     744      112605 :     lat_accel = speed * AP::ahrs().get_yaw_rate_earth();
     745      112605 :     return true;
     746             : }
     747             : 
     748             : // calculate the turn rate in rad/sec given a lateral acceleration (in m/s/s) and speed (in m/s)
     749      402146 : float AR_AttitudeControl::get_turn_rate_from_lat_accel(float lat_accel, float speed) const
     750             : {
     751             :     // enforce minimum speed to stop oscillations when first starting to move
     752      402146 :     if (fabsf(speed) < AR_ATTCONTROL_STEER_SPEED_MIN) {
     753      143509 :         if (is_negative(speed)) {
     754        1478 :             speed = -AR_ATTCONTROL_STEER_SPEED_MIN;
     755             :         } else {
     756      142031 :             speed = AR_ATTCONTROL_STEER_SPEED_MIN;
     757             :         }
     758             :     }
     759             : 
     760      402146 :     return lat_accel / speed;
     761             : }
     762             : 
     763             : // return a throttle output from -1 to +1 given a desired speed in m/s (use negative speeds to travel backwards)
     764             : //   motor_limit should be true if motors have hit their upper or lower limits
     765             : //   cruise speed should be in m/s, cruise throttle should be a number from -1 to +1
     766      180652 : float AR_AttitudeControl::get_throttle_out_speed(float desired_speed, bool motor_limit_low, bool motor_limit_high, float cruise_speed, float cruise_throttle, float dt)
     767             : {
     768             :     // sanity check dt
     769      180652 :     dt = constrain_float(dt, 0.0f, 1.0f);
     770             : 
     771             :     // get speed forward
     772             :     float speed;
     773      180652 :     if (!get_forward_speed(speed)) {
     774             :         // we expect caller will not try to control heading using rate control without a valid speed estimate
     775             :         // on failure to get speed we do not attempt to steer
     776           0 :         return 0.0f;
     777             :     }
     778             : 
     779             :     // if not called recently, reset input filter and desired speed to actual speed (used for accel limiting)
     780      180652 :     if (!speed_control_active()) {
     781          37 :         _throttle_speed_pid.reset_filter();
     782          37 :         _throttle_speed_pid.reset_I();
     783          37 :         _desired_speed = speed;
     784             :     }
     785      180652 :     _speed_last_ms = AP_HAL::millis();
     786             : 
     787             :     // acceleration limit desired speed
     788      180652 :     _desired_speed = get_desired_speed_accel_limited(desired_speed, dt);
     789             : 
     790             :     // calculate base throttle (protect against divide by zero)
     791      180652 :     float throttle_base = 0.0f;
     792      180652 :     if (is_positive(cruise_speed) && is_positive(cruise_throttle)) {
     793      158417 :         throttle_base = _desired_speed * (cruise_throttle / cruise_speed);
     794             :     }
     795             : 
     796             :     // calculate final output
     797      180652 :     float throttle_out = _throttle_speed_pid.update_all(_desired_speed, speed, dt, (motor_limit_low || motor_limit_high || _throttle_limit_low || _throttle_limit_high));
     798      180652 :     throttle_out += _throttle_speed_pid.get_ff();
     799      180652 :     throttle_out += throttle_base;
     800             : 
     801             :     // update PID info for reporting purposes
     802      180652 :     _throttle_speed_pid_info = _throttle_speed_pid.get_pid_info();
     803      180652 :     _throttle_speed_pid_info.FF += throttle_base;
     804             : 
     805             :     // clear local limit flags used to stop i-term build-up as we stop reversed outputs going to motors
     806      180652 :     _throttle_limit_low = false;
     807      180652 :     _throttle_limit_high = false;
     808             : 
     809             :     // protect against reverse output being sent to the motors unless braking has been enabled
     810      180652 :     if (!_brake_enable) {
     811             :         // if both desired speed and actual speed are positive, do not allow negative values
     812           0 :         if ((_desired_speed >= 0.0f) && (throttle_out <= 0.0f)) {
     813           0 :             throttle_out = 0.0f;
     814           0 :             _throttle_limit_low = true;
     815           0 :         } else if ((_desired_speed <= 0.0f) && (throttle_out >= 0.0f)) {
     816           0 :             throttle_out = 0.0f;
     817           0 :             _throttle_limit_high = true;
     818             :         }
     819             :     }
     820             : 
     821             :     // final output throttle in range -1 to 1
     822      180652 :     return throttle_out;
     823             : }
     824             : 
     825             : // return a throttle output from -1 to +1 to perform a controlled stop.  returns true once the vehicle has stopped
     826       67282 : float AR_AttitudeControl::get_throttle_out_stop(bool motor_limit_low, bool motor_limit_high, float cruise_speed, float cruise_throttle, float dt, bool &stopped)
     827             : {
     828             :     // get current system time
     829       67282 :     const uint32_t now = AP_HAL::millis();
     830             : 
     831             :     // if we were stopped in the last 300ms, assume we are still stopped
     832       67282 :     bool _stopped = (_stop_last_ms != 0) && (now - _stop_last_ms) < 300;
     833             : 
     834             :     // get deceleration limited speed
     835       67282 :     float desired_speed_limited = get_desired_speed_accel_limited(0.0f, dt);
     836             : 
     837             :     // get speed forward
     838             :     float speed;
     839       67282 :     if (!get_forward_speed(speed)) {
     840             :         // could not get speed so assume stopped
     841         678 :         _stopped = true;
     842             :     } else {
     843             :         // if desired speed is zero and vehicle drops below _stop_speed consider it stopped
     844       66604 :         if (is_zero(desired_speed_limited) && fabsf(speed) <= fabsf(_stop_speed)) {
     845       63069 :             _stopped = true;
     846             :         }
     847             :     }
     848             : 
     849             :     // set stopped status for caller
     850       67282 :     stopped = _stopped;
     851             : 
     852             :     // if stopped return zero
     853       67282 :     if (stopped) {
     854             :         // update last time we thought we were stopped
     855       64277 :         _stop_last_ms = now;
     856             :         // set last time speed controller was run so accelerations are limited
     857       64277 :         _speed_last_ms = now;
     858             :         // reset filters and I-term
     859       64277 :         _throttle_speed_pid.reset_filter();
     860       64277 :         _throttle_speed_pid.reset_I();
     861             :         // ensure desired speed is zero
     862       64277 :         _desired_speed = 0.0f;
     863       64277 :         return 0.0f;
     864             :     }
     865             : 
     866             :     // clear stopped system time
     867        3005 :     _stop_last_ms = 0;
     868             :     // run speed controller to bring vehicle to stop
     869        3005 :     return get_throttle_out_speed(desired_speed_limited, motor_limit_low, motor_limit_high, cruise_speed, cruise_throttle, dt);
     870             : }
     871             : 
     872             : // balancebot pitch to throttle controller
     873             : // returns a throttle output from -1 to +1 given a desired pitch angle (in radians)
     874             : // pitch_max should be the user defined max pitch angle (in radians)
     875             : // motor_limit should be true if the motors have hit their upper or lower limit
     876       54262 : float AR_AttitudeControl::get_throttle_out_from_pitch(float desired_pitch, float pitch_max, bool motor_limit, float dt)
     877             : {
     878             :     // sanity check dt
     879       54262 :     dt = constrain_float(dt, 0.0f, 1.0f);
     880             : 
     881             :     // if not called recently, reset input filter
     882       54262 :     const uint32_t now = AP_HAL::millis();
     883       54262 :     if ((_balance_last_ms == 0) || ((now - _balance_last_ms) > AR_ATTCONTROL_TIMEOUT_MS)) {
     884          31 :         _pitch_to_throttle_pid.reset_filter();
     885          31 :         _pitch_to_throttle_pid.reset_I();
     886          31 :         _pitch_limit_low = -pitch_max;
     887          31 :         _pitch_limit_high = pitch_max;
     888             :     }
     889       54262 :     _balance_last_ms = now;
     890             : 
     891             :     // limit desired pitch to protect against falling
     892       54262 :     const bool pitch_limit_active = (_pitch_limit_tc >= 0.01) && (_pitch_limit_throttle_thresh > 0);
     893       54262 :     if (pitch_limit_active) {
     894       54262 :         desired_pitch = constrain_float(desired_pitch, _pitch_limit_low, _pitch_limit_high);
     895       54262 :         _pitch_limited = (desired_pitch <= _pitch_limit_low || desired_pitch >= _pitch_limit_high);
     896             :     } else {
     897           0 :         _pitch_limited = false;
     898             :     }
     899             : 
     900             :     // initialise output to feed forward from current pitch angle
     901       54262 :     const float pitch_rad = AP::ahrs().get_pitch_rad();
     902       54262 :     float output = sinf(pitch_rad) * _pitch_to_throttle_ff;
     903             : 
     904             :     // add regular PID control
     905       54262 :     output += _pitch_to_throttle_pid.update_all(desired_pitch, pitch_rad, dt, motor_limit);
     906       54262 :     output += _pitch_to_throttle_pid.get_ff();
     907             : 
     908             :     // update pitch limits for next iteration
     909             :     // note: pitch is positive when leaning backwards, negative when leaning forward
     910       54262 :     if (pitch_limit_active) {
     911       54262 :         const float pitch_limit_incr = 1.0/_pitch_limit_tc * dt * pitch_max;
     912       54262 :         const float pitch_relax_incr = pitch_limit_incr * AR_ATTCONTROL_PITCH_RELAX_RATIO;
     913       54262 :         if (output <= -_pitch_limit_throttle_thresh) {
     914             :             // very low negative throttle output means we must lower pitch_high (e.g. reduce leaning backwards)
     915           0 :             _pitch_limit_high = MAX(_pitch_limit_high - pitch_limit_incr, 0);
     916             :         } else {
     917       54262 :             _pitch_limit_high = MIN(_pitch_limit_high + pitch_relax_incr, pitch_max);
     918             :         }
     919       54262 :         if (output >= _pitch_limit_throttle_thresh) {
     920             :             // very high positive throttle output means we must raise pitch_low (reduce leaning forwards)
     921           0 :             _pitch_limit_low = MIN(_pitch_limit_low + pitch_limit_incr, 0);
     922             :         } else {
     923       54262 :             _pitch_limit_low = MAX(_pitch_limit_low - pitch_relax_incr, -pitch_max);
     924             :         }
     925             :     }
     926             : 
     927             :     // constrain and return final output
     928       54262 :     return output;
     929             : }
     930             : 
     931             : // get latest desired pitch in radians for reporting purposes
     932      651273 : float AR_AttitudeControl::get_desired_pitch() const
     933             : {
     934             :     // if not called recently, return 0
     935      651273 :     if ((_balance_last_ms == 0) || ((AP_HAL::millis() - _balance_last_ms) > AR_ATTCONTROL_TIMEOUT_MS)) {
     936      597021 :         return 0.0f;
     937             :     }
     938             : 
     939       54252 :     return _pitch_to_throttle_pid.get_pid_info().target;
     940             : }
     941             : 
     942             : // Sailboat heel(roll) angle controller releases sail to keep at maximum heel angle
     943             : // but does not attempt to reach maximum heel angle, ie only lets sails out, does not pull them in
     944       17468 : float AR_AttitudeControl::get_sail_out_from_heel(float desired_heel, float dt)
     945             : {
     946             :     // sanity check dt
     947       17468 :     dt = constrain_float(dt, 0.0f, 1.0f);
     948             : 
     949             :     // if not called recently, reset input filter
     950       17468 :     const uint32_t now = AP_HAL::millis();
     951       17468 :     if ((_heel_controller_last_ms == 0) || ((now - _heel_controller_last_ms) > AR_ATTCONTROL_TIMEOUT_MS)) {
     952           4 :         _sailboat_heel_pid.reset_filter();
     953           4 :         _sailboat_heel_pid.reset_I();
     954             :     }
     955       17468 :     _heel_controller_last_ms = now;
     956             : 
     957       17468 :     _sailboat_heel_pid.update_all(desired_heel, fabsf(AP::ahrs().get_roll_rad()), dt);
     958             : 
     959             :     // get feed-forward
     960       17468 :     const float ff = _sailboat_heel_pid.get_ff();
     961             : 
     962             :     // get p, constrain to be zero or negative
     963       17468 :     float p = _sailboat_heel_pid.get_p();
     964       17468 :     if (is_positive(p)) {
     965       17468 :         p = 0.0f;
     966             :     }
     967             : 
     968             :     // get i, constrain to be zero or negative
     969       17468 :     float i = _sailboat_heel_pid.get_i();
     970       17468 :     if (is_positive(i)) {
     971       17468 :         i = 0.0f;
     972       17468 :         _sailboat_heel_pid.reset_I();
     973             :     }
     974             : 
     975             :     // get d
     976       17468 :     const float d = _sailboat_heel_pid.get_d();
     977             : 
     978             :     // constrain and return final output
     979       17468 :     return (ff + p + i + d) * -1.0f;
     980             : }
     981             : 
     982             : // get the slew rate value for speed and steering for oscillation detection in lua scripts
     983           0 : void AR_AttitudeControl::get_srate(float &steering_srate, float &speed_srate)
     984             : {
     985           0 :     steering_srate = get_steering_rate_pid().get_pid_info().slew_rate;
     986           0 :     speed_srate = _throttle_speed_pid_info.slew_rate;
     987           0 : }
     988             : 
     989             : // get forward speed in m/s (earth-frame horizontal velocity but only along vehicle x-axis).  returns true on success
     990     1709461 : bool AR_AttitudeControl::get_forward_speed(float &speed) const
     991             : {
     992     1709461 :     Vector3f velocity;
     993     1709461 :     const AP_AHRS &_ahrs = AP::ahrs();
     994     1709461 :     if (!_ahrs.get_velocity_NED(velocity)) {
     995             :         // use less accurate GPS, assuming entire length is along forward/back axis of vehicle
     996       55460 :         if (AP::gps().status() >= AP_GPS_FixType::FIX_3D) {
     997           2 :             if (abs(wrap_180_cd(_ahrs.yaw_sensor - AP::gps().ground_course_cd())) <= 9000) {
     998           0 :                 speed = AP::gps().ground_speed();
     999             :             } else {
    1000           2 :                 speed = -AP::gps().ground_speed();
    1001             :             }
    1002           2 :             return true;
    1003             :         } else {
    1004       55458 :             return false;
    1005             :         }
    1006             :     }
    1007             :     // calculate forward speed velocity into body frame
    1008     1654001 :     speed = velocity.x*_ahrs.cos_yaw() + velocity.y*_ahrs.sin_yaw();
    1009     1654001 :     return true;
    1010             : }
    1011             : 
    1012       37929 : float AR_AttitudeControl::get_decel_max() const
    1013             : {
    1014       37929 :     if (is_positive(_throttle_decel_max)) {
    1015           0 :         return _throttle_decel_max;
    1016             :     } else {
    1017       37929 :         return _throttle_accel_max;
    1018             :     }
    1019             : }
    1020             : 
    1021             : // check if speed controller active
    1022     2420341 : bool AR_AttitudeControl::speed_control_active() const
    1023             : {
    1024             :     // active if there have been recent calls to speed controller
    1025     2420341 :     if ((_speed_last_ms == 0) || ((AP_HAL::millis() - _speed_last_ms) > AR_ATTCONTROL_TIMEOUT_MS)) {
    1026      459415 :         return false;
    1027             :     }
    1028     1960926 :     return true;
    1029             : }
    1030             : 
    1031             : // get latest desired speed recorded during call to get_throttle_out_speed.  For reporting purposes only
    1032      345065 : float AR_AttitudeControl::get_desired_speed() const
    1033             : {
    1034             :     // return zero if no recent calls to speed controller
    1035      345065 :     if (!speed_control_active()) {
    1036       70722 :         return 0.0f;
    1037             :     }
    1038      274343 :     return _desired_speed;
    1039             : }
    1040             : 
    1041             : // get acceleration limited desired speed
    1042      675362 : float AR_AttitudeControl::get_desired_speed_accel_limited(float desired_speed, float dt) const
    1043             : {
    1044             :     // return input value if no recent calls to speed controller
    1045             :     // apply no limiting when ATC_ACCEL_MAX is set to zero
    1046      675362 :     if (!speed_control_active() || !is_positive(_throttle_accel_max)) {
    1047       34837 :         return desired_speed;
    1048             :     }
    1049             : 
    1050             :     // sanity check dt
    1051      640525 :     dt = constrain_float(dt, 0.0f, 1.0f);
    1052             : 
    1053             :     // use previous desired speed as basis for accel limiting
    1054      640525 :     float speed_prev = _desired_speed;
    1055             : 
    1056             :     // if no recent calls to speed controller limit based on current speed
    1057      640525 :     if (!speed_control_active()) {
    1058           0 :         get_forward_speed(speed_prev);
    1059             :     }
    1060             : 
    1061             :     // acceleration limit desired speed
    1062             :     float speed_change_max;
    1063      640525 :     if (fabsf(desired_speed) < fabsf(_desired_speed) && is_positive(_throttle_decel_max)) {
    1064           0 :         speed_change_max = _throttle_decel_max * dt;
    1065             :     } else {
    1066      640525 :         speed_change_max = _throttle_accel_max * dt;
    1067             :     }
    1068      640525 :     return constrain_float(desired_speed, speed_prev - speed_change_max, speed_prev + speed_change_max);
    1069             : }
    1070             : 
    1071             : // get minimum stopping distance (in meters) given a speed (in m/s)
    1072         273 : float AR_AttitudeControl::get_stopping_distance(float speed) const
    1073             : {
    1074             :     // get maximum vehicle deceleration
    1075         273 :     const float decel_max = get_decel_max();
    1076             : 
    1077         273 :     if ((decel_max <= 0.0f) || is_zero(speed)) {
    1078           0 :         return 0.0f;
    1079             :     }
    1080             : 
    1081             :     // assume linear deceleration
    1082         273 :     return 0.5f * sq(speed) / decel_max;
    1083             : }
    1084             : 
    1085             : // relax I terms of throttle and steering controllers
    1086         417 : void AR_AttitudeControl::relax_I()
    1087             : {
    1088         417 :     _steer_rate_pid.reset_I();
    1089         417 :     _throttle_speed_pid.reset_I();
    1090         417 :     _pitch_to_throttle_pid.reset_I();
    1091         417 : }
    1092             : 
    1093           0 : void AR_AttitudeControl::set_notch_sample_rate(float sample_rate)
    1094             : {
    1095             : #if AP_FILTER_ENABLED
    1096           0 :     _steer_rate_pid.set_notch_sample_rate(sample_rate);
    1097           0 :     _throttle_speed_pid.set_notch_sample_rate(sample_rate);
    1098           0 :     _pitch_to_throttle_pid.set_notch_sample_rate(sample_rate);
    1099             : #endif
    1100           0 : }

Generated by: LCOV version 1.14