mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-29 05:23:33 +08:00
ackermann: implement pure pursuit lib
This commit is contained in:
committed by
Mathieu Bresciani
parent
f2bca92221
commit
f8bebd9e41
@@ -4,6 +4,5 @@ float32 desired_speed # [m/s] Rover desired ground speed
|
|||||||
float32 lookahead_distance # [m] Lookahead distance of pure the pursuit controller
|
float32 lookahead_distance # [m] Lookahead distance of pure the pursuit controller
|
||||||
float32 heading_error # [deg] Heading error of the pure pursuit controller
|
float32 heading_error # [deg] Heading error of the pure pursuit controller
|
||||||
float32 pid_throttle_integral # [-1, 1] Integral of the PID for the normalized throttle to control the rover speed during missions
|
float32 pid_throttle_integral # [-1, 1] Integral of the PID for the normalized throttle to control the rover speed during missions
|
||||||
float32 crosstrack_error # [m] Shortest distance from the vehicle to the path
|
|
||||||
|
|
||||||
# TOPICS rover_ackermann_guidance_status
|
# TOPICS rover_ackermann_guidance_status
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ px4_add_module(
|
|||||||
RoverAckermannGuidance
|
RoverAckermannGuidance
|
||||||
px4_work_queue
|
px4_work_queue
|
||||||
SlewRate
|
SlewRate
|
||||||
|
pure_pursuit
|
||||||
MODULE_CONFIG
|
MODULE_CONFIG
|
||||||
module.yaml
|
module.yaml
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -209,21 +209,24 @@ void RoverAckermannGuidance::updateWaypoints()
|
|||||||
_position_setpoint_triplet_sub.copy(&position_setpoint_triplet);
|
_position_setpoint_triplet_sub.copy(&position_setpoint_triplet);
|
||||||
|
|
||||||
// Global waypoint coordinates
|
// Global waypoint coordinates
|
||||||
if (position_setpoint_triplet.current.valid) {
|
if (position_setpoint_triplet.current.valid && PX4_ISFINITE(position_setpoint_triplet.current.lat)
|
||||||
|
&& PX4_ISFINITE(position_setpoint_triplet.current.lon)) {
|
||||||
_curr_wp = Vector2d(position_setpoint_triplet.current.lat, position_setpoint_triplet.current.lon);
|
_curr_wp = Vector2d(position_setpoint_triplet.current.lat, position_setpoint_triplet.current.lon);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_curr_wp = Vector2d(0, 0);
|
_curr_wp = Vector2d(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (position_setpoint_triplet.previous.valid) {
|
if (position_setpoint_triplet.previous.valid && PX4_ISFINITE(position_setpoint_triplet.previous.lat)
|
||||||
|
&& PX4_ISFINITE(position_setpoint_triplet.previous.lon)) {
|
||||||
_prev_wp = Vector2d(position_setpoint_triplet.previous.lat, position_setpoint_triplet.previous.lon);
|
_prev_wp = Vector2d(position_setpoint_triplet.previous.lat, position_setpoint_triplet.previous.lon);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_prev_wp = _curr_pos;
|
_prev_wp = _curr_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (position_setpoint_triplet.next.valid) {
|
if (position_setpoint_triplet.next.valid && PX4_ISFINITE(position_setpoint_triplet.next.lat)
|
||||||
|
&& PX4_ISFINITE(position_setpoint_triplet.next.lon)) {
|
||||||
_next_wp = Vector2d(position_setpoint_triplet.next.lat, position_setpoint_triplet.next.lon);
|
_next_wp = Vector2d(position_setpoint_triplet.next.lat, position_setpoint_triplet.next.lon);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -280,45 +283,16 @@ float RoverAckermannGuidance::calcDesiredSteering(const Vector2f &curr_wp_local,
|
|||||||
const Vector2f &curr_pos_local, const float &lookahead_gain, const float &lookahead_min, const float &lookahead_max,
|
const Vector2f &curr_pos_local, const float &lookahead_gain, const float &lookahead_min, const float &lookahead_max,
|
||||||
const float &wheel_base, const float &desired_speed, const float &vehicle_yaw)
|
const float &wheel_base, const float &desired_speed, const float &vehicle_yaw)
|
||||||
{
|
{
|
||||||
// Calculate crosstrack error
|
|
||||||
const Vector2f prev_wp_to_curr_wp_local = curr_wp_local - prev_wp_local;
|
|
||||||
|
|
||||||
if (prev_wp_to_curr_wp_local.norm() < FLT_EPSILON) { // Avoid division by 0 (this case should not happen)
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Vector2f prev_wp_to_curr_pos_local = curr_pos_local - prev_wp_local;
|
|
||||||
const Vector2f distance_on_line_segment = ((prev_wp_to_curr_pos_local * prev_wp_to_curr_wp_local) /
|
|
||||||
prev_wp_to_curr_wp_local.norm()) * prev_wp_to_curr_wp_local.normalized();
|
|
||||||
const Vector2f crosstrack_error = (prev_wp_local + distance_on_line_segment) - curr_pos_local;
|
|
||||||
|
|
||||||
// Calculate desired heading towards lookahead point
|
|
||||||
float desired_heading{0.f};
|
|
||||||
float lookahead_distance = math::constrain(lookahead_gain * desired_speed,
|
|
||||||
lookahead_min, lookahead_max);
|
|
||||||
|
|
||||||
if (crosstrack_error.longerThan(lookahead_distance)) {
|
|
||||||
if (crosstrack_error.norm() < lookahead_max) {
|
|
||||||
lookahead_distance = crosstrack_error.norm(); // Scale lookahead radius
|
|
||||||
desired_heading = calcDesiredHeading(curr_wp_local, prev_wp_local, curr_pos_local, lookahead_distance);
|
|
||||||
|
|
||||||
} else { // Excessively large crosstrack error
|
|
||||||
desired_heading = calcDesiredHeading(curr_wp_local, curr_pos_local, curr_pos_local, lookahead_distance);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else { // Crosstrack error smaller than lookahead
|
|
||||||
desired_heading = calcDesiredHeading(curr_wp_local, prev_wp_local, curr_pos_local, lookahead_distance);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate desired steering to reach lookahead point
|
// Calculate desired steering to reach lookahead point
|
||||||
|
const float lookahead_distance = math::constrain(lookahead_gain * desired_speed,
|
||||||
|
lookahead_min, lookahead_max);
|
||||||
|
const float desired_heading = _pure_pursuit.calcDesiredHeading(curr_wp_local, prev_wp_local, curr_pos_local,
|
||||||
|
lookahead_distance);
|
||||||
const float heading_error = matrix::wrap_pi(desired_heading - vehicle_yaw);
|
const float heading_error = matrix::wrap_pi(desired_heading - vehicle_yaw);
|
||||||
|
|
||||||
// For logging
|
// For logging
|
||||||
_rover_ackermann_guidance_status.lookahead_distance = lookahead_distance;
|
_rover_ackermann_guidance_status.lookahead_distance = lookahead_distance;
|
||||||
_rover_ackermann_guidance_status.heading_error = (heading_error * 180.f) / (M_PI_F);
|
_rover_ackermann_guidance_status.heading_error = (heading_error * 180.f) / (M_PI_F);
|
||||||
_rover_ackermann_guidance_status.crosstrack_error = crosstrack_error.norm();
|
|
||||||
|
|
||||||
// Calculate desired steering
|
|
||||||
if (math::abs_t(heading_error) <= M_PI_2_F) {
|
if (math::abs_t(heading_error) <= M_PI_2_F) {
|
||||||
return atanf(2 * wheel_base * sinf(heading_error) / lookahead_distance);
|
return atanf(2 * wheel_base * sinf(heading_error) / lookahead_distance);
|
||||||
|
|
||||||
@@ -330,47 +304,5 @@ float RoverAckermannGuidance::calcDesiredSteering(const Vector2f &curr_wp_local,
|
|||||||
return atanf(2 * wheel_base * (-1.0f + sinf(heading_error + M_PI_2_F)) /
|
return atanf(2 * wheel_base * (-1.0f + sinf(heading_error + M_PI_2_F)) /
|
||||||
lookahead_distance);
|
lookahead_distance);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
float RoverAckermannGuidance::calcDesiredHeading(const Vector2f &curr_wp_local, const Vector2f &prev_wp_local,
|
|
||||||
const Vector2f &curr_pos_local,
|
|
||||||
const float &lookahead_distance)
|
|
||||||
{
|
|
||||||
// Setup variables
|
|
||||||
const float line_segment_slope = (curr_wp_local(1) - prev_wp_local(1)) / (curr_wp_local(0) - prev_wp_local(0));
|
|
||||||
const float line_segment_rover_offset = prev_wp_local(1) - curr_pos_local(1) + line_segment_slope * (curr_pos_local(
|
|
||||||
0) - prev_wp_local(0));
|
|
||||||
const float a = -line_segment_slope;
|
|
||||||
const float c = -line_segment_rover_offset;
|
|
||||||
const float r = lookahead_distance;
|
|
||||||
const float x0 = -a * c / (a * a + 1.0f);
|
|
||||||
const float y0 = -c / (a * a + 1.0f);
|
|
||||||
|
|
||||||
// Calculate intersection points
|
|
||||||
if (c * c > r * r * (a * a + 1.0f) + FLT_EPSILON) { // No intersection points exist
|
|
||||||
return 0.f;
|
|
||||||
|
|
||||||
} else if (abs(c * c - r * r * (a * a + 1.0f)) < FLT_EPSILON) { // One intersection point exists
|
|
||||||
return atan2f(y0, x0);
|
|
||||||
|
|
||||||
} else { // Two intersetion points exist
|
|
||||||
const float d = r * r - c * c / (a * a + 1.0f);
|
|
||||||
const float mult = sqrt(d / (a * a + 1.0f));
|
|
||||||
const float ax = x0 + mult;
|
|
||||||
const float bx = x0 - mult;
|
|
||||||
const float ay = y0 - a * mult;
|
|
||||||
const float by = y0 + a * mult;
|
|
||||||
const Vector2f point1(ax, ay);
|
|
||||||
const Vector2f point2(bx, by);
|
|
||||||
const Vector2f distance1 = (curr_wp_local - curr_pos_local) - point1;
|
|
||||||
const Vector2f distance2 = (curr_wp_local - curr_pos_local) - point2;
|
|
||||||
|
|
||||||
// Return intersection point closer to current waypoint
|
|
||||||
if (distance1.norm_squared() < distance2.norm_squared()) {
|
|
||||||
return atan2f(ay, ax);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return atan2f(by, bx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
|
|
||||||
// PX4 includes
|
// PX4 includes
|
||||||
#include <px4_platform_common/module_params.h>
|
#include <px4_platform_common/module_params.h>
|
||||||
|
#include <lib/pure_pursuit/PurePursuit.hpp>
|
||||||
|
|
||||||
// uORB includes
|
// uORB includes
|
||||||
#include <uORB/Publication.hpp>
|
#include <uORB/Publication.hpp>
|
||||||
@@ -121,17 +122,6 @@ public:
|
|||||||
const float &lookahead_gain, const float &lookahead_min, const float &lookahead_max, const float &wheel_base,
|
const float &lookahead_gain, const float &lookahead_min, const float &lookahead_max, const float &wheel_base,
|
||||||
const float &desired_speed, const float &vehicle_yaw);
|
const float &desired_speed, const float &vehicle_yaw);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return desired heading to the intersection point between a circle with a radius of
|
|
||||||
* lookahead_distance around the vehicle and a line segment from the previous to the current waypoint.
|
|
||||||
* @param curr_wp_local Current waypoint in local frame.
|
|
||||||
* @param prev_wp_local Previous waypoint in local frame.
|
|
||||||
* @param curr_pos_local Current position of the vehicle in local frame.
|
|
||||||
* @param lookahead_distance Radius of circle around vehicle.
|
|
||||||
*/
|
|
||||||
float calcDesiredHeading(const Vector2f &curr_wp_local, const Vector2f &prev_wp_local, const Vector2f &curr_pos_local,
|
|
||||||
const float &lookahead_distance);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief Update the parameters of the module.
|
* @brief Update the parameters of the module.
|
||||||
@@ -154,6 +144,7 @@ private:
|
|||||||
|
|
||||||
|
|
||||||
MapProjection _global_local_proj_ref{}; // Transform global to local coordinates.
|
MapProjection _global_local_proj_ref{}; // Transform global to local coordinates.
|
||||||
|
PurePursuit _pure_pursuit; // Pure pursuit library
|
||||||
|
|
||||||
// Rover variables
|
// Rover variables
|
||||||
Vector2d _curr_pos{};
|
Vector2d _curr_pos{};
|
||||||
|
|||||||
Reference in New Issue
Block a user