LCOV - code coverage report
Current view: top level - AC_WPNav - AC_Loiter.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 112 118 94.9 %
Date: 2026-09-09 11:02:08 Functions: 14 15 93.3 %

          Line data    Source code
       1             : #include <AP_HAL/AP_HAL.h>
       2             : #include "AC_Loiter.h"
       3             : #include <AP_Vehicle/AP_Vehicle_Type.h>
       4             : #include <AC_Avoidance/AC_Avoid.h>
       5             : 
       6             : extern const AP_HAL::HAL& hal;
       7             : 
       8             : #if APM_BUILD_TYPE(APM_BUILD_Heli)
       9             :  #define LOITER_SPEED_DEFAULT_MS             30.0    // Default horizontal loiter speed in m/s.
      10             :  #define LOITER_BRAKE_ACCEL_DEFAULT_MSS      1.25    // Default maximum braking acceleration when sticks are released (m/s²).
      11             :  #define LOITER_BRAKE_JERK_DEFAULT_MSSS      2.5    // Default maximum jerk applied during braking transitions (m/s³).
      12             : #else
      13             :  #define LOITER_SPEED_DEFAULT_MS             12.5    // Default horizontal loiter speed in m/s.
      14             :  #define LOITER_BRAKE_ACCEL_DEFAULT_MSS      2.5     // Default maximum braking acceleration when sticks are released (m/s²).
      15             :  #define LOITER_BRAKE_JERK_DEFAULT_MSSS      5.0     // Default maximum jerk applied during braking transitions (m/s³).
      16             : #endif
      17             : 
      18             : // Common defaults between trad heli and copter
      19             : #define LOITER_SPEED_MIN_MS                 0.2     // Minimum allowed horizontal loiter speed in m/s.
      20             : #define LOITER_ACCEL_MAX_DEFAULT_MSS        5.0     // Default maximum horizontal acceleration in loiter mode (m/s²).
      21             : #define LOITER_BRAKE_START_DELAY_DEFAULT_S  1.0     // Delay (in seconds) before braking begins after sticks are released.
      22             : #define LOITER_VEL_CORRECTION_MAX_MS        2.0     // Maximum speed (in m/s) used for correcting position errors in loiter.
      23             : #define LOITER_POS_CORRECTION_MAX_M         2.0     // Maximum horizontal position error allowed before correction (m).
      24             : #define LOITER_ACTIVE_TIMEOUT_MS            200     // Loiter is considered active if updated within the past 200 ms.
      25             : #define LOITER_DEFAULT_OPTIONS              1       // Enable Coordinated Turn by default.
      26             : 
      27             : const AP_Param::GroupInfo AC_Loiter::var_info[] = {
      28             : 
      29             :     // @Param: ANG_MAX
      30             :     // @DisplayName: Loiter pilot angle max
      31             :     // @Description{Copter, Sub}: Loiter maximum pilot requested lean angle. Set to zero for 2/3 of PSC_ANGLE_MAX/ATC_ANGLE_MAX. The maximum vehicle lean angle is still limited by PSC_ANGLE_MAX/ATC_ANGLE_MAX
      32             :     // @Description: Loiter maximum pilot requested lean angle. Set to zero for 2/3 of Q_P_ANGLE_MAX/Q_A_ANGLE_MAX. The maximum vehicle lean angle is still limited by Q_P_ANGLE_MAX/Q_A_ANGLE_MAX
      33             :     // @Units: deg
      34             :     // @Range: 0 45
      35             :     // @Increment: 1
      36             :     // @User: Advanced
      37             :     AP_GROUPINFO("ANG_MAX",  1, AC_Loiter, _angle_max_deg, 0.0f),
      38             : 
      39             :     // 2 was SPEED
      40             :     // 3 was ACC_MAX
      41             :     // 4 was BRK_ACCEL
      42             :     // 5 was BRK_JERK
      43             : 
      44             :     // @Param: BRK_DELAY
      45             :     // @DisplayName: Loiter brake start delay (in seconds)
      46             :     // @Description: Loiter brake start delay (in seconds)
      47             :     // @Units: s
      48             :     // @Range: 0 2
      49             :     // @Increment: 0.1
      50             :     // @User: Advanced
      51             :     AP_GROUPINFO("BRK_DELAY",  6, AC_Loiter, _brake_delay_s, LOITER_BRAKE_START_DELAY_DEFAULT_S),
      52             : 
      53             :     // @Param: OPTIONS
      54             :     // @DisplayName: Loiter mode options
      55             :     // @Description: Enables optional Loiter mode behaviors
      56             :     // @Bitmask: 0: Enable Coordinated turns
      57             :     // @User: Standard
      58             :     AP_GROUPINFO("OPTIONS", 7, AC_Loiter, _options, LOITER_DEFAULT_OPTIONS),
      59             : 
      60             :     // @Param: SPEED_MS
      61             :     // @DisplayName: Loiter Horizontal Maximum Speed
      62             :     // @Description: Defines the maximum speed in m/s which the aircraft will travel horizontally while in loiter mode
      63             :     // @Units: m/s
      64             :     // @Range: 0.20 35
      65             :     // @Increment: 0.05
      66             :     // @User: Standard
      67             :     AP_GROUPINFO("SPEED_MS", 8, AC_Loiter, _speed_max_ne_ms, LOITER_SPEED_DEFAULT_MS),
      68             : 
      69             :     // @Param: ACC_MAX_M
      70             :     // @DisplayName: Loiter maximum correction acceleration
      71             :     // @Description: Loiter maximum correction acceleration in m/s/s.  Higher values cause the copter to correct position errors more aggressively.
      72             :     // @Units: m/s/s
      73             :     // @Range: 1 9.81
      74             :     // @Increment: 0.01
      75             :     // @User: Advanced
      76             :     AP_GROUPINFO("ACC_MAX_M", 9, AC_Loiter, _accel_max_ne_mss, LOITER_ACCEL_MAX_DEFAULT_MSS),
      77             : 
      78             :     // @Param: BRK_ACC_M
      79             :     // @DisplayName: Loiter braking acceleration
      80             :     // @Description: Loiter braking acceleration in m/s/s. Higher values stop the copter more quickly when the stick is centered.
      81             :     // @Units: m/s/s
      82             :     // @Range: 0.25 2.5
      83             :     // @Increment: 0.01
      84             :     // @User: Advanced
      85             :     AP_GROUPINFO("BRK_ACC_M", 10, AC_Loiter, _brake_accel_max_mss, LOITER_BRAKE_ACCEL_DEFAULT_MSS),
      86             : 
      87             :     // @Param: BRK_JRK_M
      88             :     // @DisplayName: Loiter braking jerk
      89             :     // @Description: Loiter braking jerk in m/s/s/s. Higher values will remove braking faster if the pilot moves the sticks during a braking maneuver.
      90             :     // @Units: m/s/s/s
      91             :     // @Range: 5 50
      92             :     // @Increment: 0.01
      93             :     // @User: Advanced
      94             :     AP_GROUPINFO("BRK_JRK_M", 11, AC_Loiter, _brake_jerk_max_msss, LOITER_BRAKE_JERK_DEFAULT_MSSS),
      95             : 
      96             :     AP_GROUPEND
      97             : };
      98             : 
      99             : // Default constructor.
     100             : // Note that the Vector/Matrix constructors already implicitly zero
     101             : // their values.
     102        1285 : AC_Loiter::AC_Loiter(const AP_AHRS_View& ahrs, AC_PosControl& pos_control, const AC_AttitudeControl& attitude_control) :
     103        1285 :     _ahrs(ahrs),
     104        1285 :     _pos_control(pos_control),
     105        1285 :     _attitude_control(attitude_control)
     106             : {
     107        1285 :     AP_Param::setup_object_defaults(this, var_info);
     108        1285 : }
     109             : 
     110             : // Sets the initial loiter target position in meters from the EKF origin.
     111             : // - position_ne_m: horizontal position in the NE frame, in meters.
     112             : // - Initializes internal control state including acceleration targets and feed-forward planning.
     113          15 : void AC_Loiter::init_target_m(const Vector2p& position_ne_m)
     114             : {
     115          15 :     sanity_check_params();
     116             : 
     117             :     // Configure speed/accel limits in meters using internal parameter (_accel_max_ne_mss)
     118          15 :     _pos_control.NE_set_correction_speed_accel_m(LOITER_VEL_CORRECTION_MAX_MS, _accel_max_ne_mss);
     119          15 :     _pos_control.NE_set_pos_error_max_m(LOITER_POS_CORRECTION_MAX_M);
     120             : 
     121             :     // Reset controller state for stationary loiter
     122          15 :     _pos_control.NE_init_controller_stopping_point();
     123             : 
     124             :     // Zero out desired and predicted accelerations and angles
     125          15 :     _predicted_accel_ne_mss.zero();
     126          15 :     _desired_accel_ne_mss.zero();
     127          15 :     _predicted_euler_angle_rad.zero();
     128          15 :     _brake_accel_mss = 0.0f;
     129             : 
     130             :     // Set position target for stationary loiter
     131          15 :     _pos_control.set_pos_desired_NE_m(position_ne_m);
     132          15 : }
     133             : 
     134             : // Initializes the loiter controller using the current position and velocity.
     135             : // Updates feed-forward velocity, predicted acceleration, and resets control state.
     136     1380431 : void AC_Loiter::init_target()
     137             : {
     138     1380431 :     sanity_check_params();
     139             : 
     140             :     // Configure correction speed and acceleration limits (in m/s and m/s²)
     141     1380431 :     _pos_control.NE_set_correction_speed_accel_m(LOITER_VEL_CORRECTION_MAX_MS, _accel_max_ne_mss);
     142     1380431 :     _pos_control.NE_set_pos_error_max_m(LOITER_POS_CORRECTION_MAX_M);
     143             : 
     144             :     // Apply velocity smoothing: softly transitions target acceleration to zero
     145     1380431 :     _pos_control.NE_relax_velocity_controller();
     146             : 
     147             :     // Initialize prediction state using current acceleration and lean angles
     148     1380431 :     _predicted_accel_ne_mss = _pos_control.get_accel_target_NED_mss().xy();
     149     1380431 :     _predicted_euler_angle_rad.x = _pos_control.get_roll_rad();
     150     1380431 :     _predicted_euler_angle_rad.y = _pos_control.get_pitch_rad();
     151     1380431 :     _predicted_euler_rate.zero();
     152     1380431 :     _predicted_euler_accel.zero();
     153     1380431 :     _brake_accel_mss = 0.0f;
     154     1380431 : }
     155             : 
     156             : // Reduces loiter responsiveness for smoother descent during landing.
     157             : // Internally softens horizontal control gains.
     158     1416114 : void AC_Loiter::soften_for_landing()
     159             : {
     160     1416114 :     _pos_control.NE_soften_for_landing();
     161     1416114 : }
     162             : 
     163             : // Sets pilot desired acceleration using Euler angles in centidegrees.
     164             : // See set_pilot_desired_acceleration_rad() for full details.
     165      636619 : void AC_Loiter::set_pilot_desired_acceleration_cd(float euler_roll_angle_cd, float euler_pitch_angle_cd)
     166             : {
     167      636619 :     set_pilot_desired_acceleration_rad(cd_to_rad(euler_roll_angle_cd), cd_to_rad(euler_pitch_angle_cd));
     168      636619 : }
     169             : 
     170             : // Sets pilot desired acceleration using Euler angles in radians.
     171             : // - Internally computes a smoothed acceleration vector based on predictive rate shaping.
     172             : // - Inputs: `euler_roll_angle_rad`, `euler_pitch_angle_rad` in radians.
     173             : // - Applies internal shaping using the current attitude controller dt.
     174     4579903 : void AC_Loiter::set_pilot_desired_acceleration_rad(float euler_roll_angle_rad, float euler_pitch_angle_rad)
     175             : {
     176     4579903 :     const float dt_s = _attitude_control.get_dt_s();
     177             : 
     178             :     // convert our desired attitude to an acceleration vector assuming we are not accelerating vertically
     179     4579903 :     const Vector3f desired_euler_rad {euler_roll_angle_rad, euler_pitch_angle_rad, _ahrs.yaw};
     180     4579903 :     _desired_accel_ne_mss = _pos_control.lean_angles_rad_to_accel_NED_mss(desired_euler_rad).xy();
     181             : 
     182             :     // Reset brake timer if there is pilot input
     183     4579903 :     if (!_desired_accel_ne_mss.is_zero()) {
     184      506011 :         _brake_timer_ms = AP_HAL::millis();
     185             :     }
     186             : 
     187             :     // Compute attitude error between desired and predicted lean angles
     188     4579903 :     Vector2f angle_error_euler_rad(wrap_PI(euler_roll_angle_rad - _predicted_euler_angle_rad.x), wrap_PI(euler_pitch_angle_rad - _predicted_euler_angle_rad.y));
     189             : 
     190             :     // Predict roll/pitch rate required to achieve target attitude
     191     4579903 :     _attitude_control.command_model_rate_predictor(angle_error_euler_rad, _predicted_euler_rate, _predicted_euler_accel, dt_s);
     192             : 
     193             :     // Update internal attitude estimate for next iteration
     194     4579903 :     _predicted_euler_angle_rad += _predicted_euler_rate * dt_s;
     195             : 
     196             :     // Convert predicted angles into an acceleration vector for braking/shaping
     197     4579903 :     const Vector3f predicted_euler_rad {_predicted_euler_angle_rad.x, _predicted_euler_angle_rad.y, _ahrs.yaw};
     198     4579903 :     const Vector3f predicted_accel_ned_mss = _pos_control.lean_angles_rad_to_accel_NED_mss(predicted_euler_rad);
     199             : 
     200     4579903 :     _predicted_accel_ne_mss = predicted_accel_ned_mss.xy();
     201             : 
     202     4579903 :     if (loiter_option_is_set(LoiterOption::COORDINATED_TURN_ENABLED)) {
     203     4493130 :         Vector3f target_ang_vel_rads = _attitude_control.get_attitude_target_ang_vel();
     204     4493130 :         Vector3f desired_velocity_ms = _pos_control.get_vel_desired_NED_ms();
     205     4493130 :         Vector2f turn_accel_ne_mss = Vector2f(-desired_velocity_ms.y * target_ang_vel_rads.z, desired_velocity_ms.x * target_ang_vel_rads.z);
     206     4493130 :         _desired_accel_ne_mss += turn_accel_ne_mss;
     207     4493130 :         _predicted_accel_ne_mss += turn_accel_ne_mss;
     208             :     }
     209     4579903 : }
     210             : 
     211             : // Calculates the expected stopping point based on current velocity and position in the NE frame.
     212             : // Result is returned in meters.
     213             : // Uses the position controller’s deceleration model.
     214           0 : void AC_Loiter::get_stopping_point_NE_m(Vector2f& stopping_point_ne_m) const
     215             : {
     216           0 :     Vector2p stop_ne_m;
     217             :     // Query stopping point from position controller in postype (float or double)
     218           0 :     _pos_control.get_stopping_point_NE_m(stop_ne_m);
     219             : 
     220             :     // Convert from postype to float (Vector2f)
     221           0 :     stopping_point_ne_m = stop_ne_m.tofloat();
     222           0 : }
     223             : 
     224             : // Returns the maximum pilot-commanded lean angle in centidegrees.
     225             : // See get_angle_max_rad() for full details.
     226      636619 : float AC_Loiter::get_angle_max_cd() const
     227             : {
     228             :     // Convert radians to centidegrees
     229      636619 :     return rad_to_cd(get_angle_max_rad());
     230             : }
     231             : 
     232             : // Returns the maximum pilot-commanded lean angle in radians.
     233             : // - If `_angle_max_deg` is zero, this returns 2/3 of the limiting PSC angle.
     234             : // - Otherwise, returns the minimum of `_angle_max_deg` and PSC’s configured angle limit.
     235     7196011 : float AC_Loiter::get_angle_max_rad() const
     236             : {
     237     7196011 :     if (!is_positive(_angle_max_deg)) {
     238             :         // Use 2/3 of the smallest system-wide max lean angle
     239     5843138 :         return MIN(_attitude_control.lean_angle_max_rad(), _pos_control.get_lean_angle_max_rad()) * (2.0f / 3.0f);
     240             :     }
     241             :     // Use configured parameter (in degrees), constrained to PSC limit
     242     1352873 :     return MIN(radians(_angle_max_deg), _pos_control.get_lean_angle_max_rad());
     243             : }
     244             : 
     245             : // Runs the loiter control loop, computing desired acceleration and updating position control.
     246             : // If `avoidance_on` is true, velocity is adjusted using avoidance logic before being applied.
     247     3029099 : void AC_Loiter::update(bool avoidance_on)
     248             : {
     249             :     // Calculate desired velocity using pilot inputs, braking, and drag
     250     3029099 :     calc_desired_velocity(avoidance_on);
     251             : 
     252             :     // Run position controller to compute desired attitude and thrust
     253     3029099 :     _pos_control.NE_update_controller();
     254     3029099 : }
     255             : 
     256             : // Sets the maximum allowed horizontal loiter speed in m/s.
     257         672 : void AC_Loiter::set_speed_max_NE_ms(float speed_max_ne_ms)
     258             : {
     259         672 :     _speed_max_ne_ms.set(MAX(speed_max_ne_ms, LOITER_SPEED_MIN_MS));
     260         672 : }
     261             : 
     262             : // perform any required parameter conversions
     263        1285 : void AC_Loiter::convert_parameters()
     264             : {
     265             :     // PARAMETER_CONVERSION - Added: Jan-2026 for ArduPilot-4.7
     266             : 
     267             :     // return immediately if no conversion is needed
     268        1285 :     if (_speed_max_ne_ms.configured() || _accel_max_ne_mss.configured() || _brake_accel_max_mss.configured() || _brake_jerk_max_msss.configured()) {
     269          11 :         return;
     270             :     }
     271             : 
     272             : #if APM_BUILD_TYPE(APM_BUILD_ArduPlane)
     273             :     // convert QuadPlane parameters
     274             :     static const AP_Param::ConversionInfo conversion_info[] = {
     275             :         { 205, 8379, AP_PARAM_FLOAT, "Q_LOIT_SPEED_MS" },   // Q_LOIT_SPEED moved to Q_LOIT_SPEED_MS
     276             :         { 205, 12475, AP_PARAM_FLOAT, "Q_LOIT_ACC_MAX_M" }, // Q_LOIT_ACC_MAX moved to Q_LOIT_ACC_MAX_M
     277             :         { 205, 16571, AP_PARAM_FLOAT, "Q_LOIT_BRK_ACC_M" }, // Q_LOIT_BRK_ACCEL moved to Q_LOIT_BRK_ACC_M
     278             :         { 205, 20667, AP_PARAM_FLOAT, "Q_LOIT_BRK_JRK_M" }, // Q_LOIT_BRK_JERK moved to Q_LOIT_BRK_JRK_M
     279             :     };
     280             : #elif APM_BUILD_TYPE(APM_BUILD_ArduSub)
     281             :     // convert Sub parameters
     282             :     static const AP_Param::ConversionInfo conversion_info[] = {
     283             :         { 63, 2, AP_PARAM_FLOAT, "LOIT_SPEED_MS" },     // LOIT_SPEED moved to LOIT_SPEED_MS
     284             :         { 63, 3, AP_PARAM_FLOAT, "LOIT_ACC_MAX_M" },    // LOIT_ACC_MAX moved to LOIT_ACC_MAX_M
     285             :         { 63, 4, AP_PARAM_FLOAT, "LOIT_BRK_ACC_M" },    // LOIT_BRK_ACCEL moved to LOIT_BRK_ACC_M
     286             :         { 63, 5, AP_PARAM_FLOAT, "LOIT_BRK_JRK_M" },    // LOIT_BRK_JERK moved to LOIT_BRK_JRK_M
     287             :     };
     288             : #else
     289             :     // convert Copter parameters
     290             :     static const AP_Param::ConversionInfo conversion_info[] = {
     291             :         { 105, 2, AP_PARAM_FLOAT, "LOIT_SPEED_MS" },    // LOIT_SPEED moved to LOIT_SPEED_MS
     292             :         { 105, 3, AP_PARAM_FLOAT, "LOIT_ACC_MAX_M" },   // LOIT_ACC_MAX moved to LOIT_ACC_MAX_M
     293             :         { 105, 4, AP_PARAM_FLOAT, "LOIT_BRK_ACC_M" },   // LOIT_BRK_ACCEL moved to LOIT_BRK_ACC_M
     294             :         { 105, 5, AP_PARAM_FLOAT, "LOIT_BRK_JRK_M" },   // LOIT_BRK_JERK moved to LOIT_BRK_JRK_M
     295             :     };
     296             : #endif
     297             : 
     298        1274 :     AP_Param::convert_old_parameters_scaled(conversion_info, ARRAY_SIZE(conversion_info), 0.01, 0);
     299             : }
     300             : 
     301             : // Ensures internal parameters are within valid safety limits.
     302             : // Applies min/max constraints on speed and acceleration settings.
     303     1380446 : void AC_Loiter::sanity_check_params()
     304             : {
     305             :     // Enforce minimum loiter speed
     306     1380446 :     _speed_max_ne_ms.set(MAX(_speed_max_ne_ms, LOITER_SPEED_MIN_MS));
     307             : 
     308             :     // Clamp horizontal accel to lean-angle-limited max
     309     1380446 :     _accel_max_ne_mss.set(MIN(_accel_max_ne_mss, GRAVITY_MSS * tanf(_attitude_control.lean_angle_max_rad())));
     310     1380446 : }
     311             : 
     312     4579903 : bool AC_Loiter::loiter_option_is_set(LoiterOption option) const {
     313     4579903 :     return (_options & int8_t(option)) != 0;
     314             : }
     315             : 
     316             : // Updates feed-forward velocity using pilot-requested acceleration and braking logic.
     317             : // - Applies drag and braking forces when sticks are released.
     318             : // - Velocity is adjusted for fence/avoidance if enabled.
     319             : // - Resulting velocity and acceleration are sent to the position controller.
     320     3029099 : void AC_Loiter::calc_desired_velocity(bool avoidance_on)
     321             : {
     322             :     // the estimator might impose limits on maximum velocity (e.g. due
     323             :     // to the sensors being used to supply its estimated velocity):
     324     3029099 :     const float ekfGndSpdLimit_ms = AP::ahrs().get_control_ground_speed_limit_ms();
     325             : 
     326     3029099 :     const float dt_s = _pos_control.get_dt_s();
     327             : 
     328             :     // Apply speed limit from LOITER_SPEED and EKF constraint
     329     3029099 :     float gnd_speed_limit_ms = MIN(_speed_max_ne_ms, ekfGndSpdLimit_ms);
     330     3029099 :     gnd_speed_limit_ms = MAX(gnd_speed_limit_ms, LOITER_SPEED_MIN_MS);
     331             : 
     332             :     // Determine acceleration limit based on maximum allowed lean angle
     333     3029099 :     float pilot_acceleration_max_mss = (gnd_speed_limit_ms / _speed_max_ne_ms) * angle_rad_to_accel_mss(get_angle_max_rad());
     334             : 
     335             :     // Check for invalid dt
     336     3029099 :     if (is_negative(dt_s)) {
     337           0 :         return;
     338             :     }
     339             : 
     340             :     // Integrate predicted acceleration
     341     3029099 :     Vector2f desired_vel_ne_ms = _pos_control.get_vel_desired_NED_ms().xy();
     342             : 
     343             :     // update the desired velocity using our predicted acceleration
     344     3029099 :     desired_vel_ne_ms += _predicted_accel_ne_mss * dt_s;
     345             : 
     346     3029099 :     Vector2f loiter_accel_brake_mss;
     347     3029099 :     float desired_speed_ms = desired_vel_ne_ms.length();
     348     3029099 :     if (!is_zero(desired_speed_ms)) {
     349     2956906 :         Vector2f desired_vel_norm = desired_vel_ne_ms / desired_speed_ms;
     350             : 
     351             :         // Apply drag: deceleration proportional to current velocity
     352     2956906 :         float drag_decel_mss = pilot_acceleration_max_mss * desired_speed_ms / gnd_speed_limit_ms;
     353             : 
     354             :         // Determine braking acceleration based on stick release and delay timer, stick must have been released for at least a full loop
     355     2956906 :         float loiter_brake_accel_mss = 0.0f;
     356     2956906 :         if ((AP_HAL::millis() - _brake_timer_ms) > MAX(_brake_delay_s, dt_s) * 1000.0) {
     357     2432684 :             const float brake_gain = _pos_control.NE_get_vel_pid().kP() * 0.5f;
     358     2432684 :             loiter_brake_accel_mss = constrain_float(sqrt_controller(desired_speed_ms, brake_gain, _brake_jerk_max_msss, dt_s), 0.0f, _brake_accel_max_mss);
     359             :         }
     360             : 
     361             :         // Integrate jerk-limited brake acceleration
     362     2956906 :         _brake_accel_mss += constrain_float(loiter_brake_accel_mss - _brake_accel_mss, -_brake_jerk_max_msss * dt_s, _brake_jerk_max_msss * dt_s);
     363     2956906 :         loiter_accel_brake_mss = desired_vel_norm * _brake_accel_mss;
     364             : 
     365             :         // Update desired speed based on braking and drag
     366     2956906 :         desired_speed_ms = MAX(desired_speed_ms - (drag_decel_mss + _brake_accel_mss) * dt_s, 0.0f);
     367     2956906 :         desired_vel_ne_ms = desired_vel_norm * desired_speed_ms;
     368             :     }
     369             : 
     370             :     // Apply braking acceleration to overall feed-forward acceleration
     371     3029099 :     _desired_accel_ne_mss -= loiter_accel_brake_mss;
     372             : 
     373             :     // Apply final velocity magnitude constraint
     374     3029099 :     float desired_vel_ms = desired_vel_ne_ms.length();
     375     3029099 :     if (desired_vel_ms > gnd_speed_limit_ms) {
     376       16634 :         desired_vel_ne_ms = desired_vel_ne_ms * gnd_speed_limit_ms / desired_vel_ms;
     377             :     }
     378             : 
     379             : #if AP_AVOIDANCE_ENABLED && !APM_BUILD_TYPE(APM_BUILD_ArduPlane)
     380     2392480 :     if (avoidance_on) {
     381             :         // Apply fence/obstacle avoidance adjustments (velocity only)
     382             :         // TODO: We need to also limit the _desired_accel_ne_mss
     383     2303168 :         AC_Avoid *_avoid = AP::ac_avoid();
     384     2303168 :         if (_avoid != nullptr) {
     385     2296480 :             Vector3f avoidance_vel_ned_cms{desired_vel_ne_ms.x * 100.0, desired_vel_ne_ms.y * 100.0, 0.0f};
     386     2296480 :             _avoid->adjust_velocity(avoidance_vel_ned_cms, _pos_control.NE_get_pos_p().kP(), _accel_max_ne_mss * 100.0, _pos_control.D_get_pos_p().kP(), _pos_control.D_get_max_accel_mss() * 100.0, dt_s);
     387     2296480 :             desired_vel_ne_ms = avoidance_vel_ned_cms.xy() * 0.01;
     388             :         }
     389             :     }
     390             : #endif // !APM_BUILD_ArduPlane
     391             : 
     392             :     // Retrieve current desired position
     393     3029099 :     Vector2p desired_pos_ned_m = _pos_control.get_pos_desired_NED_m().xy();
     394             : 
     395             :     // Integrate velocity to update desired position
     396     3029099 :     desired_pos_ned_m += (desired_vel_ne_ms * dt_s).topostype();
     397             : 
     398             :     // Send updated position, velocity, and acceleration to the position controller
     399     3029099 :     _pos_control.set_pos_vel_accel_NE_m(desired_pos_ned_m, desired_vel_ne_ms, _desired_accel_ne_mss);
     400             : }

Generated by: LCOV version 1.14