LCOV - code coverage report
Current view: top level - home/pbarker/rc/ardupilot/ArduCopter - mode_land.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 66 71 93.0 %
Date: 2026-09-09 11:02:08 Functions: 9 10 90.0 %

          Line data    Source code
       1             : #include "Copter.h"
       2             : 
       3             : // table of user settable parameters
       4             : const AP_Param::GroupInfo ModeLand::var_info[] = {
       5             : 
       6             :     // @Param: SPD_MS
       7             :     // @DisplayName: Land speed
       8             :     // @Description: The descent speed for the final stage of landing in m/s
       9             :     // @Units: m/s
      10             :     // @Range: 0.3 2
      11             :     // @Increment: 0.1
      12             :     // @User: Standard
      13             :     AP_GROUPINFO("SPD_MS", 1, ModeLand, land_speed_ms, LAND_SPD_MS_DEFAULT),
      14             : 
      15             :     // @Param: SPD_HIGH_MS
      16             :     // @DisplayName: Land speed high
      17             :     // @Description: The descent speed for the first stage of landing in m/s. If this is zero then WP_SPD_DN is used
      18             :     // @Units: m/s
      19             :     // @Range: 0 5
      20             :     // @Increment: 0.1
      21             :     // @User: Standard
      22             :     AP_GROUPINFO("SPD_HIGH_MS", 2, ModeLand, land_speed_high_ms, 0),
      23             : 
      24             :     // @Param: ALT_LOW_M
      25             :     // @DisplayName: Land alt low
      26             :     // @Description: Altitude during Landing at which vehicle slows to LAND_SPD_MS
      27             :     // @Units: m
      28             :     // @Range: 1 100
      29             :     // @Increment: 0.1
      30             :     // @User: Advanced
      31             :     AP_GROUPINFO("ALT_LOW_M", 3, ModeLand, land_alt_low_m, 10),
      32             : 
      33             :     AP_GROUPEND
      34             : };
      35             : 
      36             : // constructor
      37        1001 : ModeLand::ModeLand() : Mode()
      38             : {
      39             :     // load parameter defaults
      40        1001 :     AP_Param::setup_object_defaults(this, var_info);
      41        1001 : }
      42             : 
      43             : // convert parameters
      44        1001 : void ModeLand::convert_params()
      45             : {
      46             :     // PARAMETER_CONVERSION - Added: Jan-2026 for ArduPilot-4.7
      47             : 
      48             :     // return immediately if parameter conversion has already been performed
      49        1001 :     if (land_speed_ms.configured() || land_speed_high_ms.configured() || land_alt_low_m.configured()) {
      50           9 :         return;
      51             :     }
      52             : 
      53             :     static const AP_Param::ConversionInfo conversion_info[] = {
      54             :         { Parameters::k_param_land_speed_cms, 0, AP_PARAM_INT16, "LAND_SPD_MS" },     // LAND_SPEED moved to LAND_SPD_MS
      55             :         { Parameters::k_param_land_speed_high_cms, 0, AP_PARAM_INT16, "LAND_SPD_HIGH_MS" },   // LAND_SPEED_HIGH moved to LAND_SPD_HIGH_MS
      56             :         { Parameters::k_param_g2, 25, AP_PARAM_INT16, "LAND_ALT_LOW_M" },  // LAND_ALT_LOW moved to LAND_ALT_LOW_M
      57             :     };
      58         992 :     AP_Param::convert_old_parameters_scaled(conversion_info, ARRAY_SIZE(conversion_info), 0.01, 0);
      59             : }
      60             : 
      61             : // land_init - initialise land controller
      62         102 : bool ModeLand::init(bool ignore_checks)
      63             : {
      64             :     // check if we have GPS and decide which LAND we're going to do
      65         102 :     control_position = copter.position_ok();
      66             : 
      67             :     // set horizontal speed and acceleration limits
      68         102 :     pos_control->NE_set_max_speed_accel_m(wp_nav->get_default_speed_NE_ms(), wp_nav->get_wp_acceleration_mss());
      69         102 :     pos_control->NE_set_correction_speed_accel_m(wp_nav->get_default_speed_NE_ms(), wp_nav->get_wp_acceleration_mss());
      70             : 
      71             :     // initialise the horizontal position controller
      72         102 :     if (control_position && !pos_control->NE_is_active()) {
      73          22 :         pos_control->NE_init_controller();
      74             :     }
      75             : 
      76             :     // set vertical speed and acceleration limits
      77         102 :     pos_control->D_set_max_speed_accel_m(wp_nav->get_default_speed_down_ms(), wp_nav->get_default_speed_up_ms(), wp_nav->get_accel_D_mss());
      78         102 :     pos_control->D_set_correction_speed_accel_m(wp_nav->get_default_speed_down_ms(), wp_nav->get_default_speed_up_ms(), wp_nav->get_accel_D_mss());
      79             : 
      80             :     // initialise the vertical position controller
      81         102 :     if (!pos_control->D_is_active()) {
      82          10 :         pos_control->D_init_controller();
      83             :     }
      84             : 
      85         102 :     land_start_time = millis();
      86         102 :     land_pause = false;
      87             : 
      88             :     // reset flag indicating if pilot has applied roll or pitch inputs during landing
      89         102 :     copter.ap.land_repo_active = false;
      90             : 
      91             :     // this will be set true if prec land is later active
      92         102 :     copter.ap.prec_land_active = false;
      93             : 
      94             :     // initialise yaw
      95         102 :     auto_yaw.set_mode(AutoYaw::Mode::HOLD);
      96             : 
      97             : #if AP_LANDINGGEAR_ENABLED
      98             :     // optionally deploy landing gear
      99         102 :     copter.landinggear.deploy_for_landing();
     100             : #endif
     101             : 
     102             : #if AC_PRECLAND_ENABLED
     103             :     // initialise precland state machine
     104         102 :     copter.precland_statemachine.init();
     105             : #endif
     106             : 
     107         102 :     return true;
     108             : }
     109             : 
     110             : // land_run - runs the land controller
     111             : // should be called at 100hz or more
     112     1101496 : void ModeLand::run()
     113             : {
     114     1101496 :     if (control_position) {
     115     1000133 :         gps_run();
     116             :     } else {
     117      101363 :         nogps_run();
     118             :     }
     119     1101496 : }
     120             : 
     121             : // land_gps_run - runs the land controller
     122             : //      horizontal position controlled with loiter controller
     123             : //      should be called at 100hz or more
     124     1000133 : void ModeLand::gps_run()
     125             : {
     126             :     // disarm when the landing detector says we've landed
     127     1000133 :     if (copter.ap.land_complete && motors->get_spool_state() == AP_Motors::SpoolState::GROUND_IDLE) {
     128          86 :         copter.arming.disarm(AP_Arming::Method::LANDED);
     129             :     }
     130             : 
     131             :     // Land State Machine Determination
     132     1000133 :     if (is_disarmed_or_landed()) {
     133      133866 :         make_safe_ground_handling();
     134             :     } else {
     135             :         // set motors to full range
     136      866267 :         motors->set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
     137             : 
     138             :         // pause before beginning land descent
     139      866267 :         if (land_pause && millis()-land_start_time >= LAND_WITH_DELAY_MS) {
     140          11 :             land_pause = false;
     141             :         }
     142             : 
     143             :         // run normal landing or precision landing (if enabled)
     144      866267 :         land_run_normal_or_precland(land_pause);
     145             :     }
     146     1000133 : }
     147             : 
     148             : // land_nogps_run - runs the land controller
     149             : //      pilot controls roll and pitch angles
     150             : //      should be called at 100hz or more
     151      101363 : void ModeLand::nogps_run()
     152             : {
     153      101363 :     float target_roll_rad = 0.0f, target_pitch_rad = 0.0f;
     154             : 
     155             :     // process pilot inputs
     156      101363 :     if (rc().has_valid_input()) {
     157             : #if MODE_ALTHOLD_ENABLED
     158       31793 :         if ((g.throttle_behavior & THR_BEHAVE_HIGH_THROTTLE_CANCELS_LAND) != 0 && copter.rc_throttle_control_in_filter.get() > LAND_CANCEL_TRIGGER_THR){
     159           0 :             LOGGER_WRITE_EVENT(LogEvent::LAND_CANCELLED_BY_PILOT);
     160             :             // exit land if throttle is high
     161           0 :             copter.set_mode(Mode::Number::ALT_HOLD, ModeReason::THROTTLE_LAND_ESCAPE);
     162             :         }
     163             : #endif
     164             : 
     165       31793 :         if (g.land_repositioning) {
     166             :             // get pilot desired lean angles
     167       31793 :             get_pilot_desired_lean_angles_rad(target_roll_rad, target_pitch_rad, attitude_control->lean_angle_max_rad(), attitude_control->get_althold_lean_angle_max_rad());
     168             :         }
     169             :     }
     170             : 
     171             :     // disarm when the landing detector says we've landed
     172      101363 :     if (copter.ap.land_complete && motors->get_spool_state() == AP_Motors::SpoolState::GROUND_IDLE) {
     173           4 :         copter.arming.disarm(AP_Arming::Method::LANDED);
     174             :     }
     175             : 
     176             :     // Land State Machine Determination
     177      101363 :     if (is_disarmed_or_landed()) {
     178       12423 :         make_safe_ground_handling();
     179             :     } else {
     180             :         // set motors to full range
     181       88940 :         motors->set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
     182             : 
     183             :         // pause before beginning land descent
     184       88940 :         if (land_pause && millis()-land_start_time >= LAND_WITH_DELAY_MS) {
     185           5 :             land_pause = false;
     186             :         }
     187             : 
     188       88940 :         land_run_vertical_control(land_pause);
     189             :     }
     190             : 
     191             :     // call attitude controller
     192      101363 :     attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw_rad(target_roll_rad, target_pitch_rad, auto_yaw.get_heading().yaw_rate_rads);
     193      101363 : }
     194             : 
     195             : // do_not_use_GPS - forces land-mode to not use the GPS but instead rely on pilot input for roll and pitch
     196             : //  called during GPS failsafe to ensure that if we were already in LAND mode that we do not use the GPS
     197             : //  has no effect if we are not already in LAND mode
     198           0 : void ModeLand::do_not_use_GPS()
     199             : {
     200           0 :     control_position = false;
     201           0 : }
     202             : 
     203             : // returns true if pilot's yaw input should be used to adjust vehicle's heading
     204     4299913 : bool ModeLand::use_pilot_yaw() const
     205             : {
     206             :     // only accept yaw input if repositioning is enabled
     207     4299913 :     return g.land_repositioning;
     208             : }
     209             : 
     210             : // set_mode_land_with_pause - sets mode to LAND and triggers 4 second delay before descent starts
     211             : //  this is always called from a failsafe so we trigger notification to pilot
     212          17 : void Copter::set_mode_land_with_pause(ModeReason reason)
     213             : {
     214          17 :     set_mode(Mode::Number::LAND, reason);
     215          17 :     mode_land.set_land_pause(true);
     216             : 
     217             :     // alert pilot to mode change
     218          17 :     AP_Notify::events.failsafe_mode_change = 1;
     219          17 : }
     220             : 
     221             : // landing_with_GPS - returns true if vehicle is landing using GPS
     222      715778 : bool Copter::landing_with_GPS()
     223             : {
     224      770806 :     return (flightmode->mode_number() == Mode::Number::LAND &&
     225      770806 :             mode_land.controlling_position());
     226             : }

Generated by: LCOV version 1.14