Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/libraries/AC_AttitudeControl/AC_PosControl.cpp
Views: 1798
#include <AP_HAL/AP_HAL.h>1#include "AC_PosControl.h"2#include <AP_Math/AP_Math.h>3#include <AP_Logger/AP_Logger.h>4#include <AP_Motors/AP_Motors.h> // motors library5#include <AP_Vehicle/AP_Vehicle_Type.h>6#include <AP_Scheduler/AP_Scheduler.h>78extern const AP_HAL::HAL& hal;910#if APM_BUILD_TYPE(APM_BUILD_ArduPlane)11// default gains for Plane12# define POSCONTROL_POS_Z_P 1.0f // vertical position controller P gain default13# define POSCONTROL_VEL_Z_P 5.0f // vertical velocity controller P gain default14# define POSCONTROL_VEL_Z_IMAX 1000.0f // vertical velocity controller IMAX gain default15# define POSCONTROL_VEL_Z_FILT_HZ 5.0f // vertical velocity controller input filter16# define POSCONTROL_VEL_Z_FILT_D_HZ 5.0f // vertical velocity controller input filter for D17# define POSCONTROL_ACC_Z_P 0.3f // vertical acceleration controller P gain default18# define POSCONTROL_ACC_Z_I 1.0f // vertical acceleration controller I gain default19# define POSCONTROL_ACC_Z_D 0.0f // vertical acceleration controller D gain default20# define POSCONTROL_ACC_Z_IMAX 800 // vertical acceleration controller IMAX gain default21# define POSCONTROL_ACC_Z_FILT_HZ 10.0f // vertical acceleration controller input filter default22# define POSCONTROL_ACC_Z_DT 0.02f // vertical acceleration controller dt default23# define POSCONTROL_POS_XY_P 0.5f // horizontal position controller P gain default24# define POSCONTROL_VEL_XY_P 0.7f // horizontal velocity controller P gain default25# define POSCONTROL_VEL_XY_I 0.35f // horizontal velocity controller I gain default26# define POSCONTROL_VEL_XY_D 0.17f // horizontal velocity controller D gain default27# define POSCONTROL_VEL_XY_IMAX 1000.0f // horizontal velocity controller IMAX gain default28# define POSCONTROL_VEL_XY_FILT_HZ 5.0f // horizontal velocity controller input filter29# define POSCONTROL_VEL_XY_FILT_D_HZ 5.0f // horizontal velocity controller input filter for D30#elif APM_BUILD_TYPE(APM_BUILD_ArduSub)31// default gains for Sub32# define POSCONTROL_POS_Z_P 3.0f // vertical position controller P gain default33# define POSCONTROL_VEL_Z_P 8.0f // vertical velocity controller P gain default34# define POSCONTROL_VEL_Z_IMAX 1000.0f // vertical velocity controller IMAX gain default35# define POSCONTROL_VEL_Z_FILT_HZ 5.0f // vertical velocity controller input filter36# define POSCONTROL_VEL_Z_FILT_D_HZ 5.0f // vertical velocity controller input filter for D37# define POSCONTROL_ACC_Z_P 0.5f // vertical acceleration controller P gain default38# define POSCONTROL_ACC_Z_I 0.1f // vertical acceleration controller I gain default39# define POSCONTROL_ACC_Z_D 0.0f // vertical acceleration controller D gain default40# define POSCONTROL_ACC_Z_IMAX 100 // vertical acceleration controller IMAX gain default41# define POSCONTROL_ACC_Z_FILT_HZ 20.0f // vertical acceleration controller input filter default42# define POSCONTROL_ACC_Z_DT 0.0025f // vertical acceleration controller dt default43# define POSCONTROL_POS_XY_P 1.0f // horizontal position controller P gain default44# define POSCONTROL_VEL_XY_P 1.0f // horizontal velocity controller P gain default45# define POSCONTROL_VEL_XY_I 0.5f // horizontal velocity controller I gain default46# define POSCONTROL_VEL_XY_D 0.0f // horizontal velocity controller D gain default47# define POSCONTROL_VEL_XY_IMAX 1000.0f // horizontal velocity controller IMAX gain default48# define POSCONTROL_VEL_XY_FILT_HZ 5.0f // horizontal velocity controller input filter49# define POSCONTROL_VEL_XY_FILT_D_HZ 5.0f // horizontal velocity controller input filter for D50#else51// default gains for Copter / TradHeli52# define POSCONTROL_POS_Z_P 1.0f // vertical position controller P gain default53# define POSCONTROL_VEL_Z_P 5.0f // vertical velocity controller P gain default54# define POSCONTROL_VEL_Z_IMAX 1000.0f // vertical velocity controller IMAX gain default55# define POSCONTROL_VEL_Z_FILT_HZ 5.0f // vertical velocity controller input filter56# define POSCONTROL_VEL_Z_FILT_D_HZ 5.0f // vertical velocity controller input filter for D57# define POSCONTROL_ACC_Z_P 0.5f // vertical acceleration controller P gain default58# define POSCONTROL_ACC_Z_I 1.0f // vertical acceleration controller I gain default59# define POSCONTROL_ACC_Z_D 0.0f // vertical acceleration controller D gain default60# define POSCONTROL_ACC_Z_IMAX 800 // vertical acceleration controller IMAX gain default61# define POSCONTROL_ACC_Z_FILT_HZ 20.0f // vertical acceleration controller input filter default62# define POSCONTROL_ACC_Z_DT 0.0025f // vertical acceleration controller dt default63# define POSCONTROL_POS_XY_P 1.0f // horizontal position controller P gain default64# define POSCONTROL_VEL_XY_P 2.0f // horizontal velocity controller P gain default65# define POSCONTROL_VEL_XY_I 1.0f // horizontal velocity controller I gain default66# define POSCONTROL_VEL_XY_D 0.5f // horizontal velocity controller D gain default67# define POSCONTROL_VEL_XY_IMAX 1000.0f // horizontal velocity controller IMAX gain default68# define POSCONTROL_VEL_XY_FILT_HZ 5.0f // horizontal velocity controller input filter69# define POSCONTROL_VEL_XY_FILT_D_HZ 5.0f // horizontal velocity controller input filter for D70#endif7172// vibration compensation gains73#define POSCONTROL_VIBE_COMP_P_GAIN 0.250f74#define POSCONTROL_VIBE_COMP_I_GAIN 0.125f7576// velocity offset targets timeout if not updated within 3 seconds77#define POSCONTROL_POSVELACCEL_OFFSET_TARGET_TIMEOUT_MS 30007879AC_PosControl *AC_PosControl::_singleton;8081const AP_Param::GroupInfo AC_PosControl::var_info[] = {82// 0 was used for HOVER8384// @Param: _ACC_XY_FILT85// @DisplayName: XY Acceleration filter cutoff frequency86// @Description: Lower values will slow the response of the navigation controller and reduce twitchiness87// @Units: Hz88// @Range: 0.5 589// @Increment: 0.190// @User: Advanced9192// @Param: _POSZ_P93// @DisplayName: Position (vertical) controller P gain94// @Description: Position (vertical) controller P gain. Converts the difference between the desired altitude and actual altitude into a climb or descent rate which is passed to the throttle rate controller95// @Range: 1.000 3.00096// @User: Standard97AP_SUBGROUPINFO(_p_pos_z, "_POSZ_", 2, AC_PosControl, AC_P_1D),9899// @Param: _VELZ_P100// @DisplayName: Velocity (vertical) controller P gain101// @Description: Velocity (vertical) controller P gain. Converts the difference between desired vertical speed and actual speed into a desired acceleration that is passed to the throttle acceleration controller102// @Range: 1.000 8.000103// @User: Standard104105// @Param: _VELZ_I106// @DisplayName: Velocity (vertical) controller I gain107// @Description: Velocity (vertical) controller I gain. Corrects long-term difference in desired velocity to a target acceleration108// @Range: 0.02 1.00109// @Increment: 0.01110// @User: Advanced111112// @Param: _VELZ_IMAX113// @DisplayName: Velocity (vertical) controller I gain maximum114// @Description: Velocity (vertical) controller I gain maximum. Constrains the target acceleration that the I gain will output115// @Range: 1.000 8.000116// @User: Standard117118// @Param: _VELZ_D119// @DisplayName: Velocity (vertical) controller D gain120// @Description: Velocity (vertical) controller D gain. Corrects short-term changes in velocity121// @Range: 0.00 1.00122// @Increment: 0.001123// @User: Advanced124125// @Param: _VELZ_FF126// @DisplayName: Velocity (vertical) controller Feed Forward gain127// @Description: Velocity (vertical) controller Feed Forward gain. Produces an output that is proportional to the magnitude of the target128// @Range: 0 1129// @Increment: 0.01130// @User: Advanced131132// @Param: _VELZ_FLTE133// @DisplayName: Velocity (vertical) error filter134// @Description: Velocity (vertical) error filter. This filter (in Hz) is applied to the input for P and I terms135// @Range: 0 100136// @Units: Hz137// @User: Advanced138139// @Param: _VELZ_FLTD140// @DisplayName: Velocity (vertical) input filter for D term141// @Description: Velocity (vertical) input filter for D term. This filter (in Hz) is applied to the input for D terms142// @Range: 0 100143// @Units: Hz144// @User: Advanced145AP_SUBGROUPINFO(_pid_vel_z, "_VELZ_", 3, AC_PosControl, AC_PID_Basic),146147// @Param: _ACCZ_P148// @DisplayName: Acceleration (vertical) controller P gain149// @Description: Acceleration (vertical) controller P gain. Converts the difference between desired vertical acceleration and actual acceleration into a motor output150// @Range: 0.200 1.500151// @Increment: 0.05152// @User: Standard153154// @Param: _ACCZ_I155// @DisplayName: Acceleration (vertical) controller I gain156// @Description: Acceleration (vertical) controller I gain. Corrects long-term difference in desired vertical acceleration and actual acceleration157// @Range: 0.000 3.000158// @User: Standard159160// @Param: _ACCZ_IMAX161// @DisplayName: Acceleration (vertical) controller I gain maximum162// @Description: Acceleration (vertical) controller I gain maximum. Constrains the maximum pwm that the I term will generate163// @Range: 0 1000164// @Units: d%165// @User: Standard166167// @Param: _ACCZ_D168// @DisplayName: Acceleration (vertical) controller D gain169// @Description: Acceleration (vertical) controller D gain. Compensates for short-term change in desired vertical acceleration vs actual acceleration170// @Range: 0.000 0.400171// @User: Standard172173// @Param: _ACCZ_FF174// @DisplayName: Acceleration (vertical) controller feed forward175// @Description: Acceleration (vertical) controller feed forward176// @Range: 0 0.5177// @Increment: 0.001178// @User: Standard179180// @Param: _ACCZ_FLTT181// @DisplayName: Acceleration (vertical) controller target frequency in Hz182// @Description: Acceleration (vertical) controller target frequency in Hz183// @Range: 1 50184// @Increment: 1185// @Units: Hz186// @User: Standard187188// @Param: _ACCZ_FLTE189// @DisplayName: Acceleration (vertical) controller error frequency in Hz190// @Description: Acceleration (vertical) controller error frequency in Hz191// @Range: 1 100192// @Increment: 1193// @Units: Hz194// @User: Standard195196// @Param: _ACCZ_FLTD197// @DisplayName: Acceleration (vertical) controller derivative frequency in Hz198// @Description: Acceleration (vertical) controller derivative frequency in Hz199// @Range: 1 100200// @Increment: 1201// @Units: Hz202// @User: Standard203204// @Param: _ACCZ_SMAX205// @DisplayName: Accel (vertical) slew rate limit206// @Description: Sets an upper limit on the slew rate produced by the combined P and D gains. If the amplitude of the control action produced by the rate feedback exceeds this value, then the D+P gain is reduced to respect the limit. This limits the amplitude of high frequency oscillations caused by an excessive gain. The limit should be set to no more than 25% of the actuators maximum slew rate to allow for load effects. Note: The gain will not be reduced to less than 10% of the nominal value. A value of zero will disable this feature.207// @Range: 0 200208// @Increment: 0.5209// @User: Advanced210211// @Param: _ACCZ_PDMX212// @DisplayName: Acceleration (vertical) controller PD sum maximum213// @Description: Acceleration (vertical) controller PD sum maximum. The maximum/minimum value that the sum of the P and D term can output214// @Range: 0 1000215// @Units: d%216217// @Param: _ACCZ_D_FF218// @DisplayName: Accel (vertical) Derivative FeedForward Gain219// @Description: FF D Gain which produces an output that is proportional to the rate of change of the target220// @Range: 0 0.02221// @Increment: 0.0001222// @User: Advanced223224// @Param: _ACCZ_NTF225// @DisplayName: Accel (vertical) Target notch filter index226// @Description: Accel (vertical) Target notch filter index227// @Range: 1 8228// @User: Advanced229230// @Param: _ACCZ_NEF231// @DisplayName: Accel (vertical) Error notch filter index232// @Description: Accel (vertical) Error notch filter index233// @Range: 1 8234// @User: Advanced235236AP_SUBGROUPINFO(_pid_accel_z, "_ACCZ_", 4, AC_PosControl, AC_PID),237238// @Param: _POSXY_P239// @DisplayName: Position (horizontal) controller P gain240// @Description: Position controller P gain. Converts the distance (in the latitude direction) to the target location into a desired speed which is then passed to the loiter latitude rate controller241// @Range: 0.500 2.000242// @User: Standard243AP_SUBGROUPINFO(_p_pos_xy, "_POSXY_", 5, AC_PosControl, AC_P_2D),244245// @Param: _VELXY_P246// @DisplayName: Velocity (horizontal) P gain247// @Description: Velocity (horizontal) P gain. Converts the difference between desired and actual velocity to a target acceleration248// @Range: 0.1 6.0249// @Increment: 0.1250// @User: Advanced251252// @Param: _VELXY_I253// @DisplayName: Velocity (horizontal) I gain254// @Description: Velocity (horizontal) I gain. Corrects long-term difference between desired and actual velocity to a target acceleration255// @Range: 0.02 1.00256// @Increment: 0.01257// @User: Advanced258259// @Param: _VELXY_D260// @DisplayName: Velocity (horizontal) D gain261// @Description: Velocity (horizontal) D gain. Corrects short-term changes in velocity262// @Range: 0.00 1.00263// @Increment: 0.001264// @User: Advanced265266// @Param: _VELXY_IMAX267// @DisplayName: Velocity (horizontal) integrator maximum268// @Description: Velocity (horizontal) integrator maximum. Constrains the target acceleration that the I gain will output269// @Range: 0 4500270// @Increment: 10271// @Units: cm/s/s272// @User: Advanced273274// @Param: _VELXY_FLTE275// @DisplayName: Velocity (horizontal) input filter276// @Description: Velocity (horizontal) input filter. This filter (in Hz) is applied to the input for P and I terms277// @Range: 0 100278// @Units: Hz279// @User: Advanced280281// @Param: _VELXY_FLTD282// @DisplayName: Velocity (horizontal) input filter283// @Description: Velocity (horizontal) input filter. This filter (in Hz) is applied to the input for D term284// @Range: 0 100285// @Units: Hz286// @User: Advanced287288// @Param: _VELXY_FF289// @DisplayName: Velocity (horizontal) feed forward gain290// @Description: Velocity (horizontal) feed forward gain. Converts the difference between desired velocity to a target acceleration291// @Range: 0 6292// @Increment: 0.01293// @User: Advanced294AP_SUBGROUPINFO(_pid_vel_xy, "_VELXY_", 6, AC_PosControl, AC_PID_2D),295296// @Param: _ANGLE_MAX297// @DisplayName: Position Control Angle Max298// @Description: Maximum lean angle autopilot can request. Set to zero to use ANGLE_MAX parameter value299// @Units: deg300// @Range: 0 45301// @Increment: 1302// @User: Advanced303AP_GROUPINFO("_ANGLE_MAX", 7, AC_PosControl, _lean_angle_max, 0.0f),304305// IDs 8,9 used for _TC_XY and _TC_Z in beta release candidate306307// @Param: _JERK_XY308// @DisplayName: Jerk limit for the horizontal kinematic input shaping309// @Description: Jerk limit of the horizontal kinematic path generation used to determine how quickly the aircraft varies the acceleration target310// @Units: m/s/s/s311// @Range: 1 20312// @Increment: 1313// @User: Advanced314AP_GROUPINFO("_JERK_XY", 10, AC_PosControl, _shaping_jerk_xy, POSCONTROL_JERK_XY),315316// @Param: _JERK_Z317// @DisplayName: Jerk limit for the vertical kinematic input shaping318// @Description: Jerk limit of the vertical kinematic path generation used to determine how quickly the aircraft varies the acceleration target319// @Units: m/s/s/s320// @Range: 5 50321// @Increment: 1322// @User: Advanced323AP_GROUPINFO("_JERK_Z", 11, AC_PosControl, _shaping_jerk_z, POSCONTROL_JERK_Z),324325AP_GROUPEND326};327328// Default constructor.329// Note that the Vector/Matrix constructors already implicitly zero330// their values.331//332AC_PosControl::AC_PosControl(AP_AHRS_View& ahrs, const AP_InertialNav& inav,333const AP_Motors& motors, AC_AttitudeControl& attitude_control) :334_ahrs(ahrs),335_inav(inav),336_motors(motors),337_attitude_control(attitude_control),338_p_pos_xy(POSCONTROL_POS_XY_P),339_p_pos_z(POSCONTROL_POS_Z_P),340_pid_vel_xy(POSCONTROL_VEL_XY_P, POSCONTROL_VEL_XY_I, POSCONTROL_VEL_XY_D, 0.0f, POSCONTROL_VEL_XY_IMAX, POSCONTROL_VEL_XY_FILT_HZ, POSCONTROL_VEL_XY_FILT_D_HZ),341_pid_vel_z(POSCONTROL_VEL_Z_P, 0.0f, 0.0f, 0.0f, POSCONTROL_VEL_Z_IMAX, POSCONTROL_VEL_Z_FILT_HZ, POSCONTROL_VEL_Z_FILT_D_HZ),342_pid_accel_z(POSCONTROL_ACC_Z_P, POSCONTROL_ACC_Z_I, POSCONTROL_ACC_Z_D, 0.0f, POSCONTROL_ACC_Z_IMAX, 0.0f, POSCONTROL_ACC_Z_FILT_HZ, 0.0f),343_vel_max_xy_cms(POSCONTROL_SPEED),344_vel_max_up_cms(POSCONTROL_SPEED_UP),345_vel_max_down_cms(POSCONTROL_SPEED_DOWN),346_accel_max_xy_cmss(POSCONTROL_ACCEL_XY),347_accel_max_z_cmss(POSCONTROL_ACCEL_Z),348_jerk_max_xy_cmsss(POSCONTROL_JERK_XY * 100.0),349_jerk_max_z_cmsss(POSCONTROL_JERK_Z * 100.0)350{351AP_Param::setup_object_defaults(this, var_info);352353_singleton = this;354}355356357///358/// 3D position shaper359///360361/// input_pos_xyz - calculate a jerk limited path from the current position, velocity and acceleration to an input position.362/// The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.363/// The kinematic path is constrained by the maximum jerk parameter and the velocity and acceleration limits set using the function set_max_speed_accel_xy.364/// The jerk limit defines the acceleration error decay in the kinematic path as the system approaches constant acceleration.365/// The jerk limit also defines the time taken to achieve the maximum acceleration.366/// The function alters the input velocity to be the velocity that the system could reach zero acceleration in the minimum time.367void AC_PosControl::input_pos_xyz(const Vector3p& pos, float pos_terrain_target, float terrain_buffer)368{369// Terrain following velocity scalar must be calculated before we remove the position offset370const float offset_z_scaler = pos_offset_z_scaler(pos_terrain_target, terrain_buffer);371set_pos_terrain_target_cm(pos_terrain_target);372373// calculated increased maximum acceleration and jerk if over speed374const float overspeed_gain = calculate_overspeed_gain();375const float accel_max_z_cmss = _accel_max_z_cmss * overspeed_gain;376const float jerk_max_z_cmsss = _jerk_max_z_cmsss * overspeed_gain;377378update_pos_vel_accel_xy(_pos_desired.xy(), _vel_desired.xy(), _accel_desired.xy(), _dt, _limit_vector.xy(), _p_pos_xy.get_error(), _pid_vel_xy.get_error());379380// adjust desired altitude if motors have not hit their limits381update_pos_vel_accel(_pos_desired.z, _vel_desired.z, _accel_desired.z, _dt, _limit_vector.z, _p_pos_z.get_error(), _pid_vel_z.get_error());382383// calculate the horizontal and vertical velocity limits to travel directly to the destination defined by pos384float vel_max_xy_cms = 0.0f;385float vel_max_z_cms = 0.0f;386Vector3f dest_vector = (pos - _pos_desired).tofloat();387if (is_positive(dest_vector.length_squared()) ) {388dest_vector.normalize();389float dest_vector_xy_length = dest_vector.xy().length();390391float vel_max_cms = kinematic_limit(dest_vector, _vel_max_xy_cms, _vel_max_up_cms, _vel_max_down_cms);392vel_max_xy_cms = vel_max_cms * dest_vector_xy_length;393vel_max_z_cms = fabsf(vel_max_cms * dest_vector.z);394}395396// reduce speed if we are reaching the edge of our vertical buffer397vel_max_xy_cms *= offset_z_scaler;398399Vector2f vel;400Vector2f accel;401shape_pos_vel_accel_xy(pos.xy(), vel, accel, _pos_desired.xy(), _vel_desired.xy(), _accel_desired.xy(),402vel_max_xy_cms, _accel_max_xy_cmss, _jerk_max_xy_cmsss, _dt, false);403404float posz = pos.z;405shape_pos_vel_accel(posz, 0, 0,406_pos_desired.z, _vel_desired.z, _accel_desired.z,407-vel_max_z_cms, vel_max_z_cms,408-constrain_float(accel_max_z_cmss, 0.0f, 750.0f), accel_max_z_cmss,409jerk_max_z_cmsss, _dt, false);410}411412413/// pos_offset_z_scaler - calculates a multiplier used to reduce the horizontal velocity to allow the z position controller to stay within the provided buffer range414float AC_PosControl::pos_offset_z_scaler(float pos_offset_z, float pos_offset_z_buffer) const415{416if (is_zero(pos_offset_z_buffer)) {417return 1.0;418}419float pos_offset_error_z = _inav.get_position_z_up_cm() - (_pos_target.z + (pos_offset_z - _pos_terrain));420return constrain_float((1.0 - (fabsf(pos_offset_error_z) - 0.5 * pos_offset_z_buffer) / (0.5 * pos_offset_z_buffer)), 0.01, 1.0);421}422423///424/// Lateral position controller425///426427/// set_max_speed_accel_xy - set the maximum horizontal speed in cm/s and acceleration in cm/s/s428/// This function only needs to be called if using the kinematic shaping.429/// This can be done at any time as changes in these parameters are handled smoothly430/// by the kinematic shaping.431void AC_PosControl::set_max_speed_accel_xy(float speed_cms, float accel_cmss)432{433_vel_max_xy_cms = speed_cms;434_accel_max_xy_cmss = accel_cmss;435436// ensure the horizontal jerk is less than the vehicle is capable of437const float jerk_max_cmsss = MIN(_attitude_control.get_ang_vel_roll_max_rads(), _attitude_control.get_ang_vel_pitch_max_rads()) * GRAVITY_MSS * 100.0;438const float snap_max_cmssss = MIN(_attitude_control.get_accel_roll_max_radss(), _attitude_control.get_accel_pitch_max_radss()) * GRAVITY_MSS * 100.0;439440// get specified jerk limit441_jerk_max_xy_cmsss = _shaping_jerk_xy * 100.0;442443// limit maximum jerk based on maximum angular rate444if (is_positive(jerk_max_cmsss) && _attitude_control.get_bf_feedforward()) {445_jerk_max_xy_cmsss = MIN(_jerk_max_xy_cmsss, jerk_max_cmsss);446}447448// limit maximum jerk to maximum possible average jerk based on angular acceleration449if (is_positive(snap_max_cmssss) && _attitude_control.get_bf_feedforward()) {450_jerk_max_xy_cmsss = MIN(0.5 * safe_sqrt(_accel_max_xy_cmss * snap_max_cmssss), _jerk_max_xy_cmsss);451}452}453454/// set_max_speed_accel_xy - set the position controller correction velocity and acceleration limit455/// This should be done only during initialisation to avoid discontinuities456void AC_PosControl::set_correction_speed_accel_xy(float speed_cms, float accel_cmss)457{458_p_pos_xy.set_limits(speed_cms, accel_cmss, 0.0f);459}460461/// init_xy_controller_stopping_point - initialise the position controller to the stopping point with zero velocity and acceleration.462/// This function should be used when the expected kinematic path assumes a stationary initial condition but does not specify a specific starting position.463/// The starting position can be retrieved by getting the position target using get_pos_desired_cm() after calling this function.464void AC_PosControl::init_xy_controller_stopping_point()465{466init_xy_controller();467468get_stopping_point_xy_cm(_pos_desired.xy());469_pos_target.xy() = _pos_desired.xy() + _pos_offset.xy();470_vel_desired.xy().zero();471_accel_desired.xy().zero();472}473474// relax_velocity_controller_xy - initialise the position controller to the current position and velocity with decaying acceleration.475/// This function decays the output acceleration by 95% every half second to achieve a smooth transition to zero requested acceleration.476void AC_PosControl::relax_velocity_controller_xy()477{478// decay acceleration and therefore current attitude target to zero479// this will be reset by init_xy_controller() if !is_active_xy()480if (is_positive(_dt)) {481float decay = 1.0 - _dt / (_dt + POSCONTROL_RELAX_TC);482_accel_target.xy() *= decay;483}484485init_xy_controller();486}487488/// reduce response for landing489void AC_PosControl::soften_for_landing_xy()490{491// decay position error to zero492if (is_positive(_dt)) {493_pos_target.xy() += (_inav.get_position_xy_cm().topostype() - _pos_target.xy()) * (_dt / (_dt + POSCONTROL_RELAX_TC));494_pos_desired.xy() = _pos_target.xy() - _pos_offset.xy();495}496497// Prevent I term build up in xy velocity controller.498// Note that this flag is reset on each loop in update_xy_controller()499set_externally_limited_xy();500}501502/// init_xy_controller - initialise the position controller to the current position, velocity, acceleration and attitude.503/// This function is the default initialisation for any position control that provides position, velocity and acceleration.504void AC_PosControl::init_xy_controller()505{506// initialise offsets to target offsets and ensure offset targets are zero if they have not been updated.507init_offsets_xy();508509// set roll, pitch lean angle targets to current attitude510const Vector3f &att_target_euler_cd = _attitude_control.get_att_target_euler_cd();511_roll_target = att_target_euler_cd.x;512_pitch_target = att_target_euler_cd.y;513_yaw_target = att_target_euler_cd.z; // todo: this should be thrust vector heading, not yaw.514_yaw_rate_target = 0.0f;515_angle_max_override_cd = 0.0;516517_pos_target.xy() = _inav.get_position_xy_cm().topostype();518_pos_desired.xy() = _pos_target.xy() - _pos_offset.xy();519520_vel_target.xy() = _inav.get_velocity_xy_cms();521_vel_desired.xy() = _vel_target.xy() - _vel_offset.xy();522523// Set desired accel to zero because raw acceleration is prone to noise524_accel_desired.xy().zero();525526if (!is_active_xy()) {527lean_angles_to_accel_xy(_accel_target.x, _accel_target.y);528}529530// limit acceleration using maximum lean angles531float angle_max = MIN(_attitude_control.get_althold_lean_angle_max_cd(), get_lean_angle_max_cd());532float accel_max = angle_to_accel(angle_max * 0.01) * 100.0;533_accel_target.xy().limit_length(accel_max);534535// initialise I terms from lean angles536_pid_vel_xy.reset_filter();537// initialise the I term to _accel_target - _accel_desired538// _accel_desired is zero and can be removed from the equation539_pid_vel_xy.set_integrator(_accel_target.xy() - _vel_target.xy() * _pid_vel_xy.ff());540541// initialise ekf xy reset handler542init_ekf_xy_reset();543544// initialise z_controller time out545_last_update_xy_ticks = AP::scheduler().ticks32();546}547548/// input_accel_xy - calculate a jerk limited path from the current position, velocity and acceleration to an input acceleration.549/// The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.550/// The kinematic path is constrained by the maximum acceleration and jerk set using the function set_max_speed_accel_xy.551/// The jerk limit defines the acceleration error decay in the kinematic path as the system approaches constant acceleration.552/// The jerk limit also defines the time taken to achieve the maximum acceleration.553void AC_PosControl::input_accel_xy(const Vector3f& accel)554{555update_pos_vel_accel_xy(_pos_desired.xy(), _vel_desired.xy(), _accel_desired.xy(), _dt, _limit_vector.xy(), _p_pos_xy.get_error(), _pid_vel_xy.get_error());556shape_accel_xy(accel.xy(), _accel_desired.xy(), _jerk_max_xy_cmsss, _dt);557}558559/// input_vel_accel_xy - calculate a jerk limited path from the current position, velocity and acceleration to an input velocity and acceleration.560/// The vel is projected forwards in time based on a time step of dt and acceleration accel.561/// The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.562/// The kinematic path is constrained by the maximum acceleration and jerk set using the function set_max_speed_accel_xy.563/// The parameter limit_output specifies if the velocity and acceleration limits are applied to the sum of commanded and correction values or just correction.564void AC_PosControl::input_vel_accel_xy(Vector2f& vel, const Vector2f& accel, bool limit_output)565{566update_pos_vel_accel_xy(_pos_desired.xy(), _vel_desired.xy(), _accel_desired.xy(), _dt, _limit_vector.xy(), _p_pos_xy.get_error(), _pid_vel_xy.get_error());567568shape_vel_accel_xy(vel, accel, _vel_desired.xy(), _accel_desired.xy(),569_accel_max_xy_cmss, _jerk_max_xy_cmsss, _dt, limit_output);570571update_vel_accel_xy(vel, accel, _dt, Vector2f(), Vector2f());572}573574/// input_pos_vel_accel_xy - calculate a jerk limited path from the current position, velocity and acceleration to an input position velocity and acceleration.575/// The pos and vel are projected forwards in time based on a time step of dt and acceleration accel.576/// The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.577/// The function alters the pos and vel to be the kinematic path based on accel578/// The parameter limit_output specifies if the velocity and acceleration limits are applied to the sum of commanded and correction values or just correction.579void AC_PosControl::input_pos_vel_accel_xy(Vector2p& pos, Vector2f& vel, const Vector2f& accel, bool limit_output)580{581update_pos_vel_accel_xy(_pos_desired.xy(), _vel_desired.xy(), _accel_desired.xy(), _dt, _limit_vector.xy(), _p_pos_xy.get_error(), _pid_vel_xy.get_error());582583shape_pos_vel_accel_xy(pos, vel, accel, _pos_desired.xy(), _vel_desired.xy(), _accel_desired.xy(),584_vel_max_xy_cms, _accel_max_xy_cmss, _jerk_max_xy_cmsss, _dt, limit_output);585586update_pos_vel_accel_xy(pos, vel, accel, _dt, Vector2f(), Vector2f(), Vector2f());587}588589/// update the horizontal position and velocity offsets590/// this moves the offsets (e.g _pos_offset, _vel_offset, _accel_offset) towards the targets (e.g. _pos_offset_target, _vel_offset_target, _accel_offset_target)591void AC_PosControl::update_offsets_xy()592{593// check for offset target timeout594uint32_t now_ms = AP_HAL::millis();595if (now_ms - _posvelaccel_offset_target_xy_ms > POSCONTROL_POSVELACCEL_OFFSET_TARGET_TIMEOUT_MS) {596_pos_offset_target.xy().zero();597_vel_offset_target.xy().zero();598_accel_offset_target.xy().zero();599}600601// update position, velocity, accel offsets for this iteration602update_pos_vel_accel_xy(_pos_offset_target.xy(), _vel_offset_target.xy(), _accel_offset_target.xy(), _dt, Vector2f(), Vector2f(), Vector2f());603update_pos_vel_accel_xy(_pos_offset.xy(), _vel_offset.xy(), _accel_offset.xy(), _dt, _limit_vector.xy(), _p_pos_xy.get_error(), _pid_vel_xy.get_error());604605// input shape horizontal position, velocity and acceleration offsets606shape_pos_vel_accel_xy(_pos_offset_target.xy(), _vel_offset_target.xy(), _accel_offset_target.xy(),607_pos_offset.xy(), _vel_offset.xy(), _accel_offset.xy(),608_vel_max_xy_cms, _accel_max_xy_cmss, _jerk_max_xy_cmsss, _dt, false);609}610611/// stop_pos_xy_stabilisation - sets the target to the current position to remove any position corrections from the system612void AC_PosControl::stop_pos_xy_stabilisation()613{614_pos_target.xy() = _inav.get_position_xy_cm().topostype();615_pos_desired.xy() = _pos_target.xy() - _pos_offset.xy();616}617618/// stop_vel_xy_stabilisation - sets the target to the current position and velocity to the current velocity to remove any position and velocity corrections from the system619void AC_PosControl::stop_vel_xy_stabilisation()620{621_pos_target.xy() = _inav.get_position_xy_cm().topostype();622_pos_desired.xy() = _pos_target.xy() - _pos_offset.xy();623624_vel_target.xy() = _inav.get_velocity_xy_cms();;625_vel_desired.xy() = _vel_target.xy() - _vel_offset.xy();626627// initialise I terms from lean angles628_pid_vel_xy.reset_filter();629_pid_vel_xy.reset_I();630}631632// is_active_xy - returns true if the xy position controller has been run in the previous loop633bool AC_PosControl::is_active_xy() const634{635const uint32_t dt_ticks = AP::scheduler().ticks32() - _last_update_xy_ticks;636return dt_ticks <= 1;637}638639/// update_xy_controller - runs the horizontal position controller correcting position, velocity and acceleration errors.640/// Position and velocity errors are converted to velocity and acceleration targets using PID objects641/// Desired velocity and accelerations are added to these corrections as they are calculated642/// Kinematically consistent target position and desired velocity and accelerations should be provided before calling this function643void AC_PosControl::update_xy_controller()644{645// check for ekf xy position reset646handle_ekf_xy_reset();647648// Check for position control time out649if (!is_active_xy()) {650init_xy_controller();651if (has_good_timing()) {652// call internal error because initialisation has not been done653INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);654}655}656_last_update_xy_ticks = AP::scheduler().ticks32();657658float ahrsGndSpdLimit, ahrsControlScaleXY;659AP::ahrs().getControlLimits(ahrsGndSpdLimit, ahrsControlScaleXY);660661// update the position, velocity and acceleration offsets662update_offsets_xy();663664// Position Controller665666_pos_target.xy() = _pos_desired.xy() + _pos_offset.xy();667668// determine the combined position of the actual position and the disturbance from system ID mode669const Vector3f &curr_pos = _inav.get_position_neu_cm();670Vector3f comb_pos = curr_pos;671comb_pos.xy() += _disturb_pos;672673Vector2f vel_target = _p_pos_xy.update_all(_pos_target.x, _pos_target.y, comb_pos);674_pos_desired.xy() = _pos_target.xy() - _pos_offset.xy();675676// Velocity Controller677678// add velocity feed-forward scaled to compensate for optical flow measurement induced EKF noise679vel_target *= ahrsControlScaleXY;680681_vel_target.xy() = vel_target;682_vel_target.xy() += _vel_desired.xy() + _vel_offset.xy();683684// determine the combined velocity of the actual velocity and the disturbance from system ID mode685const Vector2f &curr_vel = _inav.get_velocity_xy_cms();686Vector2f comb_vel = curr_vel;687comb_vel += _disturb_vel;688689Vector2f accel_target = _pid_vel_xy.update_all(_vel_target.xy(), comb_vel, _dt, _limit_vector.xy());690691// Acceleration Controller692693// acceleration to correct for velocity error and scale PID output to compensate for optical flow measurement induced EKF noise694accel_target *= ahrsControlScaleXY;695696// pass the correction acceleration to the target acceleration output697_accel_target.xy() = accel_target;698_accel_target.xy() += _accel_desired.xy() + _accel_offset.xy();699700// limit acceleration using maximum lean angles701float angle_max = MIN(_attitude_control.get_althold_lean_angle_max_cd(), get_lean_angle_max_cd());702float accel_max = angle_to_accel(angle_max * 0.01) * 100;703// Define the limit vector before we constrain _accel_target704_limit_vector.xy() = _accel_target.xy();705if (!limit_accel_xy(_vel_desired.xy(), _accel_target.xy(), accel_max)) {706// _accel_target was not limited so we can zero the xy limit vector707_limit_vector.xy().zero();708} else {709// Check for pitch limiting in the forward direction710const float accel_fwd_unlimited = _limit_vector.x * _ahrs.cos_yaw() + _limit_vector.y * _ahrs.sin_yaw();711const float pitch_target_unlimited = accel_to_angle(- MIN(accel_fwd_unlimited, accel_max) * 0.01f) * 100;712const float accel_fwd_limited = _accel_target.x * _ahrs.cos_yaw() + _accel_target.y * _ahrs.sin_yaw();713const float pitch_target_limited = accel_to_angle(- accel_fwd_limited * 0.01f) * 100;714_fwd_pitch_is_limited = is_negative(pitch_target_unlimited) && pitch_target_unlimited < pitch_target_limited;715}716717// update angle targets that will be passed to stabilize controller718accel_to_lean_angles(_accel_target.x, _accel_target.y, _roll_target, _pitch_target);719calculate_yaw_and_rate_yaw();720721// reset the disturbance from system ID mode to zero722_disturb_pos.zero();723_disturb_vel.zero();724}725726727///728/// Vertical position controller729///730731/// set_max_speed_accel_z - set the maximum vertical speed in cm/s and acceleration in cm/s/s732/// speed_down can be positive or negative but will always be interpreted as a descent speed.733/// This function only needs to be called if using the kinematic shaping.734/// This can be done at any time as changes in these parameters are handled smoothly735/// by the kinematic shaping.736void AC_PosControl::set_max_speed_accel_z(float speed_down, float speed_up, float accel_cmss)737{738// ensure speed_down is always negative739speed_down = -fabsf(speed_down);740741// sanity check and update742if (is_negative(speed_down)) {743_vel_max_down_cms = speed_down;744}745if (is_positive(speed_up)) {746_vel_max_up_cms = speed_up;747}748if (is_positive(accel_cmss)) {749_accel_max_z_cmss = accel_cmss;750}751752// ensure the vertical Jerk is not limited by the filters in the Z accel PID object753_jerk_max_z_cmsss = _shaping_jerk_z * 100.0;754if (is_positive(_pid_accel_z.filt_T_hz())) {755_jerk_max_z_cmsss = MIN(_jerk_max_z_cmsss, MIN(GRAVITY_MSS * 100.0, _accel_max_z_cmss) * (M_2PI * _pid_accel_z.filt_T_hz()) / 5.0);756}757if (is_positive(_pid_accel_z.filt_E_hz())) {758_jerk_max_z_cmsss = MIN(_jerk_max_z_cmsss, MIN(GRAVITY_MSS * 100.0, _accel_max_z_cmss) * (M_2PI * _pid_accel_z.filt_E_hz()) / 5.0);759}760}761762/// set_correction_speed_accel_z - set the position controller correction velocity and acceleration limit763/// speed_down can be positive or negative but will always be interpreted as a descent speed.764/// This should be done only during initialisation to avoid discontinuities765void AC_PosControl::set_correction_speed_accel_z(float speed_down, float speed_up, float accel_cmss)766{767// define maximum position error and maximum first and second differential limits768_p_pos_z.set_limits(-fabsf(speed_down), speed_up, accel_cmss, 0.0f);769}770771/// init_z_controller - initialise the position controller to the current position, velocity, acceleration and attitude.772/// This function is the default initialisation for any position control that provides position, velocity and acceleration.773/// This function does not allow any negative velocity or acceleration774void AC_PosControl::init_z_controller_no_descent()775{776// Initialise the position controller to the current throttle, position, velocity and acceleration.777init_z_controller();778779// remove all descent if present780_vel_target.z = MAX(0.0, _vel_target.z);781_vel_desired.z = MAX(0.0, _vel_desired.z);782_vel_terrain = MAX(0.0, _vel_terrain);783_vel_offset.z = MAX(0.0, _vel_offset.z);784_accel_target.z = MAX(0.0, _accel_target.z);785_accel_desired.z = MAX(0.0, _accel_desired.z);786_accel_terrain = MAX(0.0, _accel_terrain);787_accel_offset.z = MAX(0.0, _accel_offset.z);788}789790/// init_z_controller_stopping_point - initialise the position controller to the stopping point with zero velocity and acceleration.791/// This function should be used when the expected kinematic path assumes a stationary initial condition but does not specify a specific starting position.792/// The starting position can be retrieved by getting the position target using get_pos_target_cm() after calling this function.793void AC_PosControl::init_z_controller_stopping_point()794{795// Initialise the position controller to the current throttle, position, velocity and acceleration.796init_z_controller();797798get_stopping_point_z_cm(_pos_desired.z);799_pos_target.z = _pos_desired.z + _pos_offset.z;800_vel_desired.z = 0.0f;801_accel_desired.z = 0.0f;802}803804// relax_z_controller - initialise the position controller to the current position and velocity with decaying acceleration.805/// This function decays the output acceleration by 95% every half second to achieve a smooth transition to zero requested acceleration.806void AC_PosControl::relax_z_controller(float throttle_setting)807{808// Initialise the position controller to the current position, velocity and acceleration.809init_z_controller();810811// init_z_controller has set the accel PID I term to generate the current throttle set point812// Use relax_integrator to decay the throttle set point to throttle_setting813_pid_accel_z.relax_integrator((throttle_setting - _motors.get_throttle_hover()) * 1000.0f, _dt, POSCONTROL_RELAX_TC);814}815816/// init_z_controller - initialise the position controller to the current position, velocity, acceleration and attitude.817/// This function is the default initialisation for any position control that provides position, velocity and acceleration.818/// This function is private and contains all the shared z axis initialisation functions819void AC_PosControl::init_z_controller()820{821// initialise terrain targets and offsets to zero822init_terrain();823824// initialise offsets to target offsets and ensure offset targets are zero if they have not been updated.825init_offsets_z();826827_pos_target.z = _inav.get_position_z_up_cm();828_pos_desired.z = _pos_target.z - _pos_offset.z;829830_vel_target.z = _inav.get_velocity_z_up_cms();831_vel_desired.z = _vel_target.z - _vel_offset.z;832833// Reset I term of velocity PID834_pid_vel_z.reset_filter();835_pid_vel_z.set_integrator(0.0f);836837_accel_target.z = constrain_float(get_z_accel_cmss(), -_accel_max_z_cmss, _accel_max_z_cmss);838_accel_desired.z = _accel_target.z - (_accel_offset.z + _accel_terrain);839_pid_accel_z.reset_filter();840841// Set accel PID I term based on the current throttle842// Remove the expected P term due to _accel_desired.z being constrained to _accel_max_z_cmss843// Remove the expected FF term due to non-zero _accel_target.z844_pid_accel_z.set_integrator((_attitude_control.get_throttle_in() - _motors.get_throttle_hover()) * 1000.0f845- _pid_accel_z.kP() * (_accel_target.z - get_z_accel_cmss())846- _pid_accel_z.ff() * _accel_target.z);847848// initialise ekf z reset handler849init_ekf_z_reset();850851// initialise z_controller time out852_last_update_z_ticks = AP::scheduler().ticks32();853}854855/// input_accel_z - calculate a jerk limited path from the current position, velocity and acceleration to an input acceleration.856/// The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.857void AC_PosControl::input_accel_z(float accel)858{859// calculated increased maximum jerk if over speed860float jerk_max_z_cmsss = _jerk_max_z_cmsss * calculate_overspeed_gain();861862// adjust desired alt if motors have not hit their limits863update_pos_vel_accel(_pos_desired.z, _vel_desired.z, _accel_desired.z, _dt, _limit_vector.z, _p_pos_z.get_error(), _pid_vel_z.get_error());864865shape_accel(accel, _accel_desired.z, jerk_max_z_cmsss, _dt);866}867868/// input_accel_z - calculate a jerk limited path from the current position, velocity and acceleration to an input acceleration.869/// The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.870/// The kinematic path is constrained by the maximum acceleration and jerk set using the function set_max_speed_accel_z.871/// The parameter limit_output specifies if the velocity and acceleration limits are applied to the sum of commanded and correction values or just correction.872void AC_PosControl::input_vel_accel_z(float &vel, float accel, bool limit_output)873{874// calculated increased maximum acceleration and jerk if over speed875const float overspeed_gain = calculate_overspeed_gain();876const float accel_max_z_cmss = _accel_max_z_cmss * overspeed_gain;877const float jerk_max_z_cmsss = _jerk_max_z_cmsss * overspeed_gain;878879// adjust desired alt if motors have not hit their limits880update_pos_vel_accel(_pos_desired.z, _vel_desired.z, _accel_desired.z, _dt, _limit_vector.z, _p_pos_z.get_error(), _pid_vel_z.get_error());881882shape_vel_accel(vel, accel,883_vel_desired.z, _accel_desired.z,884-constrain_float(accel_max_z_cmss, 0.0f, 750.0f), accel_max_z_cmss,885jerk_max_z_cmsss, _dt, limit_output);886887update_vel_accel(vel, accel, _dt, 0.0, 0.0);888}889890/// set_pos_target_z_from_climb_rate_cm - adjusts target up or down using a commanded climb rate in cm/s891/// using the default position control kinematic path.892/// The zero target altitude is varied to follow pos_offset_z893void AC_PosControl::set_pos_target_z_from_climb_rate_cm(float vel)894{895input_vel_accel_z(vel, 0.0);896}897898/// land_at_climb_rate_cm - adjusts target up or down using a commanded climb rate in cm/s899/// using the default position control kinematic path.900/// ignore_descent_limit turns off output saturation handling to aid in landing detection. ignore_descent_limit should be false unless landing.901void AC_PosControl::land_at_climb_rate_cm(float vel, bool ignore_descent_limit)902{903if (ignore_descent_limit) {904// turn off limits in the negative z direction905_limit_vector.z = MAX(_limit_vector.z, 0.0f);906}907908input_vel_accel_z(vel, 0.0);909}910911/// input_pos_vel_accel_z - calculate a jerk limited path from the current position, velocity and acceleration to an input position velocity and acceleration.912/// The pos and vel are projected forwards in time based on a time step of dt and acceleration accel.913/// The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.914/// The function alters the pos and vel to be the kinematic path based on accel915/// The parameter limit_output specifies if the velocity and acceleration limits are applied to the sum of commanded and correction values or just correction.916void AC_PosControl::input_pos_vel_accel_z(float &pos, float &vel, float accel, bool limit_output)917{918// calculated increased maximum acceleration and jerk if over speed919const float overspeed_gain = calculate_overspeed_gain();920const float accel_max_z_cmss = _accel_max_z_cmss * overspeed_gain;921const float jerk_max_z_cmsss = _jerk_max_z_cmsss * overspeed_gain;922923// adjust desired altitude if motors have not hit their limits924update_pos_vel_accel(_pos_desired.z, _vel_desired.z, _accel_desired.z, _dt, _limit_vector.z, _p_pos_z.get_error(), _pid_vel_z.get_error());925926shape_pos_vel_accel(pos, vel, accel,927_pos_desired.z, _vel_desired.z, _accel_desired.z,928_vel_max_down_cms, _vel_max_up_cms,929-constrain_float(accel_max_z_cmss, 0.0f, 750.0f), accel_max_z_cmss,930jerk_max_z_cmsss, _dt, limit_output);931932postype_t posp = pos;933update_pos_vel_accel(posp, vel, accel, _dt, 0.0, 0.0, 0.0);934pos = posp;935}936937/// set_alt_target_with_slew - adjusts target up or down using a commanded altitude in cm938/// using the default position control kinematic path.939void AC_PosControl::set_alt_target_with_slew(float pos)940{941float zero = 0;942input_pos_vel_accel_z(pos, zero, 0);943}944945/// update_offsets_z - updates the vertical offsets used by terrain following946void AC_PosControl::update_offsets_z()947{948// check for offset target timeout949uint32_t now_ms = AP_HAL::millis();950if (now_ms - _posvelaccel_offset_target_z_ms > POSCONTROL_POSVELACCEL_OFFSET_TARGET_TIMEOUT_MS) {951_pos_offset_target.z = 0.0;952_vel_offset_target.z = 0.0;953_accel_offset_target.z = 0.0;954}955956// update position, velocity, accel offsets for this iteration957postype_t p_offset_z = _pos_offset.z;958update_pos_vel_accel(p_offset_z, _vel_offset.z, _accel_offset.z, _dt, MIN(_limit_vector.z, 0.0f), _p_pos_z.get_error(), _pid_vel_z.get_error());959_pos_offset.z = p_offset_z;960961// input shape vertical position, velocity and acceleration offsets962shape_pos_vel_accel(_pos_offset_target.z, _vel_offset_target.z, _accel_offset_target.z,963_pos_offset.z, _vel_offset.z, _accel_offset.z,964get_max_speed_down_cms(), get_max_speed_up_cms(),965-get_max_accel_z_cmss(), get_max_accel_z_cmss(),966_jerk_max_z_cmsss, _dt, false);967968p_offset_z = _pos_offset_target.z;969update_pos_vel_accel(p_offset_z, _vel_offset_target.z, _accel_offset_target.z, _dt, 0.0, 0.0, 0.0);970_pos_offset_target.z = p_offset_z;971}972973// is_active_z - returns true if the z position controller has been run in the previous loop974bool AC_PosControl::is_active_z() const975{976const uint32_t dt_ticks = AP::scheduler().ticks32() - _last_update_z_ticks;977return dt_ticks <= 1;978}979980/// update_z_controller - runs the vertical position controller correcting position, velocity and acceleration errors.981/// Position and velocity errors are converted to velocity and acceleration targets using PID objects982/// Desired velocity and accelerations are added to these corrections as they are calculated983/// Kinematically consistent target position and desired velocity and accelerations should be provided before calling this function984void AC_PosControl::update_z_controller()985{986// check for ekf z-axis position reset987handle_ekf_z_reset();988989// Check for z_controller time out990if (!is_active_z()) {991init_z_controller();992if (has_good_timing()) {993// call internal error because initialisation has not been done994INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);995}996}997_last_update_z_ticks = AP::scheduler().ticks32();998999// update the position, velocity and acceleration offsets1000update_offsets_z();1001update_terrain();1002_pos_target.z = _pos_desired.z + _pos_offset.z + _pos_terrain;10031004// calculate the target velocity correction1005float pos_target_zf = _pos_target.z;10061007_vel_target.z = _p_pos_z.update_all(pos_target_zf, _inav.get_position_z_up_cm());1008_vel_target.z *= AP::ahrs().getControlScaleZ();10091010_pos_target.z = pos_target_zf;1011_pos_desired.z = _pos_target.z - (_pos_offset.z + _pos_terrain);10121013// add feed forward component1014_vel_target.z += _vel_desired.z + _vel_offset.z + _vel_terrain;10151016// Velocity Controller10171018const float curr_vel_z = _inav.get_velocity_z_up_cms();1019_accel_target.z = _pid_vel_z.update_all(_vel_target.z, curr_vel_z, _dt, _motors.limit.throttle_lower, _motors.limit.throttle_upper);1020_accel_target.z *= AP::ahrs().getControlScaleZ();10211022// add feed forward component1023_accel_target.z += _accel_desired.z + _accel_offset.z + _accel_terrain;10241025// Acceleration Controller10261027// Calculate vertical acceleration1028const float z_accel_meas = get_z_accel_cmss();10291030// ensure imax is always large enough to overpower hover throttle1031if (_motors.get_throttle_hover() * 1000.0f > _pid_accel_z.imax()) {1032_pid_accel_z.set_imax(_motors.get_throttle_hover() * 1000.0f);1033}1034float thr_out;1035if (_vibe_comp_enabled) {1036thr_out = get_throttle_with_vibration_override();1037} else {1038thr_out = _pid_accel_z.update_all(_accel_target.z, z_accel_meas, _dt, (_motors.limit.throttle_lower || _motors.limit.throttle_upper)) * 0.001f;1039thr_out += _pid_accel_z.get_ff() * 0.001f;1040}1041thr_out += _motors.get_throttle_hover();10421043// Actuator commands10441045// send throttle to attitude controller with angle boost1046_attitude_control.set_throttle_out(thr_out, true, POSCONTROL_THROTTLE_CUTOFF_FREQ_HZ);10471048// Check for vertical controller health10491050// _speed_down_cms is checked to be non-zero when set1051float error_ratio = _pid_vel_z.get_error() / _vel_max_down_cms;1052_vel_z_control_ratio += _dt * 0.1f * (0.5 - error_ratio);1053_vel_z_control_ratio = constrain_float(_vel_z_control_ratio, 0.0f, 2.0f);10541055// set vertical component of the limit vector1056if (_motors.limit.throttle_upper) {1057_limit_vector.z = 1.0f;1058} else if (_motors.limit.throttle_lower) {1059_limit_vector.z = -1.0f;1060} else {1061_limit_vector.z = 0.0f;1062}1063}106410651066///1067/// Accessors1068///10691070/// get_lean_angle_max_cd - returns the maximum lean angle the autopilot may request1071float AC_PosControl::get_lean_angle_max_cd() const1072{1073if (is_positive(_angle_max_override_cd)) {1074return _angle_max_override_cd;1075}1076if (!is_positive(_lean_angle_max)) {1077return _attitude_control.lean_angle_max_cd();1078}1079return _lean_angle_max * 100.0f;1080}10811082/// set the desired position, velocity and acceleration targets1083void AC_PosControl::set_pos_vel_accel(const Vector3p& pos, const Vector3f& vel, const Vector3f& accel)1084{1085_pos_desired = pos;1086_vel_desired = vel;1087_accel_desired = accel;1088}10891090/// set the desired position, velocity and acceleration targets1091void AC_PosControl::set_pos_vel_accel_xy(const Vector2p& pos, const Vector2f& vel, const Vector2f& accel)1092{1093_pos_desired.xy() = pos;1094_vel_desired.xy() = vel;1095_accel_desired.xy() = accel;1096}10971098// get_lean_angles_to_accel - convert roll, pitch lean target angles to lat/lon frame accelerations in cm/s/s1099Vector3f AC_PosControl::lean_angles_to_accel(const Vector3f& att_target_euler) const1100{1101// rotate our roll, pitch angles into lat/lon frame1102const float sin_roll = sinf(att_target_euler.x);1103const float cos_roll = cosf(att_target_euler.x);1104const float sin_pitch = sinf(att_target_euler.y);1105const float cos_pitch = cosf(att_target_euler.y);1106const float sin_yaw = sinf(att_target_euler.z);1107const float cos_yaw = cosf(att_target_euler.z);11081109return Vector3f{1110(GRAVITY_MSS * 100.0f) * (-cos_yaw * sin_pitch * cos_roll - sin_yaw * sin_roll) / MAX(cos_roll * cos_pitch, 0.1f),1111(GRAVITY_MSS * 100.0f) * (-sin_yaw * sin_pitch * cos_roll + cos_yaw * sin_roll) / MAX(cos_roll * cos_pitch, 0.1f),1112(GRAVITY_MSS * 100.0f)1113};1114}11151116/// Terrain11171118/// set the terrain position, velocity and acceleration in cm, cms and cm/s/s from EKF origin in NE frame1119/// this is used to initiate the offsets when initialise the position controller or do an offset reset1120void AC_PosControl::init_terrain()1121{1122// set terrain position and target to zero1123_pos_terrain_target = 0.0;1124_pos_terrain = 0.0;11251126// set velocity offset to zero1127_vel_terrain = 0.0;11281129// set acceleration offset to zero1130_accel_terrain = 0.0;1131}11321133// init_pos_terrain_cm - initialises the current terrain altitude and target altitude to pos_offset_terrain_cm1134void AC_PosControl::init_pos_terrain_cm(float pos_terrain_cm)1135{1136_pos_desired.z -= (pos_terrain_cm - _pos_terrain);1137_pos_terrain_target = pos_terrain_cm;1138_pos_terrain = pos_terrain_cm;1139}114011411142/// Offsets11431144/// set the horizontal position, velocity and acceleration offsets in cm, cms and cm/s/s from EKF origin in NE frame1145/// this is used to initiate the offsets when initialise the position controller or do an offset reset1146void AC_PosControl::init_offsets_xy()1147{1148// check for offset target timeout1149uint32_t now_ms = AP_HAL::millis();1150if (now_ms - _posvelaccel_offset_target_xy_ms > POSCONTROL_POSVELACCEL_OFFSET_TARGET_TIMEOUT_MS) {1151_pos_offset_target.xy().zero();1152_vel_offset_target.xy().zero();1153_accel_offset_target.xy().zero();1154}11551156// set position offset to target1157_pos_offset.xy() = _pos_offset_target.xy();11581159// set velocity offset to target1160_vel_offset.xy() = _vel_offset_target.xy();11611162// set acceleration offset to target1163_accel_offset.xy() = _accel_offset_target.xy();1164}11651166/// set the horizontal position, velocity and acceleration offsets in cm, cms and cm/s/s from EKF origin in NE frame1167/// this is used to initiate the offsets when initialise the position controller or do an offset reset1168void AC_PosControl::init_offsets_z()1169{1170// check for offset target timeout1171uint32_t now_ms = AP_HAL::millis();1172if (now_ms - _posvelaccel_offset_target_z_ms > POSCONTROL_POSVELACCEL_OFFSET_TARGET_TIMEOUT_MS) {1173_pos_offset_target.z = 0.0;1174_vel_offset_target.z = 0.0;1175_accel_offset_target.z = 0.0;1176}1177// set position offset to target1178_pos_offset.z = _pos_offset_target.z;11791180// set velocity offset to target1181_vel_offset.z = _vel_offset_target.z;11821183// set acceleration offset to target1184_accel_offset.z = _accel_offset_target.z;1185}11861187#if AP_SCRIPTING_ENABLED1188// add an additional offset to vehicle's target position, velocity and acceleration1189// units are m, m/s and m/s/s in NED frame1190// Z-axis is not currently supported and is ignored1191bool AC_PosControl::set_posvelaccel_offset(const Vector3f &pos_offset_NED, const Vector3f &vel_offset_NED, const Vector3f &accel_offset_NED)1192{1193set_posvelaccel_offset_target_xy_cm(pos_offset_NED.topostype().xy() * 100.0, vel_offset_NED.xy() * 100.0, accel_offset_NED.xy() * 100.0);1194set_posvelaccel_offset_target_z_cm(-pos_offset_NED.topostype().z * 100.0, -vel_offset_NED.z * 100, -accel_offset_NED.z * 100.0);1195return true;1196}11971198// get position and velocity offset to vehicle's target velocity and acceleration1199// units are m and m/s in NED frame1200bool AC_PosControl::get_posvelaccel_offset(Vector3f &pos_offset_NED, Vector3f &vel_offset_NED, Vector3f &accel_offset_NED)1201{1202pos_offset_NED.xy() = _pos_offset_target.xy().tofloat() * 0.01;1203pos_offset_NED.z = -_pos_offset_target.z * 0.01;1204vel_offset_NED.xy() = _vel_offset_target.xy() * 0.01;1205vel_offset_NED.z = -_vel_offset_target.z * 0.01;1206accel_offset_NED.xy() = _accel_offset_target.xy() * 0.01;1207accel_offset_NED.z = -_accel_offset_target.z * 0.01;1208return true;1209}12101211// get target velocity in m/s in NED frame1212bool AC_PosControl::get_vel_target(Vector3f &vel_target_NED)1213{1214if (!is_active_xy() || !is_active_z()) {1215return false;1216}1217vel_target_NED.xy() = _vel_target.xy() * 0.01;1218vel_target_NED.z = -_vel_target.z * 0.01;1219return true;1220}12211222// get target acceleration in m/s/s in NED frame1223bool AC_PosControl::get_accel_target(Vector3f &accel_target_NED)1224{1225if (!is_active_xy() || !is_active_z()) {1226return false;1227}1228accel_target_NED.xy() = _accel_target.xy() * 0.01;1229accel_target_NED.z = -_accel_target.z * 0.01;1230return true;1231}1232#endif12331234/// set the horizontal position, velocity and acceleration offset targets in cm, cms and cm/s/s from EKF origin in NE frame1235/// these must be set every 3 seconds (or less) or they will timeout and return to zero1236void AC_PosControl::set_posvelaccel_offset_target_xy_cm(const Vector2p& pos_offset_target_xy_cm, const Vector2f& vel_offset_target_xy_cms, const Vector2f& accel_offset_target_xy_cmss)1237{1238// set position offset target1239_pos_offset_target.xy() = pos_offset_target_xy_cm;12401241// set velocity offset target1242_vel_offset_target.xy() = vel_offset_target_xy_cms;12431244// set acceleration offset target1245_accel_offset_target.xy() = accel_offset_target_xy_cmss;12461247// record time of update so we can detect timeouts1248_posvelaccel_offset_target_xy_ms = AP_HAL::millis();1249}12501251/// set the vertical position, velocity and acceleration offset targets in cm, cms and cm/s/s from EKF origin in NE frame1252/// these must be set every 3 seconds (or less) or they will timeout and return to zero1253void AC_PosControl::set_posvelaccel_offset_target_z_cm(float pos_offset_target_z_cm, float vel_offset_target_z_cms, const float accel_offset_target_z_cmss)1254{1255// set position offset target1256_pos_offset_target.z = pos_offset_target_z_cm;12571258// set velocity offset target1259_vel_offset_target.z = vel_offset_target_z_cms;12601261// set acceleration offset target1262_accel_offset_target.z = accel_offset_target_z_cmss;12631264// record time of update so we can detect timeouts1265_posvelaccel_offset_target_z_ms = AP_HAL::millis();1266}12671268// returns the NED target acceleration vector for attitude control1269Vector3f AC_PosControl::get_thrust_vector() const1270{1271Vector3f accel_target = get_accel_target_cmss();1272accel_target.z = -GRAVITY_MSS * 100.0f;1273return accel_target;1274}12751276/// get_stopping_point_xy_cm - calculates stopping point in NEU cm based on current position, velocity, vehicle acceleration1277/// function does not change the z axis1278void AC_PosControl::get_stopping_point_xy_cm(Vector2p &stopping_point) const1279{1280// todo: we should use the current target position and velocity if we are currently running the position controller1281stopping_point = _inav.get_position_xy_cm().topostype();1282stopping_point -= _pos_offset.xy();12831284Vector2f curr_vel = _inav.get_velocity_xy_cms();1285curr_vel -= _vel_offset.xy();12861287// calculate current velocity1288float vel_total = curr_vel.length();12891290if (!is_positive(vel_total)) {1291return;1292}12931294float kP = _p_pos_xy.kP();1295const float stopping_dist = stopping_distance(constrain_float(vel_total, 0.0, _vel_max_xy_cms), kP, _accel_max_xy_cmss);1296if (!is_positive(stopping_dist)) {1297return;1298}12991300// convert the stopping distance into a stopping point using velocity vector1301const float t = stopping_dist / vel_total;1302stopping_point += (curr_vel * t).topostype();1303}13041305/// get_stopping_point_z_cm - calculates stopping point in NEU cm based on current position, velocity, vehicle acceleration1306void AC_PosControl::get_stopping_point_z_cm(postype_t &stopping_point) const1307{1308float curr_pos_z = _inav.get_position_z_up_cm();1309curr_pos_z -= _pos_offset.z;13101311float curr_vel_z = _inav.get_velocity_z_up_cms();1312curr_vel_z -= _vel_offset.z;13131314// avoid divide by zero by using current position if kP is very low or acceleration is zero1315if (!is_positive(_p_pos_z.kP()) || !is_positive(_accel_max_z_cmss)) {1316stopping_point = curr_pos_z;1317return;1318}13191320stopping_point = curr_pos_z + constrain_float(stopping_distance(curr_vel_z, _p_pos_z.kP(), _accel_max_z_cmss), - POSCONTROL_STOPPING_DIST_DOWN_MAX, POSCONTROL_STOPPING_DIST_UP_MAX);1321}13221323/// get_bearing_to_target_cd - get bearing to target position in centi-degrees1324int32_t AC_PosControl::get_bearing_to_target_cd() const1325{1326return get_bearing_cd(_inav.get_position_xy_cm(), _pos_target.tofloat().xy());1327}132813291330///1331/// System methods1332///13331334// get throttle using vibration-resistant calculation (uses feed forward with manually calculated gain)1335float AC_PosControl::get_throttle_with_vibration_override()1336{1337const float thr_per_accelz_cmss = _motors.get_throttle_hover() / (GRAVITY_MSS * 100.0f);1338// during vibration compensation use feed forward with manually calculated gain1339// ToDo: clear pid_info P, I and D terms for logging1340if (!(_motors.limit.throttle_lower || _motors.limit.throttle_upper) || ((is_positive(_pid_accel_z.get_i()) && is_negative(_pid_vel_z.get_error())) || (is_negative(_pid_accel_z.get_i()) && is_positive(_pid_vel_z.get_error())))) {1341_pid_accel_z.set_integrator(_pid_accel_z.get_i() + _dt * thr_per_accelz_cmss * 1000.0f * _pid_vel_z.get_error() * _pid_vel_z.kP() * POSCONTROL_VIBE_COMP_I_GAIN);1342}1343return POSCONTROL_VIBE_COMP_P_GAIN * thr_per_accelz_cmss * _accel_target.z + _pid_accel_z.get_i() * 0.001f;1344}13451346/// standby_xyz_reset - resets I terms and removes position error1347/// This function will let Loiter and Alt Hold continue to operate1348/// in the event that the flight controller is in control of the1349/// aircraft when in standby.1350void AC_PosControl::standby_xyz_reset()1351{1352// Set _pid_accel_z integrator to zero.1353_pid_accel_z.set_integrator(0.0f);13541355// Set the target position to the current pos.1356_pos_target = _inav.get_position_neu_cm().topostype();13571358// Set _pid_vel_xy integrator and derivative to zero.1359_pid_vel_xy.reset_filter();13601361// initialise ekf xy reset handler1362init_ekf_xy_reset();1363}13641365#if HAL_LOGGING_ENABLED1366// write PSC and/or PSCZ logs1367void AC_PosControl::write_log()1368{1369if (is_active_xy()) {1370float accel_x, accel_y;1371lean_angles_to_accel_xy(accel_x, accel_y);1372Write_PSCN(_pos_desired.x, _pos_target.x, _inav.get_position_neu_cm().x,1373_vel_desired.x, _vel_target.x, _inav.get_velocity_neu_cms().x,1374_accel_desired.x, _accel_target.x, accel_x);1375Write_PSCE(_pos_desired.y, _pos_target.y, _inav.get_position_neu_cm().y,1376_vel_desired.y, _vel_target.y, _inav.get_velocity_neu_cms().y,1377_accel_desired.y, _accel_target.y, accel_y);13781379// log offsets if they are being used1380if (!_pos_offset.xy().is_zero()) {1381Write_PSON(_pos_offset_target.x, _pos_offset.x, _vel_offset_target.x, _vel_offset.x, _accel_offset_target.x, _accel_offset.x);1382Write_PSOE(_pos_offset_target.y, _pos_offset.y, _vel_offset_target.y, _vel_offset.y, _accel_offset_target.y, _accel_offset.y);1383}1384}13851386if (is_active_z()) {1387Write_PSCD(-_pos_desired.z, -_pos_target.z, -_inav.get_position_z_up_cm(),1388-_vel_desired.z, -_vel_target.z, -_inav.get_velocity_z_up_cms(),1389-_accel_desired.z, -_accel_target.z, -get_z_accel_cmss());13901391// log down and terrain offsets if they are being used1392if (!is_zero(_pos_offset.z)) {1393Write_PSOD(-_pos_offset_target.z, -_pos_offset.z, -_vel_offset_target.z, -_vel_offset.z, -_accel_offset_target.z, -_accel_offset.z);1394}1395if (!is_zero(_pos_terrain)) {1396Write_PSOT(-_pos_terrain_target, -_pos_terrain, 0, -_vel_terrain, 0, -_accel_terrain);1397}1398}1399}1400#endif // HAL_LOGGING_ENABLED14011402/// crosstrack_error - returns horizontal error to the closest point to the current track1403float AC_PosControl::crosstrack_error() const1404{1405const Vector2f pos_error = _inav.get_position_xy_cm() - (_pos_target.xy()).tofloat();1406if (is_zero(_vel_desired.xy().length_squared())) {1407// crosstrack is the horizontal distance to target when stationary1408return pos_error.length();1409} else {1410// crosstrack is the horizontal distance to the closest point to the current track1411const Vector2f vel_unit = _vel_desired.xy().normalized();1412const float dot_error = pos_error * vel_unit;14131414// todo: remove MAX of zero when safe_sqrt fixed1415return safe_sqrt(MAX(pos_error.length_squared() - sq(dot_error), 0.0));1416}1417}14181419///1420/// private methods1421///14221423/// Terrain14241425/// update_z_offsets - updates the vertical offsets used by terrain following1426void AC_PosControl::update_terrain()1427{1428// update position, velocity, accel offsets for this iteration1429postype_t pos_terrain = _pos_terrain;1430update_pos_vel_accel(pos_terrain, _vel_terrain, _accel_terrain, _dt, MIN(_limit_vector.z, 0.0f), _p_pos_z.get_error(), _pid_vel_z.get_error());1431_pos_terrain = pos_terrain;14321433// input shape horizontal position, velocity and acceleration offsets1434shape_pos_vel_accel(_pos_terrain_target, 0.0, 0.0,1435_pos_terrain, _vel_terrain, _accel_terrain,1436get_max_speed_down_cms(), get_max_speed_up_cms(),1437-get_max_accel_z_cmss(), get_max_accel_z_cmss(),1438_jerk_max_z_cmsss, _dt, false);14391440// we do not have to update _pos_terrain_target because we assume the target velocity and acceleration are zero1441// if we know how fast the terain altitude is changing we would add update_pos_vel_accel for _pos_terrain_target here1442}14431444// get_lean_angles_to_accel - convert roll, pitch lean angles to NE frame accelerations in cm/s/s1445void AC_PosControl::accel_to_lean_angles(float accel_x_cmss, float accel_y_cmss, float& roll_target, float& pitch_target) const1446{1447// rotate accelerations into body forward-right frame1448const float accel_forward = accel_x_cmss * _ahrs.cos_yaw() + accel_y_cmss * _ahrs.sin_yaw();1449const float accel_right = -accel_x_cmss * _ahrs.sin_yaw() + accel_y_cmss * _ahrs.cos_yaw();14501451// update angle targets that will be passed to stabilize controller1452pitch_target = accel_to_angle(-accel_forward * 0.01) * 100;1453float cos_pitch_target = cosf(pitch_target * M_PI / 18000.0f);1454roll_target = accel_to_angle((accel_right * cos_pitch_target)*0.01) * 100;1455}14561457// lean_angles_to_accel_xy - convert roll, pitch lean target angles to NE frame accelerations in cm/s/s1458// todo: this should be based on thrust vector attitude control1459void AC_PosControl::lean_angles_to_accel_xy(float& accel_x_cmss, float& accel_y_cmss) const1460{1461// rotate our roll, pitch angles into lat/lon frame1462Vector3f att_target_euler = _attitude_control.get_att_target_euler_rad();1463att_target_euler.z = _ahrs.yaw;1464Vector3f accel_cmss = lean_angles_to_accel(att_target_euler);14651466accel_x_cmss = accel_cmss.x;1467accel_y_cmss = accel_cmss.y;1468}14691470// calculate_yaw_and_rate_yaw - update the calculated the vehicle yaw and rate of yaw.1471void AC_PosControl::calculate_yaw_and_rate_yaw()1472{1473// Calculate the turn rate1474float turn_rate = 0.0f;1475const float vel_desired_xy_len = _vel_desired.xy().length();1476if (is_positive(vel_desired_xy_len)) {1477const float accel_forward = (_accel_desired.x * _vel_desired.x + _accel_desired.y * _vel_desired.y) / vel_desired_xy_len;1478const Vector2f accel_turn = _accel_desired.xy() - _vel_desired.xy() * accel_forward / vel_desired_xy_len;1479const float accel_turn_xy_len = accel_turn.length();1480turn_rate = accel_turn_xy_len / vel_desired_xy_len;1481if ((accel_turn.y * _vel_desired.x - accel_turn.x * _vel_desired.y) < 0.0) {1482turn_rate = -turn_rate;1483}1484}14851486// update the target yaw if velocity is greater than 5% _vel_max_xy_cms1487if (vel_desired_xy_len > _vel_max_xy_cms * 0.05f) {1488_yaw_target = degrees(_vel_desired.xy().angle()) * 100.0f;1489_yaw_rate_target = turn_rate * degrees(100.0f);1490return;1491}14921493// use the current attitude controller yaw target1494_yaw_target = _attitude_control.get_att_target_euler_cd().z;1495_yaw_rate_target = 0;1496}14971498// calculate_overspeed_gain - calculated increased maximum acceleration and jerk if over speed condition is detected1499float AC_PosControl::calculate_overspeed_gain()1500{1501if (_vel_desired.z < _vel_max_down_cms && !is_zero(_vel_max_down_cms)) {1502return POSCONTROL_OVERSPEED_GAIN_Z * _vel_desired.z / _vel_max_down_cms;1503}1504if (_vel_desired.z > _vel_max_up_cms && !is_zero(_vel_max_up_cms)) {1505return POSCONTROL_OVERSPEED_GAIN_Z * _vel_desired.z / _vel_max_up_cms;1506}1507return 1.0;1508}15091510/// initialise ekf xy position reset check1511void AC_PosControl::init_ekf_xy_reset()1512{1513Vector2f pos_shift;1514_ekf_xy_reset_ms = _ahrs.getLastPosNorthEastReset(pos_shift);1515}15161517/// handle_ekf_xy_reset - check for ekf position reset and adjust loiter or brake target position1518void AC_PosControl::handle_ekf_xy_reset()1519{1520// check for position shift1521Vector2f pos_shift;1522uint32_t reset_ms = _ahrs.getLastPosNorthEastReset(pos_shift);1523if (reset_ms != _ekf_xy_reset_ms) {15241525// ToDo: move EKF steps into the offsets for modes setting absolute position and velocity1526// for this we need some sort of switch to select what type of EKF handling we want to use15271528// To zero real position shift during relative position modes like Loiter, PosHold, Guided velocity and accleration control.1529_pos_target.xy() = (_inav.get_position_xy_cm() + _p_pos_xy.get_error()).topostype();1530_pos_desired.xy() = _pos_target.xy() - _pos_offset.xy();1531_vel_target.xy() = _inav.get_velocity_xy_cms() + _pid_vel_xy.get_error();1532_vel_desired.xy() = _vel_target.xy() - _vel_offset.xy();15331534_ekf_xy_reset_ms = reset_ms;1535}1536}15371538/// initialise ekf z axis reset check1539void AC_PosControl::init_ekf_z_reset()1540{1541float alt_shift;1542_ekf_z_reset_ms = _ahrs.getLastPosDownReset(alt_shift);1543}15441545/// handle_ekf_z_reset - check for ekf position reset and adjust loiter or brake target position1546void AC_PosControl::handle_ekf_z_reset()1547{1548// check for position shift1549float alt_shift;1550uint32_t reset_ms = _ahrs.getLastPosDownReset(alt_shift);1551if (reset_ms != 0 && reset_ms != _ekf_z_reset_ms) {15521553// ToDo: move EKF steps into the offsets for modes setting absolute position and velocity1554// for this we need some sort of switch to select what type of EKF handling we want to use15551556// To zero real position shift during relative position modes like Loiter, PosHold, Guided velocity and accleration control.1557_pos_target.z = _inav.get_position_z_up_cm() + _p_pos_z.get_error();1558_pos_desired.z = _pos_target.z - (_pos_offset.z + _pos_terrain);1559_vel_target.z = _inav.get_velocity_z_up_cms() + _pid_vel_z.get_error();1560_vel_desired.z = _vel_target.z - (_vel_offset.z + _vel_terrain);15611562_ekf_z_reset_ms = reset_ms;1563}1564}15651566bool AC_PosControl::pre_arm_checks(const char *param_prefix,1567char *failure_msg,1568const uint8_t failure_msg_len)1569{1570if (!is_positive(get_pos_xy_p().kP())) {1571hal.util->snprintf(failure_msg, failure_msg_len, "%s_POSXY_P must be > 0", param_prefix);1572return false;1573}1574if (!is_positive(get_pos_z_p().kP())) {1575hal.util->snprintf(failure_msg, failure_msg_len, "%s_POSZ_P must be > 0", param_prefix);1576return false;1577}1578if (!is_positive(get_vel_z_pid().kP())) {1579hal.util->snprintf(failure_msg, failure_msg_len, "%s_VELZ_P must be > 0", param_prefix);1580return false;1581}1582if (!is_positive(get_accel_z_pid().kP())) {1583hal.util->snprintf(failure_msg, failure_msg_len, "%s_ACCZ_P must be > 0", param_prefix);1584return false;1585}1586if (!is_positive(get_accel_z_pid().kI())) {1587hal.util->snprintf(failure_msg, failure_msg_len, "%s_ACCZ_I must be > 0", param_prefix);1588return false;1589}15901591return true;1592}15931594// return true if on a real vehicle or SITL with lock-step scheduling1595bool AC_PosControl::has_good_timing(void) const1596{1597#if CONFIG_HAL_BOARD == HAL_BOARD_SITL1598auto *sitl = AP::sitl();1599if (sitl) {1600return sitl->state.is_lock_step_scheduled;1601}1602#endif1603// real boards are assumed to have good timing1604return true;1605}160616071608