LCOV - code coverage report
Current view: top level - AC_Autorotation - AC_Autorotation.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 135 144 93.8 %
Date: 2026-09-09 11:02:08 Functions: 15 15 100.0 %

          Line data    Source code
       1             : #include "AC_Autorotation.h"
       2             : #include <AP_Logger/AP_Logger.h>
       3             : #include <AP_RPM/AP_RPM.h>
       4             : #include <AP_AHRS/AP_AHRS.h>
       5             : #include <GCS_MAVLink/GCS.h>
       6             : 
       7             : extern const AP_HAL::HAL& hal;
       8             : 
       9             : // Autorotation controller defaults
      10             : #define HEAD_SPEED_TARGET_RATIO 1.0 // Normalised target main rotor head speed
      11             : 
      12             : const AP_Param::GroupInfo AC_Autorotation::var_info[] = {
      13             : 
      14             :     // @Param: ENABLE
      15             :     // @DisplayName: Enable settings for RSC Setpoint
      16             :     // @Description: Allows you to enable (1) or disable (0) the autonomous autorotation capability.
      17             :     // @Values: 0:Disabled,1:Enabled
      18             :     // @User: Standard
      19             :     AP_GROUPINFO_FLAGS("ENABLE", 1, AC_Autorotation, _param_enable, 0, AP_PARAM_FLAG_ENABLE),
      20             : 
      21             :     // @Param: HS_P
      22             :     // @DisplayName: P gain for head speed controller
      23             :     // @Description: Increase value to increase sensitivity of head speed controller during autonomous autorotation.
      24             :     // @Range: 0.3 1
      25             :     // @Increment: 0.01
      26             :     // @User: Standard
      27             :     AP_SUBGROUPINFO(_p_hs, "HS_", 2, AC_Autorotation, AC_P),
      28             : 
      29             :     // @Param: HS_SET_PT
      30             :     // @DisplayName: Target Head Speed
      31             :     // @Description: The target head speed in RPM during autorotation. Start by setting to desired hover speed and tune from there as necessary.
      32             :     // @Units: RPM
      33             :     // @Range: 1000 2800
      34             :     // @Increment: 1
      35             :     // @User: Standard
      36             :     AP_GROUPINFO("HS_SET_PT", 3, AC_Autorotation, _param_head_speed_set_point, 1500),
      37             : 
      38             :     // @Param: FWD_SP_TARG
      39             :     // @DisplayName: Target Glide Body Frame Forward Speed
      40             :     // @Description: Target ground speed in cm/s for the autorotation controller to try and achieve/ maintain during the glide phase.
      41             :     // @Units: m/s
      42             :     // @Range: 8 20
      43             :     // @Increment: 0.5
      44             :     // @User: Standard
      45             :     AP_GROUPINFO("FWD_SP_TARG", 4, AC_Autorotation, _param_target_speed_ms, 11),
      46             : 
      47             :     // @Param: COL_FILT_E
      48             :     // @DisplayName: Entry Phase Collective Filter
      49             :     // @Description: Cut-off frequency for collective low pass filter. For the entry phase. Acts as a following trim.  Must be higher than AROT_COL_FILT_G.
      50             :     // @Units: Hz
      51             :     // @Range: 0.2 0.5
      52             :     // @Increment: 0.01
      53             :     // @User: Standard
      54             :     AP_GROUPINFO("COL_FILT_E", 5, AC_Autorotation, _param_col_entry_cutoff_freq, 0.7),
      55             : 
      56             :     // @Param: COL_FILT_G
      57             :     // @DisplayName: Glide Phase Collective Filter
      58             :     // @Description: Cut-off frequency for collective low pass filter. For the glide phase. Acts as a following trim.  Must be lower than AROT_COL_FILT_E.
      59             :     // @Units: Hz
      60             :     // @Range: 0.03 0.15
      61             :     // @Increment: 0.01
      62             :     // @User: Standard
      63             :     AP_GROUPINFO("COL_FILT_G", 6, AC_Autorotation, _param_col_glide_cutoff_freq, 0.1),
      64             : 
      65             :     // @Param: XY_ACC_MAX
      66             :     // @DisplayName: Body Frame XY Acceleration Limit
      67             :     // @Description: Maximum body frame acceleration allowed in the in speed controller. This limit defines a circular constraint in accel. Minimum used is 0.5 m/s/s.
      68             :     // @Units: m/s/s
      69             :     // @Range: 0.5 8.0
      70             :     // @Increment: 0.1
      71             :     // @User: Standard
      72             :     AP_GROUPINFO("XY_ACC_MAX", 7, AC_Autorotation, _param_accel_max_mss, 2.0),
      73             : 
      74             :     // @Param: HS_SENSOR
      75             :     // @DisplayName: Main Rotor RPM Sensor 
      76             :     // @Description: Allocate the RPM sensor instance to use for measuring head speed. RPM1 = 0.  RPM2 = 1.
      77             :     // @Units: s
      78             :     // @Range: 0.5 3
      79             :     // @Increment: 0.1
      80             :     // @User: Standard
      81             :     AP_GROUPINFO("HS_SENSOR", 8, AC_Autorotation, _param_rpm_instance, 0),
      82             : 
      83             :     // @Param: FWD_P
      84             :     // @DisplayName: Forward Speed Controller P Gain
      85             :     // @Description: Converts the difference between desired forward speed and actual speed into an acceleration target that is passed to the pitch angle controller.
      86             :     // @Range: 1.000 8.000
      87             :     // @User: Standard
      88             : 
      89             :     // @Param: FWD_I
      90             :     // @DisplayName: Forward Speed Controller I Gain
      91             :     // @Description: Corrects long-term difference in desired velocity to a target acceleration.
      92             :     // @Range: 0.02 1.00
      93             :     // @Increment: 0.01
      94             :     // @User: Advanced
      95             : 
      96             :     // @Param: FWD_IMAX
      97             :     // @DisplayName: Forward Speed Controller I Gain Maximum
      98             :     // @Description: Constrains the target acceleration that the I gain will output.
      99             :     // @Range: 1.000 8.000
     100             :     // @User: Standard
     101             : 
     102             :     // @Param: FWD_D
     103             :     // @DisplayName: Forward Speed Controller D Gain
     104             :     // @Description: Provides damping to velocity controller.
     105             :     // @Range: 0.00 1.00
     106             :     // @Increment: 0.001
     107             :     // @User: Advanced
     108             : 
     109             :     // @Param: FWD_FF
     110             :     // @DisplayName: Forward Speed Controller Feed Forward Gain
     111             :     // @Description: Produces an output that is proportional to the magnitude of the target.
     112             :     // @Range: 0 1
     113             :     // @Increment: 0.01
     114             :     // @User: Advanced
     115             : 
     116             :     // @Param: FWD_FLTE
     117             :     // @DisplayName: Forward Speed Controller Error Filter
     118             :     // @Description: This filter low pass filter is applied to the input for P and I terms.
     119             :     // @Range: 0 100
     120             :     // @Units: Hz
     121             :     // @User: Advanced
     122             : 
     123             :     // @Param: FWD_FLTD
     124             :     // @DisplayName: Forward Speed Controller input filter for D term
     125             :     // @Description: This filter low pass filter is applied to the input for D terms.
     126             :     // @Range: 0 100
     127             :     // @Units: Hz
     128             :     // @User: Advanced
     129             :     AP_SUBGROUPINFO(_fwd_speed_pid, "FWD_", 9, AC_Autorotation, AC_PID_Basic),
     130             : 
     131             :     AP_GROUPEND
     132             : };
     133             : 
     134             : // Constructor
     135          83 : AC_Autorotation::AC_Autorotation(AP_MotorsHeli*& motors, AC_AttitudeControl*& att_crtl) :
     136          83 :     _motors_heli(motors),
     137          83 :     _attitude_control(att_crtl)
     138             :     {
     139          83 :         AP_Param::setup_object_defaults(this, var_info);
     140          83 :     }
     141             : 
     142           1 : void AC_Autorotation::init(void)
     143             : {
     144             :     // Initialisation of head speed controller
     145             :     // Set initial collective position to be the current collective position for smooth init
     146           1 :     const float collective_out = _motors_heli->get_throttle_out();
     147             : 
     148             :     // Reset feed forward filter
     149           1 :     col_trim_lpf.reset(collective_out);
     150             : 
     151             :     // Protect against divide by zero TODO: move this to an accessor function
     152           1 :     _param_head_speed_set_point.set(MAX(_param_head_speed_set_point, 500.0));
     153             : 
     154             :     // Reset the landed reason
     155           1 :     _landed_reason.min_speed = false;
     156           1 :     _landed_reason.land_col = false;
     157           1 :     _landed_reason.is_still = false;
     158           1 : }
     159             : 
     160             : // Functions and config that are only to be done once at the beginning of the entry
     161           1 : void AC_Autorotation::init_entry(void)
     162             : {
     163           1 :     GCS_SEND_TEXT(MAV_SEVERITY_INFO, "AROT: Entry Phase");
     164             : 
     165             :     // Target head speed is set to rpm at initiation to prevent steps in controller
     166           1 :     if (!get_norm_head_speed(_target_head_speed)) {
     167             :         // Cannot get a valid RPM sensor reading so we default to not slewing the head speed target
     168           0 :         _target_head_speed = HEAD_SPEED_TARGET_RATIO;
     169             :     }
     170             : 
     171             :     // The rate to move the head speed from the current measurement to the target
     172           1 :     _hs_accel = (HEAD_SPEED_TARGET_RATIO - _target_head_speed) / (float(entry_time_ms)*1e-3);
     173             : 
     174             :     // Set collective following trim low pass filter cut off frequency
     175           1 :     col_trim_lpf.set_cutoff_frequency(_param_col_entry_cutoff_freq.get());
     176             : 
     177             :     // Set collective low-pass cut off filter at 2 Hz
     178           1 :     _motors_heli->set_throttle_filter_cutoff(2.0);
     179             : 
     180             :     // Set speed target to maintain the current speed whilst we enter the autorotation
     181           1 :     _desired_vel_ms = _param_target_speed_ms.get();
     182           1 :     _target_vel_ms = get_speed_forward_ms();
     183             : 
     184             :     // Reset I term of velocity PID
     185           1 :     _fwd_speed_pid.reset_filter();
     186           1 :     _fwd_speed_pid.set_integrator(0.0);
     187           1 : }
     188             : 
     189             : // The entry controller just a special case of the glide controller with head speed target slewing
     190         800 : void AC_Autorotation::run_entry(float pilot_accel_norm)
     191             : {
     192             :     // Slowly change the target head speed until the target head speed matches the parameter defined value
     193             :     float head_speed_norm;
     194         800 :     if (!get_norm_head_speed(head_speed_norm)) {
     195             :         // RPM sensor is bad, so we don't attempt to slew the head speed target as we do not know what head speed actually is
     196             :         // The collective output handling of the rpm sensor failure is handled later in the head speed controller 
     197           0 :          head_speed_norm = HEAD_SPEED_TARGET_RATIO;
     198             :     }
     199             : 
     200             :     // Slew the head speed target from the initial condition to the target head speed ratio for the glide
     201         800 :     const float max_change = _hs_accel * _dt;
     202         800 :     _target_head_speed = constrain_float(HEAD_SPEED_TARGET_RATIO, _target_head_speed - max_change, _target_head_speed + max_change);
     203             : 
     204         800 :     run_glide(pilot_accel_norm);
     205         800 : }
     206             : 
     207             : // Functions and config that are only to be done once at the beginning of the glide
     208           1 : void AC_Autorotation::init_glide(void)
     209             : {
     210           1 :     GCS_SEND_TEXT(MAV_SEVERITY_INFO, "AROT: Glide Phase");
     211             : 
     212             :     // Set collective following trim low pass filter cut off frequency
     213           1 :     col_trim_lpf.set_cutoff_frequency(_param_col_glide_cutoff_freq.get());
     214             : 
     215             :     // Ensure target head speed is set to setpoint, in case it didn't reach the target during entry
     216           1 :     _target_head_speed = HEAD_SPEED_TARGET_RATIO;
     217             : 
     218             :     // Ensure desired forward speed target is set to param value
     219           1 :     _desired_vel_ms = _param_target_speed_ms.get();
     220           1 : }
     221             : 
     222             : // Maintain head speed and forward speed as we glide to the ground
     223        6720 : void AC_Autorotation::run_glide(float pilot_accel_norm)
     224             : {
     225        6720 :     update_headspeed_controller();
     226             : 
     227        6720 :     update_forward_speed_controller(pilot_accel_norm);
     228        6720 : }
     229             : 
     230        6720 : void AC_Autorotation::update_headspeed_controller(void)
     231             : {
     232             :     // Get current rpm and update healthy signal counters
     233             :     float head_speed_norm;
     234        6720 :     if (!get_norm_head_speed(head_speed_norm)) {
     235             :         // RPM sensor is bad, set collective to angle of -2 deg and hope for the best
     236           0 :          _motors_heli->set_coll_from_ang(-2.0);
     237           0 :          return;
     238             :     }
     239             : 
     240             :     // Calculate the head speed error.
     241        6720 :     _head_speed_error = head_speed_norm - _target_head_speed;
     242             : 
     243        6720 :     _p_term_hs = _p_hs.get_p(_head_speed_error);
     244             : 
     245             :     // Adjusting collective trim using feed forward (not yet been updated, so this value is the previous time steps collective position)
     246        6720 :     _ff_term_hs = col_trim_lpf.apply(_motors_heli->get_throttle(), _dt);
     247             : 
     248             :     // Calculate collective position to be set
     249        6720 :     const float collective_out = constrain_value((_p_term_hs + _ff_term_hs), 0.0f, 1.0f);
     250             : 
     251             :     // Send collective to setting to motors output library
     252        6720 :     _motors_heli->set_throttle(collective_out);
     253             : 
     254             : #if HAL_LOGGING_ENABLED
     255             :     // @LoggerMessage: ARHS
     256             :     // @Vehicles: Copter
     257             :     // @Description: helicopter AutoRotation Head Speed (ARHS) controller information
     258             :     // @Field: TimeUS: Time since system startup
     259             :     // @Field: Tar: Normalised target head speed
     260             :     // @Field: Act: Normalised measured head speed
     261             :     // @Field: Err: Head speed controller error
     262             :     // @Field: P: P-term for head speed controller response
     263             :     // @Field: FF: FF-term for head speed controller response
     264             : 
     265             :     // Write to data flash log
     266       13440 :     AP::logger().WriteStreaming("ARHS",
     267             :                                 "TimeUS,Tar,Act,Err,P,FF",
     268             :                                 "s-----",
     269             :                                 "F00000",
     270             :                                 "Qfffff",
     271             :                                 AP_HAL::micros64(),
     272        6720 :                                 _target_head_speed,
     273             :                                 head_speed_norm,
     274        6720 :                                 _head_speed_error,
     275        6720 :                                 _p_term_hs,
     276        6720 :                                 _ff_term_hs);
     277             : #endif
     278             : }
     279             : 
     280             : // Get measured head speed and normalise by head speed set point. Returns false if a valid rpm measurement cannot be obtained
     281        7521 : bool AC_Autorotation::get_norm_head_speed(float& norm_rpm) const
     282             : {
     283             :     // Assuming zero rpm is safer as it will drive collective in the direction of increasing head speed
     284        7521 :     float current_rpm = 0.0;
     285             : 
     286             : #if AP_RPM_ENABLED
     287             :     // Get singleton for RPM library
     288        7521 :     const AP_RPM *rpm = AP_RPM::get_singleton();
     289             : 
     290             :     // Checking to ensure no nullptr, we do have a pre-arm check for this so it will be very bad if RPM has gone away
     291        7521 :     if (rpm == nullptr) {
     292           0 :         return false;
     293             :     }
     294             : 
     295             :     // Check RPM sensor is returning a healthy status
     296        7521 :     if (!rpm->get_rpm(_param_rpm_instance.get(), current_rpm)) {
     297           0 :         return false;
     298             :     }
     299             : #endif
     300             : 
     301             :     // Protect against div by zeros later in the code
     302        7521 :     float head_speed_set_point = MAX(1.0, _param_head_speed_set_point.get());
     303             : 
     304             :     // Normalize the RPM by the setpoint
     305        7521 :     norm_rpm = current_rpm/head_speed_set_point;
     306        7521 :     return true;
     307             : }
     308             : 
     309             : // Update speed controller
     310       14401 : void AC_Autorotation::update_forward_speed_controller(float pilot_accel_norm)
     311             : {
     312             :     // Limiting the desired velocity based on the max acceleration limit to get an update target
     313       14401 :     const float min_vel_ms = _target_vel_ms - get_accel_max_mss() * _dt;
     314       14401 :     const float max_vel_ms = _target_vel_ms + get_accel_max_mss() * _dt;
     315       14401 :     _target_vel_ms = constrain_float(_desired_vel_ms, min_vel_ms, max_vel_ms); // (m/s)
     316             : 
     317             :     // Calculate acceleration target
     318       14401 :     const float fwd_accel_target_mss  = _fwd_speed_pid.update_all(_target_vel_ms, get_speed_forward_ms(), _dt, _limit_accel); // (m/s/s)
     319             : 
     320             :     // Build the body frame XY accel vector.
     321             :     // Pilot can request as much as 1/2 of the max accel laterally to perform a turn.
     322             :     // We only allow up to half as we need to prioritize building/maintaining airspeed.
     323       14401 :     Vector2f bf_accel_target_mss = {fwd_accel_target_mss, pilot_accel_norm * get_accel_max_mss() * 0.5};
     324             : 
     325             :     // Ensure we do not exceed the accel limit
     326       14401 :     _limit_accel = bf_accel_target_mss.limit_length(get_accel_max_mss());
     327             : 
     328             :     // Calculate roll and pitch targets from angles, negative accel for negative pitch (pitch forward)
     329       14401 :     Vector2f angle_target_rad = { accel_mss_to_angle_rad(-bf_accel_target_mss.x), // Pitch
     330       14401 :                                   accel_mss_to_angle_rad(bf_accel_target_mss.y)}; // Roll
     331             : 
     332             :     // Ensure that the requested angles do not exceed angle max
     333       14401 :     _limit_accel |= angle_target_rad.limit_length(_attitude_control->lean_angle_max_rad());
     334             : 
     335             :     // we may have scaled the lateral accel in the angle limit scaling, so we need to
     336             :     // back calculate the resulting accel from this constrained angle for the yaw rate calc
     337       14401 :     const float bf_lat_accel_target_mss = angle_rad_to_accel_mss(angle_target_rad.y);
     338             : 
     339             :     // Calc yaw rate from desired body-frame accels
     340             :     // this seems suspiciously simple, but it is correct
     341             :     // accel = r * w^2, r = radius and w = angular rate
     342             :     // radius can be calculated as the distance traveled in the time it takes to do 360 deg
     343             :     // One rotation takes: (2*pi)/w seconds
     344             :     // Distance traveled in that time: (vel*2*pi)/w
     345             :     // radius for that distance: ((vel*2*pi)/w) / (2*pi)
     346             :     // r = vel / w
     347             :     // accel = (vel / w) * w^2
     348             :     // accel = vel * w
     349             :     // w = accel / vel
     350       14401 :     float yaw_rate_rads = 0.0;
     351       14401 :     if (!is_zero(_target_vel_ms)) {
     352        8920 :         yaw_rate_rads = bf_lat_accel_target_mss / _target_vel_ms;
     353             :     }
     354             : 
     355             :     // Output to attitude controller
     356       14401 :     _attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw_rad(angle_target_rad.y, angle_target_rad.x, yaw_rate_rads);
     357             : 
     358             : #if HAL_LOGGING_ENABLED
     359             :     // @LoggerMessage: ARSC
     360             :     // @Vehicles: Copter
     361             :     // @Description: Helicopter AutoRotation Speed Controller (ARSC) information 
     362             :     // @Field: TimeUS: Time since system startup
     363             :     // @Field: Des: Desired forward velocity
     364             :     // @Field: Tar: Target forward velocity
     365             :     // @Field: Act: Measured forward velocity
     366             :     // @Field: P: Velocity to acceleration P-term component
     367             :     // @Field: I: Velocity to acceleration I-term component
     368             :     // @Field: D: Velocity to acceleration D-term component
     369             :     // @Field: FF: Velocity to acceleration feed forward component
     370             :     // @Field: Lim: Accel limit flag
     371             :     // @Field: FA: Forward acceleration target
     372             :     // @Field: LA: Lateral acceleration target
     373             : 
     374       14401 :     const AP_PIDInfo& pid_info = _fwd_speed_pid.get_pid_info();
     375       28802 :     AP::logger().WriteStreaming("ARSC",
     376             :                                 "TimeUS,Des,Tar,Act,P,I,D,FF,Lim,FA,LA",
     377             :                                 "snnn-----oo",
     378             :                                 "F0000000-00",
     379             :                                 "QfffffffBff",
     380             :                                 AP_HAL::micros64(),
     381       14401 :                                 _desired_vel_ms,
     382       14401 :                                 pid_info.target,
     383       14401 :                                 pid_info.actual,
     384       14401 :                                 pid_info.P,
     385       14401 :                                 pid_info.I,
     386       14401 :                                 pid_info.D,
     387       14401 :                                 pid_info.FF,
     388       14401 :                                 uint8_t(_limit_accel),
     389       14401 :                                 bf_accel_target_mss.x,
     390       14401 :                                 bf_accel_target_mss.y);
     391             : #endif
     392       14401 : }
     393             : 
     394             : // smoothly zero velocity and accel
     395        7681 : void AC_Autorotation::run_landed(void)
     396             : {
     397        7681 :     _desired_vel_ms *= 0.95;
     398        7681 :     update_forward_speed_controller(0.0);
     399        7681 : }
     400             : 
     401             : // Determine the body frame forward speed
     402       14402 : float AC_Autorotation::get_speed_forward_ms(void) const
     403             : {
     404       14402 :     Vector3f vel_NED = {0,0,0};
     405       14402 :     const AP_AHRS &ahrs = AP::ahrs();
     406       14402 :     if (ahrs.get_velocity_NED(vel_NED)) {
     407       14402 :         vel_NED = ahrs.earth_to_body(vel_NED);
     408             :     }
     409             :     // TODO: need to improve the handling of the velocity NED not ok case
     410       14402 :     return vel_NED.x;
     411             : }
     412             : 
     413             : #if HAL_LOGGING_ENABLED
     414             : // Logging of lower rate autorotation specific variables. This is meant for stuff that
     415             : // doesn't need a high rate, e.g. controller variables that are need for tuning.
     416         848 : void AC_Autorotation::log_write_autorotation(void) const
     417             : {
     418             :     // enum class for bitmask documentation in logging
     419             :     enum class AC_Autorotation_Landed_Reason : uint8_t {
     420             :         LOW_SPEED = 1<<0, // true if below 1 m/s
     421             :         LAND_COL  = 1<<1, // true if collective below land col min
     422             :         IS_STILL  = 1<<2, // passes inertial nav is_still() check
     423             :     };
     424             : 
     425         848 :     uint8_t reason = 0;
     426         848 :     if (_landed_reason.min_speed) {
     427         474 :         reason |= uint8_t(AC_Autorotation_Landed_Reason::LOW_SPEED);
     428             :     }
     429         848 :     if (_landed_reason.land_col) {
     430         453 :         reason |= uint8_t(AC_Autorotation_Landed_Reason::LAND_COL);
     431             :     }
     432         848 :     if (_landed_reason.is_still) {
     433         833 :         reason |= uint8_t(AC_Autorotation_Landed_Reason::IS_STILL);
     434             :     }
     435             : 
     436             :     // @LoggerMessage: AROT
     437             :     // @Vehicles: Copter
     438             :     // @Description: Helicopter AutoROTation (AROT) information
     439             :     // @Field: TimeUS: Time since system startup
     440             :     // @Field: LR: Landed Reason state flags
     441             :     // @FieldBitmaskEnum: LR: AC_Autorotation_Landed_Reason
     442             : 
     443             :     // Write to data flash log
     444         848 :     AP::logger().WriteStreaming("AROT",
     445             :                                 "TimeUS,LR",
     446             :                                 "s-",
     447             :                                 "F-",
     448             :                                 "QB",
     449             :                                 AP_HAL::micros64(),
     450             :                                 reason);
     451         848 : }
     452             : #endif  // HAL_LOGGING_ENABLED
     453             : 
     454             : // Arming checks for autorotation, mostly checking for miss-configurations
     455        2339 : bool AC_Autorotation::arming_checks(size_t buflen, char *buffer) const
     456             : {
     457        2339 :     if (!enabled()) {
     458             :         // Don't run arming checks if not enabled
     459        2206 :         return true;
     460             :     }
     461             : 
     462             :     // Check for correct RPM sensor config
     463             : #if AP_RPM_ENABLED
     464             :     // Get singleton for RPM library
     465         133 :     const AP_RPM *rpm = AP_RPM::get_singleton();
     466             : 
     467             :     // Get current rpm, checking to ensure no nullptr
     468         133 :     if (rpm == nullptr) {
     469           0 :         hal.util->snprintf(buffer, buflen, "Can't access RPM");
     470           0 :         return false;
     471             :     }
     472             : 
     473             :     // Sanity check that the designated rpm sensor instance is there
     474         133 :     if (_param_rpm_instance.get() < 0) {
     475          21 :         hal.util->snprintf(buffer, buflen, "RPM instance <0");
     476          21 :         return false;
     477             :     }
     478             : 
     479         112 :     if (!rpm->enabled(_param_rpm_instance.get())) {
     480          32 :         hal.util->snprintf(buffer, buflen, "RPM%i not enabled", _param_rpm_instance.get()+1);
     481          32 :         return false;
     482             :     }
     483             : #endif
     484             : 
     485             :     // Check that heli motors is configured for autorotation
     486          80 :     if (!_motors_heli->rsc_autorotation_enabled()) {
     487          38 :         hal.util->snprintf(buffer, buflen, "H_RSC_AROT_* not configured");
     488          38 :         return false;
     489             :     }
     490             : 
     491          42 :     return true;
     492             : }
     493             : 
     494             : // Check if we believe we have landed. We need the landed state to zero all
     495             : // controls and make sure that the copter landing detector will trip
     496        6721 : bool AC_Autorotation::check_landed(void)
     497             : {
     498             :     // minimum speed (m/s) used for "is moving" check
     499        6721 :     const float min_moving_speed = 1.0;
     500             : 
     501        6721 :     Vector3f velocity;
     502        6721 :     const AP_AHRS &ahrs = AP::ahrs();
     503        6721 :     _landed_reason.min_speed = ahrs.get_velocity_NED(velocity) && (velocity.length() < min_moving_speed);
     504        6721 :     _landed_reason.land_col = _motors_heli->get_below_land_min_coll();
     505        6721 :     _landed_reason.is_still = AP::ins().is_still();
     506             : 
     507        6721 :     return _landed_reason.min_speed && _landed_reason.land_col && _landed_reason.is_still;
     508             : }
     509             : 
     510             : // Dynamically update time step used in autorotation controllers
     511       14401 : void AC_Autorotation::set_dt(float delta_sec)
     512             : {
     513       14401 :     if (is_positive(delta_sec)) {
     514       14401 :         _dt = delta_sec;
     515       14401 :         return;
     516             :     }
     517           0 :     _dt = 2.5e-3; // Assume 400 Hz
     518             : }

Generated by: LCOV version 1.14