2015-08-11 03:28:41 -03:00
# include <AP_HAL/AP_HAL.h>
# include "AC_PosControl.h"
# include <AP_Math/AP_Math.h>
2019-01-18 00:23:42 -04:00
# include <AP_Logger/AP_Logger.h>
2022-02-28 21:19:06 -04:00
# include <AP_Motors/AP_Motors.h> // motors library
2022-09-29 20:10:39 -03:00
# include <AP_Vehicle/AP_Vehicle_Type.h>
2023-01-28 05:43:41 -04:00
# include <AP_Scheduler/AP_Scheduler.h>
2013-12-28 07:15:29 -04:00
extern const AP_HAL : : HAL & hal ;
2018-01-15 06:50:54 -04:00
# if APM_BUILD_TYPE(APM_BUILD_ArduPlane)
// default gains for Plane
2018-01-15 06:52:55 -04:00
# define POSCONTROL_POS_Z_P 1.0f // vertical position controller P gain default
# define POSCONTROL_VEL_Z_P 5.0f // vertical velocity controller P gain default
2020-01-04 02:16:09 -04:00
# define POSCONTROL_VEL_Z_IMAX 1000.0f // vertical velocity controller IMAX gain default
# define POSCONTROL_VEL_Z_FILT_HZ 5.0f // vertical velocity controller input filter
# define POSCONTROL_VEL_Z_FILT_D_HZ 5.0f // vertical velocity controller input filter for D
2018-01-27 02:39:55 -04:00
# define POSCONTROL_ACC_Z_P 0.3f // vertical acceleration controller P gain default
# define POSCONTROL_ACC_Z_I 1.0f // vertical acceleration controller I gain default
# define POSCONTROL_ACC_Z_D 0.0f // vertical acceleration controller D gain default
# define POSCONTROL_ACC_Z_IMAX 800 // vertical acceleration controller IMAX gain default
# define POSCONTROL_ACC_Z_FILT_HZ 10.0f // vertical acceleration controller input filter default
# define POSCONTROL_ACC_Z_DT 0.02f // vertical acceleration controller dt default
2022-06-16 04:27:01 -03:00
# define POSCONTROL_POS_XY_P 0.5f // horizontal position controller P gain default
# define POSCONTROL_VEL_XY_P 0.7f // horizontal velocity controller P gain default
# define POSCONTROL_VEL_XY_I 0.35f // horizontal velocity controller I gain default
# define POSCONTROL_VEL_XY_D 0.17f // horizontal velocity controller D gain default
2018-01-15 06:50:54 -04:00
# define POSCONTROL_VEL_XY_IMAX 1000.0f // horizontal velocity controller IMAX gain default
# define POSCONTROL_VEL_XY_FILT_HZ 5.0f // horizontal velocity controller input filter
# define POSCONTROL_VEL_XY_FILT_D_HZ 5.0f // horizontal velocity controller input filter for D
2018-01-27 02:43:19 -04:00
# elif APM_BUILD_TYPE(APM_BUILD_ArduSub)
// default gains for Sub
# define POSCONTROL_POS_Z_P 3.0f // vertical position controller P gain default
# define POSCONTROL_VEL_Z_P 8.0f // vertical velocity controller P gain default
2020-01-04 02:16:09 -04:00
# define POSCONTROL_VEL_Z_IMAX 1000.0f // vertical velocity controller IMAX gain default
# define POSCONTROL_VEL_Z_FILT_HZ 5.0f // vertical velocity controller input filter
# define POSCONTROL_VEL_Z_FILT_D_HZ 5.0f // vertical velocity controller input filter for D
2018-01-27 02:43:19 -04:00
# define POSCONTROL_ACC_Z_P 0.5f // vertical acceleration controller P gain default
# define POSCONTROL_ACC_Z_I 0.1f // vertical acceleration controller I gain default
# define POSCONTROL_ACC_Z_D 0.0f // vertical acceleration controller D gain default
# define POSCONTROL_ACC_Z_IMAX 100 // vertical acceleration controller IMAX gain default
# define POSCONTROL_ACC_Z_FILT_HZ 20.0f // vertical acceleration controller input filter default
# define POSCONTROL_ACC_Z_DT 0.0025f // vertical acceleration controller dt default
# define POSCONTROL_POS_XY_P 1.0f // horizontal position controller P gain default
# define POSCONTROL_VEL_XY_P 1.0f // horizontal velocity controller P gain default
# define POSCONTROL_VEL_XY_I 0.5f // horizontal velocity controller I gain default
# define POSCONTROL_VEL_XY_D 0.0f // horizontal velocity controller D gain default
# define POSCONTROL_VEL_XY_IMAX 1000.0f // horizontal velocity controller IMAX gain default
# define POSCONTROL_VEL_XY_FILT_HZ 5.0f // horizontal velocity controller input filter
# define POSCONTROL_VEL_XY_FILT_D_HZ 5.0f // horizontal velocity controller input filter for D
2018-01-15 06:50:54 -04:00
# else
2018-01-27 02:43:19 -04:00
// default gains for Copter / TradHeli
2018-01-15 06:52:55 -04:00
# define POSCONTROL_POS_Z_P 1.0f // vertical position controller P gain default
# define POSCONTROL_VEL_Z_P 5.0f // vertical velocity controller P gain default
2020-01-04 02:16:09 -04:00
# define POSCONTROL_VEL_Z_IMAX 1000.0f // vertical velocity controller IMAX gain default
# define POSCONTROL_VEL_Z_FILT_HZ 5.0f // vertical velocity controller input filter
# define POSCONTROL_VEL_Z_FILT_D_HZ 5.0f // vertical velocity controller input filter for D
2018-01-27 02:39:55 -04:00
# define POSCONTROL_ACC_Z_P 0.5f // vertical acceleration controller P gain default
# define POSCONTROL_ACC_Z_I 1.0f // vertical acceleration controller I gain default
# define POSCONTROL_ACC_Z_D 0.0f // vertical acceleration controller D gain default
# define POSCONTROL_ACC_Z_IMAX 800 // vertical acceleration controller IMAX gain default
# define POSCONTROL_ACC_Z_FILT_HZ 20.0f // vertical acceleration controller input filter default
# define POSCONTROL_ACC_Z_DT 0.0025f // vertical acceleration controller dt default
2018-01-15 06:52:55 -04:00
# define POSCONTROL_POS_XY_P 1.0f // horizontal position controller P gain default
2018-01-19 02:07:33 -04:00
# define POSCONTROL_VEL_XY_P 2.0f // horizontal velocity controller P gain default
# define POSCONTROL_VEL_XY_I 1.0f // horizontal velocity controller I gain default
# define POSCONTROL_VEL_XY_D 0.5f // horizontal velocity controller D gain default
2018-01-15 06:50:54 -04:00
# define POSCONTROL_VEL_XY_IMAX 1000.0f // horizontal velocity controller IMAX gain default
# define POSCONTROL_VEL_XY_FILT_HZ 5.0f // horizontal velocity controller input filter
# define POSCONTROL_VEL_XY_FILT_D_HZ 5.0f // horizontal velocity controller input filter for D
# endif
2019-09-14 01:02:02 -03:00
// vibration compensation gains
# define POSCONTROL_VIBE_COMP_P_GAIN 0.250f
# define POSCONTROL_VIBE_COMP_I_GAIN 0.125f
2024-08-02 01:45:17 -03:00
// velocity offset targets timeout if not updated within 3 seconds
# define POSCONTROL_POSVELACCEL_OFFSET_TARGET_TIMEOUT_MS 3000
2024-09-17 00:54:55 -03:00
AC_PosControl * AC_PosControl : : _singleton ;
2015-10-25 14:03:46 -03:00
const AP_Param : : GroupInfo AC_PosControl : : var_info [ ] = {
2015-04-16 07:07:33 -03:00
// 0 was used for HOVER
// @Param: _ACC_XY_FILT
// @DisplayName: XY Acceleration filter cutoff frequency
// @Description: Lower values will slow the response of the navigation controller and reduce twitchiness
// @Units: Hz
// @Range: 0.5 5
// @Increment: 0.1
// @User: Advanced
2013-12-28 07:15:29 -04:00
2018-01-15 06:52:55 -04:00
// @Param: _POSZ_P
// @DisplayName: Position (vertical) controller P gain
// @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 controller
// @Range: 1.000 3.000
// @User: Standard
2020-01-04 02:16:09 -04:00
AP_SUBGROUPINFO ( _p_pos_z , " _POSZ_ " , 2 , AC_PosControl , AC_P_1D ) ,
2018-01-15 06:52:55 -04:00
// @Param: _VELZ_P
// @DisplayName: Velocity (vertical) controller P gain
// @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 controller
// @Range: 1.000 8.000
// @User: Standard
2020-01-04 02:16:09 -04:00
// @Param: _VELZ_I
// @DisplayName: Velocity (vertical) controller I gain
// @Description: Velocity (vertical) controller I gain. Corrects long-term difference in desired velocity to a target acceleration
// @Range: 0.02 1.00
// @Increment: 0.01
// @User: Advanced
// @Param: _VELZ_IMAX
// @DisplayName: Velocity (vertical) controller I gain maximum
// @Description: Velocity (vertical) controller I gain maximum. Constrains the target acceleration that the I gain will output
// @Range: 1.000 8.000
// @User: Standard
// @Param: _VELZ_D
// @DisplayName: Velocity (vertical) controller D gain
// @Description: Velocity (vertical) controller D gain. Corrects short-term changes in velocity
// @Range: 0.00 1.00
// @Increment: 0.001
// @User: Advanced
// @Param: _VELZ_FF
// @DisplayName: Velocity (vertical) controller Feed Forward gain
// @Description: Velocity (vertical) controller Feed Forward gain. Produces an output that is proportional to the magnitude of the target
// @Range: 0 1
// @Increment: 0.01
// @User: Advanced
// @Param: _VELZ_FLTE
// @DisplayName: Velocity (vertical) error filter
2021-03-11 08:05:36 -04:00
// @Description: Velocity (vertical) error filter. This filter (in Hz) is applied to the input for P and I terms
2020-01-04 02:16:09 -04:00
// @Range: 0 100
// @Units: Hz
// @User: Advanced
// @Param: _VELZ_FLTD
// @DisplayName: Velocity (vertical) input filter for D term
2021-03-11 08:05:36 -04:00
// @Description: Velocity (vertical) input filter for D term. This filter (in Hz) is applied to the input for D terms
2020-01-04 02:16:09 -04:00
// @Range: 0 100
// @Units: Hz
// @User: Advanced
AP_SUBGROUPINFO ( _pid_vel_z , " _VELZ_ " , 3 , AC_PosControl , AC_PID_Basic ) ,
2018-01-15 06:52:55 -04:00
2018-01-27 02:39:55 -04:00
// @Param: _ACCZ_P
2018-01-15 06:52:55 -04:00
// @DisplayName: Acceleration (vertical) controller P gain
// @Description: Acceleration (vertical) controller P gain. Converts the difference between desired vertical acceleration and actual acceleration into a motor output
2021-05-24 22:01:37 -03:00
// @Range: 0.200 1.500
2018-01-15 06:52:55 -04:00
// @Increment: 0.05
// @User: Standard
2018-01-27 02:39:55 -04:00
// @Param: _ACCZ_I
2018-01-15 06:52:55 -04:00
// @DisplayName: Acceleration (vertical) controller I gain
// @Description: Acceleration (vertical) controller I gain. Corrects long-term difference in desired vertical acceleration and actual acceleration
// @Range: 0.000 3.000
// @User: Standard
2018-01-27 02:39:55 -04:00
// @Param: _ACCZ_IMAX
2018-01-15 06:52:55 -04:00
// @DisplayName: Acceleration (vertical) controller I gain maximum
// @Description: Acceleration (vertical) controller I gain maximum. Constrains the maximum pwm that the I term will generate
// @Range: 0 1000
// @Units: d%
// @User: Standard
2018-01-27 02:39:55 -04:00
// @Param: _ACCZ_D
2018-01-15 06:52:55 -04:00
// @DisplayName: Acceleration (vertical) controller D gain
// @Description: Acceleration (vertical) controller D gain. Compensates for short-term change in desired vertical acceleration vs actual acceleration
// @Range: 0.000 0.400
// @User: Standard
2020-02-13 05:09:24 -04:00
// @Param: _ACCZ_FF
// @DisplayName: Acceleration (vertical) controller feed forward
// @Description: Acceleration (vertical) controller feed forward
// @Range: 0 0.5
// @Increment: 0.001
// @User: Standard
// @Param: _ACCZ_FLTT
// @DisplayName: Acceleration (vertical) controller target frequency in Hz
// @Description: Acceleration (vertical) controller target frequency in Hz
// @Range: 1 50
// @Increment: 1
// @Units: Hz
// @User: Standard
// @Param: _ACCZ_FLTE
// @DisplayName: Acceleration (vertical) controller error frequency in Hz
// @Description: Acceleration (vertical) controller error frequency in Hz
// @Range: 1 100
// @Increment: 1
// @Units: Hz
// @User: Standard
// @Param: _ACCZ_FLTD
// @DisplayName: Acceleration (vertical) controller derivative frequency in Hz
// @Description: Acceleration (vertical) controller derivative frequency in Hz
// @Range: 1 100
// @Increment: 1
2018-01-15 06:52:55 -04:00
// @Units: Hz
// @User: Standard
2020-09-24 04:26:05 -03:00
// @Param: _ACCZ_SMAX
// @DisplayName: Accel (vertical) slew rate limit
// @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.
// @Range: 0 200
// @Increment: 0.5
// @User: Advanced
2023-09-18 22:44:54 -03:00
// @Param: _ACCZ_PDMX
// @DisplayName: Acceleration (vertical) controller PD sum maximum
// @Description: Acceleration (vertical) controller PD sum maximum. The maximum/minimum value that the sum of the P and D term can output
// @Range: 0 1000
// @Units: d%
2023-07-27 10:59:16 -03:00
// @Param: _ACCZ_D_FF
// @DisplayName: Accel (vertical) Derivative FeedForward Gain
// @Description: FF D Gain which produces an output that is proportional to the rate of change of the target
// @Range: 0 0.02
// @Increment: 0.0001
// @User: Advanced
// @Param: _ACCZ_NTF
2023-10-01 14:21:00 -03:00
// @DisplayName: Accel (vertical) Target notch filter index
// @Description: Accel (vertical) Target notch filter index
// @Range: 1 8
2023-07-27 10:59:16 -03:00
// @User: Advanced
// @Param: _ACCZ_NEF
2023-10-01 14:21:00 -03:00
// @DisplayName: Accel (vertical) Error notch filter index
// @Description: Accel (vertical) Error notch filter index
// @Range: 1 8
2023-09-18 22:44:54 -03:00
// @User: Advanced
2020-09-24 04:26:05 -03:00
2018-01-27 02:39:55 -04:00
AP_SUBGROUPINFO ( _pid_accel_z , " _ACCZ_ " , 4 , AC_PosControl , AC_PID ) ,
2018-01-15 06:52:55 -04:00
// @Param: _POSXY_P
2020-11-04 20:26:13 -04:00
// @DisplayName: Position (horizontal) controller P gain
2018-01-15 06:52:55 -04:00
// @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 controller
// @Range: 0.500 2.000
// @User: Standard
2020-01-04 02:16:09 -04:00
AP_SUBGROUPINFO ( _p_pos_xy , " _POSXY_ " , 5 , AC_PosControl , AC_P_2D ) ,
2018-01-15 06:52:55 -04:00
2018-01-15 06:50:54 -04:00
// @Param: _VELXY_P
// @DisplayName: Velocity (horizontal) P gain
2020-01-04 02:16:09 -04:00
// @Description: Velocity (horizontal) P gain. Converts the difference between desired and actual velocity to a target acceleration
2018-01-15 06:50:54 -04:00
// @Range: 0.1 6.0
// @Increment: 0.1
// @User: Advanced
// @Param: _VELXY_I
// @DisplayName: Velocity (horizontal) I gain
2020-01-04 02:16:09 -04:00
// @Description: Velocity (horizontal) I gain. Corrects long-term difference between desired and actual velocity to a target acceleration
2018-01-15 06:50:54 -04:00
// @Range: 0.02 1.00
// @Increment: 0.01
// @User: Advanced
// @Param: _VELXY_D
// @DisplayName: Velocity (horizontal) D gain
// @Description: Velocity (horizontal) D gain. Corrects short-term changes in velocity
// @Range: 0.00 1.00
// @Increment: 0.001
// @User: Advanced
// @Param: _VELXY_IMAX
// @DisplayName: Velocity (horizontal) integrator maximum
// @Description: Velocity (horizontal) integrator maximum. Constrains the target acceleration that the I gain will output
// @Range: 0 4500
// @Increment: 10
// @Units: cm/s/s
// @User: Advanced
2021-08-03 01:05:35 -03:00
// @Param: _VELXY_FLTE
2018-01-15 06:50:54 -04:00
// @DisplayName: Velocity (horizontal) input filter
2021-03-11 08:05:36 -04:00
// @Description: Velocity (horizontal) input filter. This filter (in Hz) is applied to the input for P and I terms
2018-01-15 06:50:54 -04:00
// @Range: 0 100
// @Units: Hz
// @User: Advanced
2021-08-03 01:05:35 -03:00
// @Param: _VELXY_FLTD
2018-01-15 06:50:54 -04:00
// @DisplayName: Velocity (horizontal) input filter
2021-03-11 08:05:36 -04:00
// @Description: Velocity (horizontal) input filter. This filter (in Hz) is applied to the input for D term
2018-01-15 06:50:54 -04:00
// @Range: 0 100
// @Units: Hz
// @User: Advanced
2020-01-04 02:16:09 -04:00
// @Param: _VELXY_FF
2021-03-11 08:05:36 -04:00
// @DisplayName: Velocity (horizontal) feed forward gain
2020-01-04 02:16:09 -04:00
// @Description: Velocity (horizontal) feed forward gain. Converts the difference between desired velocity to a target acceleration
// @Range: 0 6
// @Increment: 0.01
// @User: Advanced
2018-01-15 06:52:55 -04:00
AP_SUBGROUPINFO ( _pid_vel_xy , " _VELXY_ " , 6 , AC_PosControl , AC_PID_2D ) ,
2018-01-15 06:50:54 -04:00
2017-12-16 09:06:51 -04:00
// @Param: _ANGLE_MAX
// @DisplayName: Position Control Angle Max
// @Description: Maximum lean angle autopilot can request. Set to zero to use ANGLE_MAX parameter value
// @Units: deg
// @Range: 0 45
// @Increment: 1
// @User: Advanced
2019-04-19 08:36:42 -03:00
AP_GROUPINFO ( " _ANGLE_MAX " , 7 , AC_PosControl , _lean_angle_max , 0.0f ) ,
2017-12-16 09:06:51 -04:00
2021-08-06 06:40:56 -03:00
// IDs 8,9 used for _TC_XY and _TC_Z in beta release candidate
// @Param: _JERK_XY
// @DisplayName: Jerk limit for the horizontal kinematic input shaping
// @Description: Jerk limit of the horizontal kinematic path generation used to determine how quickly the aircraft varies the acceleration target
// @Units: m/s/s/s
// @Range: 1 20
// @Increment: 1
2021-04-16 12:53:14 -03:00
// @User: Advanced
2021-08-06 06:40:56 -03:00
AP_GROUPINFO ( " _JERK_XY " , 10 , AC_PosControl , _shaping_jerk_xy , POSCONTROL_JERK_XY ) ,
2021-04-16 12:53:14 -03:00
2021-08-06 06:40:56 -03:00
// @Param: _JERK_Z
// @DisplayName: Jerk limit for the vertical kinematic input shaping
// @Description: Jerk limit of the vertical kinematic path generation used to determine how quickly the aircraft varies the acceleration target
// @Units: m/s/s/s
// @Range: 5 50
// @Increment: 1
2021-04-16 12:53:14 -03:00
// @User: Advanced
2021-08-06 06:40:56 -03:00
AP_GROUPINFO ( " _JERK_Z " , 11 , AC_PosControl , _shaping_jerk_z , POSCONTROL_JERK_Z ) ,
2021-04-16 12:53:14 -03:00
2013-12-28 07:15:29 -04:00
AP_GROUPEND
} ;
// Default constructor.
// Note that the Vector/Matrix constructors already implicitly zero
// their values.
//
2019-12-10 05:31:08 -04:00
AC_PosControl : : AC_PosControl ( AP_AHRS_View & ahrs , const AP_InertialNav & inav ,
2022-12-05 08:21:43 -04:00
const AP_Motors & motors , AC_AttitudeControl & attitude_control ) :
2013-12-28 07:15:29 -04:00
_ahrs ( ahrs ) ,
2013-12-28 10:04:45 -04:00
_inav ( inav ) ,
_motors ( motors ) ,
2013-12-28 07:15:29 -04:00
_attitude_control ( attitude_control ) ,
2024-09-20 09:20:41 -03:00
_p_pos_xy ( POSCONTROL_POS_XY_P ) ,
2022-12-05 08:21:43 -04:00
_p_pos_z ( POSCONTROL_POS_Z_P ) ,
2024-09-20 09:20:41 -03:00
_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 ) ,
2022-12-05 08:21:43 -04:00
_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 ) ,
_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 ) ,
2021-04-16 12:53:14 -03:00
_vel_max_xy_cms ( POSCONTROL_SPEED ) ,
2024-09-20 09:20:41 -03:00
_vel_max_up_cms ( POSCONTROL_SPEED_UP ) ,
_vel_max_down_cms ( POSCONTROL_SPEED_DOWN ) ,
2021-04-16 12:53:14 -03:00
_accel_max_xy_cmss ( POSCONTROL_ACCEL_XY ) ,
2024-09-20 09:20:41 -03:00
_accel_max_z_cmss ( POSCONTROL_ACCEL_Z ) ,
2021-10-01 09:02:30 -03:00
_jerk_max_xy_cmsss ( POSCONTROL_JERK_XY * 100.0 ) ,
_jerk_max_z_cmsss ( POSCONTROL_JERK_Z * 100.0 )
2013-12-28 07:15:29 -04:00
{
AP_Param : : setup_object_defaults ( this , var_info ) ;
2024-09-17 00:54:55 -03:00
_singleton = this ;
2013-12-28 07:15:29 -04:00
}
2021-04-16 12:53:14 -03:00
2013-12-28 10:04:45 -04:00
///
2021-04-16 12:53:14 -03:00
/// 3D position shaper
2013-12-28 10:04:45 -04:00
///
2013-12-28 07:15:29 -04:00
2021-05-30 21:57:52 -03:00
/// input_pos_xyz - calculate a jerk limited path from the current position, velocity and acceleration to an input position.
2021-04-16 12:53:14 -03:00
/// The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.
2021-08-06 06:40:56 -03:00
/// 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.
/// The jerk limit defines the acceleration error decay in the kinematic path as the system approaches constant acceleration.
/// The jerk limit also defines the time taken to achieve the maximum acceleration.
2021-04-16 12:53:14 -03:00
/// The function alters the input velocity to be the velocity that the system could reach zero acceleration in the minimum time.
2024-08-02 01:45:17 -03:00
void AC_PosControl : : input_pos_xyz ( const Vector3p & pos , float pos_terrain_target , float terrain_buffer )
2014-05-27 10:44:57 -03:00
{
2021-07-14 11:18:45 -03:00
// Terrain following velocity scalar must be calculated before we remove the position offset
2024-08-02 01:45:17 -03:00
const float offset_z_scaler = pos_offset_z_scaler ( pos_terrain_target , terrain_buffer ) ;
set_pos_terrain_target_cm ( pos_terrain_target ) ;
2021-04-16 12:53:14 -03:00
2022-01-24 10:40:38 -04:00
// calculated increased maximum acceleration and jerk if over speed
2022-12-15 07:08:51 -04:00
const float overspeed_gain = calculate_overspeed_gain ( ) ;
const float accel_max_z_cmss = _accel_max_z_cmss * overspeed_gain ;
const float jerk_max_z_cmsss = _jerk_max_z_cmsss * overspeed_gain ;
2014-05-27 10:44:57 -03:00
2024-08-02 01:45:17 -03:00
update_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 ( ) ) ;
2014-09-21 05:52:14 -03:00
2021-06-26 10:49:12 -03:00
// adjust desired altitude if motors have not hit their limits
2024-08-02 01:45:17 -03:00
update_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 ( ) ) ;
2021-04-16 12:53:14 -03:00
2021-06-26 10:49:12 -03:00
// calculate the horizontal and vertical velocity limits to travel directly to the destination defined by pos
float vel_max_xy_cms = 0.0f ;
2021-04-16 12:53:14 -03:00
float vel_max_z_cms = 0.0f ;
2024-08-02 01:45:17 -03:00
Vector3f dest_vector = ( pos - _pos_desired ) . tofloat ( ) ;
2021-04-16 12:53:14 -03:00
if ( is_positive ( dest_vector . length_squared ( ) ) ) {
dest_vector . normalize ( ) ;
2021-06-17 22:19:29 -03:00
float dest_vector_xy_length = dest_vector . xy ( ) . length ( ) ;
2021-04-16 12:53:14 -03:00
float vel_max_cms = kinematic_limit ( dest_vector , _vel_max_xy_cms , _vel_max_up_cms , _vel_max_down_cms ) ;
vel_max_xy_cms = vel_max_cms * dest_vector_xy_length ;
2021-06-26 10:49:12 -03:00
vel_max_z_cms = fabsf ( vel_max_cms * dest_vector . z ) ;
2021-04-16 12:53:14 -03:00
}
2021-07-08 04:09:05 -03:00
// reduce speed if we are reaching the edge of our vertical buffer
2021-07-14 11:18:45 -03:00
vel_max_xy_cms * = offset_z_scaler ;
2021-07-08 04:09:05 -03:00
2021-06-17 22:19:29 -03:00
Vector2f vel ;
Vector2f accel ;
2024-08-02 01:45:17 -03:00
shape_pos_vel_accel_xy ( pos . xy ( ) , vel , accel , _pos_desired . xy ( ) , _vel_desired . xy ( ) , _accel_desired . xy ( ) ,
2021-10-01 09:02:30 -03:00
vel_max_xy_cms , _accel_max_xy_cmss , _jerk_max_xy_cmsss , _dt , false ) ;
2021-06-26 10:49:12 -03:00
2021-06-21 04:26:39 -03:00
float posz = pos . z ;
2021-06-17 22:19:29 -03:00
shape_pos_vel_accel ( posz , 0 , 0 ,
2024-08-02 01:45:17 -03:00
_pos_desired . z , _vel_desired . z , _accel_desired . z ,
2021-08-06 06:40:56 -03:00
- vel_max_z_cms , vel_max_z_cms ,
2022-01-24 10:40:38 -04:00
- constrain_float ( accel_max_z_cmss , 0.0f , 750.0f ) , accel_max_z_cmss ,
jerk_max_z_cmsss , _dt , false ) ;
2014-05-27 10:44:57 -03:00
}
2021-07-08 04:09:05 -03:00
/// 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 range
2021-07-14 11:18:45 -03:00
float AC_PosControl : : pos_offset_z_scaler ( float pos_offset_z , float pos_offset_z_buffer ) const
2021-07-08 04:09:05 -03:00
{
if ( is_zero ( pos_offset_z_buffer ) ) {
return 1.0 ;
}
2024-08-02 01:45:17 -03:00
float pos_offset_error_z = _inav . get_position_z_up_cm ( ) - ( _pos_target . z + ( pos_offset_z - _pos_terrain ) ) ;
2021-07-08 04:09:05 -03:00
return 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 ) ;
}
2021-04-16 12:53:14 -03:00
///
/// Lateral position controller
///
2021-07-08 01:13:05 -03:00
/// set_max_speed_accel_xy - set the maximum horizontal speed in cm/s and acceleration in cm/s/s
2021-08-06 06:40:56 -03:00
/// This function only needs to be called if using the kinematic shaping.
2021-07-08 01:13:05 -03:00
/// This can be done at any time as changes in these parameters are handled smoothly
2021-08-06 06:40:56 -03:00
/// by the kinematic shaping.
2021-06-20 05:17:25 -03:00
void AC_PosControl : : set_max_speed_accel_xy ( float speed_cms , float accel_cmss )
2021-04-16 12:53:14 -03:00
{
_vel_max_xy_cms = speed_cms ;
_accel_max_xy_cmss = accel_cmss ;
2020-02-19 02:08:16 -04:00
2021-08-06 06:40:56 -03:00
// ensure the horizontal jerk is less than the vehicle is capable of
const 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 ;
const float snap_max_cmssss = MIN ( _attitude_control . get_accel_roll_max_radss ( ) , _attitude_control . get_accel_pitch_max_radss ( ) ) * GRAVITY_MSS * 100.0 ;
// get specified jerk limit
2021-10-01 09:02:30 -03:00
_jerk_max_xy_cmsss = _shaping_jerk_xy * 100.0 ;
2021-08-06 06:40:56 -03:00
// limit maximum jerk based on maximum angular rate
if ( is_positive ( jerk_max_cmsss ) & & _attitude_control . get_bf_feedforward ( ) ) {
2021-10-01 09:02:30 -03:00
_jerk_max_xy_cmsss = MIN ( _jerk_max_xy_cmsss , jerk_max_cmsss ) ;
2021-08-06 06:40:56 -03:00
}
// limit maximum jerk to maximum possible average jerk based on angular acceleration
if ( is_positive ( snap_max_cmssss ) & & _attitude_control . get_bf_feedforward ( ) ) {
2021-10-01 09:02:30 -03:00
_jerk_max_xy_cmsss = MIN ( 0.5 * safe_sqrt ( _accel_max_xy_cmss * snap_max_cmssss ) , _jerk_max_xy_cmsss ) ;
2014-01-23 23:27:06 -04:00
}
}
2021-07-08 01:13:05 -03:00
/// set_max_speed_accel_xy - set the position controller correction velocity and acceleration limit
/// This should be done only during initialisation to avoid discontinuities
void AC_PosControl : : set_correction_speed_accel_xy ( float speed_cms , float accel_cmss )
{
_p_pos_xy . set_limits ( speed_cms , accel_cmss , 0.0f ) ;
}
2021-04-16 12:53:14 -03:00
/// init_xy_controller_stopping_point - initialise the position controller to the stopping point with zero velocity and acceleration.
2021-08-06 06:40:56 -03:00
/// This function should be used when the expected kinematic path assumes a stationary initial condition but does not specify a specific starting position.
2024-08-02 01:45:17 -03:00
/// The starting position can be retrieved by getting the position target using get_pos_desired_cm() after calling this function.
2021-04-16 12:53:14 -03:00
void AC_PosControl : : init_xy_controller_stopping_point ( )
2014-01-23 23:27:06 -04:00
{
2022-01-01 07:18:00 -04:00
init_xy_controller ( ) ;
2021-06-22 12:07:05 -03:00
2024-08-02 01:45:17 -03:00
get_stopping_point_xy_cm ( _pos_desired . xy ( ) ) ;
_pos_target . xy ( ) = _pos_desired . xy ( ) + _pos_offset . xy ( ) ;
2021-08-22 02:14:43 -03:00
_vel_desired . xy ( ) . zero ( ) ;
2021-06-21 04:26:39 -03:00
_accel_desired . xy ( ) . zero ( ) ;
2021-04-16 12:53:14 -03:00
}
2014-01-23 23:27:06 -04:00
2021-04-16 12:53:14 -03:00
// relax_velocity_controller_xy - initialise the position controller to the current position and velocity with decaying acceleration.
/// This function decays the output acceleration by 95% every half second to achieve a smooth transition to zero requested acceleration.
void AC_PosControl : : relax_velocity_controller_xy ( )
{
2022-09-01 09:18:05 -03:00
// decay acceleration and therefore current attitude target to zero
// this will be reset by init_xy_controller() if !is_active_xy()
2022-12-05 08:21:43 -04:00
if ( is_positive ( _dt ) ) {
float decay = 1.0 - _dt / ( _dt + POSCONTROL_RELAX_TC ) ;
_accel_target . xy ( ) * = decay ;
}
2022-09-01 09:18:05 -03:00
init_xy_controller ( ) ;
2021-04-16 12:53:14 -03:00
}
2021-12-23 10:24:54 -04:00
/// reduce response for landing
void AC_PosControl : : soften_for_landing_xy ( )
{
2022-01-30 10:15:30 -04:00
// decay position error to zero
2022-12-05 08:21:43 -04:00
if ( is_positive ( _dt ) ) {
_pos_target . xy ( ) + = ( _inav . get_position_xy_cm ( ) . topostype ( ) - _pos_target . xy ( ) ) * ( _dt / ( _dt + POSCONTROL_RELAX_TC ) ) ;
2024-08-02 01:45:17 -03:00
_pos_desired . xy ( ) = _pos_target . xy ( ) - _pos_offset . xy ( ) ;
2022-12-05 08:21:43 -04:00
}
2021-12-23 10:24:54 -04:00
2022-01-30 10:15:30 -04:00
// Prevent I term build up in xy velocity controller.
// Note that this flag is reset on each loop in update_xy_controller()
2021-12-23 10:24:54 -04:00
set_externally_limited_xy ( ) ;
}
2022-01-01 07:18:00 -04:00
/// init_xy_controller - initialise the position controller to the current position, velocity, acceleration and attitude.
/// This function is the default initialisation for any position control that provides position, velocity and acceleration.
void AC_PosControl : : init_xy_controller ( )
2021-04-16 12:53:14 -03:00
{
2024-08-02 01:45:17 -03:00
// initialise offsets to target offsets and ensure offset targets are zero if they have not been updated.
init_offsets_xy ( ) ;
2021-04-16 12:53:14 -03:00
// set roll, pitch lean angle targets to current attitude
const Vector3f & att_target_euler_cd = _attitude_control . get_att_target_euler_cd ( ) ;
_roll_target = att_target_euler_cd . x ;
_pitch_target = att_target_euler_cd . y ;
_yaw_target = att_target_euler_cd . z ; // todo: this should be thrust vector heading, not yaw.
_yaw_rate_target = 0.0f ;
2022-03-14 19:26:18 -03:00
_angle_max_override_cd = 0.0 ;
2021-04-16 12:53:14 -03:00
2021-10-20 05:31:49 -03:00
_pos_target . xy ( ) = _inav . get_position_xy_cm ( ) . topostype ( ) ;
2024-08-02 01:45:17 -03:00
_pos_desired . xy ( ) = _pos_target . xy ( ) - _pos_offset . xy ( ) ;
2021-04-16 12:53:14 -03:00
2024-08-02 01:45:17 -03:00
_vel_target . xy ( ) = _inav . get_velocity_xy_cms ( ) ;
_vel_desired . xy ( ) = _vel_target . xy ( ) - _vel_offset . xy ( ) ;
2021-04-16 12:53:14 -03:00
2022-01-23 22:13:22 -04:00
// Set desired accel to zero because raw acceleration is prone to noise
_accel_desired . xy ( ) . zero ( ) ;
2021-06-22 12:07:05 -03:00
2022-09-01 09:18:05 -03:00
if ( ! is_active_xy ( ) ) {
lean_angles_to_accel_xy ( _accel_target . x , _accel_target . y ) ;
}
2021-06-22 12:07:05 -03:00
2022-01-01 07:18:00 -04:00
// limit acceleration using maximum lean angles
float angle_max = MIN ( _attitude_control . get_althold_lean_angle_max_cd ( ) , get_lean_angle_max_cd ( ) ) ;
2022-03-14 19:26:18 -03:00
float accel_max = angle_to_accel ( angle_max * 0.01 ) * 100.0 ;
2022-01-01 07:18:00 -04:00
_accel_target . xy ( ) . limit_length ( accel_max ) ;
2021-06-22 12:07:05 -03:00
// initialise I terms from lean angles
_pid_vel_xy . reset_filter ( ) ;
2022-01-23 22:13:22 -04:00
// initialise the I term to _accel_target - _accel_desired
// _accel_desired is zero and can be removed from the equation
2022-12-26 23:21:24 -04:00
_pid_vel_xy . set_integrator ( _accel_target . xy ( ) - _vel_target . xy ( ) * _pid_vel_xy . ff ( ) ) ;
2021-04-16 12:53:14 -03:00
// initialise ekf xy reset handler
init_ekf_xy_reset ( ) ;
// initialise z_controller time out
2023-01-28 05:43:41 -04:00
_last_update_xy_ticks = AP : : scheduler ( ) . ticks32 ( ) ;
2014-01-23 23:27:06 -04:00
}
2021-06-20 03:02:24 -03:00
/// input_accel_xy - calculate a jerk limited path from the current position, velocity and acceleration to an input acceleration.
/// The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.
2021-08-06 06:40:56 -03:00
/// The kinematic path is constrained by the maximum acceleration and jerk set using the function set_max_speed_accel_xy.
/// The jerk limit defines the acceleration error decay in the kinematic path as the system approaches constant acceleration.
/// The jerk limit also defines the time taken to achieve the maximum acceleration.
2021-06-20 03:02:24 -03:00
void AC_PosControl : : input_accel_xy ( const Vector3f & accel )
{
2024-08-02 01:45:17 -03:00
update_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 ( ) ) ;
shape_accel_xy ( accel . xy ( ) , _accel_desired . xy ( ) , _jerk_max_xy_cmsss , _dt ) ;
2021-06-20 03:02:24 -03:00
}
2021-05-19 11:09:31 -03:00
/// input_vel_accel_xy - calculate a jerk limited path from the current position, velocity and acceleration to an input velocity and acceleration.
/// The vel is projected forwards in time based on a time step of dt and acceleration accel.
2021-04-16 12:53:14 -03:00
/// The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.
2021-08-06 06:40:56 -03:00
/// The kinematic path is constrained by the maximum acceleration and jerk set using the function set_max_speed_accel_xy.
/// The parameter limit_output specifies if the velocity and acceleration limits are applied to the sum of commanded and correction values or just correction.
void AC_PosControl : : input_vel_accel_xy ( Vector2f & vel , const Vector2f & accel , bool limit_output )
2015-10-27 10:04:24 -03:00
{
2024-08-02 01:45:17 -03:00
update_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 ( ) ) ;
2021-04-16 12:53:14 -03:00
2021-06-21 04:26:39 -03:00
shape_vel_accel_xy ( vel , accel , _vel_desired . xy ( ) , _accel_desired . xy ( ) ,
2021-10-01 09:02:30 -03:00
_accel_max_xy_cmss , _jerk_max_xy_cmsss , _dt , limit_output ) ;
2021-04-16 12:53:14 -03:00
2021-12-05 00:54:54 -04:00
update_vel_accel_xy ( vel , accel , _dt , Vector2f ( ) , Vector2f ( ) ) ;
2015-10-27 10:04:24 -03:00
}
2021-05-19 11:09:31 -03:00
/// input_pos_vel_accel_xy - calculate a jerk limited path from the current position, velocity and acceleration to an input position velocity and acceleration.
/// The pos and vel are projected forwards in time based on a time step of dt and acceleration accel.
2021-04-16 12:53:14 -03:00
/// The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.
2021-06-22 21:03:09 -03:00
/// The function alters the pos and vel to be the kinematic path based on accel
2021-08-06 06:40:56 -03:00
/// The parameter limit_output specifies if the velocity and acceleration limits are applied to the sum of commanded and correction values or just correction.
void AC_PosControl : : input_pos_vel_accel_xy ( Vector2p & pos , Vector2f & vel , const Vector2f & accel , bool limit_output )
2014-01-23 23:27:06 -04:00
{
2024-08-02 01:45:17 -03:00
update_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 ( ) ) ;
2021-04-16 12:53:14 -03:00
2024-08-02 01:45:17 -03:00
shape_pos_vel_accel_xy ( pos , vel , accel , _pos_desired . xy ( ) , _vel_desired . xy ( ) , _accel_desired . xy ( ) ,
2021-10-01 09:02:30 -03:00
_vel_max_xy_cms , _accel_max_xy_cmss , _jerk_max_xy_cmsss , _dt , limit_output ) ;
2021-04-16 12:53:14 -03:00
2021-12-05 00:54:54 -04:00
update_pos_vel_accel_xy ( pos , vel , accel , _dt , Vector2f ( ) , Vector2f ( ) , Vector2f ( ) ) ;
2021-04-16 12:53:14 -03:00
}
2024-08-02 01:45:17 -03:00
/// update the horizontal position and velocity offsets
/// 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)
void AC_PosControl : : update_offsets_xy ( )
{
// check for offset target timeout
uint32_t now_ms = AP_HAL : : millis ( ) ;
if ( now_ms - _posvelaccel_offset_target_xy_ms > POSCONTROL_POSVELACCEL_OFFSET_TARGET_TIMEOUT_MS ) {
_pos_offset_target . xy ( ) . zero ( ) ;
_vel_offset_target . xy ( ) . zero ( ) ;
_accel_offset_target . xy ( ) . zero ( ) ;
}
// update position, velocity, accel offsets for this iteration
update_pos_vel_accel_xy ( _pos_offset_target . xy ( ) , _vel_offset_target . xy ( ) , _accel_offset_target . xy ( ) , _dt , Vector2f ( ) , Vector2f ( ) , Vector2f ( ) ) ;
update_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 ( ) ) ;
// input shape horizontal position, velocity and acceleration offsets
shape_pos_vel_accel_xy ( _pos_offset_target . xy ( ) , _vel_offset_target . xy ( ) , _accel_offset_target . xy ( ) ,
_pos_offset . xy ( ) , _vel_offset . xy ( ) , _accel_offset . xy ( ) ,
_vel_max_xy_cms , _accel_max_xy_cmss , _jerk_max_xy_cmsss , _dt , false ) ;
}
2021-04-16 12:53:14 -03:00
/// stop_pos_xy_stabilisation - sets the target to the current position to remove any position corrections from the system
void AC_PosControl : : stop_pos_xy_stabilisation ( )
{
2021-10-20 05:31:49 -03:00
_pos_target . xy ( ) = _inav . get_position_xy_cm ( ) . topostype ( ) ;
2024-08-02 01:45:17 -03:00
_pos_desired . xy ( ) = _pos_target . xy ( ) - _pos_offset . xy ( ) ;
2021-04-16 12:53:14 -03:00
}
2021-05-19 11:09:31 -03:00
/// 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 system
2021-04-16 12:53:14 -03:00
void AC_PosControl : : stop_vel_xy_stabilisation ( )
{
2021-10-20 05:31:49 -03:00
_pos_target . xy ( ) = _inav . get_position_xy_cm ( ) . topostype ( ) ;
2024-08-02 01:45:17 -03:00
_pos_desired . xy ( ) = _pos_target . xy ( ) - _pos_offset . xy ( ) ;
_vel_target . xy ( ) = _inav . get_velocity_xy_cms ( ) ; ;
_vel_desired . xy ( ) = _vel_target . xy ( ) - _vel_offset . xy ( ) ;
2021-04-16 12:53:14 -03:00
// initialise I terms from lean angles
_pid_vel_xy . reset_filter ( ) ;
_pid_vel_xy . reset_I ( ) ;
}
2024-08-22 05:09:04 -03:00
// is_active_xy - returns true if the xy position controller has been run in the previous loop
2021-04-16 12:53:14 -03:00
bool AC_PosControl : : is_active_xy ( ) const
{
2023-01-28 05:43:41 -04:00
const uint32_t dt_ticks = AP : : scheduler ( ) . ticks32 ( ) - _last_update_xy_ticks ;
return dt_ticks < = 1 ;
2021-04-16 12:53:14 -03:00
}
/// update_xy_controller - runs the horizontal position controller correcting position, velocity and acceleration errors.
/// Position and velocity errors are converted to velocity and acceleration targets using PID objects
/// Desired velocity and accelerations are added to these corrections as they are calculated
/// Kinematically consistent target position and desired velocity and accelerations should be provided before calling this function
void AC_PosControl : : update_xy_controller ( )
{
2021-06-23 09:08:14 -03:00
// check for ekf xy position reset
handle_ekf_xy_reset ( ) ;
2021-04-16 12:53:14 -03:00
// Check for position control time out
2021-11-23 06:18:24 -04:00
if ( ! is_active_xy ( ) ) {
2021-04-16 12:53:14 -03:00
init_xy_controller ( ) ;
2021-05-17 22:24:41 -03:00
if ( has_good_timing ( ) ) {
// call internal error because initialisation has not been done
INTERNAL_ERROR ( AP_InternalError : : error_t : : flow_of_control ) ;
}
2015-10-27 10:45:16 -03:00
}
2023-01-28 05:43:41 -04:00
_last_update_xy_ticks = AP : : scheduler ( ) . ticks32 ( ) ;
2015-10-27 10:45:16 -03:00
2021-08-14 03:06:34 -03:00
float ahrsGndSpdLimit , ahrsControlScaleXY ;
AP : : ahrs ( ) . getControlLimits ( ahrsGndSpdLimit , ahrsControlScaleXY ) ;
2021-04-16 12:53:14 -03:00
2024-08-02 01:45:17 -03:00
// update the position, velocity and acceleration offsets
update_offsets_xy ( ) ;
2021-04-16 12:53:14 -03:00
// Position Controller
2015-04-13 06:22:52 -03:00
2024-08-02 01:45:17 -03:00
_pos_target . xy ( ) = _pos_desired . xy ( ) + _pos_offset . xy ( ) ;
2024-05-13 20:33:26 -03:00
// determine the combined position of the actual position and the disturbance from system ID mode
2024-08-02 01:45:17 -03:00
const Vector3f & curr_pos = _inav . get_position_neu_cm ( ) ;
2023-08-18 00:57:12 -03:00
Vector3f comb_pos = curr_pos ;
2024-05-13 13:17:40 -03:00
comb_pos . xy ( ) + = _disturb_pos ;
2024-08-02 01:45:17 -03:00
2023-08-18 00:57:12 -03:00
Vector2f vel_target = _p_pos_xy . update_all ( _pos_target . x , _pos_target . y , comb_pos ) ;
2024-08-02 01:45:17 -03:00
_pos_desired . xy ( ) = _pos_target . xy ( ) - _pos_offset . xy ( ) ;
// Velocity Controller
2021-04-16 12:53:14 -03:00
// add velocity feed-forward scaled to compensate for optical flow measurement induced EKF noise
2021-08-14 03:06:34 -03:00
vel_target * = ahrsControlScaleXY ;
2015-04-13 06:22:52 -03:00
2024-08-02 01:45:17 -03:00
_vel_target . xy ( ) = vel_target ;
_vel_target . xy ( ) + = _vel_desired . xy ( ) + _vel_offset . xy ( ) ;
2020-01-04 02:16:09 -04:00
2024-05-13 20:33:26 -03:00
// determine the combined velocity of the actual velocity and the disturbance from system ID mode
2024-08-02 01:45:17 -03:00
const Vector2f & curr_vel = _inav . get_velocity_xy_cms ( ) ;
2023-08-18 00:57:12 -03:00
Vector2f comb_vel = curr_vel ;
2024-05-13 13:17:40 -03:00
comb_vel + = _disturb_vel ;
2024-08-02 01:45:17 -03:00
2023-08-18 00:57:12 -03:00
Vector2f accel_target = _pid_vel_xy . update_all ( _vel_target . xy ( ) , comb_vel , _dt , _limit_vector . xy ( ) ) ;
2024-08-02 01:45:17 -03:00
// Acceleration Controller
2022-01-31 10:45:17 -04:00
2021-04-16 12:53:14 -03:00
// acceleration to correct for velocity error and scale PID output to compensate for optical flow measurement induced EKF noise
2021-08-14 03:06:34 -03:00
accel_target * = ahrsControlScaleXY ;
2021-04-16 12:53:14 -03:00
// pass the correction acceleration to the target acceleration output
2021-08-25 01:57:21 -03:00
_accel_target . xy ( ) = accel_target ;
2024-08-02 01:45:17 -03:00
_accel_target . xy ( ) + = _accel_desired . xy ( ) + _accel_offset . xy ( ) ;
2021-04-16 12:53:14 -03:00
// limit acceleration using maximum lean angles
2021-09-06 06:45:31 -03:00
float angle_max = MIN ( _attitude_control . get_althold_lean_angle_max_cd ( ) , get_lean_angle_max_cd ( ) ) ;
2022-03-14 19:26:18 -03:00
float accel_max = angle_to_accel ( angle_max * 0.01 ) * 100 ;
2021-12-13 22:14:49 -04:00
// Define the limit vector before we constrain _accel_target
_limit_vector . xy ( ) = _accel_target . xy ( ) ;
if ( ! limit_accel_xy ( _vel_desired . xy ( ) , _accel_target . xy ( ) , accel_max ) ) {
// _accel_target was not limited so we can zero the xy limit vector
_limit_vector . xy ( ) . zero ( ) ;
2023-09-12 05:36:24 -03:00
} else {
// Check for pitch limiting in the forward direction
const float accel_fwd_unlimited = _limit_vector . x * _ahrs . cos_yaw ( ) + _limit_vector . y * _ahrs . sin_yaw ( ) ;
const float pitch_target_unlimited = accel_to_angle ( - MIN ( accel_fwd_unlimited , accel_max ) * 0.01f ) * 100 ;
const float accel_fwd_limited = _accel_target . x * _ahrs . cos_yaw ( ) + _accel_target . y * _ahrs . sin_yaw ( ) ;
const float pitch_target_limited = accel_to_angle ( - accel_fwd_limited * 0.01f ) * 100 ;
_fwd_pitch_is_limited = is_negative ( pitch_target_unlimited ) & & pitch_target_unlimited < pitch_target_limited ;
2014-01-23 23:27:06 -04:00
}
2021-04-16 12:53:14 -03:00
// update angle targets that will be passed to stabilize controller
accel_to_lean_angles ( _accel_target . x , _accel_target . y , _roll_target , _pitch_target ) ;
calculate_yaw_and_rate_yaw ( ) ;
2023-08-18 00:57:12 -03:00
2024-08-02 01:45:17 -03:00
// reset the disturbance from system ID mode to zero
2023-08-18 00:57:12 -03:00
_disturb_pos . zero ( ) ;
_disturb_vel . zero ( ) ;
2014-01-23 23:27:06 -04:00
}
2021-04-16 12:53:14 -03:00
///
/// Vertical position controller
///
2021-07-08 01:13:05 -03:00
/// set_max_speed_accel_z - set the maximum vertical speed in cm/s and acceleration in cm/s/s
/// speed_down can be positive or negative but will always be interpreted as a descent speed.
2021-08-06 06:40:56 -03:00
/// This function only needs to be called if using the kinematic shaping.
2021-07-08 01:13:05 -03:00
/// This can be done at any time as changes in these parameters are handled smoothly
2021-08-06 06:40:56 -03:00
/// by the kinematic shaping.
2021-04-16 12:53:14 -03:00
void AC_PosControl : : set_max_speed_accel_z ( float speed_down , float speed_up , float accel_cmss )
2015-04-30 10:18:05 -03:00
{
2021-04-16 12:53:14 -03:00
// ensure speed_down is always negative
speed_down = - fabsf ( speed_down ) ;
// sanity check and update
2021-05-19 11:09:31 -03:00
if ( is_negative ( speed_down ) ) {
2021-04-16 12:53:14 -03:00
_vel_max_down_cms = speed_down ;
}
2021-05-19 11:09:31 -03:00
if ( is_positive ( speed_up ) ) {
2021-04-16 12:53:14 -03:00
_vel_max_up_cms = speed_up ;
}
if ( is_positive ( accel_cmss ) ) {
_accel_max_z_cmss = accel_cmss ;
}
2021-08-06 06:40:56 -03:00
// ensure the vertical Jerk is not limited by the filters in the Z accel PID object
2021-10-01 09:02:30 -03:00
_jerk_max_z_cmsss = _shaping_jerk_z * 100.0 ;
2021-04-16 12:53:14 -03:00
if ( is_positive ( _pid_accel_z . filt_T_hz ( ) ) ) {
2021-10-01 09:02:30 -03:00
_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 ) ;
2021-04-16 12:53:14 -03:00
}
if ( is_positive ( _pid_accel_z . filt_E_hz ( ) ) ) {
2021-10-01 09:02:30 -03:00
_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 ) ;
2021-04-16 12:53:14 -03:00
}
2015-04-30 10:18:05 -03:00
}
2021-07-08 01:13:05 -03:00
/// set_correction_speed_accel_z - set the position controller correction velocity and acceleration limit
/// speed_down can be positive or negative but will always be interpreted as a descent speed.
/// This should be done only during initialisation to avoid discontinuities
void AC_PosControl : : set_correction_speed_accel_z ( float speed_down , float speed_up , float accel_cmss )
{
// define maximum position error and maximum first and second differential limits
2021-09-07 03:31:04 -03:00
_p_pos_z . set_limits ( - fabsf ( speed_down ) , speed_up , accel_cmss , 0.0f ) ;
2021-07-08 01:13:05 -03:00
}
2021-04-16 12:53:14 -03:00
/// init_z_controller - initialise the position controller to the current position, velocity, acceleration and attitude.
/// This function is the default initialisation for any position control that provides position, velocity and acceleration.
/// This function does not allow any negative velocity or acceleration
void AC_PosControl : : init_z_controller_no_descent ( )
2015-04-14 11:26:33 -03:00
{
2021-04-16 12:53:14 -03:00
// Initialise the position controller to the current throttle, position, velocity and acceleration.
init_z_controller ( ) ;
2021-05-19 11:09:31 -03:00
// remove all descent if present
2021-08-15 00:40:09 -03:00
_vel_target . z = MAX ( 0.0 , _vel_target . z ) ;
2024-08-02 01:45:17 -03:00
_vel_desired . z = MAX ( 0.0 , _vel_desired . z ) ;
_vel_terrain = MAX ( 0.0 , _vel_terrain ) ;
_vel_offset . z = MAX ( 0.0 , _vel_offset . z ) ;
2021-08-15 00:40:09 -03:00
_accel_target . z = MAX ( 0.0 , _accel_target . z ) ;
2024-08-02 01:45:17 -03:00
_accel_desired . z = MAX ( 0.0 , _accel_desired . z ) ;
_accel_terrain = MAX ( 0.0 , _accel_terrain ) ;
_accel_offset . z = MAX ( 0.0 , _accel_offset . z ) ;
2015-04-14 11:26:33 -03:00
}
2021-04-16 12:53:14 -03:00
/// init_z_controller_stopping_point - initialise the position controller to the stopping point with zero velocity and acceleration.
2021-08-06 06:40:56 -03:00
/// This function should be used when the expected kinematic path assumes a stationary initial condition but does not specify a specific starting position.
2021-04-16 12:53:14 -03:00
/// The starting position can be retrieved by getting the position target using get_pos_target_cm() after calling this function.
void AC_PosControl : : init_z_controller_stopping_point ( )
2014-01-05 23:30:51 -04:00
{
2021-04-16 12:53:14 -03:00
// Initialise the position controller to the current throttle, position, velocity and acceleration.
init_z_controller ( ) ;
2024-08-02 01:45:17 -03:00
get_stopping_point_z_cm ( _pos_desired . z ) ;
_pos_target . z = _pos_desired . z + _pos_offset . z ;
2021-08-22 02:14:43 -03:00
_vel_desired . z = 0.0f ;
_accel_desired . z = 0.0f ;
2014-01-05 23:30:51 -04:00
}
2021-04-16 12:53:14 -03:00
// relax_z_controller - initialise the position controller to the current position and velocity with decaying acceleration.
/// This function decays the output acceleration by 95% every half second to achieve a smooth transition to zero requested acceleration.
void AC_PosControl : : relax_z_controller ( float throttle_setting )
2013-12-28 10:04:45 -04:00
{
2021-04-16 12:53:14 -03:00
// Initialise the position controller to the current position, velocity and acceleration.
2022-01-01 07:18:00 -04:00
init_z_controller ( ) ;
2014-04-30 09:22:47 -03:00
2022-01-24 19:43:19 -04:00
// init_z_controller has set the accel PID I term to generate the current throttle set point
// Use relax_integrator to decay the throttle set point to throttle_setting
2022-12-05 08:21:43 -04:00
_pid_accel_z . relax_integrator ( ( throttle_setting - _motors . get_throttle_hover ( ) ) * 1000.0f , _dt , POSCONTROL_RELAX_TC ) ;
2014-01-25 04:23:55 -04:00
}
2022-01-01 07:18:00 -04:00
/// init_z_controller - initialise the position controller to the current position, velocity, acceleration and attitude.
/// This function is the default initialisation for any position control that provides position, velocity and acceleration.
2021-05-19 11:09:31 -03:00
/// This function is private and contains all the shared z axis initialisation functions
2022-01-01 07:18:00 -04:00
void AC_PosControl : : init_z_controller ( )
2014-01-25 04:23:55 -04:00
{
2024-08-02 01:45:17 -03:00
// initialise terrain targets and offsets to zero
init_terrain ( ) ;
// initialise offsets to target offsets and ensure offset targets are zero if they have not been updated.
init_offsets_z ( ) ;
2021-10-20 05:31:49 -03:00
_pos_target . z = _inav . get_position_z_up_cm ( ) ;
2024-08-02 01:45:17 -03:00
_pos_desired . z = _pos_target . z - _pos_offset . z ;
2014-01-25 04:23:55 -04:00
2024-08-02 01:45:17 -03:00
_vel_target . z = _inav . get_velocity_z_up_cms ( ) ;
_vel_desired . z = _vel_target . z - _vel_offset . z ;
2013-12-28 10:04:45 -04:00
2021-04-16 12:53:14 -03:00
// Reset I term of velocity PID
_pid_vel_z . reset_filter ( ) ;
_pid_vel_z . set_integrator ( 0.0f ) ;
2017-03-14 08:50:32 -03:00
2024-08-02 01:45:17 -03:00
_accel_target . z = constrain_float ( get_z_accel_cmss ( ) , - _accel_max_z_cmss , _accel_max_z_cmss ) ;
_accel_desired . z = _accel_target . z - ( _accel_offset . z + _accel_terrain ) ;
2021-04-16 12:53:14 -03:00
_pid_accel_z . reset_filter ( ) ;
2013-12-28 10:04:45 -04:00
2022-01-01 07:18:00 -04:00
// Set accel PID I term based on the current throttle
2022-01-24 19:43:19 -04:00
// Remove the expected P term due to _accel_desired.z being constrained to _accel_max_z_cmss
// Remove the expected FF term due to non-zero _accel_target.z
_pid_accel_z . set_integrator ( ( _attitude_control . get_throttle_in ( ) - _motors . get_throttle_hover ( ) ) * 1000.0f
- _pid_accel_z . kP ( ) * ( _accel_target . z - get_z_accel_cmss ( ) )
- _pid_accel_z . ff ( ) * _accel_target . z ) ;
2022-01-01 07:18:00 -04:00
2021-04-16 12:53:14 -03:00
// initialise ekf z reset handler
init_ekf_z_reset ( ) ;
// initialise z_controller time out
2023-01-28 05:43:41 -04:00
_last_update_z_ticks = AP : : scheduler ( ) . ticks32 ( ) ;
2013-12-28 07:15:29 -04:00
}
2022-12-15 07:08:51 -04:00
/// input_accel_z - calculate a jerk limited path from the current position, velocity and acceleration to an input acceleration.
2021-04-16 12:53:14 -03:00
/// The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.
2021-09-03 00:42:32 -03:00
void AC_PosControl : : input_accel_z ( float accel )
2021-07-09 02:28:58 -03:00
{
2022-01-24 10:40:38 -04:00
// calculated increased maximum jerk if over speed
float jerk_max_z_cmsss = _jerk_max_z_cmsss * calculate_overspeed_gain ( ) ;
2021-07-09 02:28:58 -03:00
// adjust desired alt if motors have not hit their limits
2024-08-02 01:45:17 -03:00
update_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 ( ) ) ;
2021-07-09 02:28:58 -03:00
2022-01-24 10:40:38 -04:00
shape_accel ( accel , _accel_desired . z , jerk_max_z_cmsss , _dt ) ;
2021-07-09 02:28:58 -03:00
}
/// input_accel_z - calculate a jerk limited path from the current position, velocity and acceleration to an input acceleration.
/// The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.
2021-08-06 06:40:56 -03:00
/// The kinematic path is constrained by the maximum acceleration and jerk set using the function set_max_speed_accel_z.
/// The parameter limit_output specifies if the velocity and acceleration limits are applied to the sum of commanded and correction values or just correction.
2022-12-15 07:43:31 -04:00
void AC_PosControl : : input_vel_accel_z ( float & vel , float accel , bool limit_output )
2013-12-30 09:12:59 -04:00
{
2022-01-24 10:40:38 -04:00
// calculated increased maximum acceleration and jerk if over speed
2022-12-15 07:08:51 -04:00
const float overspeed_gain = calculate_overspeed_gain ( ) ;
const float accel_max_z_cmss = _accel_max_z_cmss * overspeed_gain ;
const float jerk_max_z_cmsss = _jerk_max_z_cmsss * overspeed_gain ;
2016-11-22 01:36:17 -04:00
2021-04-16 12:53:14 -03:00
// adjust desired alt if motors have not hit their limits
2024-08-02 01:45:17 -03:00
update_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 ( ) ) ;
2021-04-16 12:53:14 -03:00
2021-06-21 04:26:39 -03:00
shape_vel_accel ( vel , accel ,
_vel_desired . z , _accel_desired . z ,
2022-01-24 10:40:38 -04:00
- constrain_float ( accel_max_z_cmss , 0.0f , 750.0f ) , accel_max_z_cmss ,
jerk_max_z_cmsss , _dt , limit_output ) ;
2021-04-16 12:53:14 -03:00
2021-12-05 00:54:54 -04:00
update_vel_accel ( vel , accel , _dt , 0.0 , 0.0 ) ;
2013-12-30 09:12:59 -04:00
}
2021-04-16 12:53:14 -03:00
/// set_pos_target_z_from_climb_rate_cm - adjusts target up or down using a commanded climb rate in cm/s
2021-08-06 06:40:56 -03:00
/// using the default position control kinematic path.
2021-08-31 01:17:32 -03:00
/// The zero target altitude is varied to follow pos_offset_z
2021-09-03 00:42:32 -03:00
void AC_PosControl : : set_pos_target_z_from_climb_rate_cm ( float vel )
2021-08-31 01:17:32 -03:00
{
2024-08-02 01:45:17 -03:00
input_vel_accel_z ( vel , 0.0 ) ;
2021-08-31 01:17:32 -03:00
}
/// land_at_climb_rate_cm - adjusts target up or down using a commanded climb rate in cm/s
/// using the default position control kinematic path.
2021-12-16 21:43:22 -04:00
/// ignore_descent_limit turns off output saturation handling to aid in landing detection. ignore_descent_limit should be false unless landing.
2021-09-03 00:42:32 -03:00
void AC_PosControl : : land_at_climb_rate_cm ( float vel , bool ignore_descent_limit )
2014-05-02 00:08:18 -03:00
{
2022-12-15 07:43:31 -04:00
if ( ignore_descent_limit ) {
// turn off limits in the negative z direction
_limit_vector . z = MAX ( _limit_vector . z , 0.0f ) ;
}
input_vel_accel_z ( vel , 0.0 ) ;
2014-05-02 00:08:18 -03:00
}
2021-05-19 11:09:31 -03:00
/// input_pos_vel_accel_z - calculate a jerk limited path from the current position, velocity and acceleration to an input position velocity and acceleration.
/// The pos and vel are projected forwards in time based on a time step of dt and acceleration accel.
2021-04-16 12:53:14 -03:00
/// The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.
2021-06-22 21:03:09 -03:00
/// The function alters the pos and vel to be the kinematic path based on accel
2021-08-06 06:40:56 -03:00
/// The parameter limit_output specifies if the velocity and acceleration limits are applied to the sum of commanded and correction values or just correction.
2021-09-03 00:42:32 -03:00
void AC_PosControl : : input_pos_vel_accel_z ( float & pos , float & vel , float accel , bool limit_output )
2013-12-28 10:04:45 -04:00
{
2022-01-24 10:40:38 -04:00
// calculated increased maximum acceleration and jerk if over speed
2022-12-15 07:08:51 -04:00
const float overspeed_gain = calculate_overspeed_gain ( ) ;
const float accel_max_z_cmss = _accel_max_z_cmss * overspeed_gain ;
const float jerk_max_z_cmsss = _jerk_max_z_cmsss * overspeed_gain ;
2014-05-02 00:08:18 -03:00
2021-06-26 10:49:12 -03:00
// adjust desired altitude if motors have not hit their limits
2024-08-02 01:45:17 -03:00
update_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 ( ) ) ;
2016-11-22 01:36:17 -04:00
2021-06-21 04:26:39 -03:00
shape_pos_vel_accel ( pos , vel , accel ,
2024-08-02 01:45:17 -03:00
_pos_desired . z , _vel_desired . z , _accel_desired . z ,
2021-08-06 06:40:56 -03:00
_vel_max_down_cms , _vel_max_up_cms ,
2022-01-24 10:40:38 -04:00
- constrain_float ( accel_max_z_cmss , 0.0f , 750.0f ) , accel_max_z_cmss ,
jerk_max_z_cmsss , _dt , limit_output ) ;
2014-01-23 23:27:06 -04:00
2021-06-17 22:19:29 -03:00
postype_t posp = pos ;
2021-12-05 00:54:54 -04:00
update_pos_vel_accel ( posp , vel , accel , _dt , 0.0 , 0.0 , 0.0 ) ;
2021-06-17 22:19:29 -03:00
pos = posp ;
2013-12-28 10:04:45 -04:00
}
2021-04-16 12:53:14 -03:00
/// set_alt_target_with_slew - adjusts target up or down using a commanded altitude in cm
2021-08-06 06:40:56 -03:00
/// using the default position control kinematic path.
2021-09-03 00:42:32 -03:00
void AC_PosControl : : set_alt_target_with_slew ( float pos )
2013-12-28 10:04:45 -04:00
{
2021-06-21 04:26:39 -03:00
float zero = 0 ;
2021-09-03 00:42:32 -03:00
input_pos_vel_accel_z ( pos , zero , 0 ) ;
2014-01-23 23:27:06 -04:00
}
2024-08-02 01:45:17 -03:00
/// update_offsets_z - updates the vertical offsets used by terrain following
void AC_PosControl : : update_offsets_z ( )
2021-06-26 10:49:12 -03:00
{
2024-08-02 01:45:17 -03:00
// check for offset target timeout
uint32_t now_ms = AP_HAL : : millis ( ) ;
if ( now_ms - _posvelaccel_offset_target_z_ms > POSCONTROL_POSVELACCEL_OFFSET_TARGET_TIMEOUT_MS ) {
_pos_offset_target . z = 0.0 ;
_vel_offset_target . z = 0.0 ;
_accel_offset_target . z = 0.0 ;
}
// update position, velocity, accel offsets for this iteration
postype_t p_offset_z = _pos_offset . z ;
update_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 ( ) ) ;
_pos_offset . z = p_offset_z ;
2021-06-26 10:49:12 -03:00
2024-08-02 01:45:17 -03:00
// input shape vertical position, velocity and acceleration offsets
shape_pos_vel_accel ( _pos_offset_target . z , _vel_offset_target . z , _accel_offset_target . z ,
_pos_offset . z , _vel_offset . z , _accel_offset . z ,
2021-08-06 06:40:56 -03:00
get_max_speed_down_cms ( ) , get_max_speed_up_cms ( ) ,
- get_max_accel_z_cmss ( ) , get_max_accel_z_cmss ( ) ,
2021-10-01 09:02:30 -03:00
_jerk_max_z_cmsss , _dt , false ) ;
2024-08-02 01:45:17 -03:00
p_offset_z = _pos_offset_target . z ;
update_pos_vel_accel ( p_offset_z , _vel_offset_target . z , _accel_offset_target . z , _dt , 0.0 , 0.0 , 0.0 ) ;
_pos_offset_target . z = p_offset_z ;
2021-06-26 10:49:12 -03:00
}
2024-08-22 05:09:04 -03:00
// is_active_z - returns true if the z position controller has been run in the previous loop
2021-04-16 12:53:14 -03:00
bool AC_PosControl : : is_active_z ( ) const
2014-01-23 23:27:06 -04:00
{
2023-01-28 05:43:41 -04:00
const uint32_t dt_ticks = AP : : scheduler ( ) . ticks32 ( ) - _last_update_z_ticks ;
return dt_ticks < = 1 ;
2021-04-16 12:53:14 -03:00
}
2015-10-27 10:44:41 -03:00
2021-04-16 12:53:14 -03:00
/// update_z_controller - runs the vertical position controller correcting position, velocity and acceleration errors.
/// Position and velocity errors are converted to velocity and acceleration targets using PID objects
/// Desired velocity and accelerations are added to these corrections as they are calculated
/// Kinematically consistent target position and desired velocity and accelerations should be provided before calling this function
void AC_PosControl : : update_z_controller ( )
{
2021-06-23 09:08:14 -03:00
// check for ekf z-axis position reset
handle_ekf_z_reset ( ) ;
2021-04-16 12:53:14 -03:00
// Check for z_controller time out
if ( ! is_active_z ( ) ) {
init_z_controller ( ) ;
2021-05-17 22:24:41 -03:00
if ( has_good_timing ( ) ) {
// call internal error because initialisation has not been done
INTERNAL_ERROR ( AP_InternalError : : error_t : : flow_of_control ) ;
}
2021-04-16 12:53:14 -03:00
}
2023-01-28 05:43:41 -04:00
_last_update_z_ticks = AP : : scheduler ( ) . ticks32 ( ) ;
2021-04-16 12:53:14 -03:00
2024-08-02 01:45:17 -03:00
// update the position, velocity and acceleration offsets
update_offsets_z ( ) ;
update_terrain ( ) ;
_pos_target . z = _pos_desired . z + _pos_offset . z + _pos_terrain ;
2020-01-04 02:16:09 -04:00
// calculate the target velocity correction
2021-06-17 22:19:29 -03:00
float pos_target_zf = _pos_target . z ;
2021-06-26 10:49:12 -03:00
2021-10-20 05:31:49 -03:00
_vel_target . z = _p_pos_z . update_all ( pos_target_zf , _inav . get_position_z_up_cm ( ) ) ;
2021-08-14 03:06:34 -03:00
_vel_target . z * = AP : : ahrs ( ) . getControlScaleZ ( ) ;
2021-06-26 10:49:12 -03:00
2021-06-17 22:19:29 -03:00
_pos_target . z = pos_target_zf ;
2024-08-02 01:45:17 -03:00
_pos_desired . z = _pos_target . z - ( _pos_offset . z + _pos_terrain ) ;
2021-04-16 12:53:14 -03:00
2015-04-13 06:22:52 -03:00
// add feed forward component
2024-08-02 01:45:17 -03:00
_vel_target . z + = _vel_desired . z + _vel_offset . z + _vel_terrain ;
2015-04-13 06:22:52 -03:00
2020-01-04 02:16:09 -04:00
// Velocity Controller
2013-12-28 07:15:29 -04:00
2022-01-23 10:27:22 -04:00
const float curr_vel_z = _inav . get_velocity_z_up_cms ( ) ;
2022-12-05 08:21:43 -04:00
_accel_target . z = _pid_vel_z . update_all ( _vel_target . z , curr_vel_z , _dt , _motors . limit . throttle_lower , _motors . limit . throttle_upper ) ;
2021-08-14 03:06:34 -03:00
_accel_target . z * = AP : : ahrs ( ) . getControlScaleZ ( ) ;
2021-04-16 12:53:14 -03:00
2021-06-26 10:49:12 -03:00
// add feed forward component
2024-08-02 01:45:17 -03:00
_accel_target . z + = _accel_desired . z + _accel_offset . z + _accel_terrain ;
2013-12-28 10:04:45 -04:00
2020-01-04 02:16:09 -04:00
// Acceleration Controller
2013-12-28 10:04:45 -04:00
2021-05-19 11:09:31 -03:00
// Calculate vertical acceleration
2021-01-29 00:43:26 -04:00
const float z_accel_meas = get_z_accel_cmss ( ) ;
2016-09-05 01:49:56 -03:00
// ensure imax is always large enough to overpower hover throttle
if ( _motors . get_throttle_hover ( ) * 1000.0f > _pid_accel_z . imax ( ) ) {
2024-07-30 08:37:50 -03:00
_pid_accel_z . set_imax ( _motors . get_throttle_hover ( ) * 1000.0f ) ;
2016-09-05 01:49:56 -03:00
}
2019-09-14 01:02:02 -03:00
float thr_out ;
if ( _vibe_comp_enabled ) {
2020-01-04 02:16:09 -04:00
thr_out = get_throttle_with_vibration_override ( ) ;
2019-09-14 01:02:02 -03:00
} else {
2022-12-05 08:21:43 -04:00
thr_out = _pid_accel_z . update_all ( _accel_target . z , z_accel_meas , _dt , ( _motors . limit . throttle_lower | | _motors . limit . throttle_upper ) ) * 0.001f ;
2020-01-04 02:16:09 -04:00
thr_out + = _pid_accel_z . get_ff ( ) * 0.001f ;
2019-09-14 01:02:02 -03:00
}
thr_out + = _motors . get_throttle_hover ( ) ;
2015-03-16 01:26:42 -03:00
2020-01-04 02:16:09 -04:00
// Actuator commands
2014-10-04 11:31:33 -03:00
// send throttle to attitude controller with angle boost
2021-05-19 11:09:31 -03:00
_attitude_control . set_throttle_out ( thr_out , true , POSCONTROL_THROTTLE_CUTOFF_FREQ_HZ ) ;
2019-06-17 12:36:22 -03:00
2020-01-04 02:16:09 -04:00
// Check for vertical controller health
2019-06-17 12:36:22 -03:00
// _speed_down_cms is checked to be non-zero when set
2021-06-22 11:39:44 -03:00
float error_ratio = _pid_vel_z . get_error ( ) / _vel_max_down_cms ;
2021-05-19 11:09:31 -03:00
_vel_z_control_ratio + = _dt * 0.1f * ( 0.5 - error_ratio ) ;
2019-06-17 12:36:22 -03:00
_vel_z_control_ratio = constrain_float ( _vel_z_control_ratio , 0.0f , 2.0f ) ;
2013-12-28 07:15:29 -04:00
2021-04-16 12:53:14 -03:00
// set vertical component of the limit vector
if ( _motors . limit . throttle_upper ) {
_limit_vector . z = 1.0f ;
} else if ( _motors . limit . throttle_lower ) {
_limit_vector . z = - 1.0f ;
} else {
_limit_vector . z = 0.0f ;
2020-01-04 02:16:09 -04:00
}
}
2014-01-23 23:27:06 -04:00
///
2021-05-19 11:09:31 -03:00
/// Accessors
2014-01-23 23:27:06 -04:00
///
2013-12-28 07:15:29 -04:00
2021-04-16 12:53:14 -03:00
/// get_lean_angle_max_cd - returns the maximum lean angle the autopilot may request
float AC_PosControl : : get_lean_angle_max_cd ( ) const
2014-01-17 22:53:46 -04:00
{
2022-03-14 19:26:18 -03:00
if ( is_positive ( _angle_max_override_cd ) ) {
return _angle_max_override_cd ;
}
2021-09-12 11:31:45 -03:00
if ( ! is_positive ( _lean_angle_max ) ) {
2021-09-06 06:45:31 -03:00
return _attitude_control . lean_angle_max_cd ( ) ;
2021-04-16 12:53:14 -03:00
}
return _lean_angle_max * 100.0f ;
2014-01-17 22:53:46 -04:00
}
2024-08-02 01:45:17 -03:00
/// set the desired position, velocity and acceleration targets
2021-06-17 22:19:29 -03:00
void AC_PosControl : : set_pos_vel_accel ( const Vector3p & pos , const Vector3f & vel , const Vector3f & accel )
2020-01-04 02:16:09 -04:00
{
2024-08-02 01:45:17 -03:00
_pos_desired = pos ;
2020-01-04 02:16:09 -04:00
_vel_desired = vel ;
_accel_desired = accel ;
}
2024-08-02 01:45:17 -03:00
/// set the desired position, velocity and acceleration targets
2021-06-17 22:19:29 -03:00
void AC_PosControl : : set_pos_vel_accel_xy ( const Vector2p & pos , const Vector2f & vel , const Vector2f & accel )
2014-05-06 05:32:30 -03:00
{
2024-08-02 01:45:17 -03:00
_pos_desired . xy ( ) = pos ;
2021-08-25 01:57:21 -03:00
_vel_desired . xy ( ) = vel ;
_accel_desired . xy ( ) = accel ;
2014-05-06 05:32:30 -03:00
}
2021-04-16 12:53:14 -03:00
// get_lean_angles_to_accel - convert roll, pitch lean target angles to lat/lon frame accelerations in cm/s/s
Vector3f AC_PosControl : : lean_angles_to_accel ( const Vector3f & att_target_euler ) const
2015-10-29 04:30:14 -03:00
{
2021-04-16 12:53:14 -03:00
// rotate our roll, pitch angles into lat/lon frame
const float sin_roll = sinf ( att_target_euler . x ) ;
const float cos_roll = cosf ( att_target_euler . x ) ;
const float sin_pitch = sinf ( att_target_euler . y ) ;
const float cos_pitch = cosf ( att_target_euler . y ) ;
const float sin_yaw = sinf ( att_target_euler . z ) ;
const float cos_yaw = cosf ( att_target_euler . z ) ;
2021-05-19 11:09:31 -03:00
return Vector3f {
2022-09-01 09:18:05 -03:00
( GRAVITY_MSS * 100.0f ) * ( - cos_yaw * sin_pitch * cos_roll - sin_yaw * sin_roll ) / MAX ( cos_roll * cos_pitch , 0.1f ) ,
( GRAVITY_MSS * 100.0f ) * ( - sin_yaw * sin_pitch * cos_roll + cos_yaw * sin_roll ) / MAX ( cos_roll * cos_pitch , 0.1f ) ,
( GRAVITY_MSS * 100.0f )
2021-05-19 11:09:31 -03:00
} ;
2015-10-29 04:30:14 -03:00
}
2024-08-02 01:45:17 -03:00
/// Terrain
/// set the terrain position, velocity and acceleration in cm, cms and cm/s/s from EKF origin in NE frame
/// this is used to initiate the offsets when initialise the position controller or do an offset reset
void AC_PosControl : : init_terrain ( )
{
// set terrain position and target to zero
_pos_terrain_target = 0.0 ;
_pos_terrain = 0.0 ;
// set velocity offset to zero
_vel_terrain = 0.0 ;
// set acceleration offset to zero
_accel_terrain = 0.0 ;
}
// init_pos_terrain_cm - initialises the current terrain altitude and target altitude to pos_offset_terrain_cm
void AC_PosControl : : init_pos_terrain_cm ( float pos_terrain_cm )
{
_pos_desired . z - = ( pos_terrain_cm - _pos_terrain ) ;
_pos_terrain_target = pos_terrain_cm ;
_pos_terrain = pos_terrain_cm ;
}
/// Offsets
/// set the horizontal position, velocity and acceleration offsets in cm, cms and cm/s/s from EKF origin in NE frame
/// this is used to initiate the offsets when initialise the position controller or do an offset reset
void AC_PosControl : : init_offsets_xy ( )
{
// check for offset target timeout
uint32_t now_ms = AP_HAL : : millis ( ) ;
if ( now_ms - _posvelaccel_offset_target_xy_ms > POSCONTROL_POSVELACCEL_OFFSET_TARGET_TIMEOUT_MS ) {
_pos_offset_target . xy ( ) . zero ( ) ;
_vel_offset_target . xy ( ) . zero ( ) ;
_accel_offset_target . xy ( ) . zero ( ) ;
}
// set position offset to target
_pos_offset . xy ( ) = _pos_offset_target . xy ( ) ;
// set velocity offset to target
_vel_offset . xy ( ) = _vel_offset_target . xy ( ) ;
// set acceleration offset to target
_accel_offset . xy ( ) = _accel_offset_target . xy ( ) ;
}
/// set the horizontal position, velocity and acceleration offsets in cm, cms and cm/s/s from EKF origin in NE frame
/// this is used to initiate the offsets when initialise the position controller or do an offset reset
void AC_PosControl : : init_offsets_z ( )
{
// check for offset target timeout
uint32_t now_ms = AP_HAL : : millis ( ) ;
if ( now_ms - _posvelaccel_offset_target_z_ms > POSCONTROL_POSVELACCEL_OFFSET_TARGET_TIMEOUT_MS ) {
_pos_offset_target . z = 0.0 ;
_vel_offset_target . z = 0.0 ;
_accel_offset_target . z = 0.0 ;
}
// set position offset to target
_pos_offset . z = _pos_offset_target . z ;
// set velocity offset to target
_vel_offset . z = _vel_offset_target . z ;
// set acceleration offset to target
_accel_offset . z = _accel_offset_target . z ;
}
# if AP_SCRIPTING_ENABLED
// add an additional offset to vehicle's target position, velocity and acceleration
// units are m, m/s and m/s/s in NED frame
// Z-axis is not currently supported and is ignored
bool AC_PosControl : : set_posvelaccel_offset ( const Vector3f & pos_offset_NED , const Vector3f & vel_offset_NED , const Vector3f & accel_offset_NED )
{
set_posvelaccel_offset_target_xy_cm ( pos_offset_NED . topostype ( ) . xy ( ) * 100.0 , vel_offset_NED . xy ( ) * 100.0 , accel_offset_NED . xy ( ) * 100.0 ) ;
set_posvelaccel_offset_target_z_cm ( - pos_offset_NED . topostype ( ) . z * 100.0 , - vel_offset_NED . z * 100 , - accel_offset_NED . z * 100.0 ) ;
return true ;
}
// get position and velocity offset to vehicle's target velocity and acceleration
// units are m and m/s in NED frame
bool AC_PosControl : : get_posvelaccel_offset ( Vector3f & pos_offset_NED , Vector3f & vel_offset_NED , Vector3f & accel_offset_NED )
{
pos_offset_NED . xy ( ) = _pos_offset_target . xy ( ) . tofloat ( ) * 0.01 ;
pos_offset_NED . z = - _pos_offset_target . z * 0.01 ;
vel_offset_NED . xy ( ) = _vel_offset_target . xy ( ) * 0.01 ;
vel_offset_NED . z = - _vel_offset_target . z * 0.01 ;
accel_offset_NED . xy ( ) = _accel_offset_target . xy ( ) * 0.01 ;
accel_offset_NED . z = - _accel_offset_target . z * 0.01 ;
return true ;
}
# endif
/// set the horizontal position, velocity and acceleration offset targets in cm, cms and cm/s/s from EKF origin in NE frame
/// these must be set every 3 seconds (or less) or they will timeout and return to zero
void 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 )
{
// set position offset target
_pos_offset_target . xy ( ) = pos_offset_target_xy_cm ;
// set velocity offset target
_vel_offset_target . xy ( ) = vel_offset_target_xy_cms ;
// set acceleration offset target
_accel_offset_target . xy ( ) = accel_offset_target_xy_cmss ;
// record time of update so we can detect timeouts
_posvelaccel_offset_target_xy_ms = AP_HAL : : millis ( ) ;
}
/// set the vertical position, velocity and acceleration offset targets in cm, cms and cm/s/s from EKF origin in NE frame
/// these must be set every 3 seconds (or less) or they will timeout and return to zero
void 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 )
{
// set position offset target
_pos_offset_target . z = pos_offset_target_z_cm ;
// set velocity offset target
_vel_offset_target . z = vel_offset_target_z_cms ;
// set acceleration offset target
_accel_offset_target . z = accel_offset_target_z_cmss ;
// record time of update so we can detect timeouts
_posvelaccel_offset_target_z_ms = AP_HAL : : millis ( ) ;
}
2021-04-16 12:53:14 -03:00
// returns the NED target acceleration vector for attitude control
Vector3f AC_PosControl : : get_thrust_vector ( ) const
2014-04-30 09:22:47 -03:00
{
2021-04-16 12:53:14 -03:00
Vector3f accel_target = get_accel_target_cmss ( ) ;
accel_target . z = - GRAVITY_MSS * 100.0f ;
return accel_target ;
2014-04-30 09:22:47 -03:00
}
2021-04-16 12:53:14 -03:00
/// get_stopping_point_xy_cm - calculates stopping point in NEU cm based on current position, velocity, vehicle acceleration
2021-05-19 11:09:31 -03:00
/// function does not change the z axis
2021-06-17 22:19:29 -03:00
void AC_PosControl : : get_stopping_point_xy_cm ( Vector2p & stopping_point ) const
2013-12-28 07:15:29 -04:00
{
2024-08-02 01:45:17 -03:00
// todo: we should use the current target position and velocity if we are currently running the position controller
2021-10-20 05:31:49 -03:00
stopping_point = _inav . get_position_xy_cm ( ) . topostype ( ) ;
2024-08-02 01:45:17 -03:00
stopping_point - = _pos_offset . xy ( ) ;
2021-04-16 12:53:14 -03:00
2021-10-20 05:31:49 -03:00
Vector2f curr_vel = _inav . get_velocity_xy_cms ( ) ;
2024-08-02 01:45:17 -03:00
curr_vel - = _vel_offset . xy ( ) ;
2014-05-06 05:32:30 -03:00
2013-12-28 07:15:29 -04:00
// calculate current velocity
2021-08-22 02:14:43 -03:00
float vel_total = curr_vel . length ( ) ;
2013-12-28 07:15:29 -04:00
2021-05-19 11:09:31 -03:00
if ( ! is_positive ( vel_total ) ) {
return ;
}
2024-08-02 01:45:17 -03:00
float kP = _p_pos_xy . kP ( ) ;
2021-05-19 11:09:31 -03:00
const float stopping_dist = stopping_distance ( constrain_float ( vel_total , 0.0 , _vel_max_xy_cms ) , kP , _accel_max_xy_cmss ) ;
if ( ! is_positive ( stopping_dist ) ) {
return ;
}
2013-12-28 07:15:29 -04:00
2014-01-17 22:53:46 -04:00
// convert the stopping distance into a stopping point using velocity vector
2021-05-19 11:09:31 -03:00
const float t = stopping_dist / vel_total ;
2021-08-25 01:57:21 -03:00
stopping_point + = ( curr_vel * t ) . topostype ( ) ;
2013-12-28 07:15:29 -04:00
}
2021-08-23 21:07:02 -03:00
/// get_stopping_point_z_cm - calculates stopping point in NEU cm based on current position, velocity, vehicle acceleration
void AC_PosControl : : get_stopping_point_z_cm ( postype_t & stopping_point ) const
{
2024-08-02 01:45:17 -03:00
float curr_pos_z = _inav . get_position_z_up_cm ( ) ;
curr_pos_z - = _pos_offset . z ;
float curr_vel_z = _inav . get_velocity_z_up_cms ( ) ;
curr_vel_z - = _vel_offset . z ;
2021-08-23 21:07:02 -03:00
// avoid divide by zero by using current position if kP is very low or acceleration is zero
if ( ! is_positive ( _p_pos_z . kP ( ) ) | | ! is_positive ( _accel_max_z_cmss ) ) {
stopping_point = curr_pos_z ;
return ;
}
2024-08-02 01:45:17 -03:00
stopping_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 ) ;
2021-08-23 21:07:02 -03:00
}
2021-04-16 12:53:14 -03:00
/// get_bearing_to_target_cd - get bearing to target position in centi-degrees
int32_t AC_PosControl : : get_bearing_to_target_cd ( ) const
2017-11-27 08:21:13 -04:00
{
2021-10-20 05:31:49 -03:00
return get_bearing_cd ( _inav . get_position_xy_cm ( ) , _pos_target . tofloat ( ) . xy ( ) ) ;
2017-11-27 08:21:13 -04:00
}
2020-02-28 01:01:59 -04:00
2021-04-16 12:53:14 -03:00
///
/// System methods
///
2014-05-06 05:32:30 -03:00
2021-04-16 12:53:14 -03:00
// get throttle using vibration-resistant calculation (uses feed forward with manually calculated gain)
float AC_PosControl : : get_throttle_with_vibration_override ( )
2017-12-16 09:06:51 -04:00
{
2021-04-16 12:53:14 -03:00
const float thr_per_accelz_cmss = _motors . get_throttle_hover ( ) / ( GRAVITY_MSS * 100.0f ) ;
// during vibration compensation use feed forward with manually calculated gain
// ToDo: clear pid_info P, I and D terms for logging
2021-06-22 11:39:44 -03:00
if ( ! ( _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 ( ) ) ) ) ) {
_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 ) ;
2017-12-16 09:06:51 -04:00
}
2021-04-16 12:53:14 -03:00
return POSCONTROL_VIBE_COMP_P_GAIN * thr_per_accelz_cmss * _accel_target . z + _pid_accel_z . get_i ( ) * 0.001f ;
2014-05-06 05:32:30 -03:00
}
2019-09-28 10:38:23 -03:00
/// standby_xyz_reset - resets I terms and removes position error
/// This function will let Loiter and Alt Hold continue to operate
/// in the event that the flight controller is in control of the
/// aircraft when in standby.
void AC_PosControl : : standby_xyz_reset ( )
{
// Set _pid_accel_z integrator to zero.
_pid_accel_z . set_integrator ( 0.0f ) ;
// Set the target position to the current pos.
2021-10-20 05:31:49 -03:00
_pos_target = _inav . get_position_neu_cm ( ) . topostype ( ) ;
2019-09-28 10:38:23 -03:00
2021-04-16 12:53:14 -03:00
// Set _pid_vel_xy integrator and derivative to zero.
2019-09-28 10:38:23 -03:00
_pid_vel_xy . reset_filter ( ) ;
// initialise ekf xy reset handler
init_ekf_xy_reset ( ) ;
}
2023-07-13 21:58:03 -03:00
# if HAL_LOGGING_ENABLED
2021-05-25 01:35:23 -03:00
// write PSC and/or PSCZ logs
2018-03-01 01:42:52 -04:00
void AC_PosControl : : write_log ( )
{
2021-05-25 01:35:23 -03:00
if ( is_active_xy ( ) ) {
float accel_x , accel_y ;
lean_angles_to_accel_xy ( accel_x , accel_y ) ;
2024-08-02 01:45:17 -03:00
Write_PSCN ( _pos_desired . x , _pos_target . x , _inav . get_position_neu_cm ( ) . x ,
_vel_desired . x , _vel_target . x , _inav . get_velocity_neu_cms ( ) . x ,
_accel_desired . x , _accel_target . x , accel_x ) ;
Write_PSCE ( _pos_desired . y , _pos_target . y , _inav . get_position_neu_cm ( ) . y ,
_vel_desired . y , _vel_target . y , _inav . get_velocity_neu_cms ( ) . y ,
_accel_desired . y , _accel_target . y , accel_y ) ;
// log offsets if they are being used
if ( ! _pos_offset . xy ( ) . is_zero ( ) ) {
Write_PSON ( _pos_offset_target . x , _pos_offset . x , _vel_offset_target . x , _vel_offset . x , _accel_offset_target . x , _accel_offset . x ) ;
Write_PSOE ( _pos_offset_target . y , _pos_offset . y , _vel_offset_target . y , _vel_offset . y , _accel_offset_target . y , _accel_offset . y ) ;
}
2021-05-25 01:35:23 -03:00
}
2014-06-02 06:02:44 -03:00
2021-05-25 01:35:23 -03:00
if ( is_active_z ( ) ) {
2024-08-02 01:45:17 -03:00
Write_PSCD ( - _pos_desired . z , - _pos_target . z , - _inav . get_position_z_up_cm ( ) ,
- _vel_desired . z , - _vel_target . z , - _inav . get_velocity_z_up_cms ( ) ,
- _accel_desired . z , - _accel_target . z , - get_z_accel_cmss ( ) ) ;
// log down and terrain offsets if they are being used
if ( ! is_zero ( _pos_offset . z ) ) {
Write_PSOD ( - _pos_offset_target . z , - _pos_offset . z , - _vel_offset_target . z , - _vel_offset . z , - _accel_offset_target . z , - _accel_offset . z ) ;
}
if ( ! is_zero ( _pos_terrain ) ) {
Write_PSOT ( - _pos_terrain_target , - _pos_terrain , 0 , - _vel_terrain , 0 , - _accel_terrain ) ;
}
2021-05-25 01:35:23 -03:00
}
2014-06-02 06:02:44 -03:00
}
2023-07-13 21:58:03 -03:00
# endif // HAL_LOGGING_ENABLED
2014-06-02 06:02:44 -03:00
2021-07-20 21:37:00 -03:00
/// crosstrack_error - returns horizontal error to the closest point to the current track
float AC_PosControl : : crosstrack_error ( ) const
{
2021-10-20 05:31:49 -03:00
const Vector2f pos_error = _inav . get_position_xy_cm ( ) - ( _pos_target . xy ( ) ) . tofloat ( ) ;
2021-07-20 21:37:00 -03:00
if ( is_zero ( _vel_desired . xy ( ) . length_squared ( ) ) ) {
// crosstrack is the horizontal distance to target when stationary
return pos_error . length ( ) ;
} else {
// crosstrack is the horizontal distance to the closest point to the current track
const Vector2f vel_unit = _vel_desired . xy ( ) . normalized ( ) ;
const float dot_error = pos_error * vel_unit ;
2021-07-21 01:53:47 -03:00
// todo: remove MAX of zero when safe_sqrt fixed
return safe_sqrt ( MAX ( pos_error . length_squared ( ) - sq ( dot_error ) , 0.0 ) ) ;
2021-07-20 21:37:00 -03:00
}
}
2014-01-17 22:53:46 -04:00
///
/// private methods
///
2013-12-28 07:15:29 -04:00
2024-08-02 01:45:17 -03:00
/// Terrain
/// update_z_offsets - updates the vertical offsets used by terrain following
void AC_PosControl : : update_terrain ( )
{
// update position, velocity, accel offsets for this iteration
postype_t pos_terrain = _pos_terrain ;
update_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 ( ) ) ;
_pos_terrain = pos_terrain ;
// input shape horizontal position, velocity and acceleration offsets
shape_pos_vel_accel ( _pos_terrain_target , 0.0 , 0.0 ,
_pos_terrain , _vel_terrain , _accel_terrain ,
get_max_speed_down_cms ( ) , get_max_speed_up_cms ( ) ,
- get_max_accel_z_cmss ( ) , get_max_accel_z_cmss ( ) ,
_jerk_max_z_cmsss , _dt , false ) ;
// we do not have to update _pos_terrain_target because we assume the target velocity and acceleration are zero
// if we know how fast the terain altitude is changing we would add update_pos_vel_accel for _pos_terrain_target here
}
2021-04-16 12:53:14 -03:00
// get_lean_angles_to_accel - convert roll, pitch lean angles to NE frame accelerations in cm/s/s
2017-12-16 09:06:51 -04:00
void AC_PosControl : : accel_to_lean_angles ( float accel_x_cmss , float accel_y_cmss , float & roll_target , float & pitch_target ) const
{
2014-12-08 20:56:53 -04:00
// rotate accelerations into body forward-right frame
2021-02-09 22:38:47 -04:00
const float accel_forward = accel_x_cmss * _ahrs . cos_yaw ( ) + accel_y_cmss * _ahrs . sin_yaw ( ) ;
const float accel_right = - accel_x_cmss * _ahrs . sin_yaw ( ) + accel_y_cmss * _ahrs . cos_yaw ( ) ;
2014-11-07 23:47:33 -04:00
2014-12-08 20:56:53 -04:00
// update angle targets that will be passed to stabilize controller
2022-03-14 19:26:18 -03:00
pitch_target = accel_to_angle ( - accel_forward * 0.01 ) * 100 ;
2019-04-19 08:36:42 -03:00
float cos_pitch_target = cosf ( pitch_target * M_PI / 18000.0f ) ;
2022-03-14 19:26:18 -03:00
roll_target = accel_to_angle ( ( accel_right * cos_pitch_target ) * 0.01 ) * 100 ;
2013-12-28 07:15:29 -04:00
}
2021-05-19 11:09:31 -03:00
// lean_angles_to_accel_xy - convert roll, pitch lean target angles to NE frame accelerations in cm/s/s
2021-04-16 12:53:14 -03:00
// todo: this should be based on thrust vector attitude control
void AC_PosControl : : lean_angles_to_accel_xy ( float & accel_x_cmss , float & accel_y_cmss ) const
2014-05-06 05:32:30 -03:00
{
// rotate our roll, pitch angles into lat/lon frame
2021-04-16 12:53:14 -03:00
Vector3f att_target_euler = _attitude_control . get_att_target_euler_rad ( ) ;
att_target_euler . z = _ahrs . yaw ;
Vector3f accel_cmss = lean_angles_to_accel ( att_target_euler ) ;
2021-03-15 13:53:51 -03:00
2021-04-16 12:53:14 -03:00
accel_x_cmss = accel_cmss . x ;
accel_y_cmss = accel_cmss . y ;
2014-05-06 05:32:30 -03:00
}
2021-05-19 11:09:31 -03:00
// calculate_yaw_and_rate_yaw - update the calculated the vehicle yaw and rate of yaw.
2024-03-22 23:41:51 -03:00
void AC_PosControl : : calculate_yaw_and_rate_yaw ( )
2021-04-22 22:16:58 -03:00
{
// Calculate the turn rate
float turn_rate = 0.0f ;
2021-08-25 01:57:21 -03:00
const float vel_desired_xy_len = _vel_desired . xy ( ) . length ( ) ;
2021-04-22 22:16:58 -03:00
if ( is_positive ( vel_desired_xy_len ) ) {
2021-08-25 01:57:21 -03:00
const float accel_forward = ( _accel_desired . x * _vel_desired . x + _accel_desired . y * _vel_desired . y ) / vel_desired_xy_len ;
const Vector2f accel_turn = _accel_desired . xy ( ) - _vel_desired . xy ( ) * accel_forward / vel_desired_xy_len ;
2021-04-22 22:16:58 -03:00
const float accel_turn_xy_len = accel_turn . length ( ) ;
turn_rate = accel_turn_xy_len / vel_desired_xy_len ;
2021-08-25 01:57:21 -03:00
if ( ( accel_turn . y * _vel_desired . x - accel_turn . x * _vel_desired . y ) < 0.0 ) {
2021-04-22 22:16:58 -03:00
turn_rate = - turn_rate ;
}
}
2021-07-08 01:13:05 -03:00
// update the target yaw if velocity is greater than 5% _vel_max_xy_cms
2021-04-16 12:53:14 -03:00
if ( vel_desired_xy_len > _vel_max_xy_cms * 0.05f ) {
2021-08-25 01:57:21 -03:00
_yaw_target = degrees ( _vel_desired . xy ( ) . angle ( ) ) * 100.0f ;
_yaw_rate_target = turn_rate * degrees ( 100.0f ) ;
2024-03-22 23:41:51 -03:00
return ;
2021-04-22 22:16:58 -03:00
}
2024-03-22 23:41:51 -03:00
// use the current attitude controller yaw target
_yaw_target = _attitude_control . get_att_target_euler_cd ( ) . z ;
_yaw_rate_target = 0 ;
2021-04-22 22:16:58 -03:00
}
2022-01-24 10:40:38 -04:00
// calculate_overspeed_gain - calculated increased maximum acceleration and jerk if over speed condition is detected
float AC_PosControl : : calculate_overspeed_gain ( )
{
if ( _vel_desired . z < _vel_max_down_cms & & ! is_zero ( _vel_max_down_cms ) ) {
return POSCONTROL_OVERSPEED_GAIN_Z * _vel_desired . z / _vel_max_down_cms ;
}
if ( _vel_desired . z > _vel_max_up_cms & & ! is_zero ( _vel_max_up_cms ) ) {
return POSCONTROL_OVERSPEED_GAIN_Z * _vel_desired . z / _vel_max_up_cms ;
}
return 1.0 ;
}
2016-11-22 01:36:17 -04:00
/// initialise ekf xy position reset check
void AC_PosControl : : init_ekf_xy_reset ( )
{
Vector2f pos_shift ;
_ekf_xy_reset_ms = _ahrs . getLastPosNorthEastReset ( pos_shift ) ;
}
2021-05-19 11:09:31 -03:00
/// handle_ekf_xy_reset - check for ekf position reset and adjust loiter or brake target position
void AC_PosControl : : handle_ekf_xy_reset ( )
2016-11-22 01:36:17 -04:00
{
// check for position shift
Vector2f pos_shift ;
uint32_t reset_ms = _ahrs . getLastPosNorthEastReset ( pos_shift ) ;
if ( reset_ms ! = _ekf_xy_reset_ms ) {
2021-04-16 12:53:14 -03:00
2024-08-02 01:45:17 -03:00
// ToDo: move EKF steps into the offsets for modes setting absolute position and velocity
// for this we need some sort of switch to select what type of EKF handling we want to use
// To zero real position shift during relative position modes like Loiter, PosHold, Guided velocity and accleration control.
2021-10-20 05:31:49 -03:00
_pos_target . xy ( ) = ( _inav . get_position_xy_cm ( ) + _p_pos_xy . get_error ( ) ) . topostype ( ) ;
2024-08-02 01:45:17 -03:00
_pos_desired . xy ( ) = _pos_target . xy ( ) - _pos_offset . xy ( ) ;
2021-10-20 05:31:49 -03:00
_vel_target . xy ( ) = _inav . get_velocity_xy_cms ( ) + _pid_vel_xy . get_error ( ) ;
2024-08-02 01:45:17 -03:00
_vel_desired . xy ( ) = _vel_target . xy ( ) - _vel_offset . xy ( ) ;
2021-04-16 12:53:14 -03:00
2016-11-22 01:36:17 -04:00
_ekf_xy_reset_ms = reset_ms ;
}
}
/// initialise ekf z axis reset check
void AC_PosControl : : init_ekf_z_reset ( )
{
float alt_shift ;
_ekf_z_reset_ms = _ahrs . getLastPosDownReset ( alt_shift ) ;
}
2021-05-19 11:09:31 -03:00
/// handle_ekf_z_reset - check for ekf position reset and adjust loiter or brake target position
void AC_PosControl : : handle_ekf_z_reset ( )
2016-11-22 01:36:17 -04:00
{
// check for position shift
float alt_shift ;
uint32_t reset_ms = _ahrs . getLastPosDownReset ( alt_shift ) ;
2018-03-31 01:20:29 -03:00
if ( reset_ms ! = 0 & & reset_ms ! = _ekf_z_reset_ms ) {
2021-04-16 12:53:14 -03:00
2024-08-02 01:45:17 -03:00
// ToDo: move EKF steps into the offsets for modes setting absolute position and velocity
// for this we need some sort of switch to select what type of EKF handling we want to use
// To zero real position shift during relative position modes like Loiter, PosHold, Guided velocity and accleration control.
2021-10-20 05:31:49 -03:00
_pos_target . z = _inav . get_position_z_up_cm ( ) + _p_pos_z . get_error ( ) ;
2024-08-02 01:45:17 -03:00
_pos_desired . z = _pos_target . z - ( _pos_offset . z + _pos_terrain ) ;
2021-10-20 05:31:49 -03:00
_vel_target . z = _inav . get_velocity_z_up_cms ( ) + _pid_vel_z . get_error ( ) ;
2024-08-02 01:45:17 -03:00
_vel_desired . z = _vel_target . z - ( _vel_offset . z + _vel_terrain ) ;
2021-04-16 12:53:14 -03:00
2016-11-22 01:36:17 -04:00
_ekf_z_reset_ms = reset_ms ;
}
}
2017-11-16 08:29:02 -04:00
2019-03-04 23:27:31 -04:00
bool AC_PosControl : : pre_arm_checks ( const char * param_prefix ,
char * failure_msg ,
const uint8_t failure_msg_len )
{
2020-01-04 02:16:09 -04:00
if ( ! is_positive ( get_pos_xy_p ( ) . kP ( ) ) ) {
hal . util - > snprintf ( failure_msg , failure_msg_len , " %s_POSXY_P must be > 0 " , param_prefix ) ;
return false ;
}
if ( ! is_positive ( get_pos_z_p ( ) . kP ( ) ) ) {
hal . util - > snprintf ( failure_msg , failure_msg_len , " %s_POSZ_P must be > 0 " , param_prefix ) ;
return false ;
}
if ( ! is_positive ( get_vel_z_pid ( ) . kP ( ) ) ) {
hal . util - > snprintf ( failure_msg , failure_msg_len , " %s_VELZ_P must be > 0 " , param_prefix ) ;
return false ;
2019-03-04 23:27:31 -04:00
}
if ( ! is_positive ( get_accel_z_pid ( ) . kP ( ) ) ) {
hal . util - > snprintf ( failure_msg , failure_msg_len , " %s_ACCZ_P must be > 0 " , param_prefix ) ;
return false ;
}
if ( ! is_positive ( get_accel_z_pid ( ) . kI ( ) ) ) {
hal . util - > snprintf ( failure_msg , failure_msg_len , " %s_ACCZ_I must be > 0 " , param_prefix ) ;
return false ;
}
return true ;
}
2021-05-17 22:24:41 -03:00
// return true if on a real vehicle or SITL with lock-step scheduling
bool AC_PosControl : : has_good_timing ( void ) const
{
# if CONFIG_HAL_BOARD == HAL_BOARD_SITL
auto * sitl = AP : : sitl ( ) ;
if ( sitl ) {
return sitl - > state . is_lock_step_scheduled ;
}
# endif
// real boards are assumed to have good timing
return true ;
}