LCOV - code coverage report
Current view: top level - home/pbarker/rc/ardupilot/ArduCopter - Copter.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 201 291 69.1 %
Date: 2026-09-09 11:02:08 Functions: 30 44 68.2 %

          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             : /*
      17             :  *  ArduCopter (also known as APM, APM:Copter or just Copter)
      18             :  *  Wiki:           copter.ardupilot.club
      19             :  *  Creator:        Jason Short
      20             :  *  Lead Developer: Randy Mackay
      21             :  *  Lead Tester:    Marco Robustini
      22             :  *  Based on code and ideas from the Arducopter team: Leonard Hall, Andrew Tridgell, Robert Lefebvre, Pat Hickey, Michael Oborne, Jani Hirvinen,
      23             :                                                       Olivier Adler, Kevin Hester, Arthur Benemann, Jonathan Challinger, John Arne Birkeland,
      24             :                                                       Jean-Louis Naudin, Mike Smith, and more
      25             :  *  Thanks to: Chris Anderson, Jordi Munoz, Jason Short, Doug Weibel, Jose Julio
      26             :  *
      27             :  *  Special Thanks to contributors (in alphabetical order by first name):
      28             :  *
      29             :  *  Adam M Rivera       :Auto Compass Declination
      30             :  *  Amilcar Lucas       :Camera mount library
      31             :  *  Andrew Tridgell     :General development, Mavlink Support
      32             :  *  Andy Piper          :Harmonic notch, In-flight FFT, Bi-directional DShot, various drivers
      33             :  *  Angel Fernandez     :Alpha testing
      34             :  *  AndreasAntonopoulous:GeoFence
      35             :  *  Arthur Benemann     :DroidPlanner GCS
      36             :  *  Benjamin Pelletier  :Libraries
      37             :  *  Bill King           :Single Copter
      38             :  *  Christof Schmid     :Alpha testing
      39             :  *  Craig Elder         :Release Management, Support
      40             :  *  Dani Saez           :V Octo Support
      41             :  *  Doug Weibel         :DCM, Libraries, Control law advice
      42             :  *  Emile Castelnuovo   :VRBrain port, bug fixes
      43             :  *  Gregory Fletcher    :Camera mount orientation math
      44             :  *  Guntars             :Arming safety suggestion
      45             :  *  HappyKillmore       :Mavlink GCS
      46             :  *  Hein Hollander      :Octo Support, Heli Testing
      47             :  *  Igor van Airde      :Control Law optimization
      48             :  *  Jack Dunkle         :Alpha testing
      49             :  *  James Goppert       :Mavlink Support
      50             :  *  Jani Hiriven        :Testing feedback
      51             :  *  Jean-Louis Naudin   :Auto Landing
      52             :  *  John Arne Birkeland :PPM Encoder
      53             :  *  Jose Julio          :Stabilization Control laws, MPU6k driver
      54             :  *  Julien Dubois       :PosHold flight mode
      55             :  *  Julian Oes          :Pixhawk
      56             :  *  Jonathan Challinger :Inertial Navigation, CompassMot, Spin-When-Armed
      57             :  *  Kevin Hester        :Andropilot GCS
      58             :  *  Max Levine          :Tri Support, Graphics
      59             :  *  Leonard Hall        :Flight Dynamics, Throttle, Loiter and Navigation Controllers
      60             :  *  Marco Robustini     :Lead tester
      61             :  *  Michael Oborne      :Mission Planner GCS
      62             :  *  Mike Smith          :Pixhawk driver, coding support
      63             :  *  Olivier Adler       :PPM Encoder, piezo buzzer
      64             :  *  Pat Hickey          :Hardware Abstraction Layer (HAL)
      65             :  *  Robert Lefebvre     :Heli Support, Copter LEDs
      66             :  *  Roberto Navoni      :Library testing, Porting to VRBrain
      67             :  *  Sandro Benigno      :Camera support, MinimOSD
      68             :  *  Sandro Tognana      :PosHold flight mode
      69             :  *  Sebastian Quilter   :SmartRTL
      70             :  *  ..and many more.
      71             :  *
      72             :  *  Code commit statistics can be found here: https://github.com/ArduPilot/ardupilot/graphs/contributors
      73             :  *  Wiki: https://copter.ardupilot.club/
      74             :  *
      75             :  */
      76             : 
      77             : #include "Copter.h"
      78             : #include <AP_InertialSensor/AP_InertialSensor_rate_config.h>
      79             : 
      80             : #define FORCE_VERSION_H_INCLUDE
      81             : #include "version.h"
      82             : #undef FORCE_VERSION_H_INCLUDE
      83             : 
      84             : const AP_HAL::HAL& hal = AP_HAL::get_HAL();
      85             : 
      86             : #define SCHED_TASK(func, rate_hz, _max_time_micros, _prio) SCHED_TASK_CLASS(Copter, &copter, func, rate_hz, _max_time_micros, _prio)
      87             : #define FAST_TASK(func) FAST_TASK_CLASS(Copter, &copter, func)
      88             : 
      89             : /*
      90             :   scheduler table - all tasks should be listed here.
      91             : 
      92             :   All entries in this table must be ordered by priority.
      93             : 
      94             :   This table is interleaved with the table in AP_Vehicle to determine
      95             :   the order in which tasks are run.  Convenience methods SCHED_TASK
      96             :   and SCHED_TASK_CLASS are provided to build entries in this structure:
      97             : 
      98             : SCHED_TASK arguments:
      99             :  - name of static function to call
     100             :  - rate (in Hertz) at which the function should be called
     101             :  - expected time (in MicroSeconds) that the function should take to run
     102             :  - priority (0 through 255, lower number meaning higher priority)
     103             : 
     104             : SCHED_TASK_CLASS arguments:
     105             :  - class name of method to be called
     106             :  - instance on which to call the method
     107             :  - method to call on that instance
     108             :  - rate (in Hertz) at which the method should be called
     109             :  - expected time (in MicroSeconds) that the method should take to run
     110             :  - priority (0 through 255, lower number meaning higher priority)
     111             : 
     112             :  */
     113             : const AP_Scheduler::Task Copter::scheduler_tasks[] = {
     114             :     // update INS immediately to get current gyro data populated
     115             :     FAST_TASK_CLASS(AP_InertialSensor, &copter.ins, update),
     116             :     // run low level rate controllers that only require IMU data
     117             :     FAST_TASK(run_rate_controller_main),
     118             : #if AC_CUSTOMCONTROL_MULTI_ENABLED
     119             :     FAST_TASK(run_custom_controller),
     120             : #endif
     121             : #if FRAME_CONFIG == HELI_FRAME
     122             :     FAST_TASK(heli_update_autorotation),
     123             : #endif //HELI_FRAME
     124             :     // send outputs to the motors library immediately
     125             :     FAST_TASK(motors_output_main),
     126             :      // run EKF state estimator (expensive)
     127             :     FAST_TASK(read_AHRS),
     128             : #if FRAME_CONFIG == HELI_FRAME
     129             :     FAST_TASK(update_heli_control_dynamics),
     130             : #endif //HELI_FRAME
     131             :     // Inertial Nav
     132             :     FAST_TASK(read_inertia),
     133             :     // check if ekf has reset target heading or position
     134             :     FAST_TASK(check_ekf_reset),
     135             :     // run the attitude controllers
     136             :     FAST_TASK(update_flight_mode),
     137             :     // update home from EKF if necessary
     138             :     FAST_TASK(update_home_from_EKF),
     139             :     // check if we've landed or crashed
     140             :     FAST_TASK(update_land_and_crash_detectors),
     141             :     // surface tracking update
     142             :     FAST_TASK(update_rangefinder_terrain_offset),
     143             : #if HAL_MOUNT_ENABLED
     144             :     // camera mount's fast update
     145             :     FAST_TASK_CLASS(AP_Mount, &copter.camera_mount, update_fast),
     146             : #endif
     147             : #if HAL_LOGGING_ENABLED
     148             :     FAST_TASK(Log_Video_Stabilisation),
     149             : #endif
     150             : 
     151             :     SCHED_TASK(rc_loop,              250,    130,  3),
     152             :     SCHED_TASK(throttle_loop,         50,     75,  6),
     153             : #if AP_FENCE_ENABLED
     154             :     SCHED_TASK(fence_check,           25,    100,  7),
     155             : #endif
     156             :     SCHED_TASK_CLASS(AP_GPS,               &copter.gps,                 update,          50, 200,   9),
     157             : #if AP_OPTICALFLOW_ENABLED
     158             :     SCHED_TASK_CLASS(AP_OpticalFlow,          &copter.optflow,             update,         200, 160,  12),
     159             : #endif
     160             :     SCHED_TASK(update_batt_compass,   10,    120, 15),
     161             :     SCHED_TASK_CLASS(RC_Channels, (RC_Channels*)&copter.g2.rc_channels, read_aux_all,    10,  50,  18),
     162             : #if TOY_MODE_ENABLED
     163             :     SCHED_TASK_CLASS(ToyMode,              &copter.g2.toy_mode,         update,          10,  50,  24),
     164             : #endif
     165             :     SCHED_TASK(auto_disarm_check,     10,     50,  27),
     166             : #if AP_COPTER_AHRS_AUTO_TRIM_ENABLED
     167             :     SCHED_TASK_CLASS(RC_Channels_Copter,   &copter.g2.rc_channels,      auto_trim_run,   10,  75,  30),
     168             : #endif
     169             : #if AP_RANGEFINDER_ENABLED
     170             :     SCHED_TASK(read_rangefinder,      20,    100,  33),
     171             : #endif
     172             : #if HAL_PROXIMITY_ENABLED
     173             :     SCHED_TASK_CLASS(AP_Proximity,         &copter.g2.proximity,        update,         200, 200,  36),
     174             : #endif
     175             :     SCHED_TASK(update_altitude,       10,    100,  42),
     176             :     SCHED_TASK(run_nav_updates,       50,    100,  45),
     177             :     SCHED_TASK(update_throttle_hover,100,     90,  48),
     178             : #if MODE_SMARTRTL_ENABLED
     179             :     SCHED_TASK_CLASS(ModeSmartRTL,         &copter.mode_smartrtl,       save_position,    3, 100,  51),
     180             : #endif
     181             : #if HAL_SPRAYER_ENABLED
     182             :     SCHED_TASK_CLASS(AC_Sprayer,           &copter.sprayer,               update,         3,  90,  54),
     183             : #endif
     184             :     SCHED_TASK(three_hz_loop,          3,     75, 57),
     185             : #if AP_SERVORELAYEVENTS_ENABLED
     186             :     SCHED_TASK_CLASS(AP_ServoRelayEvents,  &copter.ServoRelayEvents,      update_events, 50,  75,  60),
     187             : #endif
     188             : #if AC_PRECLAND_ENABLED
     189             :     SCHED_TASK(update_precland,      400,     50,  69),
     190             : #endif
     191             : #if FRAME_CONFIG == HELI_FRAME
     192             :     SCHED_TASK(check_dynamic_flight,  50,     75,  72),
     193             : #endif
     194             : #if HAL_LOGGING_ENABLED
     195             :     SCHED_TASK(loop_rate_logging, LOOP_RATE,    50,  75),
     196             : #endif
     197             :     SCHED_TASK(one_hz_loop,            1,    100,  81),
     198             :     SCHED_TASK(ekf_check,             10,     75,  84),
     199             :     SCHED_TASK(check_vibration,       10,     50,  87),
     200             :     SCHED_TASK(gpsglitch_check,       10,     50,  90),
     201             :     SCHED_TASK(takeoff_check,         50,     50,  91),
     202             : #if AP_LANDINGGEAR_ENABLED
     203             :     SCHED_TASK(landinggear_update,    10,     75,  93),
     204             : #endif
     205             :     SCHED_TASK(standby_update,        100,    75,  96),
     206             :     SCHED_TASK(lost_vehicle_check,    10,     50,  99),
     207             :     SCHED_TASK_CLASS(GCS,                  (GCS*)&copter._gcs,          update_receive, 400, 180, 102),
     208             :     SCHED_TASK_CLASS(GCS,                  (GCS*)&copter._gcs,          update_send,    400, 550, 105),
     209             : #if HAL_MOUNT_ENABLED
     210             :     SCHED_TASK_CLASS(AP_Mount,             &copter.camera_mount,        update,          50,  75, 108),
     211             : #endif
     212             : #if AP_CAMERA_ENABLED
     213             :     SCHED_TASK_CLASS(AP_Camera,            &copter.camera,              update,          50,  75, 111),
     214             : #endif
     215             : #if HAL_LOGGING_ENABLED
     216             :     SCHED_TASK(ten_hz_logging_loop,   10,    350, 114),
     217             :     SCHED_TASK(twentyfive_hz_logging, 25,    110, 117),
     218             :     SCHED_TASK_CLASS(AP_Logger,            &copter.logger,              periodic_tasks, 400, 300, 120),
     219             : #endif
     220             :     SCHED_TASK_CLASS(AP_InertialSensor,    &copter.ins,                 periodic,       400,  50, 123),
     221             : 
     222             : #if HAL_LOGGING_ENABLED
     223             :     SCHED_TASK_CLASS(AP_Scheduler,         &copter.scheduler,           update_logging, 0.1,  75, 126),
     224             : #endif
     225             : #if AP_TEMPCALIBRATION_ENABLED
     226             :     SCHED_TASK_CLASS(AP_TempCalibration,   &copter.g2.temp_calibration, update,          10, 100, 135),
     227             : #endif
     228             : #if HAL_ADSB_ENABLED || AP_ADSB_AVOIDANCE_ENABLED
     229             :     SCHED_TASK(avoidance_adsb_update, 10,    100, 138),
     230             : #endif  // HAL_ADSB_ENABLED || AP_ADSB_AVOIDANCE_ENABLED
     231             : #if AP_COPTER_ADVANCED_FAILSAFE_ENABLED
     232             :     SCHED_TASK(afs_fs_check,          10,    100, 141),
     233             : #endif
     234             : #if AP_TERRAIN_AVAILABLE
     235             :     SCHED_TASK(terrain_update,        10,    100, 144),
     236             : #endif
     237             : #if AP_WINCH_ENABLED
     238             :     SCHED_TASK_CLASS(AP_Winch,             &copter.g2.winch,            update,          50,  50, 150),
     239             : #endif
     240             : #ifdef USERHOOK_FASTLOOP
     241             :     SCHED_TASK(userhook_FastLoop,    100,     75, 153),
     242             : #endif
     243             : #ifdef USERHOOK_50HZLOOP
     244             :     SCHED_TASK(userhook_50Hz,         50,     75, 156),
     245             : #endif
     246             : #ifdef USERHOOK_MEDIUMLOOP
     247             :     SCHED_TASK(userhook_MediumLoop,   10,     75, 159),
     248             : #endif
     249             : #ifdef USERHOOK_SLOWLOOP
     250             :     SCHED_TASK(userhook_SlowLoop,      3.3,   75, 162),
     251             : #endif
     252             : #ifdef USERHOOK_SUPERSLOWLOOP
     253             :     SCHED_TASK(userhook_SuperSlowLoop, 1,     75, 165),
     254             : #endif
     255             : #if HAL_BUTTON_ENABLED
     256             :     SCHED_TASK_CLASS(AP_Button,            &copter.button,              update,           5, 100, 168),
     257             : #endif
     258             : #if AP_INERTIALSENSOR_FAST_SAMPLE_WINDOW_ENABLED
     259             :     // don't delete this, there is an equivalent (virtual) in AP_Vehicle for the non-rate loop case
     260             :     SCHED_TASK(update_dynamic_notch_at_specified_rate_main,                       LOOP_RATE, 200, 215),
     261             : #endif
     262             : };
     263             : 
     264        1001 : void Copter::get_scheduler_tasks(const AP_Scheduler::Task *&tasks,
     265             :                                  uint8_t &task_count,
     266             :                                  uint32_t &log_bit)
     267             : {
     268        1001 :     tasks = &scheduler_tasks[0];
     269        1001 :     task_count = ARRAY_SIZE(scheduler_tasks);
     270        1001 :     log_bit = MASK_LOG_PM;
     271        1001 : }
     272             : 
     273             : constexpr int8_t Copter::_failsafe_priorities[7];
     274             : 
     275             : 
     276             : #if AP_SCRIPTING_ENABLED || AP_EXTERNAL_CONTROL_ENABLED
     277             : #if MODE_GUIDED_ENABLED
     278             : // set target location (for use by external control and scripting)
     279           0 : bool Copter::set_target_location(const Location& target_loc)
     280             : {
     281             :     // exit if vehicle is not in Guided mode or Auto-Guided mode
     282           0 :     if (!flightmode->in_guided_mode()) {
     283           0 :         return false;
     284             :     }
     285             : 
     286           0 :     return mode_guided.set_destination(target_loc);
     287             : }
     288             : 
     289             : // start takeoff to given altitude (for use by scripting)
     290           1 : bool Copter::start_takeoff(const float alt_m)
     291             : {
     292             :     // exit if vehicle is not in Guided mode or Auto-Guided mode
     293           1 :     if (!flightmode->in_guided_mode()) {
     294           0 :         return false;
     295             :     }
     296             : 
     297           1 :     if (mode_guided.do_user_takeoff_start_m(alt_m)) {
     298           1 :         copter.set_auto_armed(true);
     299           1 :         return true;
     300             :     }
     301           0 :     return false;
     302             : }
     303             : #endif //MODE_GUIDED_ENABLED
     304             : #endif //AP_SCRIPTING_ENABLED || AP_EXTERNAL_CONTROL_ENABLED
     305             : 
     306             : #if AP_SCRIPTING_ENABLED
     307             : #if MODE_GUIDED_ENABLED
     308             : // set target position (for use by scripting)
     309           0 : bool Copter::set_target_pos_NED(const Vector3f& target_pos_ned_m, bool use_yaw, float yaw_deg, bool use_yaw_rate, float yaw_rate_degs, bool yaw_relative, bool is_terrain_alt)
     310             : {
     311             :     // exit if vehicle is not in Guided mode or Auto-Guided mode
     312           0 :     if (!flightmode->in_guided_mode()) {
     313           0 :         return false;
     314             :     }
     315             : 
     316           0 :     return mode_guided.set_pos_NED_m(target_pos_ned_m.topostype(), use_yaw, radians(yaw_deg), use_yaw_rate, radians(yaw_rate_degs), yaw_relative, is_terrain_alt);
     317             : }
     318             : 
     319             : // set target position and velocity (for use by scripting)
     320           0 : bool Copter::set_target_posvel_NED(const Vector3f& target_pos_ned_m, const Vector3f& target_vel_ned_ms)
     321             : {
     322             :     // exit if vehicle is not in Guided mode or Auto-Guided mode
     323           0 :     if (!flightmode->in_guided_mode()) {
     324           0 :         return false;
     325             :     }
     326             : 
     327           0 :     return mode_guided.set_pos_vel_accel_NED_m(target_pos_ned_m.topostype(), target_vel_ned_ms, Vector3f());
     328             : }
     329             : 
     330             : // set target position, velocity and acceleration (for use by scripting)
     331           0 : bool Copter::set_target_posvelaccel_NED(const Vector3f& target_pos_ned_m, const Vector3f& target_vel_ned_ms, const Vector3f& target_accel_ned_mss, bool use_yaw, float yaw_deg, bool use_yaw_rate, float yaw_rate_degs, bool yaw_relative)
     332             : {
     333             :     // exit if vehicle is not in Guided mode or Auto-Guided mode
     334           0 :     if (!flightmode->in_guided_mode()) {
     335           0 :         return false;
     336             :     }
     337             : 
     338           0 :     return mode_guided.set_pos_vel_accel_NED_m(target_pos_ned_m.topostype(), target_vel_ned_ms, target_accel_ned_mss, use_yaw, radians(yaw_deg), use_yaw_rate, radians(yaw_rate_degs), yaw_relative);
     339             : }
     340             : 
     341          47 : bool Copter::set_target_velocity_NED(const Vector3f& target_vel_ned_ms, bool align_yaw_to_target)
     342             : {
     343             :     // exit if vehicle is not in Guided mode or Auto-Guided mode
     344          47 :     if (!flightmode->in_guided_mode()) {
     345           0 :         return false;
     346             :     }
     347             : 
     348             :     // optionally line up the copter with the velocity vector
     349          47 :     float yaw_rads = 0.0f;
     350          47 :     if (align_yaw_to_target) {
     351           0 :         const float speed_sq = target_vel_ned_ms.xy().length_squared();
     352           0 :         if (copter.position_ok() && (speed_sq > (YAW_LOOK_AHEAD_MIN_SPEED_MS * YAW_LOOK_AHEAD_MIN_SPEED_MS))) {
     353           0 :             yaw_rads = atan2f(target_vel_ned_ms.y, target_vel_ned_ms.x);
     354             :         }
     355             :     }
     356             : 
     357          47 :     mode_guided.set_vel_accel_NED_m(target_vel_ned_ms, Vector3f(), align_yaw_to_target, yaw_rads);
     358          47 :     return true;
     359             : }
     360             : 
     361             : // set target velocity and acceleration (for use by scripting)
     362           0 : bool Copter::set_target_velaccel_NED(const Vector3f& target_vel_ned_ms, const Vector3f& target_accel_ned_mss, bool use_yaw, float yaw_deg, bool use_yaw_rate, float yaw_rate_degs, bool relative_yaw)
     363             : {
     364             :     // exit if vehicle is not in Guided mode or Auto-Guided mode
     365           0 :     if (!flightmode->in_guided_mode()) {
     366           0 :         return false;
     367             :     }
     368             : 
     369           0 :     mode_guided.set_vel_accel_NED_m(target_vel_ned_ms, target_accel_ned_mss, use_yaw, radians(yaw_deg), use_yaw_rate, radians(yaw_rate_degs), relative_yaw);
     370           0 :     return true;
     371             : }
     372             : 
     373             : // set target roll pitch and yaw angles with throttle (for use by scripting)
     374           0 : bool Copter::set_target_angle_and_climbrate(float roll_deg, float pitch_deg, float yaw_deg, float climb_rate_ms, bool use_yaw_rate, float yaw_rate_degs)
     375             : {
     376             :     // exit if vehicle is not in Guided mode or Auto-Guided mode
     377           0 :     if (!flightmode->in_guided_mode()) {
     378           0 :         return false;
     379             :     }
     380             : 
     381           0 :     Quaternion q;
     382           0 :     q.from_euler(radians(roll_deg),radians(pitch_deg),radians(yaw_deg));
     383             : 
     384           0 :     mode_guided.set_angle(q, Vector3f{}, climb_rate_ms, false);
     385           0 :     return true;
     386             : }
     387             : 
     388             : // set target roll pitch and yaw rates with throttle (for use by scripting)
     389         245 : bool Copter::set_target_rate_and_throttle(float roll_rate_dps, float pitch_rate_dps, float yaw_rate_dps, float throttle)
     390             : {
     391             :     // exit if vehicle is not in Guided mode or Auto-Guided mode
     392         245 :     if (!flightmode->in_guided_mode()) {
     393           0 :         return false;
     394             :     }
     395             : 
     396             :     // Zero quaternion indicates rate control
     397         245 :     Quaternion q;
     398         245 :     q.zero();
     399             : 
     400             :     // Convert from degrees per second to radians per second
     401         245 :     Vector3f ang_vel_body { roll_rate_dps, pitch_rate_dps, yaw_rate_dps };
     402         245 :     ang_vel_body *= DEG_TO_RAD;
     403             : 
     404             :     // Pass to guided mode
     405         245 :     mode_guided.set_angle(q, ang_vel_body, throttle, true);
     406         245 :     return true;
     407             : }
     408             : 
     409             : // set target roll pitch and yaw angles and roll pitch and yaw rates with throttle (for use by scripting)
     410           0 : bool Copter::set_target_angle_and_rate_and_throttle(float roll_deg, float pitch_deg, float yaw_deg, float roll_rate_degs, float pitch_rate_degs, float yaw_rate_degs, float throttle)
     411             : {
     412             :     // exit if vehicle is not in Guided mode or Auto-Guided mode
     413           0 :     if (!flightmode->in_guided_mode()) {
     414           0 :         return false;
     415             :     }
     416             : 
     417           0 :     Quaternion q;
     418           0 :     q.from_euler(radians(roll_deg),radians(pitch_deg),radians(yaw_deg));
     419             : 
     420             :     // Convert from degrees per second to radians per second
     421           0 :     Vector3f ang_vel_body_degs { roll_rate_degs, pitch_rate_degs, yaw_rate_degs };
     422           0 :     ang_vel_body_degs *= DEG_TO_RAD;
     423             : 
     424           0 :     mode_guided.set_angle(q, ang_vel_body_degs, throttle, true);
     425           0 :     return true;
     426             : }
     427             : 
     428             : // Register a custom mode with given number and names
     429           1 : AP_Vehicle::custom_mode_state* Copter::register_custom_mode(const uint8_t num, const char* full_name, const char* short_name)
     430             : {
     431           1 :     const Mode::Number number = (Mode::Number)num;
     432             : 
     433             :     // See if this mode has been registered already, if it has return the state for it
     434             :     // This allows scripting restarts
     435           1 :     for (uint8_t i = 0; i < ARRAY_SIZE(mode_guided_custom); i++) {
     436           1 :         if (mode_guided_custom[i] == nullptr) {
     437           1 :             break;
     438             :         }
     439           0 :         if ((mode_guided_custom[i]->mode_number() == number) &&
     440           0 :             (strcmp(mode_guided_custom[i]->name(), full_name) == 0) &&
     441           0 :             (strncmp(mode_guided_custom[i]->name4(), short_name, 4) == 0)) {
     442           0 :             return &mode_guided_custom[i]->state;
     443             :         }
     444             :     }
     445             : 
     446             :     // Number already registered to existing mode
     447           1 :     if (mode_from_mode_num(number) != nullptr) {
     448           0 :         return nullptr;
     449             :     }
     450             : 
     451             :     // Find free slot
     452           1 :     for (uint8_t i = 0; i < ARRAY_SIZE(mode_guided_custom); i++) {
     453           1 :         if (mode_guided_custom[i] == nullptr) {
     454             :             // Duplicate strings so were not pointing to unknown memory
     455           1 :             const char* full_name_copy = strdup(full_name);
     456           1 :             const char* short_name_copy = strndup(short_name, 4);
     457           1 :             if ((full_name_copy != nullptr) && (short_name_copy != nullptr)) {
     458           1 :                 mode_guided_custom[i] = NEW_NOTHROW ModeGuidedCustom(number, full_name_copy, short_name_copy);
     459             :             }
     460           1 :             if (mode_guided_custom[i] == nullptr) {
     461             :                 // Allocation failure
     462           0 :                 free((void*)full_name_copy);
     463           0 :                 free((void*)short_name_copy);
     464           0 :                 return nullptr;
     465             :             }
     466             : 
     467             :             // Registration successful, notify the GCS that it should re-request the available modes
     468           1 :             gcs().available_modes_changed();
     469             : 
     470           1 :             return &mode_guided_custom[i]->state;
     471             :         }
     472             :     }
     473             : 
     474             :     // No free slots
     475           0 :     return nullptr;
     476             : }
     477             : #endif // MODE_GUIDED_ENABLED
     478             : 
     479             : #if MODE_CIRCLE_ENABLED
     480             : // circle mode controls
     481         412 : bool Copter::get_circle_radius(float &radius_m)
     482             : {
     483         412 :     radius_m = circle_nav->get_radius_m();
     484         412 :     return true;
     485             : }
     486             : 
     487         412 : bool Copter::set_circle_rate(float rate_degs)
     488             : {
     489         412 :     circle_nav->set_rate_degs(rate_degs);
     490         412 :     return true;
     491             : }
     492             : #endif
     493             : 
     494             : // set desired speed (m/s). Used for scripting.
     495           0 : bool Copter::set_desired_speed(float speed_ms)
     496             : {
     497           0 :     return flightmode->set_speed_NE_ms(speed_ms);
     498             : }
     499             : 
     500             : #if MODE_AUTO_ENABLED
     501             : // returns true if mode supports NAV_SCRIPT_TIME mission commands
     502           0 : bool Copter::nav_scripting_enable(uint8_t mode)
     503             : {
     504           0 :     return mode == (uint8_t)mode_auto.mode_number();
     505             : }
     506             : 
     507             : // lua scripts use this to retrieve the contents of the active command
     508           0 : bool Copter::nav_script_time(uint16_t &id, uint8_t &cmd, float &arg1, float &arg2, int16_t &arg3, int16_t &arg4)
     509             : {
     510           0 :     if (flightmode != &mode_auto) {
     511           0 :         return false;
     512             :     }
     513             : 
     514           0 :     return mode_auto.nav_script_time(id, cmd, arg1, arg2, arg3, arg4);
     515             : }
     516             : 
     517             : // lua scripts use this to indicate when they have complete the command
     518           0 : void Copter::nav_script_time_done(uint16_t id)
     519             : {
     520           0 :     if (flightmode != &mode_auto) {
     521           0 :         return;
     522             :     }
     523             : 
     524           0 :     return mode_auto.nav_script_time_done(id);
     525             : }
     526             : #endif
     527             : 
     528             : // returns true if the EKF failsafe has triggered.  Only used by Lua scripts
     529           0 : bool Copter::has_ekf_failsafed() const
     530             : {
     531           0 :     return failsafe.ekf;
     532             : }
     533             : 
     534             : // get target location (for use by scripting)
     535           0 : bool Copter::get_target_location(Location& target_loc)
     536             : {
     537           0 :     return flightmode->get_wp(target_loc);
     538             : }
     539             : 
     540             : /*
     541             :   update_target_location() acts as a wrapper for set_target_location
     542             :  */
     543           0 : bool Copter::update_target_location(const Location &old_loc, const Location &new_loc)
     544             : {
     545             :     /*
     546             :       by checking the caller has provided the correct old target
     547             :       location we prevent a race condition where the user changes mode
     548             :       or commands a different target in the controlling lua script
     549             :     */
     550           0 :     Location next_WP_loc;
     551           0 :     flightmode->get_wp(next_WP_loc);
     552           0 :     if (!old_loc.same_loc_as(next_WP_loc) ||
     553           0 :          old_loc.get_alt_frame() != new_loc.get_alt_frame()) {
     554           0 :         return false;
     555             :     }
     556             : 
     557           0 :     return set_target_location(new_loc);
     558             : }
     559             : 
     560             : #endif // AP_SCRIPTING_ENABLED
     561             : 
     562             : // returns true if vehicle is landing.
     563        2705 : bool Copter::is_landing() const
     564             : {
     565        2705 :     return flightmode->is_landing();
     566             : }
     567             : 
     568             : // returns true if vehicle is taking off.
     569        2705 : bool Copter::is_taking_off() const
     570             : {
     571        2705 :     return flightmode->is_taking_off();
     572             : }
     573             : 
     574      478720 : bool Copter::current_mode_requires_mission() const
     575             : {
     576             : #if MODE_AUTO_ENABLED
     577      478720 :         return flightmode == &mode_auto;
     578             : #else
     579             :         return false;
     580             : #endif
     581             : }
     582             : 
     583             : // rc_loops - reads user input from transmitter/receiver
     584             : // called at 100hz
     585    30412448 : void Copter::rc_loop()
     586             : {
     587             :     // Read radio and 3-position switch on radio
     588             :     // -----------------------------------------
     589    30412448 :     read_radio();
     590    30412448 :     rc().read_mode_switch();
     591    30412448 : }
     592             : 
     593             : // throttle_loop - should be run at 50 hz
     594             : // ---------------------------
     595     3800955 : void Copter::throttle_loop()
     596             : {
     597             :     // update throttle_low_comp value (controls priority of throttle vs attitude control)
     598     3800955 :     update_throttle_mix();
     599             : 
     600             :     // check auto_armed status
     601     3800955 :     update_auto_armed();
     602             : 
     603             : #if FRAME_CONFIG == HELI_FRAME
     604             :     // update rotor speed
     605      404223 :     heli_update_rotor_speed_targets();
     606             : 
     607             :     // update trad heli swash plate movement
     608      404223 :     heli_update_landing_swash();
     609             : #endif
     610             : 
     611             :     // compensate for ground effect (if enabled)
     612             : #if AP_GROUNDEFFECT_ENABLED
     613     3800955 :     update_ground_effect_detector();
     614             : #endif
     615     3800955 :     update_ekf_terrain_height_stable();
     616     3800955 : }
     617             : 
     618             : // update_batt_compass - read battery and compass
     619             : // should be called at 10hz
     620      759512 : void Copter::update_batt_compass(void)
     621             : {
     622             :     // read battery before compass because it may be used for motor interference compensation
     623      759512 :     battery.read();
     624             : 
     625      759512 :     if(AP::compass().available()) {
     626             :         // update compass with throttle value - used for compassmot
     627      759512 :         compass.set_throttle(motors->get_throttle());
     628      759512 :         compass.set_voltage(battery.voltage());
     629      759512 :         compass.read();
     630             :     }
     631      759512 : }
     632             : 
     633             : #if HAL_LOGGING_ENABLED
     634             : // Full rate logging of attitude, rate and pid loops
     635             : // should be run at loop rate
     636    30412448 : void Copter::loop_rate_logging()
     637             : {
     638    30412448 :    if (should_log(MASK_LOG_ATTITUDE_FAST) && !copter.flightmode->logs_attitude()) {
     639      408999 :         Log_Write_Attitude();
     640      408999 :         if (!using_rate_thread) {
     641      306864 :             Log_Write_Rate();
     642      306864 :             Log_Write_PIDS(); // only logs if PIDS bitmask is set
     643             :         }
     644             :     }
     645             : #if AP_INERTIALSENSOR_HARMONICNOTCH_ENABLED
     646    30412448 :     if (should_log(MASK_LOG_FTN_FAST) && !using_rate_thread) {
     647           0 :         AP::ins().write_notch_log_messages();
     648             :     }
     649             : #endif
     650    30412448 :     if (should_log(MASK_LOG_IMU_FAST)) {
     651           0 :         AP::ins().Write_IMU();
     652             :     }
     653             : 
     654    30412448 :     motors->Log_Write_SPOL();
     655    30412448 : }
     656             : 
     657             : // ten_hz_logging_loop
     658             : // should be run at 10hz
     659      759507 : void Copter::ten_hz_logging_loop()
     660             : {
     661             :     // always write AHRS attitude at 10Hz
     662      759507 :     ahrs.Write_Attitude(attitude_control->get_att_target_euler_rad() * RAD_TO_DEG);
     663             :     // log attitude controller data if we're not already logging at the higher rate
     664      759507 :     if (should_log(MASK_LOG_ATTITUDE_MED) && !should_log(MASK_LOG_ATTITUDE_FAST) && !copter.flightmode->logs_attitude()) {
     665      718578 :         Log_Write_Attitude();
     666      718578 :         if (!using_rate_thread) {
     667      718578 :             Log_Write_Rate();
     668             :         }
     669             :     }
     670      759507 :     if (!should_log(MASK_LOG_ATTITUDE_FAST) && !copter.flightmode->logs_attitude()) {
     671             :     // log at 10Hz if PIDS bitmask is selected, even if no ATT bitmask is selected; logs at looprate if ATT_FAST and PIDS bitmask set
     672      749286 :         if (!using_rate_thread) {
     673      748962 :             Log_Write_PIDS();
     674             :         }
     675             :     }
     676             :     // log EKF attitude data always at 10Hz unless ATTITUDE_FAST, then do it in the 25Hz loop
     677      759507 :     if (!should_log(MASK_LOG_ATTITUDE_FAST)) {
     678      749286 :         Log_Write_EKF_POS();
     679             :     }
     680      678719 :     if ((FRAME_CONFIG == HELI_FRAME) || should_log(MASK_LOG_MOTBATT)) {
     681             :         // always write motors log if we are a heli
     682      700287 :         motors->Log_Write();
     683             :     }
     684      759507 :     if (should_log(MASK_LOG_RCIN)) {
     685      698661 :         logger.Write_RCIN();
     686             : #if AP_RSSI_ENABLED
     687      698661 :         if (rssi.enabled()) {
     688           0 :             logger.Write_RSSI();
     689             :         }
     690             : #endif
     691             :     }
     692      759507 :     if (should_log(MASK_LOG_RCOUT)) {
     693      698661 :         logger.Write_RCOUT();
     694             :     }
     695      759507 :     if (should_log(MASK_LOG_NTUN) && (flightmode->requires_position() || landing_with_GPS() || !flightmode->has_manual_throttle())) {
     696      563177 :         pos_control->write_log();
     697             :     }
     698      759507 :     if (should_log(MASK_LOG_IMU) || should_log(MASK_LOG_IMU_FAST) || should_log(MASK_LOG_IMU_RAW)) {
     699      728322 :         AP::ins().Write_Vibration();
     700             :     }
     701      759507 :     if (should_log(MASK_LOG_CTUN)) {
     702             : #if HAL_PROXIMITY_ENABLED
     703      728322 :         g2.proximity.log();  // Write proximity sensor distances
     704             : #endif
     705             : #if AP_BEACON_ENABLED
     706      728322 :         beacon.log();
     707             : #endif  // AP_BEACON_ENABLED
     708             :     }
     709             : #if AP_WINCH_ENABLED
     710      759507 :     if (should_log(MASK_LOG_ANY)) {
     711      728799 :         g2.winch.write_log();
     712             :     }
     713             : #endif
     714             : #if HAL_MOUNT_ENABLED
     715      759507 :     if (should_log(MASK_LOG_CAMERA)) {
     716      698661 :         camera_mount.write_log();
     717             :     }
     718             : #endif
     719      759507 : }
     720             : 
     721             : // twentyfive_hz_logging - should be run at 25hz
     722     1900261 : void Copter::twentyfive_hz_logging()
     723             : {
     724     1900261 :     if (should_log(MASK_LOG_ATTITUDE_FAST)) {
     725       25562 :         Log_Write_EKF_POS();
     726             :     }
     727             : 
     728     1900261 :     if (should_log(MASK_LOG_IMU) && !(should_log(MASK_LOG_IMU_FAST))) {
     729     1822111 :         AP::ins().Write_IMU();
     730             :     }
     731             : 
     732             : #if HAL_GYROFFT_ENABLED
     733     1900261 :     if (should_log(MASK_LOG_FTN_FAST)) {
     734           0 :         gyro_fft.write_log_messages();
     735             :     }
     736             : #endif
     737     1900261 : }
     738             : #endif  // HAL_LOGGING_ENABLED
     739             : 
     740             : // three_hz_loop - 3hz loop
     741      228158 : void Copter::three_hz_loop()
     742             : {
     743             :     // check if we've lost contact with the ground station
     744      228158 :     failsafe_gcs_check();
     745             : 
     746             :     // check if we've lost terrain data
     747      228158 :     failsafe_terrain_check();
     748             : 
     749             :     // check for deadreckoning failsafe
     750      228158 :     failsafe_deadreckon_check();
     751             : 
     752             : #if AP_RC_TRANSMITTER_TUNING_ENABLED
     753             :     //update transmitter based in flight tuning
     754      228158 :     tuning();
     755             : #endif  // AP_RC_TRANSMITTER_TUNING_ENABLED
     756             : 
     757             :     // check if avoidance should be enabled based on alt
     758      228158 :     low_alt_avoidance();
     759      228158 : }
     760             : 
     761             : // ap_value calculates a 32-bit bitmask representing various pieces of
     762             : // state about the Copter.  It replaces a global variable which was
     763             : // used to track this state.
     764       72241 : uint32_t Copter::ap_value() const
     765             : {
     766       72241 :     uint32_t ret = 0;
     767             : 
     768       72241 :     const bool *b = (const bool *)&ap;
     769     2022748 :     for (uint8_t i=0; i<sizeof(ap); i++) {
     770     1950507 :         if (b[i]) {
     771      436945 :             ret |= 1U<<i;
     772             :         }
     773             :     }
     774             : 
     775       72241 :     return ret;
     776             : }
     777             : 
     778             : // one_hz_loop - runs at 1Hz
     779       75225 : void Copter::one_hz_loop()
     780             : {
     781             : #if HAL_LOGGING_ENABLED
     782       75225 :     if (should_log(MASK_LOG_ANY)) {
     783       72241 :         Log_Write_Data(LogDataID::AP_STATE, ap_value());
     784             :     }
     785             : #endif
     786             : 
     787       75225 :     if (!motors->armed()) {
     788       25912 :         update_using_interlock();
     789             : 
     790             :         // check the user hasn't updated the frame class or type
     791       25912 :         motors->set_frame_class_and_type((AP_Motors::motor_frame_class)g2.frame_class.get(), (AP_Motors::motor_frame_type)g.frame_type.get());
     792             : 
     793             : #if FRAME_CONFIG != HELI_FRAME
     794             :         // set all throttle channel settings
     795       23652 :         motors->update_throttle_range();
     796             : #endif
     797             :     }
     798             : 
     799             :     // update assigned functions and enable auxiliary servos
     800       75225 :     AP::srv().enable_aux_servos();
     801             : 
     802             : #if HAL_LOGGING_ENABLED
     803             :     // log terrain data
     804       75225 :     terrain_logging();
     805             : #endif
     806             : 
     807             : #if HAL_ADSB_ENABLED
     808       75225 :     adsb.set_is_flying(!ap.land_complete);
     809             : #endif
     810             : 
     811       75225 :     AP_Notify::flags.flying = !ap.land_complete;
     812             : 
     813             :     // slowly update the PID notches with the average loop rate
     814       75225 :     if (!using_rate_thread) {
     815       74939 :         attitude_control->set_notch_sample_rate(AP::scheduler().get_filtered_loop_rate_hz());
     816             :     }
     817       75225 :     pos_control->D_get_accel_pid().set_notch_sample_rate(AP::scheduler().get_filtered_loop_rate_hz());
     818             : #if AC_CUSTOMCONTROL_MULTI_ENABLED
     819       67166 :     custom_control.set_notch_sample_rate(AP::scheduler().get_filtered_loop_rate_hz());
     820             : #endif
     821             : 
     822             : #if AP_INERTIALSENSOR_FAST_SAMPLE_WINDOW_ENABLED
     823             :     // see if we should have a separate rate thread
     824       75225 :     if (!started_rate_thread && get_fast_rate_type() != FastRateType::FAST_RATE_DISABLED) {
     825           3 :         if (hal.scheduler->thread_create(FUNCTOR_BIND_MEMBER(&Copter::rate_controller_thread, void),
     826             :                                          "rate",
     827             :                                          1536, AP_HAL::Scheduler::PRIORITY_RCOUT, 1)) {
     828           3 :             started_rate_thread = true;
     829             :         } else {
     830           0 :             AP_BoardConfig::allocation_error("rate thread");
     831             :         }
     832             :     }
     833             : #endif
     834       75225 : }
     835             : 
     836         552 : void Copter::init_simple_bearing()
     837             : {
     838             :     // capture current cos_yaw and sin_yaw values
     839         552 :     simple_cos_yaw = ahrs.cos_yaw();
     840         552 :     simple_sin_yaw = ahrs.sin_yaw();
     841             : 
     842             :     // initialise super simple heading (i.e. heading towards home) to be 180 deg from simple mode heading
     843         552 :     super_simple_last_bearing_rad = wrap_2PI(ahrs.get_yaw_rad() + radians(180.0));
     844         552 :     super_simple_cos_yaw = simple_cos_yaw;
     845         552 :     super_simple_sin_yaw = simple_sin_yaw;
     846             : 
     847             : #if HAL_LOGGING_ENABLED
     848             :     // log the simple bearing
     849         552 :     if (should_log(MASK_LOG_ANY)) {
     850         552 :         Log_Write_Data(LogDataID::INIT_SIMPLE_BEARING, ahrs.yaw_sensor);
     851             :     }
     852             : #endif
     853         552 : }
     854             : 
     855             : // update_super_simple_bearing - adjusts simple bearing based on location
     856             : // should be called after home_bearing_rad has been updated
     857     3801507 : void Copter::update_super_simple_bearing(bool force_update)
     858             : {
     859     3801507 :     if (!force_update) {
     860     3801507 :         if (simple_mode != SimpleMode::SUPERSIMPLE) {
     861     3801507 :             return;
     862             :         }
     863           0 :         if (home_distance_m() < SUPER_SIMPLE_RADIUS_M) {
     864           0 :             return;
     865             :         }
     866             :     }
     867             : 
     868           0 :     const float bearing_rad = home_bearing_rad();
     869             : 
     870             :     // check the bearing to home has changed by at least 5 degrees
     871             :     // todo: consider updating this continuously
     872           0 :     if (fabsf(wrap_PI(super_simple_last_bearing_rad - bearing_rad)) < radians(5.0)) {
     873           0 :         return;
     874             :     }
     875             : 
     876           0 :     super_simple_last_bearing_rad = bearing_rad;
     877           0 :     const float angle_rad = super_simple_last_bearing_rad + radians(180.0);
     878           0 :     super_simple_cos_yaw = cosf(angle_rad);
     879           0 :     super_simple_sin_yaw = sinf(angle_rad);
     880             : }
     881             : 
     882    30412448 : void Copter::read_AHRS(void)
     883             : {
     884             :     // we tell AHRS to skip INS update as we have already done it in FAST_TASK.
     885    30412448 :     ahrs.update(true);
     886    30412448 : }
     887             : 
     888             : // read baro and log control tuning
     889      759512 : void Copter::update_altitude()
     890             : {
     891             :     // read in baro altitude
     892      759512 :     read_barometer();
     893             : 
     894             : #if HAL_LOGGING_ENABLED
     895      759512 :     if (should_log(MASK_LOG_CTUN)) {
     896      728325 :         Log_Write_Control_Tuning();
     897      728325 :         if (!should_log(MASK_LOG_FTN_FAST)) {
     898             : #if AP_INERTIALSENSOR_HARMONICNOTCH_ENABLED
     899      728325 :             AP::ins().write_notch_log_messages();
     900             : #endif
     901             : #if HAL_GYROFFT_ENABLED
     902      728325 :             gyro_fft.write_log_messages();
     903             : #endif
     904             :         }
     905             :     }
     906             : #endif
     907      759512 : }
     908             : 
     909             : // vehicle specific waypoint info helpers
     910             : #if AP_MOUNT_ROI_WPNEXT_OFFSET_ENABLED
     911        6657 : bool Copter::get_wp_location(Location &loc) const
     912             : {
     913        6657 :     return flightmode->get_wp(loc);
     914             : }
     915             : #endif  // AP_MOUNT_ROI_WPNEXT_OFFSET_ENABLED
     916             : 
     917       75223 : bool Copter::get_wp_distance_m(float &distance) const
     918             : {
     919             :     // see GCS_MAVLINK_Copter::send_nav_controller_output()
     920       75223 :     distance = flightmode->wp_distance_m();
     921       75223 :     return true;
     922             : }
     923             : 
     924             : // vehicle specific waypoint info helpers
     925       75223 : bool Copter::get_wp_bearing_deg(float &bearing) const
     926             : {
     927             :     // see GCS_MAVLINK_Copter::send_nav_controller_output()
     928       75223 :     bearing = flightmode->wp_bearing_deg();
     929       75223 :     return true;
     930             : }
     931             : 
     932             : // vehicle specific waypoint info helpers
     933       75223 : bool Copter::get_wp_crosstrack_error_m(float &xtrack_error) const
     934             : {
     935             :     // see GCS_MAVLINK_Copter::send_nav_controller_output()
     936       75223 :     xtrack_error = flightmode->crosstrack_error_m() * 0.01;
     937       75223 :     return true;
     938             : }
     939             : 
     940             : // get the target earth-frame angular velocities in rad/s (Z-axis component used by some gimbals)
     941       11602 : bool Copter::get_rate_ef_targets(Vector3f& rate_ef_targets_rads) const
     942             : {
     943             :     // always returns zero vector if landed or disarmed
     944       11602 :     if (copter.ap.land_complete) {
     945        4836 :         rate_ef_targets_rads.zero();
     946             :     } else {
     947        6766 :         rate_ef_targets_rads = attitude_control->get_rate_ef_target_rads();
     948             :     }
     949       11602 :     return true;
     950             : }
     951             : 
     952             : /*
     953             :   constructor for main Copter class
     954             :  */
     955        1001 : Copter::Copter(void)
     956             :     :
     957        1001 :     pos_variance_filt(FS_EKF_FILT_DEFAULT),
     958        1001 :     vel_variance_filt(FS_EKF_FILT_DEFAULT),
     959        1001 :     flightmode(&mode_stabilize),
     960        1001 :     simple_cos_yaw(1.0f),
     961        1001 :     super_simple_cos_yaw(1.0),
     962        1001 :     land_accel_ef_filter(LAND_DETECTOR_ACCEL_LPF_CUTOFF),
     963        1001 :     rc_throttle_control_in_filter(1.0f),
     964        3003 :     param_loader(var_info)
     965             : {
     966        1001 : }
     967             : 
     968             : Copter copter;
     969             : AP_Vehicle& vehicle = copter;
     970             : 
     971        1001 : AP_HAL_MAIN_CALLBACKS(&copter);

Generated by: LCOV version 1.14