LCOV - code coverage report
Current view: top level - AP_LandingGear - AP_LandingGear.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 76 121 62.8 %
Date: 2026-09-09 11:02:08 Functions: 10 14 71.4 %

          Line data    Source code
       1             : #include "AP_LandingGear.h"
       2             : 
       3             : #if AP_LANDINGGEAR_ENABLED
       4             : 
       5             : #include <AP_Math/AP_Math.h>
       6             : #include <SRV_Channel/SRV_Channel.h>
       7             : #include <AP_HAL/AP_HAL.h>
       8             : #include <AP_Logger/AP_Logger.h>
       9             : #include <GCS_MAVLink/GCS.h>
      10             : 
      11             : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
      12             : #include <SITL/SITL.h>
      13             : #endif
      14             : 
      15             : #if defined(APM_BUILD_TYPE)
      16             : //  - this is just here to encourage the build system to supply the "legacy build defines".  The actual dependecy is in the AP_LandingGear.h and AP_LandingGear_config.h headers
      17             : #endif
      18             : 
      19             : extern const AP_HAL::HAL& hal;
      20             : 
      21             : const AP_Param::GroupInfo AP_LandingGear::var_info[] = {
      22             : 
      23             :     // 0 and 1 used by previous retract and deploy pwm, now replaced with SERVOn_MIN/MAX/REVERSED
      24             : 
      25             :     // @Param: ENABLE
      26             :     // @DisplayName: Enable landing gear
      27             :     // @Description: Enable landing gear control
      28             :     // @Values: 0:Disabled, 1:Enabled
      29             :     // @User: Standard
      30             :     AP_GROUPINFO_FLAGS("ENABLE", 10, AP_LandingGear, _enable, 0, AP_PARAM_FLAG_ENABLE),
      31             : 
      32             :     // @Param: STARTUP
      33             :     // @DisplayName: Landing Gear Startup position
      34             :     // @Description: Landing Gear Startup behaviour control
      35             :     // @Values: 0:WaitForPilotInput, 1:Retract, 2:Deploy
      36             :     // @User: Standard
      37             :     AP_GROUPINFO("STARTUP", 2, AP_LandingGear, _startup_behaviour, (uint8_t)AP_LandingGear::LandingGear_Startup_WaitForPilotInput),
      38             : 
      39             :     // @Param: DEPLOY_PIN
      40             :     // @DisplayName: Chassis deployment feedback pin
      41             :     // @Description: Pin number to use for detection of gear deployment. If set to -1 feedback is disabled. Some common values are given, but see the Wiki's "GPIOs" page for how to determine the pin number for a given autopilot.
      42             :     // @Values: -1:Disabled,50:AUX1,51:AUX2,52:AUX3,53:AUX4,54:AUX5,55:AUX6
      43             :     // @Range: -1 127
      44             :     // @User: Standard
      45             :     // @RebootRequired: True
      46             :     AP_GROUPINFO("DEPLOY_PIN", 3, AP_LandingGear, _pin_deployed, -1),
      47             : 
      48             :     // @Param: DEPLOY_POL
      49             :     // @DisplayName: Chassis deployment feedback pin polarity
      50             :     // @Description: Polarity for feedback pin. If this is 1 then the pin should be high when gear are deployed. If set to 0 then then deployed gear level is low.
      51             :     // @Values: 0:Low,1:High
      52             :     // @User: Standard
      53             :     AP_GROUPINFO("DEPLOY_POL", 4, AP_LandingGear, _pin_deployed_polarity, 0),
      54             : 
      55             :     // @Param: WOW_PIN
      56             :     // @DisplayName: Weight on wheels feedback pin
      57             :     // @Description: Pin number to use for feedback of weight on wheels condition. If set to -1 feedback is disabled. Some common values are given, but see the Wiki's "GPIOs" page for how to determine the pin number for a given autopilot.
      58             :     // @Values: -1:Disabled,50:AUX1,51:AUX2,52:AUX3,53:AUX4,54:AUX5,55:AUX6
      59             :     // @Range: -1 127
      60             :     // @User: Standard
      61             :     // @RebootRequired: True
      62             :     AP_GROUPINFO("WOW_PIN", 5, AP_LandingGear, _pin_weight_on_wheels, -1),
      63             : 
      64             :     // @Param: WOW_POL
      65             :     // @DisplayName: Weight on wheels feedback pin polarity
      66             :     // @Description: Polarity for feedback pin. If this is 1 then the pin should be high when there is weight on wheels. If set to 0 then then weight on wheels level is low.
      67             :     // @Values: 0:Low,1:High
      68             :     // @User: Standard
      69             :     AP_GROUPINFO("WOW_POL", 6, AP_LandingGear, _pin_weight_on_wheels_polarity, 0),
      70             : 
      71             :     // @Param: DEPLOY_ALT
      72             :     // @DisplayName: Landing gear deployment altitude
      73             :     // @Description: Altitude where the landing gear will be deployed. This should be lower than the RETRACT_ALT. If zero then altitude is not used for deploying landing gear. Only applies when vehicle is armed.
      74             :     // @Units: m
      75             :     // @Range: 0 1000
      76             :     // @Increment: 1
      77             :     // @User: Standard
      78             :     AP_GROUPINFO("DEPLOY_ALT", 7, AP_LandingGear, _deploy_alt_m, 0),
      79             : 
      80             :     // @Param: RETRACT_ALT
      81             :     // @DisplayName: Landing gear retract altitude
      82             :     // @Description: Altitude where the landing gear will be retracted. This should be higher than the DEPLOY_ALT. If zero then altitude is not used for retracting landing gear. Only applies when vehicle is armed.
      83             :     // @Units: m
      84             :     // @Range: 0 1000
      85             :     // @Increment: 1
      86             :     // @User: Standard
      87             :     AP_GROUPINFO("RETRACT_ALT", 8, AP_LandingGear, _retract_alt_m, 0),
      88             : 
      89             :     // @Param: OPTIONS
      90             :     // @DisplayName: Landing gear auto retract/deploy options
      91             :     // @Description{Copter}: Options to retract or deploy landing gear in Auto or Guided mode
      92             :     // @Description{Plane}: Options to retract or deploy landing gear in Auto, Takeoff and Autoland modes
      93             :     // @Bitmask: 0:Retract after Takeoff,1:Deploy during Land
      94             :     // @User: Standard
      95             :     AP_GROUPINFO("OPTIONS", 9, AP_LandingGear, _options, 3),
      96             : 
      97             :     // index 10 is enable, placed at the top of the table
      98             : 
      99             :     AP_GROUPEND
     100             : };
     101             : 
     102             : AP_LandingGear *AP_LandingGear::_singleton;
     103             : 
     104             : /// initialise state of landing gear
     105        1693 : void AP_LandingGear::init()
     106             : {
     107             : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
     108        1693 :     if (AP::sitl()->wow_pin > 0) {
     109           0 :         _pin_weight_on_wheels.set_and_default(AP::sitl()->wow_pin);
     110           0 :         _pin_weight_on_wheels_polarity.set_and_default(1);
     111             :     }
     112             : #endif
     113             : 
     114        3375 :     if (!_enable.configured() && (SRV_Channels::function_assigned(SRV_Channel::k_landing_gear_control) || 
     115        1682 :             (_pin_deployed > 0) || (_pin_weight_on_wheels > 0))) {
     116             :         // if not configured set enable param if output servo or sense pins are defined
     117           0 :         _enable.set_and_save(1);
     118             :     }
     119             : 
     120        1693 :     if (_pin_deployed != -1) {
     121           0 :         hal.gpio->pinMode(_pin_deployed, HAL_GPIO_INPUT);
     122             :         // set pullup/pulldown to default to non-deployed state
     123           0 :         hal.gpio->write(_pin_deployed, !_pin_deployed_polarity);
     124           0 :         log_wow_state(wow_state_current);
     125             :     }
     126             : 
     127        1693 :     if (_pin_weight_on_wheels != -1) {
     128           0 :         hal.gpio->pinMode(_pin_weight_on_wheels, HAL_GPIO_INPUT);
     129             :         // set pullup/pulldown to default to flying state
     130           0 :         hal.gpio->write(_pin_weight_on_wheels, !_pin_weight_on_wheels_polarity);
     131           0 :         log_wow_state(wow_state_current);
     132             :     }
     133             : 
     134        1693 :     switch ((enum LandingGearStartupBehaviour)_startup_behaviour.get()) {
     135        1693 :         default:
     136             :         case LandingGear_Startup_WaitForPilotInput:
     137             :             // do nothing
     138        1693 :             break;
     139           0 :         case LandingGear_Startup_Retract:
     140           0 :             retract();
     141           0 :             break;
     142           0 :         case LandingGear_Startup_Deploy:
     143           0 :             deploy();
     144           0 :             break;
     145             :     }
     146        1693 : }
     147             : 
     148             : /// set landing gear position to retract, deploy or deploy-and-keep-deployed
     149          17 : void AP_LandingGear::set_position(LandingGearCommand cmd)
     150             : {
     151          17 :     switch (cmd) {
     152           1 :         case LandingGear_Retract:
     153           1 :             retract();
     154           1 :             break;
     155          16 :         case LandingGear_Deploy:
     156          16 :             deploy();
     157          16 :             break;
     158             :     }
     159          17 : }
     160             : 
     161             : /// deploy - deploy landing gear
     162         710 : void AP_LandingGear::deploy()
     163             : {
     164         710 :     if (!_enable) {
     165         705 :         return;
     166             :     }
     167             : 
     168             :     // set servo and send message only if output has been configured and not already deployed
     169           9 :     if (!_deployed &&
     170           4 :         SRV_Channels::function_assigned(SRV_Channel::k_landing_gear_control)) {
     171           4 :         GCS_SEND_TEXT(MAV_SEVERITY_INFO, "LandingGear: DEPLOY");
     172             :         // set deployed flag
     173           4 :         _deployed = true;
     174           4 :         _have_changed = true;
     175           4 :         LOGGER_WRITE_EVENT(LogEvent::LANDING_GEAR_DEPLOYED);
     176             :         // set servo PWM to deployed position
     177           4 :         SRV_Channels::set_output_limit(SRV_Channel::k_landing_gear_control, SRV_Channel::Limit::MAX);
     178             :     }
     179             : }
     180             : 
     181             : /// retract - retract landing gear
     182         269 : void AP_LandingGear::retract()
     183             : {
     184         269 :     if (!_enable) {
     185         267 :         return;
     186             :     }
     187             :     
     188             :     // set servo and send message only if output has been configured and already deployed
     189           4 :     if ((_deployed || !_have_changed ) &&
     190           2 :         SRV_Channels::function_assigned(SRV_Channel::k_landing_gear_control)) {
     191           2 :         GCS_SEND_TEXT(MAV_SEVERITY_INFO, "LandingGear: RETRACT");
     192             :         // reset deployed flag
     193           2 :         _deployed = false;
     194           2 :         _have_changed = true;
     195           2 :         LOGGER_WRITE_EVENT(LogEvent::LANDING_GEAR_RETRACTED);
     196             :         // set servo PWM to retracted position
     197           2 :         SRV_Channels::set_output_limit(SRV_Channel::k_landing_gear_control, SRV_Channel::Limit::MIN);
     198             :     }
     199             : }
     200             : 
     201           0 : bool AP_LandingGear::deployed()
     202             : {
     203           0 :     if (_pin_deployed == -1) {
     204           0 :         return _deployed;
     205             :     } else {
     206           0 :         return hal.gpio->read(_pin_deployed) == _pin_deployed_polarity;
     207             :     }
     208             : }
     209             : 
     210    55206906 : AP_LandingGear::LG_WOW_State AP_LandingGear::get_wow_state()
     211             : {
     212    55206906 :     return wow_state_current;
     213             : }
     214             : 
     215         110 : AP_LandingGear::LG_LandingGear_State AP_LandingGear::get_state()
     216             : {
     217         110 :     return gear_state_current;
     218             : }
     219             : 
     220           0 : uint32_t AP_LandingGear::get_gear_state_duration_ms() const
     221             : {
     222           0 :     if (last_gear_event_ms == 0) {
     223           0 :         return 0;
     224             :     }
     225             : 
     226           0 :     return AP_HAL::millis() - last_gear_event_ms;
     227             : }
     228             : 
     229           0 : uint32_t AP_LandingGear::get_wow_state_duration_ms() const
     230             : {
     231           0 :     if (last_wow_event_ms == 0) {
     232           0 :         return 0;
     233             :     }
     234             : 
     235           0 :     return AP_HAL::millis() - last_wow_event_ms;
     236             : }
     237             : 
     238      273670 : void AP_LandingGear::update(float height_above_ground_m)
     239             : {
     240      273670 :     if (_pin_weight_on_wheels == -1) {
     241      273670 :         last_wow_event_ms = 0;
     242      273670 :         wow_state_current = LG_WOW_UNKNOWN;
     243             :     } else {
     244           0 :         LG_WOW_State wow_state_new = hal.gpio->read(_pin_weight_on_wheels) == _pin_weight_on_wheels_polarity ? LG_WOW : LG_NO_WOW;
     245             : 
     246           0 :         if (wow_state_new != wow_state_current) {
     247             :             // we changed states, lets note the time.
     248           0 :             last_wow_event_ms = AP_HAL::millis();
     249           0 :             log_wow_state(wow_state_new);
     250             :         }
     251             : 
     252           0 :         wow_state_current = wow_state_new;
     253             :     }
     254             : 
     255      273670 :     if (_pin_deployed == -1) {
     256      273670 :         last_gear_event_ms = 0;
     257             : 
     258             :         // If there was no pilot input and state is still unknown - leave it as it is
     259      273670 :         if (gear_state_current != LG_UNKNOWN) {
     260           0 :             gear_state_current = (_deployed == true ? LG_DEPLOYED : LG_RETRACTED);
     261             :         }
     262             :     } else {
     263             :         LG_LandingGear_State gear_state_new;
     264             :         
     265           0 :         if (_deployed) {
     266           0 :             gear_state_new = (deployed() == true ? LG_DEPLOYED : LG_DEPLOYING);
     267             :         } else {
     268           0 :             gear_state_new = (deployed() == false ? LG_RETRACTED : LG_RETRACTING);
     269             :         }
     270             : 
     271           0 :         if (gear_state_new != gear_state_current) {
     272             :             // we changed states, lets note the time.
     273           0 :             last_gear_event_ms = AP_HAL::millis();
     274             :             
     275           0 :             log_wow_state(wow_state_current);
     276             :         }
     277             : 
     278           0 :         gear_state_current = gear_state_new;
     279             :     }
     280             : 
     281             :     /*
     282             :       check for height based triggering
     283             :      */
     284      273670 :     float alt_m = MAX(height_above_ground_m, 0.0);
     285             : 
     286      273670 :     if (hal.util->get_soft_armed()) {
     287             :         // only do height based triggering when armed
     288      621436 :         if (!_deployed  &&
     289      207122 :             _deploy_alt_m > 0 &&
     290      414281 :             alt_m <= _deploy_alt_m &&
     291           2 :             _last_height_above_ground_m > _deploy_alt_m) {
     292           2 :             deploy();
     293      207120 :         } else if ((_deployed || !_have_changed)&&
     294      207153 :                 _retract_alt_m > 0 &&
     295          38 :                  _retract_alt_m >= _deploy_alt_m &&
     296      414311 :                 alt_m >= _retract_alt_m &&
     297           1 :                 _last_height_above_ground_m < _retract_alt_m) {
     298           1 :                 retract();
     299             :         }
     300             :     }
     301             : 
     302      273670 :     _last_height_above_ground_m = alt_m;
     303      273670 : }
     304             : 
     305             : #if HAL_LOGGING_ENABLED
     306             : // log weight on wheels state
     307           0 : void AP_LandingGear::log_wow_state(LG_WOW_State state)
     308             : {
     309           0 :     AP::logger().Write("LGR", "TimeUS,LandingGear,WeightOnWheels", "Qbb",
     310             :                                            AP_HAL::micros64(),
     311           0 :                                            (int8_t)gear_state_current, (int8_t)state);
     312           0 : }
     313             : #endif
     314             : 
     315         110 : bool AP_LandingGear::check_before_land(void)
     316             : {
     317             :     // If the landing gear state is not known (most probably as it is not used)
     318         110 :     if (get_state() == LG_UNKNOWN) {
     319         110 :         return true;
     320             :     }
     321             : 
     322             :     // If the landing gear was not used - return true, otherwise - check for deployed
     323           0 :     return (get_state() == LG_DEPLOYED);
     324             : }
     325             : 
     326             : // retract after takeoff if configured via the OPTIONS parameter
     327         267 : void AP_LandingGear::retract_after_takeoff()
     328             : {
     329         267 :     if (_options.get() & (uint16_t)Option::RETRACT_AFTER_TAKEOFF) {
     330         267 :         retract();
     331             :     }
     332         267 : }
     333             : 
     334             : // deploy for landing if configured via the OPTIONS parameter
     335         692 : void AP_LandingGear::deploy_for_landing()
     336             : {
     337         692 :     if (_options.get() & (uint16_t)Option::DEPLOY_DURING_LANDING) {
     338         692 :         deploy();
     339             :     }
     340         692 : }
     341             : 
     342             : #endif

Generated by: LCOV version 1.14