Formula Student Autonomous Systems
The code for the main driverless system
Loading...
Searching...
No Matches
velocity_planning.cpp
Go to the documentation of this file.
2
4 const PathPoint &p3) {
5 // lengths of the sides of the triangle formed by the three points
6 double a = std::hypot(p2.position.x - p1.position.x, p2.position.y - p1.position.y);
7 double b = std::hypot(p3.position.x - p2.position.x, p3.position.y - p2.position.y);
8 double c = std::hypot(p3.position.x - p1.position.x, p3.position.y - p1.position.y);
9
10 // area of the triangle using the determinant method
11 double area = 0.5 * std::abs(p1.position.x * (p2.position.y - p3.position.y) +
12 p2.position.x * (p3.position.y - p1.position.y) +
13 p3.position.x * (p1.position.y - p2.position.y));
14
15 // To avoid division by zero in case of near duplicate points
16 if (a * b * c < epsilon) {
17 return 0.0;
18 }
19
20 /* The Menger curvature is given by the formula: K = 4A / (abc),
21 where A is the triangle area and a,b,c are the side lengths*/
22 return 4 * area / (a * b * c);
23}
24
25void VelocityPlanning::point_speed(const std::vector<double> &curvatures,
26 std::vector<double> &velocities) {
27 for (const auto &k : curvatures) {
28 // This is a straight line, there is no curvature limit on the velocity
29 if (std::abs(k) < epsilon) {
30 velocities.push_back(config_.desired_velocity_);
31 continue;
32 }
33
34 double velocity = std::sqrt(config_.lateral_acceleration_ / std::abs(k));
35 velocities.push_back(std::min(velocity, config_.desired_velocity_));
36 }
37 // The last point is always the minimum velocity for safety
38 velocities.back() = config_.minimum_velocity_;
39}
40
41void VelocityPlanning::acceleration_limiter(const std::vector<PathPoint> &points,
42 std::vector<double> &velocities,
43 const std::vector<double> &curvatures) {
44 velocities[0] = config_.minimum_velocity_;
45 for (int i = 1; i < (int)points.size(); i++) {
46 double dx = points[i].position.x - points[i - 1].position.x;
47 double dy = points[i].position.y - points[i - 1].position.y;
48 double d = std::sqrt(dx * dx + dy * dy);
49
50 // lateral acceleration at previous point: v(i-1)^2 * curvature
51 double ay = std::min(velocities[i - 1] * velocities[i - 1] * std::abs(curvatures[i - 1]),
53 double ax_max =
54 std::sqrt(std::max(0.0, config_.acceleration_ * config_.acceleration_ - ay * ay));
55
56 // Cap by acceleration limit
57 ax_max = std::min(ax_max, config_.longitudinal_acceleration_);
58
59 // v_i^2 = v_(i-1)^2 + 2 * a_x_available * d
60 double max_velocity =
61 std::sqrt(std::max(0.0, velocities[i - 1] * velocities[i - 1] + 2 * ax_max * d));
62 velocities[i] = std::min(velocities[i], max_velocity);
63 }
64}
65
66void VelocityPlanning::braking_limiter(std::vector<PathPoint> &points,
67 std::vector<double> &velocities,
68 const std::vector<double> &curvatures) {
69 for (int i = static_cast<int>(points.size()) - 2; i >= 0; i--) {
70 // Calculate segment distance
71 int j = i + 1;
72 double distance = std::hypot(points[j].position.x - points[i].position.x,
73 points[j].position.y - points[i].position.y);
74
75 // Lateral acceleration at the next point: a = v(j)^2 * curvature
76 // Clamped to lateral_acceleration_ to avoid ay exceeding the lateral acceleration limit
77 double ay = std::min(velocities[j] * velocities[j] * std::abs(curvatures[j]),
79
80 // Friction ellipse: remaining longitudinal braking
81 double ax_brake =
82 std::sqrt(std::max(0.0, config_.acceleration_ * config_.acceleration_ - ay * ay));
83
84 // Cap by braking limit
85 ax_brake = -(std::min(ax_brake, config_.braking_acceleration_));
86
87 // Correct kinematic speed calculation
88 // v_f² = v_i² + 2ad
89 double max_speed =
90 std::sqrt(std::max(0.0, velocities[j] * velocities[j] + 2 * ax_brake * distance));
91
92 max_speed = std::min(max_speed, config_.desired_velocity_);
93 velocities[i] = std::min(max_speed, velocities[i]);
94 }
95}
96
97void VelocityPlanning::set_velocity(std::vector<PathPoint> &final_path) {
98 int path_size = static_cast<int>(final_path.size());
99
100 if (!config_.use_velocity_planning_ || path_size <= 3) {
101 for (auto &p : final_path) {
102 p.ideal_velocity = config_.minimum_velocity_;
103 }
104 return;
105 }
106
107 std::vector<double> curvatures(path_size, 0.0);
108 for (int i = 1; i < path_size - 1; ++i) {
109 curvatures[i] = find_curvature(final_path[i - 1], final_path[i], final_path[i + 1]);
110 }
111
112 std::vector<double> velocities;
113 point_speed(curvatures, velocities);
114 acceleration_limiter(final_path, velocities, curvatures);
115 braking_limiter(final_path, velocities, curvatures);
116
117 for (int i = 0; i < path_size; ++i) {
118 velocities[i] = std::max(velocities[i], config_.minimum_velocity_);
119 velocities[i] = std::min(velocities[i], config_.desired_velocity_);
120 final_path[i].ideal_velocity = velocities[i];
121 }
122}
123
124void VelocityPlanning::trackdrive_velocity(std::vector<PathPoint> &final_path) {
125 int path_size = static_cast<int>(final_path.size());
126 if (!config_.use_velocity_planning_ || path_size <= 3) {
127 for (auto &p : final_path) {
128 p.ideal_velocity = config_.minimum_velocity_;
129 }
130 return;
131 }
132
133 // Triple the path
134 std::vector<PathPoint> triple_path;
135 triple_path.reserve(3 * path_size);
136 for (int lap = 0; lap < 3; ++lap) {
137 for (int i = 0; i < path_size; ++i) {
138 triple_path.push_back(final_path[i]);
139 }
140 }
141
142 set_velocity(triple_path);
143
144 // Extract middle path velocities ----
145 int offset = path_size; // middle lap start
146 for (int i = 0; i < path_size; ++i) {
147 final_path[i].ideal_velocity = triple_path[offset + i].ideal_velocity;
148 }
149}
150
151void VelocityPlanning::stop(std::vector<PathPoint> &final_path, double braking_distance) {
152 int path_size = final_path.size();
153 if (path_size <= 3) {
154 for (auto &p : final_path) {
155 p.ideal_velocity = config_.minimum_velocity_;
156 }
157 RCLCPP_ERROR(rclcpp::get_logger("planning"), "Not enough path point to do velocity profile.");
158 return;
159 }
160
161 double dist = 0.0;
162 int index = 1;
163 while (dist < braking_distance && index < path_size) {
164 dist += final_path[index].position.euclidean_distance(final_path[index - 1].position);
165 ++index;
166 }
167
168 while (index < static_cast<int>(path_size) - 1 && final_path[index].ideal_velocity > 0.0) {
169 int j = index + 1;
170
171 // Segment distance
172 double d = final_path[j].position.euclidean_distance(final_path[index].position);
173
174 double vi = final_path[index].ideal_velocity;
175
176 // Lateral acceleration at current point
177 // Clamped to lateral_acceleration_ to avoid ay exceeding the lateral grip limit
178 double ay = std::min(vi * vi *
179 std::abs(find_curvature(final_path[std::max(index - 1, 0)],
180 final_path[index], final_path[j])),
182
183 // Friction ellipse: remaining longitudinal braking
184 double ax_available =
185 std::sqrt(std::max(0.0, config_.acceleration_ * config_.acceleration_ - ay * ay));
186
187 // Cap with maximum braking capability
188 ax_available = -(std::min(ax_available, -config_.braking_acceleration_));
189
190 // Forward braking kinematics: v_j^2 = v_i^2 + 2 * a * d
191 double vj = std::sqrt(std::max(0.0, vi * vi + 2.0 * ax_available * d));
192 vj = std::max(vj, 0.0);
193
194 final_path[j].ideal_velocity = std::min(final_path[j].ideal_velocity, vj);
195 ++index;
196 }
197
198 // After the car stop the rest of the points should have 0.0 speed
199 while (index < path_size) {
200 final_path[index].ideal_velocity = 0.0;
201 ++index;
202 }
203}
static constexpr double epsilon
Numerical tolerance for floating-point comparisons.
void acceleration_limiter(const std::vector< PathPoint > &points, std::vector< double > &velocities, const std::vector< double > &curvatures)
Limits velocities based on forward acceleration constraints and friction ellipse.
double find_curvature(const PathPoint &p1, const PathPoint &p2, const PathPoint &p3)
Computes the curvature at a point using the Menger curvature formula.
void point_speed(const std::vector< double > &curvatures, std::vector< double > &velocities)
Computes the maximum velocity at each point based on curvature constraints.
void braking_limiter(std::vector< PathPoint > &points, std::vector< double > &velocities, const std::vector< double > &curvatures)
Limits velocities based on backward braking constraints and friction ellipse.
VelocityPlanningConfig config_
configuration of the velocity planning algorithm
void stop(std::vector< PathPoint > &final_path, double braking_distance)
Applies a braking velocity profile starting after a given braking distance.
void set_velocity(std::vector< PathPoint > &final_path)
Assigns an velocity to each point of the path.
void trackdrive_velocity(std::vector< PathPoint > &final_path)
Computes velocity for trackdrive scenarios.
double desired_velocity_
The desired velocity of the car.
bool use_velocity_planning_
Flag to enable/disable velocity planning.
double lateral_acceleration_
Maximum lateral acceleration.
double acceleration_
Maximum forward acceleration.
double longitudinal_acceleration_
Maximum longitudinal acceleration.
double braking_acceleration_
Maximum braking acceleration.
double minimum_velocity_
Minimum speed in the velocity planning.