@@ -84,12 +84,20 @@ PathSampler::PathSampler(const rclcpp::NodeOptions & node_options)
84
84
declare_parameter<double >(" constraints.hard.max_curvature" );
85
85
params_.constraints .hard .min_curvature =
86
86
declare_parameter<double >(" constraints.hard.min_curvature" );
87
+ params_.constraints .hard .min_dist_from_obstacles =
88
+ declare_parameter<double >(" constraints.hard.min_distance_from_obstacles" );
89
+ params_.constraints .hard .limit_footprint_inside_drivable_area =
90
+ declare_parameter<bool >(" constraints.hard.limit_footprint_inside_drivable_area" );
87
91
params_.constraints .soft .lateral_deviation_weight =
88
92
declare_parameter<double >(" constraints.soft.lateral_deviation_weight" );
89
93
params_.constraints .soft .length_weight =
90
94
declare_parameter<double >(" constraints.soft.length_weight" );
91
95
params_.constraints .soft .curvature_weight =
92
96
declare_parameter<double >(" constraints.soft.curvature_weight" );
97
+ params_.path_reuse .max_lat_dev =
98
+ declare_parameter<double >(" path_reuse.maximum_lateral_deviation" );
99
+ params_.path_reuse .direct_reuse_dist =
100
+ declare_parameter<double >(" path_reuse.direct_reuse_distance" );
93
101
params_.sampling .enable_frenet = declare_parameter<bool >(" sampling.enable_frenet" );
94
102
params_.sampling .enable_bezier = declare_parameter<bool >(" sampling.enable_bezier" );
95
103
params_.sampling .resolution = declare_parameter<double >(" sampling.resolution" );
@@ -144,6 +152,12 @@ rcl_interfaces::msg::SetParametersResult PathSampler::onParam(
144
152
145
153
updateParam (parameters, " constraints.hard.max_curvature" , params_.constraints .hard .max_curvature );
146
154
updateParam (parameters, " constraints.hard.min_curvature" , params_.constraints .hard .min_curvature );
155
+ updateParam (
156
+ parameters, " constraints.hard.min_distance_from_obstacles" ,
157
+ params_.constraints .hard .min_dist_from_obstacles );
158
+ updateParam (
159
+ parameters, " constraints.hard.limit_footprint_inside_drivable_area" ,
160
+ params_.constraints .hard .limit_footprint_inside_drivable_area );
147
161
updateParam (
148
162
parameters, " constraints.soft.lateral_deviation_weight" ,
149
163
params_.constraints .soft .lateral_deviation_weight );
@@ -243,9 +257,8 @@ void PathSampler::onPath(const Path::SharedPtr path_ptr)
243
257
const auto generated_traj_points = generateTrajectory (planner_data);
244
258
// 3. extend trajectory to connect the optimized trajectory and the following path smoothly
245
259
if (!generated_traj_points.empty ()) {
246
- auto full_traj_points = extendTrajectory (planner_data.traj_points , generated_traj_points);
247
260
const auto output_traj_msg =
248
- motion_utils::convertToTrajectory (full_traj_points , path_ptr->header );
261
+ motion_utils::convertToTrajectory (generated_traj_points , path_ptr->header );
249
262
traj_pub_->publish (output_traj_msg);
250
263
} else {
251
264
auto stopping_traj = trajectory_utils::convertToTrajectoryPoints (planner_data.traj_points );
@@ -367,7 +380,7 @@ std::vector<TrajectoryPoint> PathSampler::generateTrajectory(const PlannerData &
367
380
368
381
const auto & input_traj_points = planner_data.traj_points ;
369
382
370
- auto generated_traj_points = generatePath (planner_data);
383
+ auto generated_traj_points = generateTrajectoryPoints (planner_data);
371
384
372
385
copyVelocity (input_traj_points, generated_traj_points, planner_data.ego_pose );
373
386
copyZ (input_traj_points, generated_traj_points);
@@ -377,65 +390,89 @@ std::vector<TrajectoryPoint> PathSampler::generateTrajectory(const PlannerData &
377
390
return generated_traj_points;
378
391
}
379
392
380
- std::vector<TrajectoryPoint> PathSampler::generatePath (const PlannerData & planner_data)
393
+ std::vector<sampler_common::Path> PathSampler::generateCandidatesFromPreviousPath (
394
+ const PlannerData & planner_data, const sampler_common::transform::Spline2D & path_spline)
381
395
{
382
- std::vector<TrajectoryPoint> trajectory;
383
- time_keeper_ptr_->tic (__func__);
384
- const auto & p = planner_data;
385
-
386
- const auto path_spline = preparePathSpline (p.traj_points , params_.preprocessing .smooth_reference );
396
+ std::vector<sampler_common::Path> candidates;
397
+ if (!prev_path_ || prev_path_->points .size () < 2 ) return candidates;
398
+ // Update previous path
387
399
sampler_common::State current_state;
388
400
current_state.pose = {planner_data.ego_pose .position .x , planner_data.ego_pose .position .y };
389
401
current_state.heading = tf2::getYaw (planner_data.ego_pose .orientation );
402
+ const auto closest_iter = std::min_element (
403
+ prev_path_->points .begin (), prev_path_->points .end () - 1 ,
404
+ [&](const auto & p1, const auto & p2) {
405
+ return boost::geometry::distance (p1, current_state.pose ) <=
406
+ boost::geometry::distance (p2, current_state.pose );
407
+ });
408
+ if (closest_iter != prev_path_->points .end ()) {
409
+ const auto current_idx = std::distance (prev_path_->points .begin (), closest_iter);
410
+ const auto length_offset = prev_path_->lengths [current_idx];
411
+ for (auto & l : prev_path_->lengths ) l -= length_offset;
412
+ constexpr auto behind_dist = -5.0 ; // [m] TODO(Maxime): param
413
+ auto behind_idx = current_idx;
414
+ while (behind_idx > 0 && prev_path_->lengths [behind_idx] > behind_dist) --behind_idx;
415
+ *prev_path_ = *prev_path_->subset (behind_idx, prev_path_->points .size ());
416
+
417
+ // Use previous path for replanning
418
+ const auto prev_path_length = prev_path_->lengths .back ();
419
+ const auto reuse_step = prev_path_length / params_.sampling .previous_path_reuse_points_nb ;
420
+ for (double reuse_length = reuse_step; reuse_length <= prev_path_length;
421
+ reuse_length += reuse_step) {
422
+ sampler_common::State reuse_state;
423
+ size_t reuse_idx = 0 ;
424
+ for (reuse_idx = 0 ; reuse_idx + 1 < prev_path_->lengths .size () &&
425
+ prev_path_->lengths [reuse_idx] < reuse_length;
426
+ ++reuse_idx)
427
+ ;
428
+ if (reuse_idx == 0UL ) continue ;
429
+ const auto reused_path = *prev_path_->subset (0UL , reuse_idx);
430
+ reuse_state.curvature = reused_path.curvatures .back ();
431
+ reuse_state.pose = reused_path.points .back ();
432
+ reuse_state.heading = reused_path.yaws .back ();
433
+ reuse_state.frenet = path_spline.frenet (reuse_state.pose );
434
+ auto paths = generateCandidatePaths (reuse_state, path_spline, reuse_length, params_);
435
+ for (auto & p : paths) candidates.push_back (reused_path.extend (p));
436
+ }
437
+ }
438
+ return candidates;
439
+ }
390
440
391
- const auto planning_state = getPlanningState (current_state, path_spline);
392
- prepareConstraints (params_.constraints , *in_objects_ptr_, p.left_bound , p.right_bound );
393
-
394
- auto candidate_paths = generateCandidatePaths (planning_state, path_spline, 0.0 , params_);
395
- if (prev_path_ && prev_path_->lengths .size () > 1 ) {
396
- // Update previous path
397
- constexpr auto max_deviation = 2.0 ; // [m] TODO(Maxime): param
398
- const auto closest_iter = std::min_element (
399
- prev_path_->points .begin (), prev_path_->points .end () - 1 ,
400
- [&](const auto & p1, const auto & p2) {
401
- return boost::geometry::distance (p1, current_state.pose ) <=
402
- boost::geometry::distance (p2, current_state.pose );
403
- });
404
- if (
405
- closest_iter != prev_path_->points .end () &&
406
- boost::geometry::distance (*closest_iter, current_state.pose ) <= max_deviation) {
407
- const auto current_idx = std::distance (prev_path_->points .begin (), closest_iter);
408
- const auto length_offset = prev_path_->lengths [current_idx];
409
- for (auto & l : prev_path_->lengths ) l -= length_offset;
410
- constexpr auto behind_dist = -5.0 ; // [m] TODO(Maxime): param
411
- auto behind_idx = current_idx;
412
- while (behind_idx > 0 && prev_path_->lengths [behind_idx] > behind_dist) --behind_idx;
413
- *prev_path_ = *prev_path_->subset (behind_idx, prev_path_->points .size ());
414
-
415
- // Use previous path for replanning
416
- const auto prev_path_length = prev_path_->lengths .back ();
417
- const auto reuse_step = prev_path_length / params_.sampling .previous_path_reuse_points_nb ;
418
- for (double reuse_length = reuse_step; reuse_length <= prev_path_length;
419
- reuse_length += reuse_step) {
420
- sampler_common::State reuse_state;
421
- size_t reuse_idx = 0 ;
422
- for (reuse_idx = 0 ; reuse_idx + 1 < prev_path_->lengths .size () &&
423
- prev_path_->lengths [reuse_idx] < reuse_length;
424
- ++reuse_idx)
425
- ;
426
- if (reuse_idx == 0UL ) continue ;
427
- const auto reused_path = *prev_path_->subset (0UL , reuse_idx);
428
- reuse_state.curvature = reused_path.curvatures .back ();
429
- reuse_state.pose = reused_path.points .back ();
430
- reuse_state.heading = reused_path.yaws .back ();
431
- reuse_state.frenet = path_spline.frenet (reuse_state.pose );
432
- auto paths = generateCandidatePaths (reuse_state, path_spline, reuse_length, params_);
433
- for (auto & p : paths) candidate_paths.push_back (reused_path.extend (p));
434
- }
441
+ sampler_common::Path PathSampler::generatePath (const PlannerData & planner_data)
442
+ {
443
+ time_keeper_ptr_->tic (__func__);
444
+ sampler_common::Path generated_path{};
445
+
446
+ if (prev_path_ && prev_path_->points .size () > 1 ) {
447
+ sampler_common::constraints::checkHardConstraints (*prev_path_, params_.constraints );
448
+ if (prev_path_->constraint_results .isValid ()) {
449
+ const auto prev_path_spline =
450
+ preparePathSpline (trajectory_utils::convertToTrajectoryPoints (*prev_path_), false );
451
+ const auto frenet_p = prev_path_spline.frenet (
452
+ {planner_data.ego_pose .position .x , planner_data.ego_pose .position .y });
453
+ if (std::abs (frenet_p.d ) > params_.path_reuse .max_lat_dev || frenet_p.s < 0.0 )
454
+ resetPreviousData ();
455
+ else if (frenet_p.s <= params_.path_reuse .direct_reuse_dist )
456
+ return *prev_path_;
435
457
} else {
436
458
resetPreviousData ();
437
459
}
438
460
}
461
+ const auto path_spline =
462
+ preparePathSpline (planner_data.traj_points , params_.preprocessing .smooth_reference );
463
+ sampler_common::State current_state;
464
+ current_state.pose = {planner_data.ego_pose .position .x , planner_data.ego_pose .position .y };
465
+ current_state.heading = tf2::getYaw (planner_data.ego_pose .orientation );
466
+
467
+ const auto planning_state = getPlanningState (current_state, path_spline);
468
+ prepareConstraints (
469
+ params_.constraints , *in_objects_ptr_, planner_data.left_bound , planner_data.right_bound );
470
+
471
+ auto candidate_paths = generateCandidatePaths (planning_state, path_spline, 0.0 , params_);
472
+ const auto candidates_from_prev_path =
473
+ generateCandidatesFromPreviousPath (planner_data, path_spline);
474
+ candidate_paths.insert (
475
+ candidate_paths.end (), candidates_from_prev_path.begin (), candidates_from_prev_path.end ());
439
476
debug_data_.footprints .clear ();
440
477
for (auto & path : candidate_paths) {
441
478
const auto footprint =
@@ -457,9 +494,7 @@ std::vector<TrajectoryPoint> PathSampler::generatePath(const PlannerData & plann
457
494
};
458
495
const auto selected_path_idx = best_path_idx (candidate_paths);
459
496
if (selected_path_idx) {
460
- const auto & selected_path = candidate_paths[*selected_path_idx];
461
- trajectory = trajectory_utils::convertToTrajectoryPoints (selected_path);
462
- prev_path_ = selected_path;
497
+ generated_path = candidate_paths[*selected_path_idx];
463
498
} else {
464
499
RCLCPP_WARN (
465
500
get_logger (), " No valid path found (out of %lu) outputting %s\n " , candidate_paths.size (),
@@ -468,18 +503,28 @@ std::vector<TrajectoryPoint> PathSampler::generatePath(const PlannerData & plann
468
503
int da = 0 ;
469
504
int k = 0 ;
470
505
for (const auto & p : candidate_paths) {
471
- coll += static_cast <int >(!p.constraint_results .collision );
472
- da += static_cast <int >(!p.constraint_results .drivable_area );
473
- k += static_cast <int >(!p.constraint_results .curvature );
506
+ coll += static_cast <int >(!p.constraint_results .collision_free );
507
+ da += static_cast <int >(!p.constraint_results .inside_drivable_area );
508
+ k += static_cast <int >(!p.constraint_results .valid_curvature );
474
509
}
475
510
RCLCPP_WARN (get_logger (), " \t Invalid coll/da/k = %d/%d/%d\n " , coll, da, k);
476
- if (prev_path_) trajectory = trajectory_utils::convertToTrajectoryPoints ( *prev_path_) ;
511
+ if (prev_path_) generated_path = *prev_path_;
477
512
}
478
513
time_keeper_ptr_->toc (__func__, " " );
479
514
debug_data_.previous_sampled_candidates_nb = debug_data_.sampled_candidates .size ();
480
515
debug_data_.sampled_candidates = candidate_paths;
481
516
debug_data_.obstacles = params_.constraints .obstacle_polygons ;
482
- return trajectory;
517
+
518
+ prev_path_ = generated_path;
519
+ return generated_path;
520
+ }
521
+
522
+ std::vector<TrajectoryPoint> PathSampler::generateTrajectoryPoints (const PlannerData & planner_data)
523
+ {
524
+ std::vector<TrajectoryPoint> trajectory;
525
+ time_keeper_ptr_->tic (__func__);
526
+ const auto path = generatePath (planner_data);
527
+ return trajectory_utils::convertToTrajectoryPoints (path);
483
528
}
484
529
485
530
void PathSampler::publishVirtualWall (const geometry_msgs::msg::Pose & stop_pose) const
0 commit comments