mirror of
https://github.com/ArduPilot/ardupilot
synced 2025-02-22 07:44:03 -04:00
AP_Math: Control: Add XY S-Curve shapers and shaping limits
This commit is contained in:
parent
6bed10c434
commit
c4bb8baf0c
@ -22,19 +22,190 @@
|
||||
#include "AP_Math.h"
|
||||
#include "vector2.h"
|
||||
#include "vector3.h"
|
||||
#include <AP_InternalError/AP_InternalError.h>
|
||||
|
||||
// control default definitions
|
||||
#define CONTROL_TIME_CONSTANT_RATIO 4.0f // minimum horizontal acceleration in cm/s/s - used for sanity checking acceleration in leash length calculation
|
||||
#define CONTROL_TIME_CONSTANT_RATIO 4.0f // time constant to ensure stable kinimatic path generation
|
||||
|
||||
// update_pos_vel_accel - single axis projection of position and velocity, pos and vel, forwards in time based on a time step of dt and acceleration of accel.
|
||||
void update_pos_vel_accel(float& pos, float& vel, float accel, float dt)
|
||||
// update_vel_accel - single axis projection of position and velocity, pos and vel, forwards in time based on a time step of dt and acceleration of accel.
|
||||
void update_vel_accel(float& vel, float accel, float dt, float limit)
|
||||
{
|
||||
// move position and velocity forward by dt.
|
||||
pos = pos + vel * dt + accel * 0.5f * sq(dt);
|
||||
vel = vel + accel * dt;
|
||||
const float delta_vel = accel * dt;
|
||||
if (!is_positive(delta_vel * limit)){
|
||||
vel += delta_vel;
|
||||
}
|
||||
}
|
||||
|
||||
/* shape_vel and shape_vel_xy calculate a jerk limited path from the current position, velocity and acceleration to an input velocity.
|
||||
// update_vel_accel_z - single axis projection of position and velocity, pos and vel, forwards in time based on a time step of dt and acceleration of accel.
|
||||
void update_vel_accel_z(Vector3f& vel, const Vector3f& accel, float dt, Vector3f limit)
|
||||
{
|
||||
update_vel_accel(vel.z, accel.z, dt, limit.z);
|
||||
}
|
||||
|
||||
// update_pos_vel_accel - single axis projection of position and velocity, pos and vel, forwards in time based on a time step of dt and acceleration of accel.
|
||||
void update_pos_vel_accel(float& pos, float& vel, float accel, float dt, float limit)
|
||||
{
|
||||
// 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);
|
||||
if (!is_positive(delta_pos * limit)){
|
||||
pos += delta_pos;
|
||||
}
|
||||
|
||||
update_vel_accel(vel, accel, dt, limit);
|
||||
}
|
||||
|
||||
// update_pos_vel_accel_z - single axis projection of position and velocity, pos and vel, forwards in time based on a time step of dt and acceleration of accel.
|
||||
void update_pos_vel_accel_z(Vector3f& pos, Vector3f& vel, const Vector3f& accel, float dt, Vector3f limit)
|
||||
{
|
||||
update_pos_vel_accel(pos.z, vel.z, accel.z, dt, limit.z);
|
||||
}
|
||||
|
||||
// update_vel_accel - dual axis projection of position and velocity, pos and vel, forwards in time based on a time step of dt and acceleration of accel.
|
||||
void update_vel_accel(Vector2f& vel, const Vector2f& accel, float dt, Vector2f limit)
|
||||
{
|
||||
// increase velocity by acceleration * dt if it does not increase error when limited.
|
||||
Vector2f delta_vel = accel * dt;
|
||||
|
||||
if (!is_zero(limit.length_squared())) {
|
||||
// zero delta_vel if it will increase the velocity error
|
||||
limit.normalize();
|
||||
if (is_positive(delta_vel * limit)) {
|
||||
delta_vel.zero();
|
||||
}
|
||||
}
|
||||
|
||||
vel += delta_vel;
|
||||
}
|
||||
|
||||
// update_vel_accel_xy - dual axis projection of position and velocity, pos and vel, forwards in time based on a time step of dt and acceleration of accel.
|
||||
// This function only updates the x and y axis leaving the z axis unchanged.
|
||||
void update_vel_accel_xy(Vector3f& vel, const Vector3f& accel, float dt, Vector3f limit)
|
||||
{
|
||||
Vector2f vel_2f = Vector2f{vel.x, vel.y};
|
||||
Vector2f accel_2f = Vector2f{accel.x, accel.y};
|
||||
Vector2f limit_2f = Vector2f{limit.x, limit.y};
|
||||
update_vel_accel(vel_2f, accel_2f, dt, limit_2f);
|
||||
vel.x = vel_2f.x;
|
||||
vel.y = vel_2f.y;
|
||||
}
|
||||
|
||||
// update_pos_vel_accel - dual axis projection of position and velocity, pos and vel, forwards in time based on a time step of dt and acceleration of accel.
|
||||
void update_pos_vel_accel(Vector2f& pos, Vector2f& vel, const Vector2f& accel, float dt, Vector2f limit)
|
||||
{
|
||||
// move position and velocity forward by dt.
|
||||
Vector2f delta_pos = vel * dt + accel * 0.5f * sq(dt);
|
||||
|
||||
if (!is_zero(limit.length_squared())) {
|
||||
// zero delta_vel if it will increase the velocity error
|
||||
limit.normalize();
|
||||
if (is_positive(delta_pos * limit)) {
|
||||
delta_pos.zero();
|
||||
}
|
||||
}
|
||||
|
||||
pos += delta_pos;
|
||||
|
||||
update_vel_accel(vel, accel, dt, limit);
|
||||
}
|
||||
|
||||
// update_pos_vel_accel_xy - dual axis projection of position and velocity, pos and vel, forwards in time based on a time step of dt and acceleration of accel.
|
||||
// This function only updates the x and y axis leaving the z axis unchanged.
|
||||
void update_pos_vel_accel_xy(Vector3f& pos, Vector3f& vel, const Vector3f& accel, float dt, Vector3f limit)
|
||||
{
|
||||
Vector2f pos_2f = Vector2f{pos.x, pos.y};
|
||||
Vector2f vel_2f = Vector2f{vel.x, vel.y};
|
||||
Vector2f accel_2f = Vector2f{accel.x, accel.y};
|
||||
Vector2f limit_2f = Vector2f{limit.x, limit.y};
|
||||
update_pos_vel_accel(pos_2f, vel_2f, accel_2f, dt, limit_2f);
|
||||
pos.x = pos_2f.x;
|
||||
pos.y = pos_2f.y;
|
||||
vel.x = vel_2f.x;
|
||||
vel.y = vel_2f.y;
|
||||
}
|
||||
|
||||
/* shape_accel calculates a jerk limited path from the current acceleration to an input acceleration.
|
||||
The function takes the current acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.
|
||||
The kinematic path is constrained by :
|
||||
acceleration limits - accel_min, accel_max,
|
||||
time constant - tc.
|
||||
The time constant defines the acceleration error decay in the kinematic path as the system approaches constant acceleration.
|
||||
The time constant also defines the time taken to achieve the maximum acceleration.
|
||||
The time constant must be positive.
|
||||
The function alters the input velocity to be the velocity that the system could reach zero acceleration in the minimum time.
|
||||
*/
|
||||
void shape_accel(float accel_input, float& accel,
|
||||
float accel_min, float accel_max,
|
||||
float tc, float dt)
|
||||
{
|
||||
// sanity check tc
|
||||
if (!is_positive(tc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate time constants and limits to ensure stable operation
|
||||
const float KPa = 1.0 / tc;
|
||||
|
||||
float jerk_max = 0.0;
|
||||
if (is_negative(accel_min) && is_positive(accel_max)){
|
||||
jerk_max = MAX(-accel_min, accel_max) * KPa;
|
||||
}
|
||||
|
||||
// jerk limit acceleration change
|
||||
float accel_delta = accel_input - accel;
|
||||
if (is_positive(jerk_max)) {
|
||||
accel_delta = constrain_float(accel_delta, -jerk_max * dt, jerk_max * dt);
|
||||
}
|
||||
accel += accel_delta;
|
||||
|
||||
// limit acceleration to accel_max
|
||||
if (is_negative(accel_min) && is_positive(accel_max)){
|
||||
accel = constrain_float(accel, accel_min, accel_max);
|
||||
}
|
||||
}
|
||||
|
||||
/* shape_accel_xy calculate a jerk limited path from the current position, velocity and acceleration to an input velocity.
|
||||
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:
|
||||
vel_max : maximum velocity
|
||||
accel_max : maximum acceleration
|
||||
tc : time constant
|
||||
The time constant defines the acceleration error decay in the kinematic path as the system approaches constant acceleration.
|
||||
The time constant also defines the time taken to achieve the maximum acceleration.
|
||||
The time constant must be positive.
|
||||
The function alters the input velocity to be the velocity that the system could reach zero acceleration in the minimum time.
|
||||
This function operates on the x and y axis of both Vector2f or Vector3f inputs.
|
||||
The accel_max limit can be removed by setting it to zero.
|
||||
*/
|
||||
void shape_accel_xy(const Vector2f& accel_input, Vector2f& accel,
|
||||
float accel_max, float tc, float dt)
|
||||
{
|
||||
// sanity check tc
|
||||
if (!is_positive(tc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate time constants and limits to ensure stable operation
|
||||
float KPa = 1.0 / tc;
|
||||
float jerk_max = accel_max * KPa;
|
||||
|
||||
// jerk limit acceleration change
|
||||
Vector2f accel_delta = accel_input - accel;
|
||||
if (is_positive(jerk_max)) {
|
||||
accel_delta.limit_length(jerk_max * dt);
|
||||
}
|
||||
accel = accel + accel_delta;
|
||||
|
||||
// limit acceleration to accel_max
|
||||
if (is_negative(accel_max)) {
|
||||
// we may want to allow this for some applications but call error for now.
|
||||
INTERNAL_ERROR(AP_InternalError::error_t::invalid_arg_or_result);
|
||||
} else if (is_positive(accel_max)) {
|
||||
accel.limit_length(accel_max);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* shape_vel_accel and shape_vel_xy calculate a jerk limited path from the current position, velocity and acceleration to an input velocity.
|
||||
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 :
|
||||
maximum velocity - vel_max,
|
||||
@ -46,7 +217,11 @@ void update_pos_vel_accel(float& pos, float& vel, float accel, float dt)
|
||||
The function alters the input velocity to be the velocity that the system could reach zero acceleration in the minimum time.
|
||||
The accel_max limit can be removed by setting it to zero.
|
||||
*/
|
||||
void shape_vel(float& vel_input, float vel, float& accel, float accel_max, float tc, float dt)
|
||||
void shape_vel_accel(float vel_input, float accel_input,
|
||||
float vel, float& accel,
|
||||
float vel_min, float vel_max,
|
||||
float accel_min, float accel_max,
|
||||
float tc, float dt)
|
||||
{
|
||||
// sanity check tc
|
||||
if (!is_positive(tc)) {
|
||||
@ -55,33 +230,92 @@ void shape_vel(float& vel_input, float vel, float& accel, float accel_max, float
|
||||
|
||||
// Calculate time constants and limits to ensure stable operation
|
||||
const float KPa = 1.0 / tc;
|
||||
const float jerk_max = accel_max * KPa;
|
||||
|
||||
// limit velocity to vel_max
|
||||
if (is_negative(vel_min) && is_positive(vel_max)){
|
||||
vel_input = constrain_float(vel_input, vel_min, vel_max);
|
||||
}
|
||||
|
||||
// velocity error to be corrected
|
||||
float vel_error = vel_input - vel;
|
||||
|
||||
// acceleration to correct velocity
|
||||
const float accel_target = vel_error * KPa;
|
||||
float accel_target = vel_error * KPa;
|
||||
|
||||
// jerk limit acceleration change
|
||||
float accel_delta = accel_target - accel;
|
||||
if (is_positive(jerk_max)) {
|
||||
accel_delta = constrain_float(accel_delta, -jerk_max * dt, jerk_max * dt);
|
||||
}
|
||||
accel += accel_delta;
|
||||
// velocity correction with input velocity
|
||||
accel_target += accel_input;
|
||||
|
||||
// limit acceleration to accel_max
|
||||
if (is_positive(accel_max)) {
|
||||
accel = constrain_float(accel, -accel_max, accel_max);
|
||||
}
|
||||
|
||||
// Calculate maximum pos_input and vel_input based on limited system
|
||||
vel_error = accel / KPa;
|
||||
vel_input = vel_error + vel;
|
||||
shape_accel(accel_target, accel, accel_min, accel_max, tc, dt);
|
||||
}
|
||||
|
||||
void shape_vel_accel_z(const Vector3f& vel_input, const Vector3f& accel_input,
|
||||
const Vector3f& vel, Vector3f& accel,
|
||||
float vel_min, float vel_max,
|
||||
float accel_min, float accel_max,
|
||||
float tc, float dt)
|
||||
{
|
||||
shape_vel_accel(vel_input.z, accel_input.z,
|
||||
vel.z, accel.z,
|
||||
vel_min, vel_max,
|
||||
accel_min, accel_max,
|
||||
tc, dt);
|
||||
}
|
||||
|
||||
/* shape_pos_vel calculate a jerk limited path from the current position, velocity and acceleration to an input position and velocity.
|
||||
/* shape_vel_accel_xy calculate a jerk limited path from the current position, velocity and acceleration to an input velocity.
|
||||
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:
|
||||
vel_max : maximum velocity
|
||||
accel_max : maximum acceleration
|
||||
tc : time constant
|
||||
The time constant defines the acceleration error decay in the kinematic path as the system approaches constant acceleration.
|
||||
The time constant also defines the time taken to achieve the maximum acceleration.
|
||||
The time constant must be positive.
|
||||
The function alters the input velocity to be the velocity that the system could reach zero acceleration in the minimum time.
|
||||
This function operates on the x and y axis of both Vector2f or Vector3f inputs.
|
||||
The accel_max limit can be removed by setting it to zero.
|
||||
*/
|
||||
void shape_vel_accel_xy(Vector2f vel_input, const Vector2f& accel_input,
|
||||
const Vector2f& vel, Vector2f& accel, float vel_max, float accel_max, float tc, float dt)
|
||||
{
|
||||
// sanity check tc
|
||||
if (!is_positive(tc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// limit velocity to vel_max
|
||||
if (is_negative(vel_max)) {
|
||||
INTERNAL_ERROR(AP_InternalError::error_t::invalid_arg_or_result);
|
||||
} else if (is_positive(vel_max)) {
|
||||
vel_input.limit_length(vel_max);
|
||||
}
|
||||
|
||||
// Calculate time constants and limits to ensure stable operation
|
||||
float KPa = 1.0 / tc;
|
||||
|
||||
// velocity error to be corrected
|
||||
Vector2f vel_error = vel_input - vel;
|
||||
|
||||
// acceleration to correct velocity
|
||||
Vector2f accel_target = vel_error * KPa;
|
||||
accel_target += accel_input;
|
||||
|
||||
shape_accel_xy(accel_target, accel, accel_max, tc, dt);
|
||||
}
|
||||
|
||||
void shape_vel_accel_xy(const Vector3f& vel_input, const Vector3f& accel_input,
|
||||
const Vector3f& vel, Vector3f& accel, float vel_max, float accel_max, float tc, float dt)
|
||||
{
|
||||
Vector2f vel_input_2f = Vector2f{vel_input.x, vel_input.y};
|
||||
Vector2f accel_input_2f = Vector2f{accel_input.x, accel_input.y};
|
||||
Vector2f vel_2f = Vector2f{vel.x, vel.y};
|
||||
Vector2f accel_2f = Vector2f{accel.x, accel.y};
|
||||
|
||||
shape_vel_accel_xy(vel_input_2f, accel_input_2f, vel_2f, accel_2f, vel_max, accel_max, tc, dt);
|
||||
accel.x = accel_2f.x;
|
||||
accel.y = accel_2f.y;
|
||||
}
|
||||
|
||||
/* shape_pos_vel_accel calculate a jerk limited path from the current position, velocity and acceleration to an input position and velocity.
|
||||
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 :
|
||||
maximum velocity - vel_max,
|
||||
@ -93,7 +327,10 @@ void shape_vel(float& vel_input, float vel, float& accel, float accel_max, float
|
||||
The function alters the input position to be the closest position that the system could reach zero acceleration in the minimum time.
|
||||
The vel_max, vel_correction_max, and accel_max limits can be removed by setting the desired limit to zero.
|
||||
*/
|
||||
void shape_pos_vel(float& pos_input, float vel_input, float pos, float vel, float& accel, float vel_max, float vel_correction_max, float accel_max, float tc, float dt)
|
||||
void shape_pos_vel_accel(float pos_input, float vel_input, float accel_input,
|
||||
float pos, float vel, float& accel,
|
||||
float vel_correction_max, float vel_min, float vel_max,
|
||||
float accel_min, float accel_max, float tc, float dt)
|
||||
{
|
||||
// sanity check tc
|
||||
if (!is_positive(tc)) {
|
||||
@ -118,16 +355,91 @@ void shape_pos_vel(float& pos_input, float vel_input, float pos, float vel, floa
|
||||
// velocity correction with input velocity
|
||||
vel_target += vel_input;
|
||||
|
||||
// limit velocity to vel_max
|
||||
if (is_positive(vel_max)) {
|
||||
vel_target = constrain_float(vel_target, -vel_max, vel_max);
|
||||
shape_vel_accel(vel_target, accel_input, vel, accel, vel_min, vel_max, accel_min, accel_max, tc, dt);
|
||||
}
|
||||
|
||||
void shape_pos_vel_accel_z(const Vector3f& pos_input, const Vector3f& vel_input, const Vector3f& accel_input,
|
||||
const Vector3f& pos, const Vector3f& vel, Vector3f& accel,
|
||||
float vel_correction_max, float vel_min, float vel_max,
|
||||
float accel_min, float accel_max, float tc, float dt)
|
||||
{
|
||||
shape_pos_vel_accel(pos_input.z, vel_input.z, accel_input.z,
|
||||
pos.z, vel.z, accel.z,
|
||||
vel_correction_max, vel_min, vel_max,
|
||||
accel_min, accel_max,
|
||||
tc, dt);
|
||||
}
|
||||
|
||||
/* shape_pos_vel_accel_xy calculate a jerk limited path from the current position, velocity and acceleration to an input position and velocity.
|
||||
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:
|
||||
vel_max : maximum velocity
|
||||
accel_max : maximum acceleration
|
||||
tc : time constant
|
||||
The time constant defines the acceleration error decay in the kinematic path as the system approaches constant acceleration.
|
||||
The time constant also defines the time taken to achieve the maximum acceleration.
|
||||
The time constant must be positive.
|
||||
The function alters the input position to be the closest position that the system could reach zero acceleration in the minimum time.
|
||||
This function operates on the x and y axis of both Vector2f or Vector3f inputs.
|
||||
The vel_max, vel_correction_max, and accel_max limits can be removed by setting the desired limit to zero.
|
||||
*/
|
||||
void shape_pos_vel_accel_xy(const Vector2f& pos_input, const Vector2f& vel_input, const Vector2f& accel_input,
|
||||
const Vector2f& pos, const Vector2f& vel, Vector2f& accel,
|
||||
float vel_correction_max, float vel_max, float accel_max, float tc, float dt)
|
||||
{
|
||||
if (!is_positive(tc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
shape_vel(vel_target, vel, accel, accel_max, tc, dt);
|
||||
// Calculate time constants and limits to ensure stable operation
|
||||
const float KPv = 1.0f / (CONTROL_TIME_CONSTANT_RATIO*tc);
|
||||
const float accel_tc_max = accel_max*(1.0f - 1.0f/CONTROL_TIME_CONSTANT_RATIO);
|
||||
|
||||
vel_target -= vel_input;
|
||||
pos_error = stopping_distance(vel_target, KPv, accel_tc_max);
|
||||
pos_input = pos_error + pos;
|
||||
// position error to be corrected
|
||||
Vector2f pos_error = pos_input - pos;
|
||||
|
||||
// velocity to correct position
|
||||
Vector2f vel_target = sqrt_controller(pos_error, KPv, accel_tc_max, dt);
|
||||
|
||||
// limit velocity correction to vel_correction_max
|
||||
if (is_positive(vel_correction_max)) {
|
||||
vel_target.limit_length(vel_correction_max);
|
||||
}
|
||||
|
||||
// velocity correction with input velocity
|
||||
vel_target = vel_target + vel_input;
|
||||
|
||||
shape_vel_accel_xy(vel_target, accel_input, vel, accel, vel_max, accel_max, tc, dt);
|
||||
}
|
||||
|
||||
/* shape_pos_vel_accel_xy calculate a jerk limited path from the current position, velocity and acceleration to an input position and velocity.
|
||||
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:
|
||||
vel_max : maximum velocity
|
||||
accel_max : maximum acceleration
|
||||
tc : time constant
|
||||
The time constant defines the acceleration error decay in the kinematic path as the system approaches constant acceleration.
|
||||
The time constant also defines the time taken to achieve the maximum acceleration.
|
||||
The time constant must be positive.
|
||||
The function alters the input position to be the closest position that the system could reach zero acceleration in the minimum time.
|
||||
This function operates only on the x and y axis of the Vector2f or Vector3f inputs.
|
||||
The vel_max, vel_correction_max, and accel_max limits can be removed by setting the desired limit to zero.
|
||||
*/
|
||||
void shape_pos_vel_accel_xy(const Vector3f& pos_input, const Vector3f& vel_input, const Vector3f& accel_input,
|
||||
const Vector3f& pos, const Vector3f& vel, Vector3f& accel,
|
||||
float vel_max, float vel_correction_max, float accel_max, float tc, float dt)
|
||||
{
|
||||
Vector2f pos_input_2f = Vector2f{pos_input.x, pos_input.y};
|
||||
Vector2f vel_input_2f = Vector2f{vel_input.x, vel_input.y};
|
||||
Vector2f accel_input_2f = Vector2f{accel_input.x, accel_input.y};
|
||||
Vector2f pos_2f = Vector2f{pos.x, pos.y};
|
||||
Vector2f vel_2f = Vector2f{vel.x, vel.y};
|
||||
Vector2f accel_2f = Vector2f{accel.x, accel.y};
|
||||
|
||||
shape_pos_vel_accel_xy(pos_input_2f, vel_input_2f, accel_input_2f,
|
||||
pos_2f, vel_2f, accel_2f, vel_max, vel_correction_max, accel_max, tc, dt);
|
||||
accel.x = accel_2f.x;
|
||||
accel.y = accel_2f.y;
|
||||
}
|
||||
|
||||
// proportional controller with piecewise sqrt sections to constrain second derivative
|
||||
@ -180,59 +492,33 @@ Vector2f sqrt_controller(const Vector2f& error, float p, float second_ord_lim, f
|
||||
// inverse of the sqrt controller. calculates the input (aka error) to the sqrt_controller required to achieve a given output
|
||||
float inv_sqrt_controller(float output, float p, float D_max)
|
||||
{
|
||||
if (!is_positive(D_max) && is_zero(p)) {
|
||||
if (is_positive(D_max) && is_zero(p)) {
|
||||
return (output * output) / (2.0f * D_max);
|
||||
}
|
||||
if ((is_negative(D_max) || is_zero(D_max)) && !is_zero(p)) {
|
||||
return output / p;
|
||||
}
|
||||
if ((is_negative(D_max) || is_zero(D_max)) && is_zero(p)) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (!is_positive(D_max)) {
|
||||
// second order limit is zero or negative.
|
||||
// calculate the velocity at which we switch from calculating the stopping point using a linear function to a sqrt function
|
||||
const float linear_velocity = D_max / p;
|
||||
|
||||
if (fabsf(output) < linear_velocity) {
|
||||
// if our current velocity is below the cross-over point we use a linear function
|
||||
return output / p;
|
||||
}
|
||||
|
||||
if (is_zero(p)) {
|
||||
// P term is zero but we have a second order limit.
|
||||
if (is_positive(D_max)) {
|
||||
return sq(output)/(2*D_max);
|
||||
}
|
||||
return -sq(output)/(2*D_max);
|
||||
}
|
||||
|
||||
// both the P and second order limit have been defined.
|
||||
float linear_out = D_max / p;
|
||||
if (output > linear_out) {
|
||||
if (is_positive(D_max)) {
|
||||
return sq(output)/(2*D_max) + D_max/(4*sq(p));
|
||||
}
|
||||
return -sq(output)/(2*D_max) + D_max/(4*sq(p));
|
||||
}
|
||||
|
||||
return output / p;
|
||||
const float linear_dist = D_max / sq(p);
|
||||
const float stopping_dist = (linear_dist * 0.5f) + sq(output) / (2.0f * D_max);
|
||||
return is_positive(output) ? stopping_dist : -stopping_dist;
|
||||
}
|
||||
|
||||
// calculate the stopping distance for the square root controller based deceleration path
|
||||
float stopping_distance(float velocity, float p, float accel_max)
|
||||
{
|
||||
if (is_positive(accel_max) && is_zero(p)) {
|
||||
return (velocity * velocity) / (2.0f * accel_max);
|
||||
}
|
||||
if ((is_negative(accel_max) || is_zero(accel_max)) && !is_zero(p)) {
|
||||
return velocity / p;
|
||||
}
|
||||
if ((is_negative(accel_max) || is_zero(accel_max)) && is_zero(p)) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// calculate the velocity at which we switch from calculating the stopping point using a linear function to a sqrt function
|
||||
const float linear_velocity = accel_max / p;
|
||||
|
||||
if (fabsf(velocity) < linear_velocity) {
|
||||
// if our current velocity is below the cross-over point we use a linear function
|
||||
return velocity / p;
|
||||
}
|
||||
|
||||
const float linear_dist = accel_max / sq(p);
|
||||
const float stopping_dist = (linear_dist * 0.5f) + sq(velocity) / (2.0f * accel_max);
|
||||
return is_positive(velocity) ? stopping_dist : -stopping_dist;
|
||||
return inv_sqrt_controller(velocity, p, accel_max);
|
||||
}
|
||||
|
||||
// calculate the maximum acceleration or velocity in a given direction
|
||||
|
@ -4,22 +4,82 @@
|
||||
common controller helper functions
|
||||
*/
|
||||
|
||||
// update_pos_vel_accel projects the position and velocity, pos and vel, forward in time based on a time step of dt and acceleration of accel.
|
||||
// update_pos_vel_accel - single axis projection.
|
||||
void update_pos_vel_accel(float& pos, float& vel, float accel, float dt);
|
||||
// update_vel_accel projects the velocity, vel, forward in time based on a time step of dt and acceleration of accel.
|
||||
// update_vel_accel - single axis projection.
|
||||
void update_vel_accel(float& vel, float accel, float dt, float limit);
|
||||
void update_vel_accel_z(Vector3f& vel, const Vector3f& accel, float dt, Vector3f limit);
|
||||
|
||||
/* shape_vel calculates a jerk limited path from the current position, velocity and acceleration to an input velocity.
|
||||
The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.
|
||||
// update_vel_accel projects the velocity, vel, forward in time based on a time step of dt and acceleration of accel.
|
||||
// update_vel_accel - single axis projection.
|
||||
void update_pos_vel_accel(float& pos, float& vel, float accel, float dt, float limit);
|
||||
void update_pos_vel_accel_z(Vector3f& pos, Vector3f& vel, const Vector3f& accel, float dt, Vector3f limit);
|
||||
|
||||
// update_pos_vel_accel_xy - dual axis projection operating on the x, y axis of Vector2f or Vector3f inputs.
|
||||
void update_vel_accel(Vector2f& vel, const Vector2f& accel, float dt, Vector2f limit);
|
||||
void update_vel_accel_xy(Vector3f& vel, const Vector3f& accel, float dt, Vector3f limit);
|
||||
|
||||
// update_pos_vel_accel_xy - dual axis projection operating on the x, y axis of Vector2f or Vector3f inputs.
|
||||
void update_pos_vel_accel(Vector2f& pos, Vector2f& vel, const Vector2f& accel, float dt, Vector2f limit);
|
||||
void update_pos_vel_accel_xy(Vector3f& pos, Vector3f& vel, const Vector3f& accel, float dt, Vector3f limit);
|
||||
|
||||
/* shape_accel calculates a jerk limited path from the current acceleration to an input acceleration.
|
||||
The function takes the current acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.
|
||||
The kinematic path is constrained by :
|
||||
maximum velocity - vel_max,
|
||||
maximum acceleration - accel_max,
|
||||
acceleration limits - accel_min, accel_max,
|
||||
time constant - tc.
|
||||
The time constant defines the acceleration error decay in the kinematic path as the system approaches constant acceleration.
|
||||
The time constant also defines the time taken to achieve the maximum acceleration.
|
||||
The time constant must be positive.
|
||||
The function alters the input velocity to be the velocity that the system could reach zero acceleration in the minimum time.
|
||||
*/
|
||||
void shape_vel(float& vel_input, float vel, float& accel, float accel_max, float tc, float dt);
|
||||
void shape_accel(float accel_input, float& accel,
|
||||
float accel_min, float accel_max,
|
||||
float tc, float dt);
|
||||
|
||||
void shape_accel_xy(const Vector2f& accel_input, Vector2f& accel,
|
||||
float accel_max, float tc, float dt);
|
||||
|
||||
/* shape_vel calculates a jerk limited path from the current velocity and acceleration to an input velocity.
|
||||
The function takes the current velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.
|
||||
The kinematic path is constrained by :
|
||||
velocity limits - vel_min, vel_max,
|
||||
acceleration limits - accel_min, accel_max,
|
||||
time constant - tc.
|
||||
The time constant defines the acceleration error decay in the kinematic path as the system approaches constant acceleration.
|
||||
The time constant also defines the time taken to achieve the maximum acceleration.
|
||||
The time constant must be positive.
|
||||
The function alters the input velocity to be the velocity that the system could reach zero acceleration in the minimum time.
|
||||
*/
|
||||
void shape_vel_accel(float vel_input, float accel_input,
|
||||
float vel, float& accel,
|
||||
float vel_min, float vel_max,
|
||||
float accel_min, float accel_max,
|
||||
float tc, float dt);
|
||||
|
||||
void shape_vel_accel_z(const Vector3f& vel_input, const Vector3f& accel_input,
|
||||
const Vector3f& vel, Vector3f& accel,
|
||||
float vel_min, float vel_max,
|
||||
float accel_min, float accel_max,
|
||||
float tc, float dt);
|
||||
|
||||
/* shape_vel_xy calculate a jerk limited path from the current position, velocity and acceleration to an input velocity.
|
||||
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:
|
||||
vel_max : maximum velocity
|
||||
accel_max : maximum acceleration
|
||||
tc : time constant
|
||||
The time constant defines the acceleration error decay in the kinematic path as the system approaches constant acceleration.
|
||||
The time constant also defines the time taken to achieve the maximum acceleration.
|
||||
The time constant must be positive.
|
||||
The function alters the input velocity to be the velocity that the system could reach zero acceleration in the minimum time.
|
||||
This function operates on the x and y axis of both Vector2f or Vector3f inputs.
|
||||
The accel_max limit can be removed by setting it to zero.
|
||||
*/
|
||||
void shape_vel_accel_xy(Vector2f vel_input, const Vector2f& accel_input,
|
||||
const Vector2f& vel, Vector2f& accel, float vel_max, float accel_max, float tc, float dt);
|
||||
|
||||
void shape_vel_accel_xy(const Vector3f& vel_input, const Vector3f& accel_input,
|
||||
const Vector3f& vel, Vector3f& accel, float vel_max, float accel_max, float tc, float dt);
|
||||
|
||||
/* shape_pos_vel calculate a jerk limited path from the current position, velocity and acceleration to an input position and velocity.
|
||||
The function takes the current position, velocity, and acceleration and calculates the required jerk limited adjustment to the acceleration for the next time dt.
|
||||
@ -32,7 +92,36 @@ void shape_vel(float& vel_input, float vel, float& accel, float accel_max, float
|
||||
The time constant must be positive.
|
||||
The function alters the input position to be the closest position that the system could reach zero acceleration in the minimum time.
|
||||
*/
|
||||
void shape_pos_vel(float& pos_input, float vel_input, float pos, float vel, float& accel, float vel_max, float vel_correction_max, float accel_max, float tc, float dt);
|
||||
void shape_pos_vel_accel(float pos_input, float vel_input, float accel_input,
|
||||
float pos, float vel, float& accel,
|
||||
float vel_correction_max, float vel_min, float vel_max,
|
||||
float accel_min, float accel_max, float tc, float dt);
|
||||
|
||||
void shape_pos_vel_accel_z(const Vector3f& pos_input, const Vector3f& vel_input, const Vector3f& accel_input,
|
||||
const Vector3f& pos, const Vector3f& vel, Vector3f& accel,
|
||||
float vel_correction_max, float vel_min, float vel_max,
|
||||
float accel_min, float accel_max, float tc, float dt);
|
||||
|
||||
/* shape_pos_vel_xy calculate a jerk limited path from the current position, velocity and acceleration to an input position and velocity.
|
||||
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:
|
||||
vel_max : maximum velocity
|
||||
accel_max : maximum acceleration
|
||||
tc : time constant
|
||||
The time constant defines the acceleration error decay in the kinematic path as the system approaches constant acceleration.
|
||||
The time constant also defines the time taken to achieve the maximum acceleration.
|
||||
The time constant must be positive.
|
||||
The function alters the input position to be the closest position that the system could reach zero acceleration in the minimum time.
|
||||
This function operates only on the x and y axis of the Vector2f or Vector3f inputs.
|
||||
The vel_max, vel_correction_max, and accel_max limits can be removed by setting the desired limit to zero.
|
||||
*/
|
||||
void shape_pos_vel_accel_xy(const Vector2f& pos_input, const Vector2f& vel_input, const Vector2f& accel_input,
|
||||
const Vector2f& pos, const Vector2f& vel, Vector2f& accel,
|
||||
float vel_correction_max, float vel_max, float accel_max, float tc, float dt);
|
||||
|
||||
void shape_pos_vel_accel_xy(const Vector3f& pos_input, const Vector3f& vel_input, const Vector3f& accel_input,
|
||||
const Vector3f& pos, const Vector3f& vel, Vector3f& accel,
|
||||
float vel_max, float vel_correction_max, float accel_max, float tc, float dt);
|
||||
|
||||
// proportional controller with piecewise sqrt sections to constrain second derivative
|
||||
float sqrt_controller(float error, float p, float second_ord_lim, float dt);
|
||||
|
Loading…
Reference in New Issue
Block a user