You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
212 lines
10 KiB
212 lines
10 KiB
#pragma once |
|
|
|
#include <AP_Common/AP_Common.h> |
|
|
|
/* |
|
* SCurves calculate paths between waypoints (including the corners) using specified speed, acceleration and jerk limits |
|
* |
|
* How to use: |
|
* 1. create three SCurve objects called something like "prev_leg", "this_leg" and "next_leg" |
|
* 2. call this_leg.calculate_track() to calculate the path from the origin to the destination for the given speed, accel and jerk limits |
|
* 3. if the vehicle will fly past the destination to another "next destination": |
|
* a) call next_leg.calculate_track() with the appropriate arguments |
|
* b) set a "fast_waypoint" boolean to true. this will be passed into "advance_target_along_track()" in the next step |
|
* if there is no "next destination" |
|
* a) call next_leg.init() |
|
* b) set the "fast_waypoint" boolean to false |
|
* 4. call this_leg.advance_target_along_track() with a small "dt" value and retrieve the resulting target position, velocity and acceleration |
|
* Note: the target_pos should be set to the segments's earth frame origin before this function is called |
|
* 5. pass the target position, velocity and acceleration into the position controller |
|
* 6. repeat steps 4 and 5 until finished() returns true |
|
* 7. promote the legs: |
|
* a) set prev_leg = this_leg |
|
* b) set this_leg = next_leg |
|
* c) jump back to step 3 |
|
* |
|
* Other features: |
|
* 1. set_speed_max() allows changing the max speeds mid path. The path will be recalculated |
|
* 2. set_origin_speed_max() and set_destination_speed_max() allows setting the speed along the path at the beginning and end of the leg |
|
* this is used to smoothly integrate with spline segments |
|
* |
|
* This library works with any units (meters, cm, etc) as long as they are used consistently. |
|
* e.g. if origin and destination are meters, speeds should be in m/s, accel in m/s/s, etc. |
|
* |
|
* Terminology: |
|
* position: a point in space |
|
* velocity: rate of change of position. aka speed |
|
* acceleration: rate of change of speed |
|
* jerk: rate of change of acceleration |
|
* jerk time: the time (in seconds) for jerk to increase from zero to its maximum value |
|
* jounce: rate of change of jerk |
|
* track: 3D path that the vehicle will follow |
|
* path: position, velocity, accel and jerk kinematic profile that this library generates |
|
*/ |
|
|
|
class SCurve { |
|
|
|
public: |
|
|
|
// constructor |
|
SCurve(); |
|
|
|
// initialise and clear the path |
|
void init(); |
|
|
|
// calculate the segment times for the trigonometric S-Curve path defined by: |
|
// tj - duration of the raised cosine jerk profile (aka jerk time) |
|
// Jm - maximum value of the raised cosine jerk profile (aka jerk max) |
|
// V0 - initial velocity magnitude |
|
// Am - maximum constant acceleration |
|
// Vm - maximum constant velocity |
|
// L - Length of the path |
|
// this is an internal function, static for test suite |
|
static void calculate_path(float tj, float Jm, float V0, float Am, float Vm, float L, float &Jm_out, float &t2_out, float &t4_out, float &t6_out); |
|
|
|
// generate a trigonometric track in 3D space that moves over a straight line |
|
// between two points defined by the origin and destination |
|
void calculate_track(const Vector3f &origin, const Vector3f &destination, |
|
float speed_xy, float speed_up, float speed_down, |
|
float accel_xy, float accel_z, |
|
float jerk_time_sec, float jerk_maximum); |
|
|
|
// set maximum velocity and re-calculate the path using these limits |
|
void set_speed_max(float speed_xy, float speed_up, float speed_down); |
|
|
|
// set the maximum vehicle speed at the origin |
|
// returns the expected speed at the origin which will always be equal or lower than speed |
|
float set_origin_speed_max(float speed); |
|
|
|
// set the maximum vehicle speed at the destination |
|
void set_destination_speed_max(float speed); |
|
|
|
// move target location along path from origin to destination |
|
// prev_leg and next_leg are the paths before and after this path |
|
// wp_radius is max distance from the waypoint at the apex of the turn |
|
// fast_waypoint should be true if vehicle will not stop at end of this leg |
|
// dt is the time increment the vehicle will move along the path |
|
// target_pos should be set to this segment's origin and it will be updated to the current position target |
|
// target_vel and target_accel are updated with new targets |
|
// returns true if vehicle has passed the apex of the corner |
|
bool advance_target_along_track(SCurve &prev_leg, SCurve &next_leg, float wp_radius, bool fast_waypoint, float dt, Vector3f &target_pos, Vector3f &target_vel, Vector3f &target_accel) WARN_IF_UNUSED; |
|
|
|
// time has reached the end of the sequence |
|
bool finished() const WARN_IF_UNUSED; |
|
|
|
private: |
|
|
|
// increment time and return the position, velocity and acceleration vectors relative to the origin |
|
void move_from_pos_vel_accel(float dt, Vector3f &pos, Vector3f &vel, Vector3f &accel); |
|
|
|
// increment time and return the position, velocity and acceleration vectors relative to the destination |
|
void move_to_pos_vel_accel(float dt, Vector3f &pos, Vector3f &vel, Vector3f &accel); |
|
|
|
// return the position, velocity and acceleration vectors relative to the origin at a specified time along the path |
|
void move_from_time_pos_vel_accel(float t, Vector3f &pos, Vector3f &vel, Vector3f &accel); |
|
|
|
// get desired maximum speed along track |
|
float get_speed_along_track() const WARN_IF_UNUSED { return vel_max; } |
|
|
|
// get desired maximum acceleration along track |
|
float get_accel_along_track() const WARN_IF_UNUSED { return accel_max; } |
|
|
|
// return the change in position from origin to destination |
|
const Vector3f& get_track() const WARN_IF_UNUSED { return track; }; |
|
|
|
// return the current time elapsed |
|
float get_time_elapsed() const WARN_IF_UNUSED { return time; } |
|
|
|
// time at the end of the sequence |
|
float time_end() const WARN_IF_UNUSED; |
|
|
|
// time left before sequence will complete |
|
float get_time_remaining() const WARN_IF_UNUSED; |
|
|
|
// time when acceleration section of the sequence will complete |
|
float get_accel_finished_time() const WARN_IF_UNUSED; |
|
|
|
// return true if the sequence is braking to a stop |
|
bool braking() const WARN_IF_UNUSED; |
|
|
|
// increment the internal time |
|
void advance_time(float dt); |
|
|
|
// calculate the jerk, acceleration, velocity and position at time t |
|
void get_jerk_accel_vel_pos_at_time(float time_now, float &Jt_out, float &At_out, float &Vt_out, float &Pt_out) const; |
|
|
|
// calculate the jerk, acceleration, velocity and position at time t when running the constant jerk time segment |
|
void calc_javp_for_segment_const_jerk(float time_now, float J0, float A0, float V0, float P0, float &Jt, float &At, float &Vt, float &Pt) const; |
|
|
|
// Calculate the jerk, acceleration, velocity and position at time t when running the increasing jerk magnitude time segment based on a raised cosine profile |
|
void calc_javp_for_segment_incr_jerk(float time_now, float tj, float Jm, float A0, float V0, float P0, float &Jt, float &At, float &Vt, float &Pt) const; |
|
|
|
// Calculate the jerk, acceleration, velocity and position at time t when running the decreasing jerk magnitude time segment based on a raised cosine profile |
|
void calc_javp_for_segment_decr_jerk(float time_now, float tj, float Jm, float A0, float V0, float P0, float &Jt, float &At, float &Vt, float &Pt) const; |
|
|
|
// generate time segments for straight segment |
|
void add_segments(float L); |
|
|
|
// generate three time segments forming the jerk profile |
|
void add_segments_jerk(uint8_t &seg_pnt, float tj, float Jm, float Tcj); |
|
|
|
// generate constant jerk time segment |
|
void add_segment_const_jerk(uint8_t &seg_pnt, float tin, float J0); |
|
|
|
// generate increasing jerk magnitude time segment based on a raised cosine profile |
|
void add_segment_incr_jerk(uint8_t &seg_pnt, float tj, float Jm); |
|
|
|
// generate decreasing jerk magnitude time segment based on a raised cosine profile |
|
void add_segment_decr_jerk(uint8_t &seg_pnt, float tj, float Jm); |
|
|
|
// set speed and acceleration limits for the path |
|
// origin and destination are offsets from EKF origin |
|
// speed and acceleration parameters are given in horizontal, up and down. |
|
void set_kinematic_limits(const Vector3f &origin, const Vector3f &destination, |
|
float speed_xy, float speed_up, float speed_down, |
|
float accel_xy, float accel_z); |
|
|
|
// return true if the curve is valid. Used to identify and protect against code errors |
|
bool valid() const WARN_IF_UNUSED; |
|
|
|
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL |
|
// debugging messages |
|
void debug() const; |
|
#endif |
|
|
|
// segment types |
|
enum class SegmentType { |
|
CONSTANT_JERK, |
|
POSITIVE_JERK, |
|
NEGATIVE_JERK |
|
}; |
|
|
|
// add single segment |
|
void add_segment(uint8_t &seg_pnt, float end_time, SegmentType seg_type, float jerk_ref, float end_accel, float end_vel, float end_pos); |
|
|
|
// members |
|
float jerk_time; // duration of jerk raised cosine time segment |
|
float jerk_max; // maximum jerk magnitude |
|
float accel_max; // maximum acceleration magnitude |
|
float vel_max; // maximum velocity magnitude |
|
float time; // time that defines position on the path |
|
float position_sq; // position (squared) on the path at the last time step (used to detect finish) |
|
|
|
// segment 0 is the initial segment and holds the vehicle's initial position and velocity |
|
// segments 1 to 7 are the acceleration segments |
|
// segments 8 to 14 are the speed change segments |
|
// segment 15 is the constant velocity segment |
|
// segment 16 to 22 is the deceleration segment |
|
const static uint8_t segments_max = 23; // maximum number of time segments |
|
|
|
uint8_t num_segs; // number of time segments being used |
|
struct { |
|
float jerk_ref; // jerk reference value for time segment (the jerk at the beginning, middle or end depending upon the segment type) |
|
SegmentType seg_type; // segment type (jerk is constant, increasing or decreasing) |
|
float end_time; // final time value for segment |
|
float end_accel; // final acceleration value for segment |
|
float end_vel; // final velocity value for segment |
|
float end_pos; // final position value for segment |
|
} segment[segments_max]; |
|
|
|
Vector3f track; // total change in position from origin to destination |
|
Vector3f delta_unit; // reference direction vector for path |
|
};
|
|
|