Skip to content

Commit 35d1ecc

Browse files
authored
Merge pull request #1419 from tier4/fix/start_goal_v0.26.1
fix(start/goal_planner): improve start/goal planner
2 parents ac9a23c + b2144aa commit 35d1ecc

File tree

12 files changed

+221
-60
lines changed

12 files changed

+221
-60
lines changed

common/motion_utils/include/motion_utils/trajectory/trajectory.hpp

+33-15
Original file line numberDiff line numberDiff line change
@@ -994,33 +994,51 @@ calcCurvature<std::vector<autoware_auto_planning_msgs::msg::TrajectoryPoint>>(
994994
* curvature calculation
995995
*/
996996
template <class T>
997-
std::vector<std::pair<double, double>> calcCurvatureAndArcLength(const T & points)
997+
std::vector<std::pair<double, std::pair<double, double>>> calcCurvatureAndSegmentLength(
998+
const T & points)
998999
{
999-
// Note that arclength is for the segment, not the sum.
1000-
std::vector<std::pair<double, double>> curvature_arc_length_vec;
1001-
curvature_arc_length_vec.emplace_back(0.0, 0.0);
1000+
// segment length is pair of segment length between {p1, p2} and {p2, p3}
1001+
std::vector<std::pair<double, std::pair<double, double>>> curvature_and_segment_length_vec;
1002+
curvature_and_segment_length_vec.reserve(points.size());
1003+
curvature_and_segment_length_vec.emplace_back(0.0, std::make_pair(0.0, 0.0));
10021004
for (size_t i = 1; i < points.size() - 1; ++i) {
10031005
const auto p1 = tier4_autoware_utils::getPoint(points.at(i - 1));
10041006
const auto p2 = tier4_autoware_utils::getPoint(points.at(i));
10051007
const auto p3 = tier4_autoware_utils::getPoint(points.at(i + 1));
10061008
const double curvature = tier4_autoware_utils::calcCurvature(p1, p2, p3);
1007-
const double arc_length = tier4_autoware_utils::calcDistance2d(points.at(i - 1), points.at(i)) +
1008-
tier4_autoware_utils::calcDistance2d(points.at(i), points.at(i + 1));
1009-
curvature_arc_length_vec.emplace_back(curvature, arc_length);
1009+
1010+
// The first point has only the next point, so put the distance to that point.
1011+
// In other words, assign the first segment length at the second point to the
1012+
// second_segment_length at the first point.
1013+
if (i == 1) {
1014+
curvature_and_segment_length_vec.at(0).second.second =
1015+
tier4_autoware_utils::calcDistance2d(p1, p2);
1016+
}
1017+
1018+
// The second_segment_length of the previous point and the first segment length of the current
1019+
// point are equal.
1020+
const std::pair<double, double> arc_length{
1021+
curvature_and_segment_length_vec.back().second.second,
1022+
tier4_autoware_utils::calcDistance2d(p2, p3)};
1023+
1024+
curvature_and_segment_length_vec.emplace_back(curvature, arc_length);
10101025
}
1011-
curvature_arc_length_vec.emplace_back(0.0, 0.0);
10121026

1013-
return curvature_arc_length_vec;
1027+
// set to the last point
1028+
curvature_and_segment_length_vec.emplace_back(
1029+
0.0, std::make_pair(curvature_and_segment_length_vec.back().second.second, 0.0));
1030+
1031+
return curvature_and_segment_length_vec;
10141032
}
10151033

1016-
extern template std::vector<std::pair<double, double>>
1017-
calcCurvatureAndArcLength<std::vector<autoware_auto_planning_msgs::msg::PathPoint>>(
1034+
extern template std::vector<std::pair<double, std::pair<double, double>>>
1035+
calcCurvatureAndSegmentLength<std::vector<autoware_auto_planning_msgs::msg::PathPoint>>(
10181036
const std::vector<autoware_auto_planning_msgs::msg::PathPoint> & points);
1019-
extern template std::vector<std::pair<double, double>>
1020-
calcCurvatureAndArcLength<std::vector<autoware_auto_planning_msgs::msg::PathPointWithLaneId>>(
1037+
extern template std::vector<std::pair<double, std::pair<double, double>>>
1038+
calcCurvatureAndSegmentLength<std::vector<autoware_auto_planning_msgs::msg::PathPointWithLaneId>>(
10211039
const std::vector<autoware_auto_planning_msgs::msg::PathPointWithLaneId> & points);
1022-
extern template std::vector<std::pair<double, double>>
1023-
calcCurvatureAndArcLength<std::vector<autoware_auto_planning_msgs::msg::TrajectoryPoint>>(
1040+
extern template std::vector<std::pair<double, std::pair<double, double>>>
1041+
calcCurvatureAndSegmentLength<std::vector<autoware_auto_planning_msgs::msg::TrajectoryPoint>>(
10241042
const std::vector<autoware_auto_planning_msgs::msg::TrajectoryPoint> & points);
10251043

10261044
/**

common/motion_utils/src/trajectory/trajectory.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -250,14 +250,14 @@ calcCurvature<std::vector<autoware_auto_planning_msgs::msg::TrajectoryPoint>>(
250250
const std::vector<autoware_auto_planning_msgs::msg::TrajectoryPoint> & points);
251251

252252
//
253-
template std::vector<std::pair<double, double>>
254-
calcCurvatureAndArcLength<std::vector<autoware_auto_planning_msgs::msg::PathPoint>>(
253+
template std::vector<std::pair<double, std::pair<double, double>>>
254+
calcCurvatureAndSegmentLength<std::vector<autoware_auto_planning_msgs::msg::PathPoint>>(
255255
const std::vector<autoware_auto_planning_msgs::msg::PathPoint> & points);
256-
template std::vector<std::pair<double, double>>
257-
calcCurvatureAndArcLength<std::vector<autoware_auto_planning_msgs::msg::PathPointWithLaneId>>(
256+
template std::vector<std::pair<double, std::pair<double, double>>>
257+
calcCurvatureAndSegmentLength<std::vector<autoware_auto_planning_msgs::msg::PathPointWithLaneId>>(
258258
const std::vector<autoware_auto_planning_msgs::msg::PathPointWithLaneId> & points);
259-
template std::vector<std::pair<double, double>>
260-
calcCurvatureAndArcLength<std::vector<autoware_auto_planning_msgs::msg::TrajectoryPoint>>(
259+
template std::vector<std::pair<double, std::pair<double, double>>>
260+
calcCurvatureAndSegmentLength<std::vector<autoware_auto_planning_msgs::msg::TrajectoryPoint>>(
261261
const std::vector<autoware_auto_planning_msgs::msg::TrajectoryPoint> & points);
262262

263263
//

planning/behavior_path_goal_planner_module/config/goal_planner.param.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
lateral_offset_interval: 0.25
2323
ignore_distance_from_lane_start: 0.0
2424
margin_from_boundary: 0.5
25+
high_curvature_threshold: 0.1
2526

2627
# occupancy grid map
2728
occupancy_grid:

planning/behavior_path_goal_planner_module/include/behavior_path_goal_planner_module/goal_planner_parameters.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ struct GoalPlannerParameters
6060
double lateral_offset_interval{0.0};
6161
double ignore_distance_from_lane_start{0.0};
6262
double margin_from_boundary{0.0};
63+
double high_curvature_threshold{0.0};
6364

6465
// occupancy grid map
6566
bool use_occupancy_grid_for_goal_search{false};

planning/behavior_path_goal_planner_module/include/behavior_path_goal_planner_module/pull_over_planner_base.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ struct PullOverPath
5252
size_t goal_id{};
5353
size_t id{};
5454
bool decided_velocity{false};
55+
double max_curvature{0.0}; // max curvature of the parking path
5556

5657
PathWithLaneId getFullPath() const
5758
{
@@ -72,6 +73,7 @@ struct PullOverPath
7273
return path;
7374
}
7475

76+
// path from the pull over start pose to the end pose
7577
PathWithLaneId getParkingPath() const
7678
{
7779
const PathWithLaneId full_path = getFullPath();

planning/behavior_path_goal_planner_module/src/goal_planner_module.cpp

+87-34
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,18 @@ void GoalPlannerModule::onTimer()
269269
planner->setPlannerData(local_planner_data);
270270
planner->setPreviousModuleOutput(previous_module_output);
271271
auto pull_over_path = planner->plan(goal_candidate.goal_pose);
272-
if (pull_over_path) {
272+
if (pull_over_path && pull_over_path->getParkingPath().points.size() >= 3) {
273273
pull_over_path->goal_id = goal_candidate.id;
274274
pull_over_path->id = path_candidates.size();
275+
276+
// calculate absolute maximum curvature of parking path(start pose to end pose) for path
277+
// priority
278+
const std::vector<double> curvatures =
279+
autoware::motion_utils::calcCurvature(pull_over_path->getParkingPath().points);
280+
pull_over_path->max_curvature = std::abs(*std::max_element(
281+
curvatures.begin(), curvatures.end(),
282+
[](const double & a, const double & b) { return std::abs(a) < std::abs(b); }));
283+
275284
path_candidates.push_back(*pull_over_path);
276285
// calculate closest pull over start pose for stop path
277286
const double start_arc_length =
@@ -795,23 +804,37 @@ std::vector<PullOverPath> GoalPlannerModule::sortPullOverPathCandidatesByGoalPri
795804
const auto debugPrintPathPriority =
796805
[this](
797806
const std::vector<PullOverPath> & sorted_pull_over_path_candidates,
798-
const std::map<size_t, size_t> & goal_id_to_index,
799-
const std::optional<std::map<size_t, double>> & path_id_to_margin_map_opt = std::nullopt,
800-
const std::optional<std::function<bool(const PullOverPath &)>> & isSoftMarginOpt =
801-
std::nullopt) {
807+
const std::map<size_t, size_t> & goal_id_to_index, const GoalCandidates & goal_candidates,
808+
const std::map<size_t, double> & path_id_to_margin_map,
809+
const std::function<bool(const PullOverPath &)> & isSoftMargin,
810+
const std::function<bool(const PullOverPath &)> & isHighCurvature) {
802811
std::stringstream ss;
803-
ss << "\n---------------------- path priority ----------------------\n";
804-
for (const auto & path : sorted_pull_over_path_candidates) {
805-
// clang-format off
806-
ss << "path_type: " << magic_enum::enum_name(path.type)
807-
<< ", path_id: " << path.id
808-
<< ", goal_id: " << path.goal_id
809-
<< ", goal_priority:" << goal_id_to_index.at(path.goal_id);
810-
// clang-format on
811-
if (path_id_to_margin_map_opt && isSoftMarginOpt) {
812-
ss << ", margin: " << path_id_to_margin_map_opt->at(path.id)
813-
<< ((*isSoftMarginOpt)(path) ? " (soft)" : " (hard)");
812+
813+
// unsafe goal and it's priority are not visible as debug marker in rviz,
814+
// so exclude unsafe goal from goal_priority
815+
std::map<size_t, int> goal_id_and_priority;
816+
{
817+
int priority = 0;
818+
for (const auto & goal_candidate : goal_candidates) {
819+
goal_id_and_priority[goal_candidate.id] = goal_candidate.is_safe ? priority++ : -1;
814820
}
821+
}
822+
823+
ss << "\n---------------------- path priority ----------------------\n";
824+
for (size_t i = 0; i < sorted_pull_over_path_candidates.size(); ++i) {
825+
const auto & path = sorted_pull_over_path_candidates[i];
826+
827+
// goal_index is same to goal priority including unsafe goal
828+
const int goal_index = static_cast<int>(goal_id_to_index.at(path.goal_id));
829+
const bool is_safe_goal = goal_candidates[goal_index].is_safe;
830+
const int goal_priority = goal_id_and_priority[path.goal_id];
831+
832+
ss << "path_priority: " << i << ", path_type: " << magic_enum::enum_name(path.type)
833+
<< ", path_id: " << path.id << ", goal_id: " << path.goal_id
834+
<< ", goal_priority: " << (is_safe_goal ? std::to_string(goal_priority) : "unsafe")
835+
<< ", margin: " << path_id_to_margin_map.at(path.id)
836+
<< (isSoftMargin(path) ? " (soft)" : " (hard)") << ", curvature: " << path.max_curvature
837+
<< (isHighCurvature(path) ? " (high)" : " (low)");
815838
ss << "\n";
816839
}
817840
ss << "-----------------------------------------------------------\n";
@@ -822,6 +845,7 @@ std::vector<PullOverPath> GoalPlannerModule::sortPullOverPathCandidatesByGoalPri
822845
const auto & soft_margins = parameters_->object_recognition_collision_check_soft_margins;
823846
const auto & hard_margins = parameters_->object_recognition_collision_check_hard_margins;
824847

848+
// (1) Sort pull_over_path_candidates based on the order in goal_candidates
825849
// Create a map of goal_id to its index in goal_candidates
826850
std::map<size_t, size_t> goal_id_to_index;
827851
for (size_t i = 0; i < goal_candidates.size(); ++i) {
@@ -846,6 +870,7 @@ std::vector<PullOverPath> GoalPlannerModule::sortPullOverPathCandidatesByGoalPri
846870

847871
// if object recognition is enabled, sort by collision check margin
848872
if (parameters_->use_object_recognition) {
873+
// (2) Sort by collision check margins
849874
const std::vector<double> margins = std::invoke([&]() {
850875
std::vector<double> combined_margins = soft_margins;
851876
combined_margins.insert(combined_margins.end(), hard_margins.begin(), hard_margins.end());
@@ -892,42 +917,70 @@ std::vector<PullOverPath> GoalPlannerModule::sortPullOverPathCandidatesByGoalPri
892917
return path_id_to_margin_map[a.id] > path_id_to_margin_map[b.id];
893918
});
894919

895-
// Sort pull_over_path_candidates based on the order in efficient_path_order
896-
if (parameters_->path_priority == "efficient_path") {
897-
const auto isSoftMargin = [&](const PullOverPath & path) -> bool {
898-
const double margin = path_id_to_margin_map[path.id];
899-
return std::any_of(
900-
soft_margins.begin(), soft_margins.end(),
901-
[margin](const double soft_margin) { return std::abs(margin - soft_margin) < 0.01; });
902-
};
903-
const auto isSameHardMargin = [&](const PullOverPath & a, const PullOverPath & b) -> bool {
904-
return !isSoftMargin(a) && !isSoftMargin(b) &&
905-
std::abs(path_id_to_margin_map[a.id] - path_id_to_margin_map[b.id]) < 0.01;
906-
};
920+
// (3) Sort by curvature
921+
// If the curvature is less than the threshold, prioritize the path.
922+
const auto isHighCurvature = [&](const PullOverPath & path) -> bool {
923+
return path.max_curvature >= parameters_->high_curvature_threshold;
924+
};
907925

926+
const auto isSoftMargin = [&](const PullOverPath & path) -> bool {
927+
const double margin = path_id_to_margin_map[path.id];
928+
return std::any_of(
929+
soft_margins.begin(), soft_margins.end(),
930+
[margin](const double soft_margin) { return std::abs(margin - soft_margin) < 0.01; });
931+
};
932+
const auto isSameHardMargin = [&](const PullOverPath & a, const PullOverPath & b) -> bool {
933+
return !isSoftMargin(a) && !isSoftMargin(b) &&
934+
std::abs(path_id_to_margin_map[a.id] - path_id_to_margin_map[b.id]) < 0.01;
935+
};
936+
937+
// NOTE: this is just partition sort based on curvature threshold within each sub partitions
938+
std::stable_sort(
939+
sorted_pull_over_path_candidates.begin(), sorted_pull_over_path_candidates.end(),
940+
[&](const PullOverPath & a, const PullOverPath & b) {
941+
// if both are soft margin or both are same hard margin, prioritize the path with lower
942+
// curvature.
943+
if ((isSoftMargin(a) && isSoftMargin(b)) || isSameHardMargin(a, b)) {
944+
return !isHighCurvature(a) && isHighCurvature(b);
945+
}
946+
// otherwise, keep the order based on the margin.
947+
return false;
948+
});
949+
950+
// (4) Sort pull_over_path_candidates based on the order in efficient_path_order keeping the
951+
// collision check margin and curvature priority.
952+
if (parameters_->path_priority == "efficient_path") {
908953
std::stable_sort(
909954
sorted_pull_over_path_candidates.begin(), sorted_pull_over_path_candidates.end(),
910955
[&](const auto & a, const auto & b) {
911-
// if both are soft margin or both are same hard margin, sort by planner priority
956+
// if any of following conditions are met, sort by path type priority
957+
// - both are soft margin
958+
// - both are same hard margin
912959
if ((isSoftMargin(a) && isSoftMargin(b)) || isSameHardMargin(a, b)) {
913960
return comparePathTypePriority(a, b);
914961
}
915962
// otherwise, keep the order.
916963
return false;
917964
});
918965

919-
// debug print path priority: sorted by efficient_path_order and collision check margin
966+
// debug print path priority sorted by
967+
// - efficient_path_order
968+
// - collision check margin
969+
// - curvature
920970
debugPrintPathPriority(
921-
sorted_pull_over_path_candidates, goal_id_to_index, path_id_to_margin_map, isSoftMargin);
971+
sorted_pull_over_path_candidates, goal_id_to_index, goal_candidates, path_id_to_margin_map,
972+
isSoftMargin, isHighCurvature);
922973
}
923974
} else {
924-
// Sort pull_over_path_candidates based on the order in efficient_path_order
975+
/**
976+
* NOTE: use_object_recognition=false is not recommended. This option will be deprecated in the
977+
* future. sort by curvature is not implemented yet.
978+
* Sort pull_over_path_candidates based on the order in efficient_path_order
979+
*/
925980
if (parameters_->path_priority == "efficient_path") {
926981
std::stable_sort(
927982
sorted_pull_over_path_candidates.begin(), sorted_pull_over_path_candidates.end(),
928983
[&](const auto & a, const auto & b) { return comparePathTypePriority(a, b); });
929-
// debug print path priority: sorted by efficient_path_order and collision check margin
930-
debugPrintPathPriority(sorted_pull_over_path_candidates, goal_id_to_index);
931984
}
932985
}
933986

planning/behavior_path_goal_planner_module/src/manager.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ void GoalPlannerModuleManager::init(rclcpp::Node * node)
6161
p.ignore_distance_from_lane_start =
6262
node->declare_parameter<double>(ns + "ignore_distance_from_lane_start");
6363
p.margin_from_boundary = node->declare_parameter<double>(ns + "margin_from_boundary");
64+
p.high_curvature_threshold = node->declare_parameter<double>(ns + "high_curvature_threshold");
6465

6566
const std::string parking_policy_name =
6667
node->declare_parameter<std::string>(ns + "parking_policy");

planning/behavior_path_goal_planner_module/src/shift_pull_over.cpp

+13-2
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,19 @@ double ShiftPullOver::calcBeforeShiftedArcLength(
313313

314314
double before_arc_length{0.0};
315315
double after_arc_length{0.0};
316-
for (const auto & [k, segment_length] :
317-
motion_utils::calcCurvatureAndArcLength(reversed_path.points)) {
316+
317+
const auto curvature_and_segment_length =
318+
motion_utils::calcCurvatureAndSegmentLength(reversed_path.points);
319+
320+
for (size_t i = 0; i < curvature_and_segment_length.size(); ++i) {
321+
const auto & [k, segment_length_pair] = curvature_and_segment_length[i];
322+
323+
// If it is the last point, add the lengths of the previous and next segments.
324+
// For other points, only add the length of the previous segment.
325+
const double segment_length = i == curvature_and_segment_length.size() - 1
326+
? segment_length_pair.first
327+
: segment_length_pair.first + segment_length_pair.second;
328+
318329
// after shifted segment length
319330
const double after_segment_length =
320331
k > 0 ? segment_length * (1 + k * dr) : segment_length / (1 - k * dr);

planning/behavior_path_start_planner_module/include/behavior_path_start_planner_module/data_structs.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ struct StartPlannerDebugData
5252
std::vector<Pose> start_pose_candidates;
5353
size_t selected_start_pose_candidate_index;
5454
double margin_for_start_pose_candidate;
55+
56+
// for isPreventingRearVehicleFromPassingThrough
57+
std::optional<Pose> estimated_stop_pose;
5558
};
5659

5760
struct StartPlannerParameters

planning/behavior_path_start_planner_module/include/behavior_path_start_planner_module/start_planner_module.hpp

+23
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,31 @@ class StartPlannerModule : public SceneModuleInterface
229229

230230
bool isModuleRunning() const;
231231
bool isCurrentPoseOnMiddleOfTheRoad() const;
232+
233+
/**
234+
* @brief Check if the ego vehicle is preventing the rear vehicle from passing through.
235+
*
236+
* This function just call isPreventingRearVehicleFromPassingThrough(const Pose & ego_pose) with
237+
* two poses. If rear vehicle is obstructed by ego vehicle at either of the two poses, it returns
238+
* true.
239+
*
240+
* @return true if the ego vehicle is preventing the rear vehicle from passing through with the
241+
* current pose or the pose if it stops.
242+
*/
232243
bool isPreventingRearVehicleFromPassingThrough() const;
233244

245+
/**
246+
* @brief Check if the ego vehicle is preventing the rear vehicle from passing through.
247+
*
248+
* This function measures the distance to the lane boundary from the current pose and the pose if
249+
it stops, and determines whether there is enough space for the rear vehicle to pass through. If
250+
* it is obstructing at either of the two poses, it returns true.
251+
*
252+
* @return true if the ego vehicle is preventing the rear vehicle from passing through with given
253+
ego pose.
254+
*/
255+
bool isPreventingRearVehicleFromPassingThrough(const Pose & ego_pose) const;
256+
234257
bool isCloseToOriginalStartPose() const;
235258
bool hasArrivedAtGoal() const;
236259
bool isMoving() const;

planning/behavior_path_start_planner_module/src/shift_pull_out.cpp

+11-1
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,17 @@ double ShiftPullOut::calcBeforeShiftedArcLength(
407407
double before_arc_length{0.0};
408408
double after_arc_length{0.0};
409409

410-
for (const auto & [k, segment_length] : motion_utils::calcCurvatureAndArcLength(path.points)) {
410+
const auto curvatures_and_segment_lengths =
411+
motion_utils::calcCurvatureAndSegmentLength(path.points);
412+
for (size_t i = 0; i < curvatures_and_segment_lengths.size(); ++i) {
413+
const auto & [k, segment_length_pair] = curvatures_and_segment_lengths.at(i);
414+
415+
// If it is the last point, add the lengths of the previous and next segments.
416+
// For other points, only add the length of the previous segment.
417+
const double segment_length = i == curvatures_and_segment_lengths.size() - 1
418+
? segment_length_pair.first + segment_length_pair.second
419+
: segment_length_pair.first;
420+
411421
// after shifted segment length
412422
const double after_segment_length =
413423
k < 0 ? segment_length * (1 - k * dr) : segment_length / (1 + k * dr);

0 commit comments

Comments
 (0)