Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Position Control Limit Handling #22428

Merged
merged 9 commits into from Dec 30, 2022
6 changes: 3 additions & 3 deletions ArduCopter/mode_guided.cpp
Expand Up @@ -736,7 +736,7 @@ void ModeGuided::accel_control_run()
auto_yaw.set_mode(AutoYaw::Mode::HOLD);
}
pos_control->input_vel_accel_xy(guided_vel_target_cms.xy(), guided_accel_target_cmss.xy(), false);
pos_control->input_vel_accel_z(guided_vel_target_cms.z, guided_accel_target_cmss.z, false, false);
pos_control->input_vel_accel_z(guided_vel_target_cms.z, guided_accel_target_cmss.z, false);
} else {
// update position controller with new target
pos_control->input_accel_xy(guided_accel_target_cmss);
Expand Down Expand Up @@ -804,7 +804,7 @@ void ModeGuided::velaccel_control_run()
// set position errors to zero
pos_control->stop_pos_xy_stabilisation();
}
pos_control->input_vel_accel_z(guided_vel_target_cms.z, guided_accel_target_cmss.z, false, false);
pos_control->input_vel_accel_z(guided_vel_target_cms.z, guided_accel_target_cmss.z, false);

// call velocity controller which includes z axis controller
pos_control->update_xy_controller();
Expand Down Expand Up @@ -834,7 +834,7 @@ void ModeGuided::pause_control_run()

// set the vertical velocity and acceleration targets to zero
float vel_z = 0.0;
pos_control->input_vel_accel_z(vel_z, 0.0, false, false);
pos_control->input_vel_accel_z(vel_z, 0.0, false);

// call velocity controller which includes z axis controller
pos_control->update_xy_controller();
Expand Down
2 changes: 1 addition & 1 deletion ArduPlane/mode_qhover.cpp
Expand Up @@ -8,7 +8,7 @@ bool ModeQHover::_enter()
// set vertical speed and acceleration limits
pos_control->set_max_speed_accel_z(-quadplane.get_pilot_velocity_z_max_dn(), quadplane.pilot_velocity_z_max_up, quadplane.pilot_accel_z);
pos_control->set_correction_speed_accel_z(-quadplane.get_pilot_velocity_z_max_dn(), quadplane.pilot_velocity_z_max_up, quadplane.pilot_accel_z);
quadplane.set_climb_rate_cms(0, false);
quadplane.set_climb_rate_cms(0);

quadplane.init_throttle_wait();
return true;
Expand Down
6 changes: 3 additions & 3 deletions ArduPlane/mode_qloiter.cpp
Expand Up @@ -103,13 +103,13 @@ void ModeQLoiter::run()
quadplane.ahrs.set_touchdown_expected(true);
}

quadplane.set_climb_rate_cms(-descent_rate_cms, descent_rate_cms>0);
pos_control->land_at_climb_rate_cm(-descent_rate_cms, descent_rate_cms>0);
quadplane.check_land_complete();
} else if (plane.control_mode == &plane.mode_guided && quadplane.guided_takeoff) {
quadplane.set_climb_rate_cms(0, false);
quadplane.set_climb_rate_cms(0);
} else {
// update altitude target and call position controller
quadplane.set_climb_rate_cms(quadplane.get_pilot_desired_climb_rate_cms(), false);
quadplane.set_climb_rate_cms(quadplane.get_pilot_desired_climb_rate_cms());
}
quadplane.run_z_controller();
}
Expand Down
2 changes: 1 addition & 1 deletion ArduPlane/mode_qrtl.cpp
Expand Up @@ -88,7 +88,7 @@ void ModeQRTL::run()
quadplane.get_weathervane_yaw_rate_cds());

// climb at full WP nav speed
quadplane.set_climb_rate_cms(quadplane.wp_nav->get_default_speed_up(), false);
quadplane.set_climb_rate_cms(quadplane.wp_nav->get_default_speed_up());
quadplane.run_z_controller();

ftype alt_diff;
Expand Down
16 changes: 8 additions & 8 deletions ArduPlane/quadplane.cpp
Expand Up @@ -1003,9 +1003,9 @@ void QuadPlane::check_yaw_reset(void)
}
}

void QuadPlane::set_climb_rate_cms(float target_climb_rate_cms, bool force_descend)
void QuadPlane::set_climb_rate_cms(float target_climb_rate_cms)
{
pos_control->input_vel_accel_z(target_climb_rate_cms, 0, force_descend);
pos_control->input_vel_accel_z(target_climb_rate_cms, 0, false);
}

/*
Expand All @@ -1023,7 +1023,7 @@ void QuadPlane::hold_hover(float target_climb_rate_cms)
multicopter_attitude_rate_update(get_desired_yaw_rate_cds(false));

// call position controller
set_climb_rate_cms(target_climb_rate_cms, false);
set_climb_rate_cms(target_climb_rate_cms);

run_z_controller();
}
Expand Down Expand Up @@ -2790,7 +2790,7 @@ void QuadPlane::vtol_position_controller(void)
float zero = 0;
pos_control->input_pos_vel_accel_z(target_z, zero, 0);
} else {
set_climb_rate_cms(0, false);
set_climb_rate_cms(0);
}
break;
}
Expand All @@ -2804,7 +2804,7 @@ void QuadPlane::vtol_position_controller(void)
}
}
const float descent_rate_cms = landing_descent_rate_cms(height_above_ground);
set_climb_rate_cms(-descent_rate_cms, descent_rate_cms>0);
pos_control->land_at_climb_rate_cm(-descent_rate_cms, descent_rate_cms>0);
lthall marked this conversation as resolved.
Show resolved Hide resolved
break;
}

Expand Down Expand Up @@ -2952,10 +2952,10 @@ void QuadPlane::takeoff_controller(void)
vel_z = 0;
pos_control->input_pos_vel_accel_z(pos_z, vel_z, 0);
} else {
set_climb_rate_cms(vel_z, false);
set_climb_rate_cms(vel_z);
}
} else {
set_climb_rate_cms(vel_z, false);
set_climb_rate_cms(vel_z);
}

run_z_controller();
Expand Down Expand Up @@ -3000,7 +3000,7 @@ void QuadPlane::waypoint_controller(void)
true);

// climb based on altitude error
set_climb_rate_cms(assist_climb_rate_cms(), false);
set_climb_rate_cms(assist_climb_rate_cms());
run_z_controller();
}

Expand Down
2 changes: 1 addition & 1 deletion ArduPlane/quadplane.h
Expand Up @@ -228,7 +228,7 @@ class QuadPlane
void hold_stabilize(float throttle_in);

// set climb rate in position controller
void set_climb_rate_cms(float target_climb_rate_cms, bool force_descend);
void set_climb_rate_cms(float target_climb_rate_cms);

// get pilot desired yaw rate in cd/s
float get_pilot_input_yaw_rate_cds(void) const;
Expand Down
35 changes: 18 additions & 17 deletions libraries/AC_AttitudeControl/AC_PosControl.cpp
Expand Up @@ -344,8 +344,9 @@ void AC_PosControl::input_pos_xyz(const Vector3p& pos, float pos_offset_z, float
_accel_desired.z -= _accel_offset_z;

// calculated increased maximum acceleration and jerk if over speed
float accel_max_z_cmss = _accel_max_z_cmss * calculate_overspeed_gain();
float jerk_max_z_cmsss = _jerk_max_z_cmsss * calculate_overspeed_gain();
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;

update_pos_vel_accel_xy(_pos_target.xy(), _vel_desired.xy(), _accel_desired.xy(), _dt, _limit_vector.xy(), _p_pos_xy.get_error(), _pid_vel_xy.get_error());

Expand Down Expand Up @@ -780,10 +781,8 @@ void AC_PosControl::init_z_controller()
_last_update_z_us = AP::ins().get_last_update_usec();
}

/// input_vel_accel_z - 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.
/// 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.
/// The function alters the vel to be the kinematic path based on accel
void AC_PosControl::input_accel_z(float accel)
{
// calculated increased maximum jerk if over speed
Expand All @@ -799,16 +798,12 @@ void AC_PosControl::input_accel_z(float accel)
/// The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.
/// 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.
void AC_PosControl::input_vel_accel_z(float &vel, float accel, bool ignore_descent_limit, bool limit_output)
void AC_PosControl::input_vel_accel_z(float &vel, float accel, bool limit_output)
{
if (ignore_descent_limit) {
// turn off limits in the negative z direction
_limit_vector.z = MAX(_limit_vector.z, 0.0f);
}

// calculated increased maximum acceleration and jerk if over speed
float accel_max_z_cmss = _accel_max_z_cmss * calculate_overspeed_gain();
float jerk_max_z_cmsss = _jerk_max_z_cmsss * calculate_overspeed_gain();
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;

// adjust desired alt if motors have not hit their limits
update_pos_vel_accel(_pos_target.z, _vel_desired.z, _accel_desired.z, _dt, _limit_vector.z, _p_pos_z.get_error(), _pid_vel_z.get_error());
Expand All @@ -832,7 +827,7 @@ void AC_PosControl::set_pos_target_z_from_climb_rate_cm(float vel)
_accel_desired.z -= _accel_offset_z;

float vel_temp = vel;
input_vel_accel_z(vel_temp, 0, false);
input_vel_accel_z(vel_temp, 0.0);

// update the vertical position, velocity and acceleration offsets
update_pos_offset_z(_pos_offset_target_z);
Expand All @@ -848,7 +843,12 @@ void AC_PosControl::set_pos_target_z_from_climb_rate_cm(float vel)
/// ignore_descent_limit turns off output saturation handling to aid in landing detection. ignore_descent_limit should be false unless landing.
void AC_PosControl::land_at_climb_rate_cm(float vel, bool ignore_descent_limit)
{
input_vel_accel_z(vel, 0, ignore_descent_limit);
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);
}

/// input_pos_vel_accel_z - calculate a jerk limited path from the current position, velocity and acceleration to an input position velocity and acceleration.
Expand All @@ -859,8 +859,9 @@ void AC_PosControl::land_at_climb_rate_cm(float vel, bool ignore_descent_limit)
void AC_PosControl::input_pos_vel_accel_z(float &pos, float &vel, float accel, bool limit_output)
{
// calculated increased maximum acceleration and jerk if over speed
float accel_max_z_cmss = _accel_max_z_cmss * calculate_overspeed_gain();
float jerk_max_z_cmsss = _jerk_max_z_cmsss * calculate_overspeed_gain();
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;

// adjust desired altitude if motors have not hit their limits
update_pos_vel_accel(_pos_target.z, _vel_desired.z, _accel_desired.z, _dt, _limit_vector.z, _p_pos_z.get_error(), _pid_vel_z.get_error());
Expand Down
2 changes: 1 addition & 1 deletion libraries/AC_AttitudeControl/AC_PosControl.h
Expand Up @@ -201,7 +201,7 @@ class AC_PosControl
/// The kinematic path is constrained by the maximum acceleration and jerk set using the function set_max_speed_accel_z.
/// The function alters the vel to be the kinematic path based on accel
/// The parameter limit_output specifies if the velocity and acceleration limits are applied to the sum of commanded and correction values or just correction.
virtual void input_vel_accel_z(float &vel, float accel, bool ignore_descent_limit, bool limit_output = true);
virtual void input_vel_accel_z(float &vel, float accel, bool limit_output = true);

/// set_pos_target_z_from_climb_rate_cm - adjusts target up or down using a commanded climb rate in cm/s
/// using the default position control kinematic path.
Expand Down
32 changes: 21 additions & 11 deletions libraries/AP_Math/control.cpp
Expand Up @@ -33,11 +33,17 @@
// vel_error - specifies the direction of the velocity error used in limit handling.
void update_vel_accel(float& vel, float accel, float dt, float limit, float vel_error)
{
const float delta_vel = accel * dt;
float delta_vel = accel * dt;
// do not add delta_vel if it will increase the velocity error in the direction of limit
if (!(is_positive(delta_vel * limit) && is_positive(vel_error * limit))) {
vel += delta_vel;
// unless adding delta_vel will reduce vel towards zero
if (is_positive(delta_vel * limit) && is_positive(vel_error * limit)) {
if (is_negative(vel * limit)) {
delta_vel = constrain_float(delta_vel, -fabsf(vel), fabsf(vel));
} else {
delta_vel = 0.0;
}
}
vel += delta_vel;
}

// update_pos_vel_accel - single axis projection of position and velocity forward in time based on a time step of dt and acceleration of accel.
Expand All @@ -49,9 +55,10 @@ void update_pos_vel_accel(postype_t& pos, float& vel, float accel, float dt, flo
// move position and velocity forward by dt if it does not increase error when limited.
float delta_pos = vel * dt + accel * 0.5f * sq(dt);
// do not add delta_pos if it will increase the velocity error in the direction of limit
if (!(is_positive(delta_pos * limit) && is_positive(pos_error * limit))) {
pos += delta_pos;
if (is_positive(delta_pos * limit) && is_positive(pos_error * limit)) {
delta_pos = 0.0;
}
pos += delta_pos;

update_vel_accel(vel, accel, dt, limit, vel_error);
}
Expand All @@ -63,13 +70,12 @@ void update_pos_vel_accel(postype_t& pos, float& vel, float accel, float dt, flo
void update_vel_accel_xy(Vector2f& vel, const Vector2f& accel, float dt, const Vector2f& limit, const Vector2f& vel_error)
{
// increase velocity by acceleration * dt if it does not increase error when limited.
// unless adding delta_vel will reduce the magnitude of vel
Vector2f delta_vel = accel * dt;
if (!limit.is_zero() && !delta_vel.is_zero()) {
// check if delta_vel will increase the velocity error in the direction of limit
if (is_positive(delta_vel * limit) && is_positive(vel_error * limit)) {
// remove component of delta_vel in direction of limit
Vector2f limit_unit = limit.normalized();
delta_vel -= limit_unit * (limit_unit * delta_vel);
if (is_positive(delta_vel * limit) && is_positive(vel_error * limit) && !is_negative(vel * limit)) {
delta_vel.zero();
}
}
vel += delta_vel;
Expand Down Expand Up @@ -299,7 +305,9 @@ void shape_pos_vel_accel(postype_t pos_input, float vel_input, float accel_input
float vel_target = sqrt_controller(pos_error, KPv, accel_tc_max, dt);

// limit velocity between vel_min and vel_max
vel_target = constrain_float(vel_target, vel_min, vel_max);
if (is_negative(vel_min) || is_positive(vel_max)) {
rmackay9 marked this conversation as resolved.
Show resolved Hide resolved
vel_target = constrain_float(vel_target, vel_min, vel_max);
}

// velocity correction with input velocity
vel_target += vel_input;
Expand Down Expand Up @@ -336,7 +344,9 @@ void shape_pos_vel_accel_xy(const Vector2p& pos_input, const Vector2f& vel_input
Vector2f vel_target = sqrt_controller(pos_error, KPv, accel_tc_max, dt);

// limit velocity to vel_max
vel_target.limit_length(vel_max);
if (is_positive(vel_max)) {
vel_target.limit_length(vel_max);
}

// velocity correction with input velocity
vel_target = vel_target + vel_input;
Expand Down