LCOV - code coverage report
Current view: top level - home/pbarker/rc/ardupilot/ArduPlane - mode_qloiter.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 80 90 88.9 %
Date: 2026-09-09 11:02:08 Functions: 3 3 100.0 %

          Line data    Source code
       1             : #include "mode.h"
       2             : #include "Plane.h"
       3             : 
       4             : #if HAL_QUADPLANE_ENABLED
       5             : 
       6       15142 : bool ModeQLoiter::_enter()
       7             : {
       8             :     // initialise loiter
       9       15142 :     loiter_nav->clear_pilot_desired_acceleration();
      10       15142 :     loiter_nav->init_target();
      11             : 
      12             :     // set vertical speed and acceleration limits
      13             :     // All limits must be positive
      14       15142 :     pos_control->D_set_max_speed_accel_m(quadplane.get_pilot_velocity_z_max_dn_m(), quadplane.pilot_speed_z_max_up_ms, quadplane.pilot_accel_z_mss);
      15       15142 :     pos_control->D_set_correction_speed_accel_m(quadplane.get_pilot_velocity_z_max_dn_m(), quadplane.pilot_speed_z_max_up_ms, quadplane.pilot_accel_z_mss);
      16             : 
      17       15142 :     quadplane.init_throttle_wait();
      18             : 
      19             :     // prevent re-init of target position
      20       15142 :     quadplane.last_loiter_ms = AP_HAL::millis();
      21             : 
      22             :     // clear precland timestamp
      23       15142 :     last_target_loc_set_ms = 0;
      24             : 
      25       15142 :     return true;
      26             : }
      27             : 
      28      485907 : void ModeQLoiter::update()
      29             : {
      30      485907 :     plane.mode_qstabilize.update();
      31      485907 : }
      32             : 
      33             : // run quadplane loiter controller
      34      759335 : void ModeQLoiter::run()
      35             : {
      36      759335 :     if (quadplane.assist.check_VTOL_recovery()) {
      37             :         // use QHover to recover from extreme attitudes, this allows
      38             :         // for the fixed wing controller to handle the recovery
      39       16404 :         plane.mode_qhover.run();
      40      122716 :         return;
      41             :     }
      42             : 
      43      742931 :     const uint32_t now = AP_HAL::millis();
      44             : 
      45             : #if AC_PRECLAND_ENABLED
      46      742931 :     const uint32_t precland_timeout_ms = 250;
      47             :     /*
      48             :       see if precision landing or precision loiter is active with
      49             :       an override of the target location.
      50             : 
      51             :     */
      52      742931 :     const uint32_t last_pos_set_ms = last_target_loc_set_ms;
      53      742931 :     const uint32_t last_vel_set_ms = quadplane.poscontrol.last_velocity_match_ms;
      54             : 
      55      742931 :     if (last_pos_set_ms != 0 && now - last_pos_set_ms < precland_timeout_ms) {
      56             :         // we have an active landing target override
      57           0 :         Vector2f rel_origin;
      58           0 :         if (plane.next_WP_loc.get_vector_xy_from_origin_NE_cm(rel_origin)) {
      59           0 :             quadplane.pos_control->set_pos_desired_NE_m(rel_origin.topostype() * 0.01);
      60           0 :             last_target_loc_set_ms = 0;
      61             :         }
      62             :     }
      63             : 
      64             :     // allow for velocity override as well
      65      742931 :     if (last_vel_set_ms != 0 && now - last_vel_set_ms < precland_timeout_ms) {
      66             :         // we have an active landing velocity override
      67           0 :         Vector2f target_accel;
      68           0 :         Vector2f target_speed_xy_ms{quadplane.poscontrol.velocity_match_ms.x, quadplane.poscontrol.velocity_match_ms.y};
      69           0 :         quadplane.pos_control->input_vel_accel_NE_m(target_speed_xy_ms, target_accel);
      70           0 :         quadplane.poscontrol.last_velocity_match_ms = 0;
      71             :     }
      72             : #endif // AC_PRECLAND_ENABLED
      73             : 
      74      742931 :     if (quadplane.tailsitter.in_vtol_transition(now)) {
      75             :         // Tailsitters in FW pull up phase of VTOL transition run FW controllers
      76         427 :         Mode::run();
      77         427 :         return;
      78             :     }
      79             : 
      80      742504 :     if (quadplane.throttle_wait) {
      81      105885 :         quadplane.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
      82      105885 :         attitude_control->set_throttle_out(0, true, 0);
      83      105885 :         quadplane.relax_attitude_control();
      84      105885 :         pos_control->D_relax_controller(0);
      85      105885 :         loiter_nav->clear_pilot_desired_acceleration();
      86      105885 :         loiter_nav->init_target();
      87             : 
      88             :         // Stabilize with fixed wing surfaces
      89      105885 :         plane.stabilize_roll();
      90      105885 :         plane.stabilize_pitch();
      91      105885 :         return;
      92             :     }
      93      636619 :     if (!quadplane.motors->armed()) {
      94       15049 :         plane.mode_qloiter._enter();
      95             :     }
      96             : 
      97      636619 :     if (quadplane.should_relax()) {
      98       55270 :         loiter_nav->soften_for_landing();
      99             :     }
     100             : 
     101      636619 :     if (now - quadplane.last_loiter_ms > 500) {
     102          72 :         loiter_nav->clear_pilot_desired_acceleration();
     103          72 :         loiter_nav->init_target();
     104             :     }
     105      636619 :     quadplane.last_loiter_ms = now;
     106             : 
     107             :     // motors use full range
     108      636619 :     quadplane.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
     109             : 
     110             :     // set vertical speed and acceleration limits
     111             :     // All limits must be positive
     112      636619 :     pos_control->D_set_max_speed_accel_m(quadplane.get_pilot_velocity_z_max_dn_m(), quadplane.pilot_speed_z_max_up_ms, quadplane.pilot_accel_z_mss);
     113             : 
     114             :     // process pilot's roll and pitch input
     115             :     float target_roll_cd, target_pitch_cd;
     116      636619 :     quadplane.get_pilot_desired_lean_angles(target_roll_cd, target_pitch_cd, loiter_nav->get_angle_max_cd(), attitude_control->get_althold_lean_angle_max_cd());
     117      636619 :     loiter_nav->set_pilot_desired_acceleration_cd(target_roll_cd, target_pitch_cd);
     118             :     
     119             :     // run loiter controller
     120      636619 :     if (!pos_control->NE_is_active()) {
     121           0 :         pos_control->NE_init_controller();
     122             :     }
     123      636619 :     loiter_nav->update();
     124             : 
     125             :     // nav roll and pitch are controller by loiter controller
     126      636619 :     plane.nav_roll_cd = loiter_nav->get_roll_cd();
     127      636619 :     plane.nav_pitch_cd = loiter_nav->get_pitch_cd();
     128             : 
     129      636619 :     plane.quadplane.assign_tilt_to_fwd_thr();
     130             : 
     131      636619 :     if (quadplane.transition->set_VTOL_roll_pitch_limit(plane.nav_roll_cd, plane.nav_pitch_cd)) {
     132       14305 :         pos_control->NE_set_externally_limited();
     133             :     }
     134             : 
     135             :     // Pilot input, use yaw rate time constant
     136      636619 :     quadplane.set_pilot_yaw_rate_time_constant();
     137             : 
     138      636619 :     Vector3f target { plane.nav_roll_cd*0.01, plane.nav_pitch_cd*0.01, quadplane.get_desired_yaw_rate_cds() * 0.01 };
     139             : 
     140             : #if AP_PLANE_SYSTEMID_ENABLED
     141      636619 :     auto &systemid = plane.g2.systemid;
     142      636619 :     systemid.vtol_update();
     143      636619 :     target += systemid.get_attitude_offset_deg();
     144             : #endif
     145             : 
     146             :     // call attitude controller with conservative smoothing gain of 4.0f
     147      636619 :     attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw_cd(target.x*100,
     148      636619 :                                                                   target.y*100,
     149      636619 :                                                                   target.z*100);
     150             : 
     151      636619 :     if (plane.control_mode == &plane.mode_qland) {
     152      267747 :         if (poscontrol.get_state() < QuadPlane::QPOS_LAND_FINAL && quadplane.check_land_final()) {
     153          17 :             poscontrol.set_state(QuadPlane::QPOS_LAND_FINAL);
     154          17 :             quadplane.setup_target_position();
     155             : #if AP_ICENGINE_ENABLED
     156             :             // cut IC engine if enabled
     157          17 :             if (quadplane.land_icengine_cut != 0) {
     158          17 :                 plane.g2.ice_control.engine_control(0, 0, 0, false);
     159             :             }
     160             : #endif  // AP_ICENGINE_ENABLED
     161             :         }
     162      267747 :         float height_above_ground = plane.relative_ground_altitude(RangeFinderUse::TAKEOFF_LANDING);
     163      267747 :         float descent_rate_ms = quadplane.landing_descent_rate_ms(height_above_ground);
     164             : 
     165      267747 :         if (poscontrol.get_state() == QuadPlane::QPOS_LAND_FINAL && !quadplane.option_is_set(QuadPlane::Option::DISABLE_GROUND_EFFECT_COMP)) {
     166       84044 :             ahrs.set_touchdown_expected(true);
     167             :         }
     168             : 
     169      267747 :         pos_control->D_set_pos_target_from_climb_rate_ms(-descent_rate_ms, descent_rate_ms>0);
     170      267747 :         quadplane.check_land_complete();
     171      368872 :     } else if (plane.control_mode == &plane.mode_guided && quadplane.guided_takeoff) {
     172           0 :         quadplane.set_climb_rate_ms(0);
     173             :     } else {
     174             :         // update altitude target and call position controller
     175      368872 :         quadplane.set_climb_rate_ms(quadplane.get_pilot_desired_climb_rate_cms() * 0.01);
     176             :     }
     177      636619 :     quadplane.run_z_controller();
     178             : 
     179             :     // Stabilize with fixed wing surfaces
     180      636619 :     plane.stabilize_roll();
     181      636619 :     plane.stabilize_pitch();
     182             : 
     183             :     // Center rudder
     184      636619 :     output_rudder_and_steering(0.0);
     185             : }
     186             : 
     187             : #endif

Generated by: LCOV version 1.14