From 02a48c158e512331a74673ee4f764647b2b233ab Mon Sep 17 00:00:00 2001 From: Maxime CLEMENT <maxime.clement@tier4.jp> Date: Tue, 20 Feb 2024 21:22:57 +0900 Subject: [PATCH 1/6] add function to cut a predicted path beyond a red light stop line TODO: check perf, take object footprint size into account when cutting, add param Signed-off-by: Maxime CLEMENT <maxime.clement@tier4.jp> --- .../package.xml | 1 + .../src/filter_predicted_objects.hpp | 106 +++++++++++++++++- .../src/scene_out_of_lane.cpp | 4 +- .../src/types.hpp | 6 +- 4 files changed, 108 insertions(+), 9 deletions(-) diff --git a/planning/behavior_velocity_out_of_lane_module/package.xml b/planning/behavior_velocity_out_of_lane_module/package.xml index 43dea2f2153ff..b61441132969c 100644 --- a/planning/behavior_velocity_out_of_lane_module/package.xml +++ b/planning/behavior_velocity_out_of_lane_module/package.xml @@ -27,6 +27,7 @@ <depend>tf2</depend> <depend>tier4_autoware_utils</depend> <depend>tier4_planning_msgs</depend> + <depend>traffic_light_utils</depend> <depend>vehicle_info_util</depend> <depend>visualization_msgs</depend> diff --git a/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp b/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp index 7bad4974ea9af..96aa474380afb 100644 --- a/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp +++ b/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp @@ -18,23 +18,112 @@ #include "types.hpp" #include <motion_utils/trajectory/trajectory.hpp> +#include <traffic_light_utils/traffic_light_utils.hpp> +#include <boost/geometry/algorithms/intersects.hpp> + +#include <lanelet2_core/geometry/LaneletMap.h> +#include <lanelet2_core/primitives/BasicRegulatoryElements.h> + +#include <algorithm> +#include <optional> #include <string> +#include <vector> + +// for writing the svg file +#include <fstream> +#include <iostream> +// for the geometry types +#include <tier4_autoware_utils/geometry/geometry.hpp> +// for the svg mapper +#include <boost/geometry/io/svg/svg_mapper.hpp> +#include <boost/geometry/io/svg/write.hpp> namespace behavior_velocity_planner::out_of_lane { +void cut_predicted_path_beyond_line( + autoware_auto_perception_msgs::msg::PredictedPath & predicted_path, + const lanelet::BasicLineString2d & stop_line) +{ + lanelet::BasicSegment2d path_segment; + path_segment.first.x() = predicted_path.path.front().position.x; + path_segment.first.y() = predicted_path.path.front().position.y; + for (auto i = 1; i < predicted_path.path.size(); ++i) { + path_segment.second.x() = predicted_path.path[i].position.x; + path_segment.second.y() = predicted_path.path[i].position.y; + if (boost::geometry::intersects(stop_line, path_segment)) { + predicted_path.path.resize(i - std::min(i, 10)); + return; + } + path_segment.first = path_segment.second; + } +} + +std::optional<const lanelet::BasicLineString2d> find_next_stop_line( + const autoware_auto_perception_msgs::msg::PredictedPath & path, const PlannerData & planner_data, + const double max_length) +{ + lanelet::ConstLanelets lanelets; + lanelet::BasicPoint2d query_point; + for (const auto & p : path.path) { + query_point.x() = p.position.x; + query_point.y() = p.position.y; + const auto results = lanelet::geometry::findWithin2d( + planner_data.route_handler_->getLaneletMapPtr()->laneletLayer, query_point); + for (const auto & r : results) lanelets.push_back(r.second); + } + for (const auto & ll : lanelets) { + for (const auto & element : ll.regulatoryElementsAs<lanelet::TrafficLight>()) { + const auto traffic_signal_stamped = planner_data.getTrafficSignal(element->id()); + if ( + traffic_signal_stamped.has_value() && element->stopLine().has_value() && + traffic_light_utils::isTrafficSignalStop(ll, traffic_signal_stamped.value().signal)) { + lanelet::BasicLineString2d stop_line; + for (const auto & p : *(element->stopLine())) stop_line.emplace_back(p.x(), p.y()); + return stop_line; + } + } + } + return std::nullopt; +} + +/// @brief cut predicted path beyond stop lines of red lights +/// @param [inout] predicted_path predicted path to cut +/// @param [in] planner_data planner data to get the map and traffic light information +void cut_predicted_path_beyond_red_lights( + autoware_auto_perception_msgs::msg::PredictedPath & predicted_path, + const PlannerData & planner_data) +{ + // Declare a stream and an SVG mapper + std::ofstream svg("/home/mclement/Pictures/image.svg"); // /!\ CHANGE PATH + boost::geometry::svg_mapper<tier4_autoware_utils::Point2d> mapper(svg, 400, 400); + const lanelet::BasicPoint2d first_point = { + predicted_path.path.front().position.x, predicted_path.path.front().position.y}; + const auto stop_line = find_next_stop_line( + predicted_path, planner_data, + motion_utils::calcSignedArcLength(predicted_path.path, 0, predicted_path.path.size() - 1)); + lanelet::BasicLineString2d path_ls; + for (const auto & p : predicted_path.path) path_ls.emplace_back(p.position.x, p.position.y); + if (stop_line) cut_predicted_path_beyond_line(predicted_path, *stop_line); + lanelet::BasicLineString2d cut_path_ls; + for (const auto & p : predicted_path.path) cut_path_ls.emplace_back(p.position.x, p.position.y); + mapper.add(cut_path_ls); + mapper.map(first_point, "opacity:1.0;fill:red;stroke:green;stroke-width:2", 2); + mapper.map(path_ls, "opacity:0.3;fill:black;stroke:black;stroke-width:2"); + mapper.map(cut_path_ls, "opacity:0.3;fill:red;stroke:red;stroke-width:2"); +} + /// @brief filter predicted objects and their predicted paths -/// @param [in] objects predicted objects to filter +/// @param [in] planner_data planner data /// @param [in] ego_data ego data /// @param [in] params parameters /// @return filtered predicted objects autoware_auto_perception_msgs::msg::PredictedObjects filter_predicted_objects( - const autoware_auto_perception_msgs::msg::PredictedObjects & objects, const EgoData & ego_data, - const PlannerParam & params) + const PlannerData & planner_data, const EgoData & ego_data, const PlannerParam & params) { autoware_auto_perception_msgs::msg::PredictedObjects filtered_objects; - filtered_objects.header = objects.header; - for (const auto & object : objects.objects) { + filtered_objects.header = planner_data.predicted_objects->header; + for (const auto & object : planner_data.predicted_objects->objects) { const auto is_pedestrian = std::find_if(object.classification.begin(), object.classification.end(), [](const auto & c) { return c.label == autoware_auto_perception_msgs::msg::ObjectClassification::PEDESTRIAN; @@ -60,7 +149,14 @@ autoware_auto_perception_msgs::msg::PredictedObjects filter_predicted_objects( const auto new_end = std::remove_if(predicted_paths.begin(), predicted_paths.end(), is_invalid_predicted_path); predicted_paths.erase(new_end, predicted_paths.end()); + if (true || params.objects_cut_predicted_paths_beyond_red_lights) + for (auto & predicted_path : predicted_paths) + cut_predicted_path_beyond_red_lights(predicted_path, planner_data); + predicted_paths.erase( + std::remove_if(predicted_paths.begin(), predicted_paths.end(), is_invalid_predicted_path), + predicted_paths.end()); } + if (!params.objects_use_predicted_paths || !filtered_object.kinematics.predicted_paths.empty()) filtered_objects.objects.push_back(filtered_object); } diff --git a/planning/behavior_velocity_out_of_lane_module/src/scene_out_of_lane.cpp b/planning/behavior_velocity_out_of_lane_module/src/scene_out_of_lane.cpp index ef4434e235244..6ce8338401e22 100644 --- a/planning/behavior_velocity_out_of_lane_module/src/scene_out_of_lane.cpp +++ b/planning/behavior_velocity_out_of_lane_module/src/scene_out_of_lane.cpp @@ -113,7 +113,7 @@ bool OutOfLaneModule::modifyPathVelocity(PathWithLaneId * path, StopReason * sto DecisionInputs inputs; inputs.ranges = ranges; inputs.ego_data = ego_data; - inputs.objects = filter_predicted_objects(*planner_data_->predicted_objects, ego_data, params_); + inputs.objects = filter_predicted_objects(*planner_data_, ego_data, params_); inputs.route_handler = planner_data_->route_handler_; inputs.lanelets = other_lanelets; const auto decisions = calculate_decisions(inputs, params_, logger_); @@ -157,7 +157,7 @@ bool OutOfLaneModule::modifyPathVelocity(PathWithLaneId * path, StopReason * sto } if (point_to_insert) { prev_inserted_point_ = point_to_insert; - RCLCPP_INFO(logger_, "Avoiding lane %lu", point_to_insert->slowdown.lane_to_avoid.id()); + RCLCPP_DEBUG(logger_, "Avoiding lane %lu", point_to_insert->slowdown.lane_to_avoid.id()); debug_data_.slowdowns = {*point_to_insert}; auto path_idx = motion_utils::findNearestSegmentIndex( path->points, point_to_insert->point.point.pose.position) + diff --git a/planning/behavior_velocity_out_of_lane_module/src/types.hpp b/planning/behavior_velocity_out_of_lane_module/src/types.hpp index 34bd52634ce7b..d482870e5ce18 100644 --- a/planning/behavior_velocity_out_of_lane_module/src/types.hpp +++ b/planning/behavior_velocity_out_of_lane_module/src/types.hpp @@ -47,8 +47,10 @@ struct PlannerParam double ego_min_velocity; // [m/s] minimum velocity of ego used to calculate its ttc or time range bool objects_use_predicted_paths; // whether to use the objects' predicted paths - double objects_min_vel; // [m/s] objects lower than this velocity will be ignored - double objects_min_confidence; // minimum confidence to consider a predicted path + bool objects_cut_predicted_paths_beyond_red_lights; // whether to cut predicted paths beyond red + // lights' stop lines + double objects_min_vel; // [m/s] objects lower than this velocity will be ignored + double objects_min_confidence; // minimum confidence to consider a predicted path double objects_dist_buffer; // [m] distance buffer used to determine if a collision will occur in // the other lane From aa75a5b44321fffeb7b4c90943bbe55c1f4d7471 Mon Sep 17 00:00:00 2001 From: Maxime CLEMENT <maxime.clement@tier4.jp> Date: Thu, 22 Feb 2024 15:14:33 +0900 Subject: [PATCH 2/6] account for predicted object front overhang+dont extrapolate pred paths Signed-off-by: Maxime CLEMENT <maxime.clement@tier4.jp> --- .../src/decisions.cpp | 13 +++- .../src/filter_predicted_objects.hpp | 62 +++++++++++-------- .../src/scene_out_of_lane.cpp | 9 ++- 3 files changed, 53 insertions(+), 31 deletions(-) diff --git a/planning/behavior_velocity_out_of_lane_module/src/decisions.cpp b/planning/behavior_velocity_out_of_lane_module/src/decisions.cpp index be72109db4548..8c2466bf9cd37 100644 --- a/planning/behavior_velocity_out_of_lane_module/src/decisions.cpp +++ b/planning/behavior_velocity_out_of_lane_module/src/decisions.cpp @@ -73,6 +73,7 @@ std::optional<std::pair<double, double>> object_time_to_range( if (!object_is_incoming(object_point, route_handler, range.lane)) return {}; const auto max_deviation = object.shape.dimensions.y + range.inside_distance + dist_buffer; + const auto max_lon_deviation = object.shape.dimensions.x / 2.0; auto worst_enter_time = std::optional<double>(); auto worst_exit_time = std::optional<double>(); @@ -121,7 +122,17 @@ std::optional<std::pair<double, double>> object_time_to_range( max_deviation); continue; } - // else we rely on the interpolation to estimate beyond the end of the predicted path + const auto is_last_predicted_path_point = + (exit_segment_idx + 2 == unique_path_points.size() || + enter_segment_idx + 2 == unique_path_points.size()); + const auto does_not_reach_overlap = + is_last_predicted_path_point && (std::min(exit_offset, enter_offset) > max_lon_deviation); + if (does_not_reach_overlap) { + RCLCPP_DEBUG( + logger, " * does not reach the overlap = %2.2fm | max_dev = %2.2fm\n", + std::min(exit_offset, enter_offset), max_lon_deviation); + continue; + } const auto same_driving_direction_as_ego = enter_time < exit_time; if (same_driving_direction_as_ego) { diff --git a/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp b/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp index 96aa474380afb..19b6af66db5fb 100644 --- a/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp +++ b/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp @@ -43,35 +43,41 @@ namespace behavior_velocity_planner::out_of_lane { void cut_predicted_path_beyond_line( autoware_auto_perception_msgs::msg::PredictedPath & predicted_path, - const lanelet::BasicLineString2d & stop_line) + const lanelet::BasicLineString2d & stop_line, const double object_front_overhang) { + auto stop_line_idx = 0UL; + bool found = false; lanelet::BasicSegment2d path_segment; path_segment.first.x() = predicted_path.path.front().position.x; path_segment.first.y() = predicted_path.path.front().position.y; - for (auto i = 1; i < predicted_path.path.size(); ++i) { - path_segment.second.x() = predicted_path.path[i].position.x; - path_segment.second.y() = predicted_path.path[i].position.y; + for (stop_line_idx = 1; stop_line_idx < predicted_path.path.size(); ++stop_line_idx) { + path_segment.second.x() = predicted_path.path[stop_line_idx].position.x; + path_segment.second.y() = predicted_path.path[stop_line_idx].position.y; if (boost::geometry::intersects(stop_line, path_segment)) { - predicted_path.path.resize(i - std::min(i, 10)); - return; + found = true; + break; } path_segment.first = path_segment.second; } + auto cut_idx = stop_line_idx; + double arc_length = 0; + while (cut_idx > 0 && arc_length < object_front_overhang) { + arc_length += tier4_autoware_utils::calcDistance2d( + predicted_path.path[cut_idx], predicted_path.path[cut_idx - 1]); + --cut_idx; + } + predicted_path.path.resize(cut_idx); } std::optional<const lanelet::BasicLineString2d> find_next_stop_line( - const autoware_auto_perception_msgs::msg::PredictedPath & path, const PlannerData & planner_data, - const double max_length) + const autoware_auto_perception_msgs::msg::PredictedPath & path, const PlannerData & planner_data) { lanelet::ConstLanelets lanelets; - lanelet::BasicPoint2d query_point; - for (const auto & p : path.path) { - query_point.x() = p.position.x; - query_point.y() = p.position.y; - const auto results = lanelet::geometry::findWithin2d( - planner_data.route_handler_->getLaneletMapPtr()->laneletLayer, query_point); - for (const auto & r : results) lanelets.push_back(r.second); - } + lanelet::BasicLineString2d query_line; + for (const auto & p : path.path) query_line.emplace_back(p.position.x, p.position.y); + const auto query_results = lanelet::geometry::findWithin2d( + planner_data.route_handler_->getLaneletMapPtr()->laneletLayer, query_line); + for (const auto & r : query_results) lanelets.push_back(r.second); for (const auto & ll : lanelets) { for (const auto & element : ll.regulatoryElementsAs<lanelet::TrafficLight>()) { const auto traffic_signal_stamped = planner_data.getTrafficSignal(element->id()); @@ -92,24 +98,22 @@ std::optional<const lanelet::BasicLineString2d> find_next_stop_line( /// @param [in] planner_data planner data to get the map and traffic light information void cut_predicted_path_beyond_red_lights( autoware_auto_perception_msgs::msg::PredictedPath & predicted_path, - const PlannerData & planner_data) + const PlannerData & planner_data, const double object_front_overhang, int i) { // Declare a stream and an SVG mapper - std::ofstream svg("/home/mclement/Pictures/image.svg"); // /!\ CHANGE PATH + std::ofstream svg( + "/home/mclement/Pictures/image" + std::to_string(i) + ".svg"); // /!\ CHANGE PATH boost::geometry::svg_mapper<tier4_autoware_utils::Point2d> mapper(svg, 400, 400); - const lanelet::BasicPoint2d first_point = { - predicted_path.path.front().position.x, predicted_path.path.front().position.y}; - const auto stop_line = find_next_stop_line( - predicted_path, planner_data, - motion_utils::calcSignedArcLength(predicted_path.path, 0, predicted_path.path.size() - 1)); + const auto stop_line = find_next_stop_line(predicted_path, planner_data); lanelet::BasicLineString2d path_ls; for (const auto & p : predicted_path.path) path_ls.emplace_back(p.position.x, p.position.y); - if (stop_line) cut_predicted_path_beyond_line(predicted_path, *stop_line); + if (stop_line) cut_predicted_path_beyond_line(predicted_path, *stop_line, object_front_overhang); lanelet::BasicLineString2d cut_path_ls; for (const auto & p : predicted_path.path) cut_path_ls.emplace_back(p.position.x, p.position.y); mapper.add(cut_path_ls); - mapper.map(first_point, "opacity:1.0;fill:red;stroke:green;stroke-width:2", 2); + if (stop_line) mapper.add(*stop_line); mapper.map(path_ls, "opacity:0.3;fill:black;stroke:black;stroke-width:2"); + if (stop_line) mapper.map(*stop_line, "opacity:0.5;fill:black;stroke:red;stroke-width:2"); mapper.map(cut_path_ls, "opacity:0.3;fill:red;stroke:red;stroke-width:2"); } @@ -149,11 +153,15 @@ autoware_auto_perception_msgs::msg::PredictedObjects filter_predicted_objects( const auto new_end = std::remove_if(predicted_paths.begin(), predicted_paths.end(), is_invalid_predicted_path); predicted_paths.erase(new_end, predicted_paths.end()); + auto i = 0; if (true || params.objects_cut_predicted_paths_beyond_red_lights) for (auto & predicted_path : predicted_paths) - cut_predicted_path_beyond_red_lights(predicted_path, planner_data); + cut_predicted_path_beyond_red_lights( + predicted_path, planner_data, filtered_object.shape.dimensions.x, i++); predicted_paths.erase( - std::remove_if(predicted_paths.begin(), predicted_paths.end(), is_invalid_predicted_path), + std::remove_if( + predicted_paths.begin(), predicted_paths.end(), + [](const auto & p) { return p.path.empty(); }), predicted_paths.end()); } diff --git a/planning/behavior_velocity_out_of_lane_module/src/scene_out_of_lane.cpp b/planning/behavior_velocity_out_of_lane_module/src/scene_out_of_lane.cpp index 6ce8338401e22..47020fb1cb623 100644 --- a/planning/behavior_velocity_out_of_lane_module/src/scene_out_of_lane.cpp +++ b/planning/behavior_velocity_out_of_lane_module/src/scene_out_of_lane.cpp @@ -109,13 +109,15 @@ bool OutOfLaneModule::modifyPathVelocity(PathWithLaneId * path, StopReason * sto calculate_overlapping_ranges(path_footprints, path_lanelets, other_lanelets, params_); const auto calculate_overlapping_ranges_us = stopwatch.toc("calculate_overlapping_ranges"); // Calculate stop and slowdown points - stopwatch.tic("calculate_decisions"); DecisionInputs inputs; inputs.ranges = ranges; inputs.ego_data = ego_data; + stopwatch.tic("filter_predicted_objects"); inputs.objects = filter_predicted_objects(*planner_data_, ego_data, params_); + const auto filter_predicted_objects_ms = stopwatch.toc("filter_predicted_objects"); inputs.route_handler = planner_data_->route_handler_; inputs.lanelets = other_lanelets; + stopwatch.tic("calculate_decisions"); const auto decisions = calculate_decisions(inputs, params_, logger_); const auto calculate_decisions_us = stopwatch.toc("calculate_decisions"); stopwatch.tic("calc_slowdown_points"); @@ -187,12 +189,13 @@ bool OutOfLaneModule::modifyPathVelocity(PathWithLaneId * path, StopReason * sto "\tcalculate_lanelets = %2.0fus\n" "\tcalculate_path_footprints = %2.0fus\n" "\tcalculate_overlapping_ranges = %2.0fus\n" + "\tfilter_pred_objects = %2.0fus\n" "\tcalculate_decisions = %2.0fus\n" "\tcalc_slowdown_points = %2.0fus\n" "\tinsert_slowdown_points = %2.0fus\n", total_time_us, calculate_lanelets_us, calculate_path_footprints_us, - calculate_overlapping_ranges_us, calculate_decisions_us, calc_slowdown_points_us, - insert_slowdown_points_us); + calculate_overlapping_ranges_us, filter_predicted_objects_ms, calculate_decisions_us, + calc_slowdown_points_us, insert_slowdown_points_us); return true; } From 9813c1285d1849b63227b3a9a9dca96b554b0143 Mon Sep 17 00:00:00 2001 From: Maxime CLEMENT <maxime.clement@tier4.jp> Date: Thu, 22 Feb 2024 15:29:35 +0900 Subject: [PATCH 3/6] add param and remove debug svg Signed-off-by: Maxime CLEMENT <maxime.clement@tier4.jp> --- .../config/out_of_lane.param.yaml | 1 + .../src/filter_predicted_objects.hpp | 45 +++++-------------- .../src/manager.cpp | 2 + 3 files changed, 15 insertions(+), 33 deletions(-) diff --git a/planning/behavior_velocity_out_of_lane_module/config/out_of_lane.param.yaml b/planning/behavior_velocity_out_of_lane_module/config/out_of_lane.param.yaml index 092f1d32b27b3..1b483b95510ed 100644 --- a/planning/behavior_velocity_out_of_lane_module/config/out_of_lane.param.yaml +++ b/planning/behavior_velocity_out_of_lane_module/config/out_of_lane.param.yaml @@ -18,6 +18,7 @@ # if false, assume the object moves at constant velocity along *all* lanelets it currently is located in. predicted_path_min_confidence : 0.1 # when using predicted paths, ignore the ones whose confidence is lower than this value. distance_buffer: 1.0 # [m] distance buffer used to determine if a collision will occur in the other lane + cut_predicted_paths_beyond_red_lights: true # if true, predicted paths are cut beyond the stop line of red traffic lights overlap: minimum_distance: 0.0 # [m] minimum distance inside a lanelet for an overlap to be considered diff --git a/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp b/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp index 19b6af66db5fb..ed3f893887ece 100644 --- a/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp +++ b/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp @@ -30,15 +30,6 @@ #include <string> #include <vector> -// for writing the svg file -#include <fstream> -#include <iostream> -// for the geometry types -#include <tier4_autoware_utils/geometry/geometry.hpp> -// for the svg mapper -#include <boost/geometry/io/svg/svg_mapper.hpp> -#include <boost/geometry/io/svg/write.hpp> - namespace behavior_velocity_planner::out_of_lane { void cut_predicted_path_beyond_line( @@ -59,14 +50,16 @@ void cut_predicted_path_beyond_line( } path_segment.first = path_segment.second; } - auto cut_idx = stop_line_idx; - double arc_length = 0; - while (cut_idx > 0 && arc_length < object_front_overhang) { - arc_length += tier4_autoware_utils::calcDistance2d( - predicted_path.path[cut_idx], predicted_path.path[cut_idx - 1]); - --cut_idx; + if(found) { + auto cut_idx = stop_line_idx; + double arc_length = 0; + while (cut_idx > 0 && arc_length < object_front_overhang) { + arc_length += tier4_autoware_utils::calcDistance2d( + predicted_path.path[cut_idx], predicted_path.path[cut_idx - 1]); + --cut_idx; + } + predicted_path.path.resize(cut_idx); } - predicted_path.path.resize(cut_idx); } std::optional<const lanelet::BasicLineString2d> find_next_stop_line( @@ -98,23 +91,10 @@ std::optional<const lanelet::BasicLineString2d> find_next_stop_line( /// @param [in] planner_data planner data to get the map and traffic light information void cut_predicted_path_beyond_red_lights( autoware_auto_perception_msgs::msg::PredictedPath & predicted_path, - const PlannerData & planner_data, const double object_front_overhang, int i) + const PlannerData & planner_data, const double object_front_overhang) { - // Declare a stream and an SVG mapper - std::ofstream svg( - "/home/mclement/Pictures/image" + std::to_string(i) + ".svg"); // /!\ CHANGE PATH - boost::geometry::svg_mapper<tier4_autoware_utils::Point2d> mapper(svg, 400, 400); const auto stop_line = find_next_stop_line(predicted_path, planner_data); - lanelet::BasicLineString2d path_ls; - for (const auto & p : predicted_path.path) path_ls.emplace_back(p.position.x, p.position.y); if (stop_line) cut_predicted_path_beyond_line(predicted_path, *stop_line, object_front_overhang); - lanelet::BasicLineString2d cut_path_ls; - for (const auto & p : predicted_path.path) cut_path_ls.emplace_back(p.position.x, p.position.y); - mapper.add(cut_path_ls); - if (stop_line) mapper.add(*stop_line); - mapper.map(path_ls, "opacity:0.3;fill:black;stroke:black;stroke-width:2"); - if (stop_line) mapper.map(*stop_line, "opacity:0.5;fill:black;stroke:red;stroke-width:2"); - mapper.map(cut_path_ls, "opacity:0.3;fill:red;stroke:red;stroke-width:2"); } /// @brief filter predicted objects and their predicted paths @@ -153,11 +133,10 @@ autoware_auto_perception_msgs::msg::PredictedObjects filter_predicted_objects( const auto new_end = std::remove_if(predicted_paths.begin(), predicted_paths.end(), is_invalid_predicted_path); predicted_paths.erase(new_end, predicted_paths.end()); - auto i = 0; - if (true || params.objects_cut_predicted_paths_beyond_red_lights) + if (params.objects_cut_predicted_paths_beyond_red_lights) for (auto & predicted_path : predicted_paths) cut_predicted_path_beyond_red_lights( - predicted_path, planner_data, filtered_object.shape.dimensions.x, i++); + predicted_path, planner_data, filtered_object.shape.dimensions.x); predicted_paths.erase( std::remove_if( predicted_paths.begin(), predicted_paths.end(), diff --git a/planning/behavior_velocity_out_of_lane_module/src/manager.cpp b/planning/behavior_velocity_out_of_lane_module/src/manager.cpp index 23de809e429ec..8055f5c9106ef 100644 --- a/planning/behavior_velocity_out_of_lane_module/src/manager.cpp +++ b/planning/behavior_velocity_out_of_lane_module/src/manager.cpp @@ -51,6 +51,8 @@ OutOfLaneModuleManager::OutOfLaneModuleManager(rclcpp::Node & node) pp.objects_min_confidence = getOrDeclareParameter<double>(node, ns + ".objects.predicted_path_min_confidence"); pp.objects_dist_buffer = getOrDeclareParameter<double>(node, ns + ".objects.distance_buffer"); + pp.objects_cut_predicted_paths_beyond_red_lights = + getOrDeclareParameter<bool>(node, ns + ".objects.cut_predicted_paths_beyond_red_lights"); pp.overlap_min_dist = getOrDeclareParameter<double>(node, ns + ".overlap.minimum_distance"); pp.overlap_extra_length = getOrDeclareParameter<double>(node, ns + ".overlap.extra_length"); From 7a9c4adc90750d83641ffa8fa43ee824b30a8f5b Mon Sep 17 00:00:00 2001 From: Maxime CLEMENT <maxime.clement@tier4.jp> Date: Fri, 1 Mar 2024 14:34:05 +0900 Subject: [PATCH 4/6] skip pred paths with only 1 non-overlapping point to avoid error msgs Signed-off-by: Maxime CLEMENT <maxime.clement@tier4.jp> --- planning/behavior_velocity_out_of_lane_module/src/decisions.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/planning/behavior_velocity_out_of_lane_module/src/decisions.cpp b/planning/behavior_velocity_out_of_lane_module/src/decisions.cpp index 8c2466bf9cd37..d68c7c97df7d2 100644 --- a/planning/behavior_velocity_out_of_lane_module/src/decisions.cpp +++ b/planning/behavior_velocity_out_of_lane_module/src/decisions.cpp @@ -79,6 +79,7 @@ std::optional<std::pair<double, double>> object_time_to_range( for (const auto & predicted_path : object.kinematics.predicted_paths) { const auto unique_path_points = motion_utils::removeOverlapPoints(predicted_path.path); + if(unique_path_points.size() < 2) continue; const auto time_step = rclcpp::Duration(predicted_path.time_step).seconds(); const auto enter_point = geometry_msgs::msg::Point().set__x(range.entering_point.x()).set__y(range.entering_point.y()); From 3f17ebf2a57129c3bc4aea21205f1f66383ac768 Mon Sep 17 00:00:00 2001 From: Maxime CLEMENT <maxime.clement@tier4.jp> Date: Fri, 1 Mar 2024 14:35:18 +0900 Subject: [PATCH 5/6] fix lint Signed-off-by: Maxime CLEMENT <maxime.clement@tier4.jp> --- planning/behavior_velocity_out_of_lane_module/src/decisions.cpp | 2 +- .../src/filter_predicted_objects.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/planning/behavior_velocity_out_of_lane_module/src/decisions.cpp b/planning/behavior_velocity_out_of_lane_module/src/decisions.cpp index d68c7c97df7d2..e948bd74eba45 100644 --- a/planning/behavior_velocity_out_of_lane_module/src/decisions.cpp +++ b/planning/behavior_velocity_out_of_lane_module/src/decisions.cpp @@ -79,7 +79,7 @@ std::optional<std::pair<double, double>> object_time_to_range( for (const auto & predicted_path : object.kinematics.predicted_paths) { const auto unique_path_points = motion_utils::removeOverlapPoints(predicted_path.path); - if(unique_path_points.size() < 2) continue; + if (unique_path_points.size() < 2) continue; const auto time_step = rclcpp::Duration(predicted_path.time_step).seconds(); const auto enter_point = geometry_msgs::msg::Point().set__x(range.entering_point.x()).set__y(range.entering_point.y()); diff --git a/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp b/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp index ed3f893887ece..a5da98c614ff7 100644 --- a/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp +++ b/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp @@ -50,7 +50,7 @@ void cut_predicted_path_beyond_line( } path_segment.first = path_segment.second; } - if(found) { + if (found) { auto cut_idx = stop_line_idx; double arc_length = 0; while (cut_idx > 0 && arc_length < object_front_overhang) { From 5d121853426aece5a68fadf6ca4766101307536e Mon Sep 17 00:00:00 2001 From: Maxime CLEMENT <maxime.clement@tier4.jp> Date: Mon, 4 Mar 2024 13:10:42 +0900 Subject: [PATCH 6/6] split filter_predicted_objects in hpp/cpp and add docstrings Signed-off-by: Maxime CLEMENT <maxime.clement@tier4.jp> --- .../src/filter_predicted_objects.cpp | 139 ++++++++++++++++++ .../src/filter_predicted_objects.hpp | 126 ++-------------- 2 files changed, 153 insertions(+), 112 deletions(-) create mode 100644 planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.cpp diff --git a/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.cpp b/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.cpp new file mode 100644 index 0000000000000..4a76ef2078d63 --- /dev/null +++ b/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.cpp @@ -0,0 +1,139 @@ +// Copyright 2023-2024 TIER IV, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "filter_predicted_objects.hpp" + +#include <motion_utils/trajectory/trajectory.hpp> +#include <traffic_light_utils/traffic_light_utils.hpp> + +#include <boost/geometry/algorithms/intersects.hpp> + +#include <lanelet2_core/geometry/LaneletMap.h> +#include <lanelet2_core/primitives/BasicRegulatoryElements.h> + +#include <algorithm> + +namespace behavior_velocity_planner::out_of_lane +{ +void cut_predicted_path_beyond_line( + autoware_auto_perception_msgs::msg::PredictedPath & predicted_path, + const lanelet::BasicLineString2d & stop_line, const double object_front_overhang) +{ + auto stop_line_idx = 0UL; + bool found = false; + lanelet::BasicSegment2d path_segment; + path_segment.first.x() = predicted_path.path.front().position.x; + path_segment.first.y() = predicted_path.path.front().position.y; + for (stop_line_idx = 1; stop_line_idx < predicted_path.path.size(); ++stop_line_idx) { + path_segment.second.x() = predicted_path.path[stop_line_idx].position.x; + path_segment.second.y() = predicted_path.path[stop_line_idx].position.y; + if (boost::geometry::intersects(stop_line, path_segment)) { + found = true; + break; + } + path_segment.first = path_segment.second; + } + if (found) { + auto cut_idx = stop_line_idx; + double arc_length = 0; + while (cut_idx > 0 && arc_length < object_front_overhang) { + arc_length += tier4_autoware_utils::calcDistance2d( + predicted_path.path[cut_idx], predicted_path.path[cut_idx - 1]); + --cut_idx; + } + predicted_path.path.resize(cut_idx); + } +} + +std::optional<const lanelet::BasicLineString2d> find_next_stop_line( + const autoware_auto_perception_msgs::msg::PredictedPath & path, const PlannerData & planner_data) +{ + lanelet::ConstLanelets lanelets; + lanelet::BasicLineString2d query_line; + for (const auto & p : path.path) query_line.emplace_back(p.position.x, p.position.y); + const auto query_results = lanelet::geometry::findWithin2d( + planner_data.route_handler_->getLaneletMapPtr()->laneletLayer, query_line); + for (const auto & r : query_results) lanelets.push_back(r.second); + for (const auto & ll : lanelets) { + for (const auto & element : ll.regulatoryElementsAs<lanelet::TrafficLight>()) { + const auto traffic_signal_stamped = planner_data.getTrafficSignal(element->id()); + if ( + traffic_signal_stamped.has_value() && element->stopLine().has_value() && + traffic_light_utils::isTrafficSignalStop(ll, traffic_signal_stamped.value().signal)) { + lanelet::BasicLineString2d stop_line; + for (const auto & p : *(element->stopLine())) stop_line.emplace_back(p.x(), p.y()); + return stop_line; + } + } + } + return std::nullopt; +} + +void cut_predicted_path_beyond_red_lights( + autoware_auto_perception_msgs::msg::PredictedPath & predicted_path, + const PlannerData & planner_data, const double object_front_overhang) +{ + const auto stop_line = find_next_stop_line(predicted_path, planner_data); + if (stop_line) cut_predicted_path_beyond_line(predicted_path, *stop_line, object_front_overhang); +} + +autoware_auto_perception_msgs::msg::PredictedObjects filter_predicted_objects( + const PlannerData & planner_data, const EgoData & ego_data, const PlannerParam & params) +{ + autoware_auto_perception_msgs::msg::PredictedObjects filtered_objects; + filtered_objects.header = planner_data.predicted_objects->header; + for (const auto & object : planner_data.predicted_objects->objects) { + const auto is_pedestrian = + std::find_if(object.classification.begin(), object.classification.end(), [](const auto & c) { + return c.label == autoware_auto_perception_msgs::msg::ObjectClassification::PEDESTRIAN; + }) != object.classification.end(); + if (is_pedestrian) continue; + + auto filtered_object = object; + const auto is_invalid_predicted_path = [&](const auto & predicted_path) { + const auto is_low_confidence = predicted_path.confidence < params.objects_min_confidence; + const auto no_overlap_path = motion_utils::removeOverlapPoints(predicted_path.path); + if (no_overlap_path.size() <= 1) return true; + const auto lat_offset_to_current_ego = + std::abs(motion_utils::calcLateralOffset(no_overlap_path, ego_data.pose.position)); + const auto is_crossing_ego = + lat_offset_to_current_ego <= + object.shape.dimensions.y / 2.0 + std::max( + params.left_offset + params.extra_left_offset, + params.right_offset + params.extra_right_offset); + return is_low_confidence || is_crossing_ego; + }; + if (params.objects_use_predicted_paths) { + auto & predicted_paths = filtered_object.kinematics.predicted_paths; + const auto new_end = + std::remove_if(predicted_paths.begin(), predicted_paths.end(), is_invalid_predicted_path); + predicted_paths.erase(new_end, predicted_paths.end()); + if (params.objects_cut_predicted_paths_beyond_red_lights) + for (auto & predicted_path : predicted_paths) + cut_predicted_path_beyond_red_lights( + predicted_path, planner_data, filtered_object.shape.dimensions.x); + predicted_paths.erase( + std::remove_if( + predicted_paths.begin(), predicted_paths.end(), + [](const auto & p) { return p.path.empty(); }), + predicted_paths.end()); + } + + if (!params.objects_use_predicted_paths || !filtered_object.kinematics.predicted_paths.empty()) + filtered_objects.objects.push_back(filtered_object); + } + return filtered_objects; +} + +} // namespace behavior_velocity_planner::out_of_lane diff --git a/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp b/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp index a5da98c614ff7..bb6b5f4d00005 100644 --- a/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp +++ b/planning/behavior_velocity_out_of_lane_module/src/filter_predicted_objects.hpp @@ -1,4 +1,4 @@ -// Copyright 2023 TIER IV, Inc. +// Copyright 2023-2024 TIER IV, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,85 +17,33 @@ #include "types.hpp" -#include <motion_utils/trajectory/trajectory.hpp> -#include <traffic_light_utils/traffic_light_utils.hpp> +#include <behavior_velocity_planner_common/planner_data.hpp> -#include <boost/geometry/algorithms/intersects.hpp> - -#include <lanelet2_core/geometry/LaneletMap.h> -#include <lanelet2_core/primitives/BasicRegulatoryElements.h> - -#include <algorithm> #include <optional> -#include <string> -#include <vector> namespace behavior_velocity_planner::out_of_lane { +/// @brief cut a predicted path beyond the given stop line +/// @param [inout] predicted_path predicted path to cut +/// @param [in] stop_line stop line used for cutting +/// @param [in] object_front_overhang extra distance to cut ahead of the stop line void cut_predicted_path_beyond_line( autoware_auto_perception_msgs::msg::PredictedPath & predicted_path, - const lanelet::BasicLineString2d & stop_line, const double object_front_overhang) -{ - auto stop_line_idx = 0UL; - bool found = false; - lanelet::BasicSegment2d path_segment; - path_segment.first.x() = predicted_path.path.front().position.x; - path_segment.first.y() = predicted_path.path.front().position.y; - for (stop_line_idx = 1; stop_line_idx < predicted_path.path.size(); ++stop_line_idx) { - path_segment.second.x() = predicted_path.path[stop_line_idx].position.x; - path_segment.second.y() = predicted_path.path[stop_line_idx].position.y; - if (boost::geometry::intersects(stop_line, path_segment)) { - found = true; - break; - } - path_segment.first = path_segment.second; - } - if (found) { - auto cut_idx = stop_line_idx; - double arc_length = 0; - while (cut_idx > 0 && arc_length < object_front_overhang) { - arc_length += tier4_autoware_utils::calcDistance2d( - predicted_path.path[cut_idx], predicted_path.path[cut_idx - 1]); - --cut_idx; - } - predicted_path.path.resize(cut_idx); - } -} + const lanelet::BasicLineString2d & stop_line, const double object_front_overhang); +/// @brief find the next red light stop line along the given path +/// @param [in] path predicted path to check for a stop line +/// @param [in] planner_data planner data with stop line information +/// @return the first red light stop line found along the path (if any) std::optional<const lanelet::BasicLineString2d> find_next_stop_line( - const autoware_auto_perception_msgs::msg::PredictedPath & path, const PlannerData & planner_data) -{ - lanelet::ConstLanelets lanelets; - lanelet::BasicLineString2d query_line; - for (const auto & p : path.path) query_line.emplace_back(p.position.x, p.position.y); - const auto query_results = lanelet::geometry::findWithin2d( - planner_data.route_handler_->getLaneletMapPtr()->laneletLayer, query_line); - for (const auto & r : query_results) lanelets.push_back(r.second); - for (const auto & ll : lanelets) { - for (const auto & element : ll.regulatoryElementsAs<lanelet::TrafficLight>()) { - const auto traffic_signal_stamped = planner_data.getTrafficSignal(element->id()); - if ( - traffic_signal_stamped.has_value() && element->stopLine().has_value() && - traffic_light_utils::isTrafficSignalStop(ll, traffic_signal_stamped.value().signal)) { - lanelet::BasicLineString2d stop_line; - for (const auto & p : *(element->stopLine())) stop_line.emplace_back(p.x(), p.y()); - return stop_line; - } - } - } - return std::nullopt; -} + const autoware_auto_perception_msgs::msg::PredictedPath & path, const PlannerData & planner_data); /// @brief cut predicted path beyond stop lines of red lights /// @param [inout] predicted_path predicted path to cut /// @param [in] planner_data planner data to get the map and traffic light information void cut_predicted_path_beyond_red_lights( autoware_auto_perception_msgs::msg::PredictedPath & predicted_path, - const PlannerData & planner_data, const double object_front_overhang) -{ - const auto stop_line = find_next_stop_line(predicted_path, planner_data); - if (stop_line) cut_predicted_path_beyond_line(predicted_path, *stop_line, object_front_overhang); -} + const PlannerData & planner_data, const double object_front_overhang); /// @brief filter predicted objects and their predicted paths /// @param [in] planner_data planner data @@ -103,53 +51,7 @@ void cut_predicted_path_beyond_red_lights( /// @param [in] params parameters /// @return filtered predicted objects autoware_auto_perception_msgs::msg::PredictedObjects filter_predicted_objects( - const PlannerData & planner_data, const EgoData & ego_data, const PlannerParam & params) -{ - autoware_auto_perception_msgs::msg::PredictedObjects filtered_objects; - filtered_objects.header = planner_data.predicted_objects->header; - for (const auto & object : planner_data.predicted_objects->objects) { - const auto is_pedestrian = - std::find_if(object.classification.begin(), object.classification.end(), [](const auto & c) { - return c.label == autoware_auto_perception_msgs::msg::ObjectClassification::PEDESTRIAN; - }) != object.classification.end(); - if (is_pedestrian) continue; - - auto filtered_object = object; - const auto is_invalid_predicted_path = [&](const auto & predicted_path) { - const auto is_low_confidence = predicted_path.confidence < params.objects_min_confidence; - const auto no_overlap_path = motion_utils::removeOverlapPoints(predicted_path.path); - if (no_overlap_path.size() <= 1) return true; - const auto lat_offset_to_current_ego = - std::abs(motion_utils::calcLateralOffset(no_overlap_path, ego_data.pose.position)); - const auto is_crossing_ego = - lat_offset_to_current_ego <= - object.shape.dimensions.y / 2.0 + std::max( - params.left_offset + params.extra_left_offset, - params.right_offset + params.extra_right_offset); - return is_low_confidence || is_crossing_ego; - }; - if (params.objects_use_predicted_paths) { - auto & predicted_paths = filtered_object.kinematics.predicted_paths; - const auto new_end = - std::remove_if(predicted_paths.begin(), predicted_paths.end(), is_invalid_predicted_path); - predicted_paths.erase(new_end, predicted_paths.end()); - if (params.objects_cut_predicted_paths_beyond_red_lights) - for (auto & predicted_path : predicted_paths) - cut_predicted_path_beyond_red_lights( - predicted_path, planner_data, filtered_object.shape.dimensions.x); - predicted_paths.erase( - std::remove_if( - predicted_paths.begin(), predicted_paths.end(), - [](const auto & p) { return p.path.empty(); }), - predicted_paths.end()); - } - - if (!params.objects_use_predicted_paths || !filtered_object.kinematics.predicted_paths.empty()) - filtered_objects.objects.push_back(filtered_object); - } - return filtered_objects; -} - + const PlannerData & planner_data, const EgoData & ego_data, const PlannerParam & params); } // namespace behavior_velocity_planner::out_of_lane #endif // FILTER_PREDICTED_OBJECTS_HPP_