#pragma once12#include <AP_Common/AP_Common.h>3#include <AP_Param/AP_Param.h>4#include <AP_Math/AP_Math.h>5#include <AP_Common/Location.h>6#include <AC_AttitudeControl/AC_PosControl.h>7#include <AC_AttitudeControl/AC_AttitudeControl.h>8#include <AC_Avoidance/AC_Avoid.h>910class AC_Loiter11{12public:1314/// Constructor15AC_Loiter(const AP_AHRS_View& ahrs, AC_PosControl& pos_control, const AC_AttitudeControl& attitude_control);1617// Sets the initial loiter target position in meters from the EKF origin.18// - position_ne_m: horizontal position in the NE frame, in meters.19// - Initializes internal control state including acceleration targets and feed-forward planning.20void init_target_m(const Vector2p& position_ne_m);2122// Initializes the loiter controller using the current position and velocity.23// Updates feed-forward velocity, predicted acceleration, and resets control state.24void init_target();2526// Reduces loiter responsiveness for smoother descent during landing.27// Internally softens horizontal control gains.28void soften_for_landing();2930// Sets pilot desired acceleration using Euler angles in centidegrees.31// See set_pilot_desired_acceleration_rad() for full details.32void set_pilot_desired_acceleration_cd(float euler_roll_angle_cd, float euler_pitch_angle_cd);3334// Sets pilot desired acceleration using Euler angles in radians.35// - Internally computes a smoothed acceleration vector based on predictive rate shaping.36// - Inputs: `euler_roll_angle_rad`, `euler_pitch_angle_rad` in radians.37// - Applies internal shaping using the current attitude controller dt.38void set_pilot_desired_acceleration_rad(float euler_roll_angle_rad, float euler_pitch_angle_rad);3940// Returns pilot-requested horizontal acceleration in the NE frame in m/s².41// This is the internally computed and smoothed acceleration vector applied by the loiter controller.42const Vector2f& get_pilot_desired_acceleration_NE_mss() const { return _desired_accel_ne_mss; }4344// Clears any pilot-requested acceleration by setting roll and pitch inputs to zero.45void clear_pilot_desired_acceleration() { set_pilot_desired_acceleration_rad(0.0, 0.0); }4647// Calculates the expected stopping point based on current velocity and position in the NE frame.48// Result is returned in meters.49// Uses the position controller’s deceleration model.50void get_stopping_point_NE_m(Vector2f& stopping_point_ne_m) const;5152// Returns the horizontal distance to the loiter target in meters.53// Computed using the NE position error from the position controller.54float get_distance_to_target_m() const { return _pos_control.get_pos_error_NE_m(); }5556// Returns the bearing from current position to the loiter target in radians.57// Bearing is relative to true north, using the NE frame.58float get_bearing_to_target_rad() const { return _pos_control.get_bearing_to_target_rad(); }5960// Returns the maximum pilot-commanded lean angle in centidegrees.61// See get_angle_max_rad() for full details.62float get_angle_max_cd() const;6364// Returns the maximum pilot-commanded lean angle in radians.65// - If `_angle_max_deg` is zero, this returns 2/3 of the limiting PSC angle.66// - Otherwise, returns the minimum of `_angle_max_deg` and PSC’s configured angle limit.67float get_angle_max_rad() const;6869// Runs the loiter control loop, computing desired acceleration and updating position control.70// If `avoidance_on` is true, velocity is adjusted using avoidance logic before being applied.71void update(bool avoidance_on = true);7273// Sets the maximum allowed horizontal loiter speed in m/s.74void set_speed_max_NE_ms(float speed_max_NE_ms);7576// Returns the desired roll angle in centidegrees from the loiter controller.77float get_roll_cd() const { return rad_to_cd(get_roll_rad()); }7879// Returns the desired pitch angle in centidegrees from the loiter controller.80float get_pitch_cd() const { return rad_to_cd(get_pitch_rad()); }8182// Returns the desired roll angle in radians from the loiter controller.83float get_roll_rad() const { return _pos_control.get_roll_rad(); }8485// Returns the desired pitch angle in radians from the loiter controller.86float get_pitch_rad() const { return _pos_control.get_pitch_rad(); }8788// Returns the desired 3D thrust vector from the loiter controller for attitude control.89// Directional only; magnitude is handled by the attitude controller.90Vector3f get_thrust_vector() const { return _pos_control.get_thrust_vector(); }9192// perform any required parameter conversions93void convert_parameters();9495static const struct AP_Param::GroupInfo var_info[];9697protected:9899// Ensures internal parameters are within valid safety limits.100// Applies min/max constraints on speed and acceleration settings.101void sanity_check_params();102103// Updates feed-forward velocity using pilot-requested acceleration and braking logic.104// - Applies drag and braking forces when sticks are released.105// - Velocity is adjusted for fence/avoidance if enabled.106// - Resulting velocity and acceleration are sent to the position controller.107void calc_desired_velocity(bool avoidance_on = true);108109// references and pointers to external libraries110const AP_AHRS_View& _ahrs;111AC_PosControl& _pos_control;112const AC_AttitudeControl& _attitude_control;113114// parameters115AP_Float _angle_max_deg; // Maximum pilot-commanded lean angle in degrees. Set to zero to default to 2/3 of PSC_ANGLE_MAX (or Q_ANGLE_MAX for QuadPlane).116AP_Float _speed_max_ne_ms; // Maximum horizontal speed in m/s while in loiter mode. Used to limit both user and internal trajectory velocities.117AP_Float _accel_max_ne_mss; // Maximum horizontal acceleration (in m/s²) applied during normal loiter corrections.118AP_Float _brake_accel_max_mss; // Maximum braking acceleration (in m/s²) applied when pilot sticks are released.119AP_Float _brake_jerk_max_msss; // Maximum braking jerk (in m/s³) applied during braking transitions after pilot release.120AP_Float _brake_delay_s; // Delay in seconds before braking begins after sticks are centered. Prevents premature deceleration during brief pauses.121AP_Int8 _options; // Loiter options bit mask122123// Bitfields of LOITER_OPTIONS124enum class LoiterOption {125COORDINATED_TURN_ENABLED = (1U << 0), // Enable Coordinated Turn126};127bool loiter_option_is_set(LoiterOption option) const;128129// loiter controller internal variables130Vector2f _desired_accel_ne_mss; // Pilot-requested horizontal acceleration in m/s² (after smoothing), in the NE (horizontal) frame.131Vector2f _predicted_accel_ne_mss; // Predicted acceleration in m/s² based on internal rate shaping of pilot input.132Vector2f _predicted_euler_angle_rad; // Predicted roll/pitch angles (in radians) used for rate shaping of pilot input.133Vector2f _predicted_euler_rate; // Predicted roll/pitch angular rates (in rad/s) for pilot acceleration shaping.134Vector2f _predicted_euler_accel; // Predicted roll/pitch angular rates (in rad/s) for pilot acceleration shaping.135uint32_t _brake_timer_ms; // Timestamp (in ms) when braking logic was last triggered (sticks released).136float _brake_accel_mss; // Current braking acceleration in m/s², updated using jerk limits over time.137};138139140