LCOV - code coverage report
Current view: top level - home/pbarker/rc/ardupilot/Rover - system.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 120 128 93.8 %
Date: 2026-09-09 11:02:08 Functions: 12 14 85.7 %

          Line data    Source code
       1             : #include "Rover.h"
       2             : 
       3    15369390 : static void failsafe_check_static()
       4             : {
       5    15369390 :     rover.failsafe_check();
       6    15369390 : }
       7             : 
       8         285 : void Rover::init_ardupilot()
       9             : {
      10             :     // initialise notify system
      11         285 :     notify.init();
      12         285 :     notify_mode(control_mode);
      13             : 
      14         285 :     battery.init();
      15             : 
      16             : #if AP_RSSI_ENABLED
      17         285 :     rssi.init();
      18             : #endif
      19             : 
      20         285 :     g2.windvane.init(serial_manager);
      21             : 
      22             :     // init baro before we start the GCS, so that the CLI baro test works
      23         285 :     barometer.init();
      24             : 
      25             :     // setup telem slots with serial ports
      26         285 :     gcs().setup_uarts();
      27             : 
      28             : #if OSD_ENABLED
      29         285 :     osd.init();
      30             : #endif
      31             : 
      32             :     // initialise compass
      33         285 :     AP::compass().set_log_bit(MASK_LOG_COMPASS);
      34         285 :     AP::compass().init();
      35             : 
      36             : #if AP_AIRSPEED_ENABLED
      37         285 :     airspeed.set_log_bit(MASK_LOG_IMU);
      38             : #endif
      39             : 
      40             : #if AP_RANGEFINDER_ENABLED
      41             :     // initialise rangefinder
      42         285 :     rangefinder.set_log_rfnd_bit(MASK_LOG_RANGEFINDER);
      43         285 :     rangefinder.init(ROTATION_NONE);
      44             : #endif
      45             : 
      46             : #if HAL_PROXIMITY_ENABLED
      47             :     // init proximity sensor
      48         285 :     g2.proximity.init();
      49             : #endif
      50             : 
      51             :     // and baro for EKF
      52         285 :     barometer.set_log_baro_bit(MASK_LOG_IMU);
      53         285 :     barometer.calibrate();
      54             : 
      55             :     // Do GPS init
      56         283 :     gps.set_log_gps_bit(MASK_LOG_GPS);
      57         283 :     gps.init();
      58             : 
      59         283 :     ins.set_log_raw_bit(MASK_LOG_IMU_RAW);
      60             : 
      61         283 :     init_rc_in();            // sets up rc channels deadzone
      62         283 :     g2.motors.init(get_frame_type());        // init motors including setting servo out channels ranges
      63         283 :     AP::srv().enable_aux_servos();
      64             : 
      65             :     // init wheel encoders
      66         283 :     g2.wheel_encoder.init();
      67             : 
      68             : #if HAL_TORQEEDO_ENABLED
      69             :     // init torqeedo motor driver
      70         283 :     g2.torqeedo.init();
      71             : #endif
      72             : 
      73             : #if AP_OPTICALFLOW_ENABLED
      74             :     // initialise optical flow sensor
      75         283 :     optflow.init(MASK_LOG_OPTFLOW);
      76             : #endif      // AP_OPTICALFLOW_ENABLED
      77             : 
      78             : #if AP_RELAY_ENABLED
      79         283 :     relay.init();
      80             : #endif
      81             : 
      82             : #if HAL_MOUNT_ENABLED
      83             :     // initialise camera mount
      84         283 :     camera_mount.init();
      85             : #endif
      86             : 
      87             : #if AP_CAMERA_ENABLED
      88             :     // initialise camera
      89         283 :     camera.init();
      90             : #endif
      91             : 
      92             : #if AC_PRECLAND_ENABLED
      93             :     // initialise precision landing
      94         283 :     init_precland();
      95             : #endif
      96             : 
      97             :     /*
      98             :       setup the 'main loop is dead' check. Note that this relies on
      99             :       the RC library being initialised.
     100             :      */
     101         283 :     hal.scheduler->register_timer_failsafe(failsafe_check_static, 1000);
     102             : 
     103             :     // initialize SmartRTL
     104         283 :     g2.smart_rtl.init();
     105             : 
     106             : #if AP_OAPATHPLANNER_ENABLED
     107             :     // initialise object avoidance
     108         283 :     g2.oa.init();
     109             : #endif
     110             : 
     111         283 :     set_mode(mode_initializing, ModeReason::INITIALISED);
     112             : 
     113         283 :     startup_INS();
     114             : 
     115             : #if AP_MISSION_ENABLED
     116             :     // initialise mission library
     117         283 :     mode_auto.mission.init();
     118             : #if HAL_LOGGING_ENABLED
     119         283 :     mode_auto.mission.set_log_start_mission_item_bit(MASK_LOG_CMD);
     120             : #endif
     121             : #endif
     122             : 
     123             :     // initialise AP_Logger library
     124             : #if HAL_LOGGING_ENABLED
     125         283 :     logger.setVehicle_Startup_Writer(
     126             :         FUNCTOR_BIND(&rover, &Rover::Log_Write_Vehicle_Startup_Messages, void)
     127             :         );
     128             : #endif
     129             : 
     130         283 :     Mode *initial_mode = mode_from_mode_num((enum Mode::Number)g.initial_mode.get());
     131         283 :     if (initial_mode == nullptr) {
     132           0 :         initial_mode = &mode_initializing;
     133             :     }
     134         283 :     set_mode(*initial_mode, ModeReason::INITIALISED);
     135             : 
     136             :     // initialise rc channels
     137         283 :     rc().init();
     138             : 
     139         283 :     rover.g2.sailboat.init();
     140             : 
     141             :     // boat should loiter after completing a mission to avoid drifting off
     142         283 :     if (is_boat()) {
     143           7 :         rover.g2.mis_done_behave.set_default(uint8_t(ModeAuto::DoneBehaviour::LOITER));
     144             :     }
     145             : 
     146             :     // flag that initialisation has completed
     147         283 :     initialised = true;
     148         283 : }
     149             : 
     150             : // update the ahrs flyforward setting which can allow
     151             : // the vehicle's movements to be used to estimate heading
     152      629048 : void Rover::update_ahrs_flyforward()
     153             : {
     154      629048 :     bool flyforward = false;
     155             : 
     156             :     // boats never use movement to estimate heading
     157      629048 :     if (!is_boat()) {
     158             :         // throttle threshold is 15% or 1/2 cruise throttle
     159      578737 :         bool throttle_over_thresh = g2.motors.get_throttle() > MIN(g.throttle_cruise * 0.50f, 15.0f);
     160             :         // desired speed threshold of 1m/s
     161      578737 :         bool desired_speed_over_thresh = g2.attitude_control.speed_control_active() && (g2.attitude_control.get_desired_speed() > 0.5f);
     162      578737 :         if (throttle_over_thresh || (is_positive(g2.motors.get_throttle()) && desired_speed_over_thresh)) {
     163      144866 :             uint32_t now = AP_HAL::millis();
     164             :             // if throttle over threshold start timer
     165      144866 :             if (flyforward_start_ms == 0) {
     166         186 :                 flyforward_start_ms = now;
     167             :             }
     168             :             // if throttle over threshold for 2 seconds set flyforward to true
     169      144866 :             flyforward = (now - flyforward_start_ms > 2000);
     170             :         } else {
     171             :             // reset timer
     172      433871 :             flyforward_start_ms = 0;
     173             :         }
     174             :     }
     175             : 
     176      629048 :     ahrs.set_fly_forward(flyforward);
     177      629048 : }
     178             : 
     179             : // Check if this mode can be entered from the GCS
     180      138294 : bool Rover::gcs_mode_enabled(const Mode::Number mode_num) const
     181             : {
     182             :     // List of modes that can be blocked, index is bit number in parameter bitmask
     183             :     static const uint8_t mode_list [] {
     184             :         (uint8_t)Mode::Number::MANUAL,
     185             :         (uint8_t)Mode::Number::ACRO,
     186             :         (uint8_t)Mode::Number::STEERING,
     187             :         (uint8_t)Mode::Number::LOITER,
     188             :         (uint8_t)Mode::Number::FOLLOW,
     189             :         (uint8_t)Mode::Number::SIMPLE,
     190             :         (uint8_t)Mode::Number::CIRCLE,
     191             :         (uint8_t)Mode::Number::AUTO,
     192             :         (uint8_t)Mode::Number::RTL,
     193             :         (uint8_t)Mode::Number::SMART_RTL,
     194             :         (uint8_t)Mode::Number::GUIDED,
     195             : #if MODE_DOCK_ENABLED
     196             :         (uint8_t)Mode::Number::DOCK
     197             : #endif
     198             :     };
     199             : 
     200      138294 :     return !block_GCS_mode_change((uint8_t)mode_num, mode_list, ARRAY_SIZE(mode_list));
     201             : }
     202             : 
     203             : // Return mask of enabled modes, order does not matter, its just for tracking changes
     204       12526 : uint32_t Rover::get_available_mode_enabled_mask() const
     205             : {
     206       12526 :     const Mode* flight_modes[] {
     207             :         &rover.mode_manual,
     208             :         &rover.mode_acro,
     209             :         &rover.mode_steering,
     210             :         &rover.mode_hold,
     211             :         &rover.mode_loiter,
     212             : #if MODE_FOLLOW_ENABLED
     213             :         &rover.mode_follow,
     214             : #endif
     215             :         &rover.mode_simple,
     216             :         &rover.g2.mode_circle,
     217             :         &rover.mode_auto,
     218             :         &rover.mode_rtl,
     219             :         &rover.mode_smartrtl,
     220             :         &rover.mode_guided,
     221             :         &rover.mode_initializing,
     222             : #if MODE_DOCK_ENABLED
     223       12526 :         (Mode *)rover.g2.mode_dock_ptr,
     224             : #endif
     225       12526 :     };
     226             : 
     227             :     static_assert(ARRAY_SIZE(flight_modes) <= 32, "Flight modes must fit in 32 bit bitmask");
     228             : 
     229       12526 :     uint32_t mask = 0;
     230      187890 :     for (uint8_t i = 0; i < ARRAY_SIZE(flight_modes); i++) {
     231      175364 :         const Mode* mode = flight_modes[i];
     232             : 
     233             :         // the check here must be the same as the one in `send_available_mode`
     234      175364 :         const bool user_selectable = mode->enabled() && rover.gcs_mode_enabled(mode->mode_number());
     235             : 
     236      175364 :         if (user_selectable) {
     237      138088 :             mask |= 1U << i;
     238             :         }
     239             :     }
     240             : 
     241       12526 :     return mask;
     242             : }
     243             : 
     244             : 
     245        1266 : bool Rover::set_mode(Mode &new_mode, ModeReason reason)
     246             : {
     247        1266 :     if (control_mode == &new_mode) {
     248             :         // don't switch modes if we are already in the correct mode.
     249         724 :         return true;
     250             :     }
     251             : 
     252             :     // Check if GCS mode change is disabled via parameter
     253         542 :     if ((reason == ModeReason::GCS_COMMAND) && !gcs_mode_enabled((Mode::Number)new_mode.mode_number())) {
     254           0 :         GCS_SEND_TEXT(MAV_SEVERITY_NOTICE,"Mode change to %s denied, GCS entry disabled (FLTMODE_GCSBLOCK)", new_mode.name());
     255           0 :         return false;
     256             :     }
     257             : 
     258         542 :     Mode &old_mode = *control_mode;
     259         542 :     if (!new_mode.enter()) {
     260             :         // Log error that we failed to enter desired flight mode
     261          21 :         LOGGER_WRITE_ERROR(LogErrorSubsystem::FLIGHT_MODE,
     262             :                            LogErrorCode(new_mode.mode_number()));
     263          21 :         GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "Flight mode change failed");
     264          21 :         return false;
     265             :     }
     266             : 
     267         521 :     control_mode = &new_mode;
     268             : 
     269             : #if AP_FENCE_ENABLED
     270             :     // pilot requested flight mode change during a fence breach indicates pilot is attempting to manually recover
     271             :     // this flight mode change could be automatic (i.e. fence, battery, GPS or GCS failsafe)
     272             :     // but it should be harmless to disable the fence temporarily in these situations as well
     273         521 :     fence.manual_recovery_start();
     274             : #endif
     275             : 
     276             : #if AP_CAMERA_ENABLED
     277         521 :     camera.set_is_auto_mode(control_mode->mode_number() == Mode::Number::AUTO);
     278             : #endif
     279             : 
     280         521 :     old_mode.exit();
     281             : 
     282         521 :     control_mode_reason = reason;
     283             : #if HAL_LOGGING_ENABLED
     284         521 :     logger.Write_Mode((uint8_t)control_mode->mode_number(), control_mode_reason);
     285             : #endif
     286         521 :     gcs().send_message(MSG_HEARTBEAT);
     287             : 
     288         521 :     notify_mode(control_mode);
     289         521 :     return true;
     290             : }
     291             : 
     292         348 : bool Rover::set_mode(const uint8_t new_mode, ModeReason reason)
     293             : {
     294             :     static_assert(sizeof(Mode::Number) == sizeof(new_mode), "The new mode can't be mapped to the vehicles mode number");
     295         348 :     return rover.set_mode(static_cast<Mode::Number>(new_mode), reason);
     296             : }
     297             : 
     298         662 : bool Rover::set_mode(Mode::Number new_mode, ModeReason reason)
     299             : {
     300         662 :     Mode *mode = rover.mode_from_mode_num(new_mode);
     301         662 :     if (mode == nullptr) {
     302           2 :         notify_no_such_mode((uint8_t)new_mode);
     303           2 :         return false;
     304             :     }
     305         660 :     return rover.set_mode(*mode, reason);
     306             : }
     307             : 
     308         283 : void Rover::startup_INS(void)
     309             : {
     310         283 :     GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Beginning INS calibration. Do not move vehicle");
     311         283 :     hal.scheduler->delay(100);
     312             : 
     313         283 :     ahrs.init();
     314             :     // say to EKF that rover only move by going forward
     315         283 :     ahrs.set_fly_forward(true);
     316         283 :     ahrs.set_vehicle_class(AP_AHRS::VehicleClass::GROUND);
     317             : 
     318         283 :     ins.init(scheduler.get_loop_rate_hz());
     319         283 :     ahrs.reset();
     320         283 : }
     321             : 
     322             : // update notify with mode change
     323         806 : void Rover::notify_mode(const Mode *mode)
     324             : {
     325         806 :     AP_Notify::flags.autopilot_mode = mode->is_autopilot_mode();
     326         806 :     notify.flags.flight_mode = (uint8_t)mode->mode_number();
     327         806 :     notify.set_flight_mode_str(mode->name4());
     328         806 : }
     329             : 
     330             : /*
     331             :   check a digital pin for high,low (1/0)
     332             :  */
     333           0 : uint8_t Rover::check_digital_pin(uint8_t pin)
     334             : {
     335             :     // ensure we are in input mode
     336           0 :     hal.gpio->pinMode(pin, HAL_GPIO_INPUT);
     337             : 
     338             :     // enable pullup
     339           0 :     hal.gpio->write(pin, 1);
     340             : 
     341           0 :     return hal.gpio->read(pin);
     342             : }
     343             : 
     344             : #if HAL_LOGGING_ENABLED
     345             : /*
     346             :   should we log a message type now?
     347             :  */
     348     3012744 : bool Rover::should_log(uint32_t mask)
     349             : {
     350     3012744 :     return logger.should_log(mask);
     351             : }
     352             : #endif
     353             : 
     354             : // returns true if vehicle is a boat
     355             : // this affects whether the vehicle tries to maintain position after reaching waypoints
     356     1491317 : bool Rover::is_boat() const
     357             : {
     358     1491317 :     return ((enum frame_class)g2.frame_class.get() == FRAME_BOAT);
     359             : }
     360             : 
     361             : #include <AP_Avoidance/AP_Avoidance.h>
     362             : #if AP_ADSB_AVOIDANCE_ENABLED
     363             : // dummy method to avoid linking AP_Avoidance
     364           0 : AP_Avoidance *AP::ap_avoidance() { return nullptr; }
     365             : #endif  // AP_ADSB_AVOIDANCE_ENABLED

Generated by: LCOV version 1.14