#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_Math/SCurve.h>6#include <AP_Math/SplineCurve.h>7#include <AP_Common/Location.h>8#include <AC_AttitudeControl/AC_PosControl.h> // Position control library9#include <AC_AttitudeControl/AC_AttitudeControl.h> // Attitude control library10#include <AP_Terrain/AP_Terrain.h>11#include <AC_Avoidance/AC_Avoid.h> // Stop at fence library1213// maximum velocities and accelerations14#define WPNAV_ACCELERATION_MS 2.5 // default horizontal acceleration limit for waypoint navigation (m/s²)1516class AC_WPNav17{18public:1920/// Constructor21AC_WPNav(const AP_AHRS_View& ahrs, AC_PosControl& pos_control, const AC_AttitudeControl& attitude_control);2223// Sets terrain offset in cm from EKF origin using rangefinder.24// See set_rangefinder_terrain_U_m() for full details.25void set_rangefinder_terrain_U_cm(bool use, bool healthy, float terrain_u_cm) { _rangefinder_available = use; _rangefinder_healthy = healthy; _rangefinder_terrain_u_m = terrain_u_cm * 0.01;}2627// Sets terrain offset in meters from EKF origin using rangefinder data.28// This value is used to determine alt-above-terrain for terrain following.29void set_rangefinder_terrain_U_m(bool use, bool healthy, float terrain_u_m) { _rangefinder_available = use; _rangefinder_healthy = healthy; _rangefinder_terrain_u_m = terrain_u_m;}3031// Returns true if rangefinder is enabled and may be used for terrain following.32bool rangefinder_used() const { return _rangefinder_use; }3334// Returns true if rangefinder is enabled and currently healthy.35bool rangefinder_used_and_healthy() const { return _rangefinder_use && _rangefinder_healthy; }3637// Returns the expected source of terrain data when using alt-above-terrain commands.38// Used by systems like ModeRTL to determine which terrain provider is active.39enum class TerrainSource {40TERRAIN_UNAVAILABLE,41TERRAIN_FROM_RANGEFINDER,42TERRAIN_FROM_TERRAINDATABASE,43};44AC_WPNav::TerrainSource get_terrain_source() const;4546// Returns terrain offset in meters above the EKF origin at the current position.47// Positive values mean terrain lies above the EKF origin altitude.48// Source may be rangefinder or terrain database depending on availability.49bool get_terrain_U_m(float& terrain_u_m);50bool get_terrain_D_m(float& terrain_d_m);5152// Returns the terrain following altitude margin in meters.53// Vehicle will stop if distance from target altitude exceeds this margin.54float get_terrain_margin_m() const { return MAX(_terrain_margin_m, 0.1); }5556// Converts a Location to a NED position vector in meters from the EKF origin.57// Sets `is_terrain_alt` to true if the resulting Z position is relative to terrain.58// Returns false if terrain data is unavailable or conversion fails.59bool get_vector_NED_m(const Location &loc, Vector3p &pos_from_origin_ned_m, bool &is_terrain_alt);6061///62/// waypoint controller63///6465// Initializes waypoint and spline navigation using inputs in meters.66// Sets speed and acceleration limits, calculates jerk constraints,67// and initializes spline or S-curve leg with a defined starting point.68void wp_and_spline_init_m(float speed_ms = 0.0f, Vector3p stopping_point_ned_m = Vector3p{});6970// Sets the target horizontal speed in cm/s during waypoint navigation.71// See set_speed_NE_ms() for full details.72void set_speed_NE_cms(float speed_cms);7374// Sets the target horizontal speed in m/s during waypoint navigation.75// Also updates internal velocity offsets and path shaping limits.76void set_speed_NE_ms(float speed_ms);7778// Pauses progression along the waypoint track.79void set_pause() { _paused = true; }8081// Resumes waypoint navigation after a pause. Track advancement continues from the current position.82void set_resume() { _paused = false; }8384// Returns true if waypoint navigation is currently paused via set_pause().85bool paused() { return _paused; }8687// Sets the climb speed for waypoint navigation in m/s.88// Updates the vertical controller with the new ascent rate limit.89void set_speed_up_ms(float speed_up_ms);9091// Sets the descent speed for waypoint navigation in m/s.92// Updates the vertical controller with the new descent rate limit.93void set_speed_down_ms(float speed_down_ms);9495// Returns the default horizontal speed in cm/s used during waypoint navigation.96// See get_default_speed_NE_ms() for full details.97float get_default_speed_NE_cms() const { return get_default_speed_NE_ms() * 100.0; }9899// Returns the default horizontal speed in m/s used during waypoint navigation.100// Derived from the WPNAV_SPEED parameter.101float get_default_speed_NE_ms() const { return _wp_speed_cms * 0.01; }102103// Returns the default climb speed in cm/s used during waypoint navigation.104// See get_default_speed_up_ms() for full details.105float get_default_speed_up_cms() const { return get_default_speed_up_ms() * 100.0; }106107// Returns the default climb speed in m/s used during waypoint navigation.108// Derived from the WPNAV_SPEED_UP parameter.109float get_default_speed_up_ms() const { return _wp_speed_up_cms * 0.01; }110111// Returns the default descent rate in cm/s used during waypoint navigation.112// Always positive. See get_default_speed_down_ms() for full details.113float get_default_speed_down_cms() const { return get_default_speed_down_ms() * 100.0; }114115// Returns the default descent rate in m/s used during waypoint navigation.116// Derived from the WPNAV_SPEED_DN parameter. Always positive.117float get_default_speed_down_ms() const { return fabsf(_wp_speed_down_cms * 0.01); }118119// Returns the vertical acceleration in cm/s² used during waypoint navigation.120// Always positive. See get_accel_D_mss() for full details.121float get_accel_D_cmss() const { return get_accel_D_mss() * 100.0; }122123// Returns the vertical acceleration in m/s² used during waypoint navigation.124// Derived from the WPNAV_ACCEL_Z parameter. Always positive.125float get_accel_D_mss() const { return _wp_accel_z_cmss * 0.01; }126127// Returns the horizontal acceleration in cm/s² used during waypoint navigation.128// See get_wp_acceleration_mss() for full details.129float get_wp_acceleration_cmss() const { return get_wp_acceleration_mss() * 100.0; }130131// Returns the horizontal acceleration in m/s² used during waypoint navigation.132// Derived from the WPNAV_ACCEL parameter. Falls back to a default if unset.133float get_wp_acceleration_mss() const { return (is_positive(_wp_accel_cmss)) ? _wp_accel_cmss * 0.01 : WPNAV_ACCELERATION_MS; }134135// Returns the maximum lateral acceleration in m/s² used during waypoint cornering.136// Derived from WPNAV_ACCEL_C or defaults to 2x WPNAV_ACCEL if unset.137float get_corner_acceleration_mss() const { return (is_positive(_wp_accel_c_cmss)) ? _wp_accel_c_cmss * 0.01 : 2.0 * get_wp_acceleration_mss(); }138139// Returns the destination waypoint vector in NEU frame, in centimeters from EKF origin.140// See get_wp_destination_NED_m() for full details.141const Vector3f get_wp_destination_NEU_cm() const { return Vector3f(_destination_ned_m.x, _destination_ned_m.y, -_destination_ned_m.z) * 100.0; }142143// Returns the destination waypoint vector in NED frame, in meters from EKF origin.144// Z is relative to terrain or EKF origin, depending on _is_terrain_alt.145const Vector3p &get_wp_destination_NED_m() const { return _destination_ned_m; }146147// Returns the origin waypoint vector in NED frame, in centimeters from EKF origin.148// See get_wp_origin_NED_m() for full details.149const Vector3f get_wp_origin_NEU_cm() const { return Vector3f(_origin_ned_m.x, _origin_ned_m.y, -_origin_ned_m.z) * 100.0; }150151// Returns the origin waypoint vector in NED frame, in meters from EKF origin.152// This marks the start of the current waypoint leg.153const Vector3p &get_wp_origin_NED_m() const { return _origin_ned_m; }154155// Returns true if origin.z and destination.z are specified as altitudes above terrain.156// Returns false if altitudes are relative to the EKF origin.157bool origin_and_destination_are_terrain_alt() const { return _is_terrain_alt; }158159// Sets the current waypoint destination using a Location object.160// Converts global coordinates to NED position and sets destination.161// arc_rad specifies the signed arc angle in radians for an ARC_WAYPOINT segment (0 for straight path)162// Returns false if conversion fails (e.g. missing terrain data).163bool set_wp_destination_loc(const Location& destination, float arc_rad = 0.0);164165// Sets the next waypoint destination using a Location object.166// Converts global coordinates to NED position and preloads the trajectory.167// arc_rad specifies the signed arc angle in radians for an ARC_WAYPOINT segment (0 for straight path)168// Returns false if conversion fails or terrain data is unavailable.169bool set_wp_destination_next_loc(const Location& destination, float arc_rad = 0.0);170171// Gets the current waypoint destination as a Location object.172// Altitude frame will be ABOVE_TERRAIN or ABOVE_ORIGIN depending on path configuration.173// Returns false if origin is not set or coordinate conversion fails.174bool get_wp_destination_loc(Location& destination) const;175176// Returns the waypoint destination adjusted for object avoidance.177// In the base class this is identical to get_wp_destination_loc().178// Used to unify the AC_WPNav and AC_WPNav_OA interfaces.179virtual bool get_oa_wp_destination(Location& destination) const { return get_wp_destination_loc(destination); }180181// Sets waypoint destination using NED position vector in centimeters from EKF origin.182// See set_wp_destination_NED_m() for full details.183virtual bool set_wp_destination_NEU_cm(const Vector3f& destination_neu_cm, bool is_terrain_alt = false);184185// Sets waypoint destination using NED position vector in meters from EKF origin.186// If `is_terrain_alt` is true, altitude is interpreted as height above terrain.187// Reinitializes the current leg if interrupted, updates origin, and computes trajectory.188// arc_rad specifies the signed arc angle in radians for an ARC_WAYPOINT segment (0 for straight path)189// Returns false if terrain offset cannot be determined when required.190virtual bool set_wp_destination_NED_m(const Vector3p& destination_ned_m, bool is_terrain_alt = false, float arc_rad = 0.0);191192// Sets the next waypoint destination using a NED position vector in meters.193// Only updates if terrain frame matches current leg.194// Calculates trajectory preview for smoother transition into next segment.195// Updates velocity handoff if previous leg is a spline.196// arc_rad specifies the signed arc angle in radians for an ARC_WAYPOINT segment (0 for straight path)197bool set_wp_destination_next_NED_m(const Vector3p& destination_ned_m, bool is_terrain_alt = false, float arc_rad = 0.0);198199// Computes the horizontal stopping point in NE frame, returned in centimeters.200// See get_wp_stopping_point_NE_m() for full details.201void get_wp_stopping_point_NE_cm(Vector2f& stopping_point_ne_cm) const;202203// Computes the horizontal stopping point in NE frame, in meters, based on current velocity and configured acceleration.204// This is the point where the vehicle would come to a stop if decelerated using the configured limits.205void get_wp_stopping_point_NE_m(Vector2p& stopping_point_ne_m) const;206207// Computes the full 3D NED stopping point vector in centimeters based on current kinematics.208// See get_wp_stopping_point_NED_m() for full details.209void get_wp_stopping_point_NEU_cm(Vector3f& stopping_point_neu_cm) const;210211// Computes the full 3D NED stopping point in meters based on current velocity and configured acceleration in all axes.212// Represents where the vehicle will stop if decelerated from current velocity using configured limits.213void get_wp_stopping_point_NED_m(Vector3p& stopping_point_ned_m) const;214215// Returns the horizontal distance to the destination waypoint in centimeters.216// See get_wp_distance_to_destination_m() for full details.217virtual float get_wp_distance_to_destination_cm() const;218219// Returns the horizontal distance in meters between the current position and the destination waypoint.220virtual float get_wp_distance_to_destination_m() const;221222// Returns the bearing to the current waypoint destination in centidegrees.223// See get_wp_bearing_to_destination_rad() for full details.224virtual int32_t get_wp_bearing_to_destination_cd() const;225226// Returns the bearing to the current waypoint destination in radians.227// The bearing is measured clockwise from North, with 0 = North.228virtual float get_wp_bearing_to_destination_rad() const;229230// Returns true if the vehicle has reached the waypoint destination.231// A waypoint is considered reached when the vehicle comes within the defined radius threshold.232virtual bool reached_wp_destination() const { return _flags.reached_destination; }233234// Returns true if the vehicle's horizontal (NE) distance to the waypoint is less than the waypoint radius.235// Uses the waypoint radius in meters for comparison.236bool reached_wp_destination_NE() const {237return get_wp_distance_to_destination_m() < _wp_radius_cm * 0.01;238}239240// Returns the waypoint acceptance radius in meters.241// This radius defines the distance from the target waypoint within which the vehicle is considered to have arrived.242float get_wp_radius_m() const { return _wp_radius_cm * 0.01; }243244// Runs the waypoint navigation controller.245// Advances the target position and updates the position controller.246// Should be called at 100 Hz or higher for accurate tracking.247virtual bool update_wpnav();248249// Returns true if update_wpnav() has been called within the last 200 ms.250// Used to check if waypoint navigation is currently active.251bool is_active() const;252253// Forces a stop at the next waypoint instead of continuing to the subsequent one.254// Used by Dijkstra’s object avoidance when the future path is obstructed.255// Only affects regular (non-spline) waypoints.256// Returns true if the stop behavior was newly enforced.257bool force_stop_at_next_wp();258259///260/// spline methods261///262263// Sets the current spline waypoint using global coordinates.264// Converts `destination` and `next_destination` to NED position vectors and sets up a spline between them.265// Returns false if conversion from location to vector fails.266bool set_spline_destination_loc(const Location& destination, const Location& next_destination, bool next_is_spline);267268// Sets the next spline segment using global coordinates.269// Converts the next and next-next destinations to NED position vectors and initializes the spline transition.270// Returns false if any conversion from location to vector fails.271bool set_spline_destination_next_loc(const Location& next_destination, const Location& next_next_destination, bool next_next_is_spline);272273// Sets the current spline waypoint using NED position vectors in meters.274// Initializes a spline path from `destination_ned_m` to `next_destination_ned_m`, respecting terrain altitude framing.275// Both waypoints must use the same altitude frame (either above terrain or above origin).276// Returns false if terrain altitude cannot be determined when required.277bool set_spline_destination_NED_m(const Vector3p& destination_ned_m, bool is_terrain_alt, const Vector3p& next_destination_ned_m, bool next_terrain_alt, bool next_is_spline);278279// Sets the next spline segment using NED position vectors in meters.280// Creates a spline path from the current destination to `next_destination_ned_m`, and prepares transition toward `next_next_destination_ned_m`.281// All waypoints must use the same altitude frame (above terrain or origin).282// Returns false if terrain data is missing and required.283bool set_spline_destination_next_NED_m(const Vector3p& next_destination_ned_m, bool next_is_terrain_alt, const Vector3p& next_next_destination_ned_m, bool next_next_is_terrain_alt, bool next_next_is_spline);284285///286/// shared methods287///288289// Returns the desired roll angle in radians from the position controller.290// This value is passed to the attitude controller to achieve lateral motion.291float get_roll_rad() const { return _pos_control.get_roll_rad(); }292293// Returns the desired pitch angle in radians from the position controller.294// This angle controls forward or backward acceleration.295float get_pitch_rad() const { return _pos_control.get_pitch_rad(); }296297// Returns the desired yaw angle in radians from the position controller.298// Used to align the vehicle heading with track direction or command input.299float get_yaw_rad() const { return _pos_control.get_yaw_rad(); }300301// Returns the desired 3D unit vector representing the commanded thrust direction.302// Used to calculate tilt angles for the attitude controller.303Vector3f get_thrust_vector() const { return _pos_control.get_thrust_vector(); }304305// Returns the desired roll angle in centidegrees from the position controller.306// See get_roll_rad() for full details.307float get_roll() const { return rad_to_cd(get_roll_rad()); }308309// Returns the desired pitch angle in centidegrees from the position controller.310// See get_pitch_rad() for full details.311float get_pitch() const { return rad_to_cd(get_pitch_rad()); }312313// Returns the desired yaw angle in centidegrees from the position controller.314// See get_yaw_rad() for full details.315float get_yaw() const { return rad_to_cd(get_yaw_rad()); }316317// Advances the target location along the current path segment.318// Updates target position, velocity, and acceleration based on jerk-limited profile (or spline).319// Returns true if the update succeeded (e.g., terrain data was available).320bool advance_wp_target_along_track(float dt);321322// Updates the current and next path segment to reflect new speed and acceleration limits.323// Should be called after modifying NE/U controller limits or vehicle configuration.324void update_track_with_speed_accel_limits();325326// Returns lateral (cross-track) position error in meters.327// Computed as the perpendicular distance between current position and the planned path.328// Used to assess horizontal deviation from the trajectory.329float crosstrack_error_m() const { return _pos_control.crosstrack_error_m();}330331static const struct AP_Param::GroupInfo var_info[];332333protected:334335// flags structure336struct wpnav_flags {337uint8_t reached_destination : 1; // true if we have reached the destination338uint8_t fast_waypoint : 1; // true if we should ignore the waypoint radius and consider the waypoint complete once the intermediate target has reached the waypoint339uint8_t wp_yaw_set : 1; // true if yaw target has been set340} _flags;341342// Calculates s-curve jerk and snap limits based on attitude controller capabilities.343// Updates _scurve_jerk_max_msss and _scurve_snap_max_mssss with constrained values.344void calc_scurve_jerk_and_snap();345346// References to shared sensor fusion, position, and attitude control subsystems.347const AP_AHRS_View& _ahrs;348AC_PosControl& _pos_control;349const AC_AttitudeControl& _attitude_control;350351// parameters352AP_Float _wp_speed_cms; // default horizontal speed in cm/s for waypoint navigation353AP_Float _wp_speed_up_cms; // default climb rate in cm/s for waypoint navigation354AP_Float _wp_speed_down_cms; // default descent rate in cm/s for waypoint navigation355AP_Float _wp_radius_cm; // waypoint radius in cm; waypoint is considered reached when within this distance356AP_Float _wp_accel_cmss; // maximum horizontal acceleration in cm/s² used during waypoint tracking357AP_Float _wp_accel_c_cmss; // maximum acceleration in cm/s² for turns; defaults to 2x horizontal accel if unset358AP_Float _wp_accel_z_cmss; // maximum vertical acceleration in cm/s² used during climb or descent359AP_Float _wp_jerk_msss; // maximum jerk in m/s³ used for s-curve trajectory shaping360AP_Float _terrain_margin_m; // minimum altitude margin in meters when terrain following is active361362// WPNAV_SPEED param change checker363bool _check_wp_speed_change; // true if WPNAV_SPEED should be monitored for changes during flight364float _last_wp_speed_cms; // last recorded WPNAV_SPEED value (cm/s) for change detection365float _last_wp_speed_up_cms; // last recorded WPNAV_SPEED_UP value (cm/s)366float _last_wp_speed_down_cms; // last recorded WPNAV_SPEED_DN value (cm/s)367368// s-curve trajectory objects369SCurve _scurve_prev_leg; // s-curve for the previous waypoint leg, used for smoothing transitions370SCurve _scurve_this_leg; // s-curve for the current active waypoint leg371SCurve _scurve_next_leg; // s-curve for the next waypoint leg, used for lookahead blending372float _scurve_jerk_max_msss; // computed maximum jerk in m/s³ used for trajectory shaping373float _scurve_snap_max_mssss; // computed maximum snap in m/s⁴ derived from controller responsiveness374375// spline curves376SplineCurve _spline_this_leg; // spline curve for the current segment377SplineCurve _spline_next_leg; // spline curve for the next segment378379// path type flags380bool _this_leg_is_spline; // true if the current leg uses spline trajectory381bool _next_leg_is_spline; // true if the next leg will use spline trajectory382383// waypoint navigation state384uint32_t _wp_last_update_ms; // timestamp of the last update_wpnav() call (milliseconds)385float _wp_desired_speed_ne_ms; // desired horizontal speed in m/s for the current segment386Vector3p _origin_ned_m; // origin of the current leg in meters (NED frame)387Vector3p _destination_ned_m; // destination of the current leg in meters (NED frame)388Vector3p _next_destination_ned_m; // destination of the next leg in meters (NED frame)389float _track_dt_scalar; // scalar to reduce or increase the advancement along the track (0.0–1.0)390float _offset_vel_ms; // filtered horizontal speed target (used for terrain following or pause handling)391float _offset_accel_mss; // filtered horizontal acceleration target (used for terrain following or pause handling)392bool _paused; // true if waypoint controller is paused393394// terrain following state395bool _is_terrain_alt; // true if altitude values are relative to terrain height, false if relative to EKF origin396bool _rangefinder_available; // true if a rangefinder is enabled and available for use397AP_Int8 _rangefinder_use; // parameter specifying whether rangefinder should be used for terrain tracking398bool _rangefinder_healthy; // true if the rangefinder reading is valid and within operational range399float _rangefinder_terrain_u_m; // rangefinder-derived terrain offset (meters above EKF origin)400};401402403