@@ -269,106 +269,104 @@ void RegulatedPurePursuitController::computeOptimalVelocityUsingDynamicWindow(
269269 dynamic_window_max_angular_vel,
270270 dynamic_window_min_angular_vel);
271271
272- // Reflect regulated v (tighten upper limit)
272+ // clip dynamic window's max linear velocity to regulated linear velocity
273273 if (dynamic_window_max_linear_vel > regulated_linear_vel) {
274274 dynamic_window_max_linear_vel = std::max (dynamic_window_min_linear_vel, regulated_linear_vel);
275275 }
276276
277- const double k = curvature;
277+ // consider linear_vel - angular_vel space (horizontal and vertical axes respectively)
278+ // Select the closest point to the line angular_vel = curvature * linear_vel within the dynamic window.
279+ // If multiple points are equally close, select the one with the highest linear_vel.
278280
279- // ---- Curvature is 0 (w = 0) ----
280- if (abs (k ) < 1e-3 ) {
281- // If w=0 is within DW, then the maximum linear speed is adopted as it is.
281+ // When curvature == 0, the line is angular_vel = 0
282+ if (abs (curvature ) < 1e-3 ) {
283+ // If the line angular_vel = 0 intersects the dynamic window, select (dynamic_window_max_linear_vel, 0)
282284 if (dynamic_window_min_angular_vel <= 0.0 && 0.0 <= dynamic_window_max_angular_vel) {
283- optimal_linear_vel = dynamic_window_max_linear_vel; // Always maximum v
285+ optimal_linear_vel = dynamic_window_max_linear_vel;
284286 optimal_angular_vel = 0.0 ;
285- return ;
287+ } else {
288+ // If not, select (dynamic_window_max_linear_vel, angular vel within dynamic window closest to 0)
289+ optimal_linear_vel = dynamic_window_max_linear_vel;
290+ if (std::abs (dynamic_window_min_angular_vel) <= std::abs (dynamic_window_max_angular_vel)) {
291+ optimal_angular_vel = dynamic_window_min_angular_vel;
292+ } else {
293+ optimal_angular_vel = dynamic_window_max_angular_vel;
294+ }
286295 }
287- // If w=0 is outside, choose the side closer to w=0 and with smaller |w|.
288- const double w_choice = (std::abs (dynamic_window_min_angular_vel) <=
289- std::abs (dynamic_window_max_angular_vel)) ? dynamic_window_min_angular_vel :
290- dynamic_window_max_angular_vel;
291- optimal_linear_vel = dynamic_window_max_linear_vel; // Always maximum v
292- optimal_angular_vel = w_choice;
293296 return ;
294297 }
295298
296- // ---- 2) Select 'max v' from the candidates in the DW among the intersections. ----
297- double best_v = -std::numeric_limits<double >::infinity (); // Initial value for maximization
298- double best_w = 0.0 ;
299-
300- // Intersection with vertical edges
301- {
302- const double v1 = dynamic_window_min_linear_vel;
303- const double w1 = k * v1;
304- if (w1 >= dynamic_window_min_angular_vel && w1 <= dynamic_window_max_angular_vel) {
305- if (v1 > best_v) {best_v = v1; best_w = w1;}
306- }
307- }
308- {
309- const double v2 = dynamic_window_max_linear_vel;
310- const double w2 = k * v2;
311- if (w2 >= dynamic_window_min_angular_vel && w2 <= dynamic_window_max_angular_vel) {
312- if (v2 > best_v) {best_v = v2; best_w = w2;}
313- }
314- }
315-
316- // Intersection with horizontal edge (k ! = 0)
317- {
318- const double v3 = dynamic_window_min_angular_vel / k;
319- if (v3 >= dynamic_window_min_linear_vel && v3 <= dynamic_window_max_linear_vel) {
320- const double w3 = dynamic_window_min_angular_vel;
321- if (v3 > best_v) {best_v = v3; best_w = w3;}
322- }
323- }
324- {
325- const double v4 = dynamic_window_max_angular_vel / k;
326- if (v4 >= dynamic_window_min_linear_vel && v4 <= dynamic_window_max_linear_vel) {
327- const double w4 = dynamic_window_max_angular_vel;
328- if (v4 > best_v) {best_v = v4; best_w = w4;}
299+ // When the dynamic window and the line angular_vel = curvature * linear_vel intersect,
300+ // select the intersection point that yields the highest linear velocity.
301+
302+ // List the four candidate intersection points
303+ std::pair<double , double > candidates[] = {
304+ {dynamic_window_min_linear_vel, curvature * dynamic_window_min_linear_vel},
305+ {dynamic_window_max_linear_vel, curvature * dynamic_window_max_linear_vel},
306+ {dynamic_window_min_angular_vel / curvature, dynamic_window_min_angular_vel},
307+ {dynamic_window_max_angular_vel / curvature, dynamic_window_max_angular_vel}
308+ };
309+
310+ double best_linear_vel = -std::numeric_limits<double >::infinity ();
311+ double best_angular_vel = 0.0 ;
312+
313+ for (auto [linear_vel, angular_vel] : candidates) {
314+ // Check whether the candidate lies within the dynamic window
315+ if (linear_vel >= dynamic_window_min_linear_vel &&
316+ linear_vel <= dynamic_window_max_linear_vel &&
317+ angular_vel >= dynamic_window_min_angular_vel &&
318+ angular_vel <= dynamic_window_max_angular_vel)
319+ {
320+ // Update if this candidate has the highest linear velocity so far
321+ if (linear_vel > best_linear_vel) {
322+ best_linear_vel = linear_vel;
323+ best_angular_vel = angular_vel;
324+ }
329325 }
330326 }
331327
332- if (best_v > -std::numeric_limits< double >:: infinity ()) {
333- // Intersection found → Adopt max. v
334- optimal_linear_vel = best_v ;
335- optimal_angular_vel = best_w ;
328+ // If best_linear_vel was updated, it means that a valid intersection exists
329+ if (best_linear_vel > -std::numeric_limits< double >:: infinity ()) {
330+ optimal_linear_vel = best_linear_vel ;
331+ optimal_angular_vel = best_angular_vel ;
336332 return ;
337333 }
338334
339- // ---- 3) If no intersection exists: Select the one with the smallest
340- // Euclidean distance to the line w = k v among the 4 corners
335+ // When the dynamic window and the line angular_vel = curvature * linear_vel have no intersection,
336+ // select the point within the dynamic window that is closest to the line.
337+
338+ // Because the dynamic window is a convex region, the closest point must be one of its four corners.
341339 const std::array<std::array<double , 2 >, 4 > corners = {{
342340 {dynamic_window_min_linear_vel, dynamic_window_min_angular_vel},
343341 {dynamic_window_min_linear_vel, dynamic_window_max_angular_vel},
344342 {dynamic_window_max_linear_vel, dynamic_window_min_angular_vel},
345343 {dynamic_window_max_linear_vel, dynamic_window_max_angular_vel}
346344 }};
347345
348- const double denom = std::sqrt (k * k + 1.0 ); // Just sqrt once
349-
350- auto euclid_dist = [&](const std::array<double , 2 > & corner) -> double {
351- // Distance from point (v, w) to line w - k v = 0
352- return std::abs (k * corner[0 ] - corner[1 ]) / denom;
346+ // Compute the distance from a point (linear_vel, angular_vel) to the line angular_vel = curvature * linear_vel
347+ const double denom = std::sqrt (curvature * curvature + 1.0 );
348+ auto compute_dist = [&](const std::array<double , 2 > & corner) -> double {
349+ return std::abs (curvature * corner[0 ] - corner[1 ]) / denom;
353350 };
354351
355- double best_dist = std::numeric_limits<double >::infinity ();
356- best_v = corners[ 0 ][ 0 ] ;
357- best_w = corners[ 0 ][ 1 ] ;
352+ double closest_dist = std::numeric_limits<double >::infinity ();
353+ best_linear_vel = -std::numeric_limits< double >:: infinity () ;
354+ best_angular_vel = 0.0 ;
358355
359356 for (const auto & corner : corners) {
360- const double d = euclid_dist (corner);
361- // 1) Smaller distance → Adopted
362- // 2) If distances are equal (~1e-12) → Choose the one with larger v (acceleration policy)
363- if (d < best_dist || (std::abs (d - best_dist) <= 1e-3 && corner[0 ] > best_v)) {
364- best_dist = d;
365- best_v = corner[0 ];
366- best_w = corner[1 ];
357+ const double dist = compute_dist (corner);
358+ // Update if this corner is closer to the line, or equally close but has a higher linear velocity
359+ if (dist < closest_dist ||
360+ (std::abs (dist - closest_dist) <= 1e-3 && corner[0 ] > best_linear_vel))
361+ {
362+ closest_dist = dist;
363+ best_linear_vel = corner[0 ];
364+ best_angular_vel = corner[1 ];
367365 }
368366 }
369367
370- optimal_linear_vel = best_v ;
371- optimal_angular_vel = best_w ;
368+ optimal_linear_vel = best_linear_vel ;
369+ optimal_angular_vel = best_angular_vel ;
372370}
373371
374372geometry_msgs::msg::TwistStamped RegulatedPurePursuitController::computeVelocityCommands (
0 commit comments