Skip to content

Commit 2b4b64e

Browse files
maxime-clemHansRobo
authored andcommitted
feat(out_of_lane): cut predicted paths after red lights (#6478)
Signed-off-by: Maxime CLEMENT <maxime.clement@tier4.jp> Signed-off-by: Kotaro Yoshimoto <pythagora.yoshimoto@gmail.com>
1 parent 6e300a9 commit 2b4b64e

File tree

8 files changed

+195
-50
lines changed

8 files changed

+195
-50
lines changed

planning/behavior_velocity_out_of_lane_module/config/out_of_lane.param.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
# if false, assume the object moves at constant velocity along *all* lanelets it currently is located in.
1919
predicted_path_min_confidence : 0.1 # when using predicted paths, ignore the ones whose confidence is lower than this value.
2020
distance_buffer: 1.0 # [m] distance buffer used to determine if a collision will occur in the other lane
21+
cut_predicted_paths_beyond_red_lights: true # if true, predicted paths are cut beyond the stop line of red traffic lights
2122

2223
overlap:
2324
minimum_distance: 0.0 # [m] minimum distance inside a lanelet for an overlap to be considered

planning/behavior_velocity_out_of_lane_module/package.xml

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
<depend>tf2</depend>
2828
<depend>tier4_autoware_utils</depend>
2929
<depend>tier4_planning_msgs</depend>
30+
<depend>traffic_light_utils</depend>
3031
<depend>vehicle_info_util</depend>
3132
<depend>visualization_msgs</depend>
3233

planning/behavior_velocity_out_of_lane_module/src/decisions.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,13 @@ std::optional<std::pair<double, double>> object_time_to_range(
7373
if (!object_is_incoming(object_point, route_handler, range.lane)) return {};
7474

7575
const auto max_deviation = object.shape.dimensions.y + range.inside_distance + dist_buffer;
76+
const auto max_lon_deviation = object.shape.dimensions.x / 2.0;
7677
auto worst_enter_time = std::optional<double>();
7778
auto worst_exit_time = std::optional<double>();
7879

7980
for (const auto & predicted_path : object.kinematics.predicted_paths) {
8081
const auto unique_path_points = motion_utils::removeOverlapPoints(predicted_path.path);
82+
if (unique_path_points.size() < 2) continue;
8183
const auto time_step = rclcpp::Duration(predicted_path.time_step).seconds();
8284
const auto enter_point =
8385
geometry_msgs::msg::Point().set__x(range.entering_point.x()).set__y(range.entering_point.y());
@@ -121,7 +123,17 @@ std::optional<std::pair<double, double>> object_time_to_range(
121123
max_deviation);
122124
continue;
123125
}
124-
// else we rely on the interpolation to estimate beyond the end of the predicted path
126+
const auto is_last_predicted_path_point =
127+
(exit_segment_idx + 2 == unique_path_points.size() ||
128+
enter_segment_idx + 2 == unique_path_points.size());
129+
const auto does_not_reach_overlap =
130+
is_last_predicted_path_point && (std::min(exit_offset, enter_offset) > max_lon_deviation);
131+
if (does_not_reach_overlap) {
132+
RCLCPP_DEBUG(
133+
logger, " * does not reach the overlap = %2.2fm | max_dev = %2.2fm\n",
134+
std::min(exit_offset, enter_offset), max_lon_deviation);
135+
continue;
136+
}
125137

126138
const auto same_driving_direction_as_ego = enter_time < exit_time;
127139
if (same_driving_direction_as_ego) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// Copyright 2023-2024 TIER IV, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "filter_predicted_objects.hpp"
16+
17+
#include <motion_utils/trajectory/trajectory.hpp>
18+
#include <traffic_light_utils/traffic_light_utils.hpp>
19+
20+
#include <boost/geometry/algorithms/intersects.hpp>
21+
22+
#include <lanelet2_core/geometry/LaneletMap.h>
23+
#include <lanelet2_core/primitives/BasicRegulatoryElements.h>
24+
25+
#include <algorithm>
26+
27+
namespace behavior_velocity_planner::out_of_lane
28+
{
29+
void cut_predicted_path_beyond_line(
30+
autoware_auto_perception_msgs::msg::PredictedPath & predicted_path,
31+
const lanelet::BasicLineString2d & stop_line, const double object_front_overhang)
32+
{
33+
auto stop_line_idx = 0UL;
34+
bool found = false;
35+
lanelet::BasicSegment2d path_segment;
36+
path_segment.first.x() = predicted_path.path.front().position.x;
37+
path_segment.first.y() = predicted_path.path.front().position.y;
38+
for (stop_line_idx = 1; stop_line_idx < predicted_path.path.size(); ++stop_line_idx) {
39+
path_segment.second.x() = predicted_path.path[stop_line_idx].position.x;
40+
path_segment.second.y() = predicted_path.path[stop_line_idx].position.y;
41+
if (boost::geometry::intersects(stop_line, path_segment)) {
42+
found = true;
43+
break;
44+
}
45+
path_segment.first = path_segment.second;
46+
}
47+
if (found) {
48+
auto cut_idx = stop_line_idx;
49+
double arc_length = 0;
50+
while (cut_idx > 0 && arc_length < object_front_overhang) {
51+
arc_length += tier4_autoware_utils::calcDistance2d(
52+
predicted_path.path[cut_idx], predicted_path.path[cut_idx - 1]);
53+
--cut_idx;
54+
}
55+
predicted_path.path.resize(cut_idx);
56+
}
57+
}
58+
59+
std::optional<const lanelet::BasicLineString2d> find_next_stop_line(
60+
const autoware_auto_perception_msgs::msg::PredictedPath & path, const PlannerData & planner_data)
61+
{
62+
lanelet::ConstLanelets lanelets;
63+
lanelet::BasicLineString2d query_line;
64+
for (const auto & p : path.path) query_line.emplace_back(p.position.x, p.position.y);
65+
const auto query_results = lanelet::geometry::findWithin2d(
66+
planner_data.route_handler_->getLaneletMapPtr()->laneletLayer, query_line);
67+
for (const auto & r : query_results) lanelets.push_back(r.second);
68+
for (const auto & ll : lanelets) {
69+
for (const auto & element : ll.regulatoryElementsAs<lanelet::TrafficLight>()) {
70+
const auto traffic_signal_stamped = planner_data.getTrafficSignal(element->id());
71+
if (
72+
traffic_signal_stamped.has_value() && element->stopLine().has_value() &&
73+
traffic_light_utils::isTrafficSignalStop(ll, traffic_signal_stamped.value().signal)) {
74+
lanelet::BasicLineString2d stop_line;
75+
for (const auto & p : *(element->stopLine())) stop_line.emplace_back(p.x(), p.y());
76+
return stop_line;
77+
}
78+
}
79+
}
80+
return std::nullopt;
81+
}
82+
83+
void cut_predicted_path_beyond_red_lights(
84+
autoware_auto_perception_msgs::msg::PredictedPath & predicted_path,
85+
const PlannerData & planner_data, const double object_front_overhang)
86+
{
87+
const auto stop_line = find_next_stop_line(predicted_path, planner_data);
88+
if (stop_line) cut_predicted_path_beyond_line(predicted_path, *stop_line, object_front_overhang);
89+
}
90+
91+
autoware_auto_perception_msgs::msg::PredictedObjects filter_predicted_objects(
92+
const PlannerData & planner_data, const EgoData & ego_data, const PlannerParam & params)
93+
{
94+
autoware_auto_perception_msgs::msg::PredictedObjects filtered_objects;
95+
filtered_objects.header = planner_data.predicted_objects->header;
96+
for (const auto & object : planner_data.predicted_objects->objects) {
97+
const auto is_pedestrian =
98+
std::find_if(object.classification.begin(), object.classification.end(), [](const auto & c) {
99+
return c.label == autoware_auto_perception_msgs::msg::ObjectClassification::PEDESTRIAN;
100+
}) != object.classification.end();
101+
if (is_pedestrian) continue;
102+
103+
auto filtered_object = object;
104+
const auto is_invalid_predicted_path = [&](const auto & predicted_path) {
105+
const auto is_low_confidence = predicted_path.confidence < params.objects_min_confidence;
106+
const auto no_overlap_path = motion_utils::removeOverlapPoints(predicted_path.path);
107+
if (no_overlap_path.size() <= 1) return true;
108+
const auto lat_offset_to_current_ego =
109+
std::abs(motion_utils::calcLateralOffset(no_overlap_path, ego_data.pose.position));
110+
const auto is_crossing_ego =
111+
lat_offset_to_current_ego <=
112+
object.shape.dimensions.y / 2.0 + std::max(
113+
params.left_offset + params.extra_left_offset,
114+
params.right_offset + params.extra_right_offset);
115+
return is_low_confidence || is_crossing_ego;
116+
};
117+
if (params.objects_use_predicted_paths) {
118+
auto & predicted_paths = filtered_object.kinematics.predicted_paths;
119+
const auto new_end =
120+
std::remove_if(predicted_paths.begin(), predicted_paths.end(), is_invalid_predicted_path);
121+
predicted_paths.erase(new_end, predicted_paths.end());
122+
if (params.objects_cut_predicted_paths_beyond_red_lights)
123+
for (auto & predicted_path : predicted_paths)
124+
cut_predicted_path_beyond_red_lights(
125+
predicted_path, planner_data, filtered_object.shape.dimensions.x);
126+
predicted_paths.erase(
127+
std::remove_if(
128+
predicted_paths.begin(), predicted_paths.end(),
129+
[](const auto & p) { return p.path.empty(); }),
130+
predicted_paths.end());
131+
}
132+
133+
if (!params.objects_use_predicted_paths || !filtered_object.kinematics.predicted_paths.empty())
134+
filtered_objects.objects.push_back(filtered_object);
135+
}
136+
return filtered_objects;
137+
}
138+
139+
} // namespace behavior_velocity_planner::out_of_lane
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2023 TIER IV, Inc.
1+
// Copyright 2023-2024 TIER IV, Inc.
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -17,56 +17,41 @@
1717

1818
#include "types.hpp"
1919

20-
#include <motion_utils/trajectory/trajectory.hpp>
20+
#include <behavior_velocity_planner_common/planner_data.hpp>
2121

22-
#include <string>
22+
#include <optional>
2323

2424
namespace behavior_velocity_planner::out_of_lane
2525
{
26+
/// @brief cut a predicted path beyond the given stop line
27+
/// @param [inout] predicted_path predicted path to cut
28+
/// @param [in] stop_line stop line used for cutting
29+
/// @param [in] object_front_overhang extra distance to cut ahead of the stop line
30+
void cut_predicted_path_beyond_line(
31+
autoware_auto_perception_msgs::msg::PredictedPath & predicted_path,
32+
const lanelet::BasicLineString2d & stop_line, const double object_front_overhang);
33+
34+
/// @brief find the next red light stop line along the given path
35+
/// @param [in] path predicted path to check for a stop line
36+
/// @param [in] planner_data planner data with stop line information
37+
/// @return the first red light stop line found along the path (if any)
38+
std::optional<const lanelet::BasicLineString2d> find_next_stop_line(
39+
const autoware_auto_perception_msgs::msg::PredictedPath & path, const PlannerData & planner_data);
40+
41+
/// @brief cut predicted path beyond stop lines of red lights
42+
/// @param [inout] predicted_path predicted path to cut
43+
/// @param [in] planner_data planner data to get the map and traffic light information
44+
void cut_predicted_path_beyond_red_lights(
45+
autoware_auto_perception_msgs::msg::PredictedPath & predicted_path,
46+
const PlannerData & planner_data, const double object_front_overhang);
47+
2648
/// @brief filter predicted objects and their predicted paths
27-
/// @param [in] objects predicted objects to filter
49+
/// @param [in] planner_data planner data
2850
/// @param [in] ego_data ego data
2951
/// @param [in] params parameters
3052
/// @return filtered predicted objects
3153
autoware_auto_perception_msgs::msg::PredictedObjects filter_predicted_objects(
32-
const autoware_auto_perception_msgs::msg::PredictedObjects & objects, const EgoData & ego_data,
33-
const PlannerParam & params)
34-
{
35-
autoware_auto_perception_msgs::msg::PredictedObjects filtered_objects;
36-
filtered_objects.header = objects.header;
37-
for (const auto & object : objects.objects) {
38-
const auto is_pedestrian =
39-
std::find_if(object.classification.begin(), object.classification.end(), [](const auto & c) {
40-
return c.label == autoware_auto_perception_msgs::msg::ObjectClassification::PEDESTRIAN;
41-
}) != object.classification.end();
42-
if (is_pedestrian) continue;
43-
44-
auto filtered_object = object;
45-
const auto is_invalid_predicted_path = [&](const auto & predicted_path) {
46-
const auto is_low_confidence = predicted_path.confidence < params.objects_min_confidence;
47-
const auto no_overlap_path = motion_utils::removeOverlapPoints(predicted_path.path);
48-
if (no_overlap_path.size() <= 1) return true;
49-
const auto lat_offset_to_current_ego =
50-
std::abs(motion_utils::calcLateralOffset(no_overlap_path, ego_data.pose.position));
51-
const auto is_crossing_ego =
52-
lat_offset_to_current_ego <=
53-
object.shape.dimensions.y / 2.0 + std::max(
54-
params.left_offset + params.extra_left_offset,
55-
params.right_offset + params.extra_right_offset);
56-
return is_low_confidence || is_crossing_ego;
57-
};
58-
if (params.objects_use_predicted_paths) {
59-
auto & predicted_paths = filtered_object.kinematics.predicted_paths;
60-
const auto new_end =
61-
std::remove_if(predicted_paths.begin(), predicted_paths.end(), is_invalid_predicted_path);
62-
predicted_paths.erase(new_end, predicted_paths.end());
63-
}
64-
if (!params.objects_use_predicted_paths || !filtered_object.kinematics.predicted_paths.empty())
65-
filtered_objects.objects.push_back(filtered_object);
66-
}
67-
return filtered_objects;
68-
}
69-
54+
const PlannerData & planner_data, const EgoData & ego_data, const PlannerParam & params);
7055
} // namespace behavior_velocity_planner::out_of_lane
7156

7257
#endif // FILTER_PREDICTED_OBJECTS_HPP_

planning/behavior_velocity_out_of_lane_module/src/manager.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ OutOfLaneModuleManager::OutOfLaneModuleManager(rclcpp::Node & node)
5151
pp.objects_min_confidence =
5252
getOrDeclareParameter<double>(node, ns + ".objects.predicted_path_min_confidence");
5353
pp.objects_dist_buffer = getOrDeclareParameter<double>(node, ns + ".objects.distance_buffer");
54+
pp.objects_cut_predicted_paths_beyond_red_lights =
55+
getOrDeclareParameter<bool>(node, ns + ".objects.cut_predicted_paths_beyond_red_lights");
5456

5557
pp.overlap_min_dist = getOrDeclareParameter<double>(node, ns + ".overlap.minimum_distance");
5658
pp.overlap_extra_length = getOrDeclareParameter<double>(node, ns + ".overlap.extra_length");

planning/behavior_velocity_out_of_lane_module/src/scene_out_of_lane.cpp

+8-5
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,15 @@ bool OutOfLaneModule::modifyPathVelocity(PathWithLaneId * path, StopReason * sto
109109
calculate_overlapping_ranges(path_footprints, path_lanelets, other_lanelets, params_);
110110
const auto calculate_overlapping_ranges_us = stopwatch.toc("calculate_overlapping_ranges");
111111
// Calculate stop and slowdown points
112-
stopwatch.tic("calculate_decisions");
113112
DecisionInputs inputs;
114113
inputs.ranges = ranges;
115114
inputs.ego_data = ego_data;
116-
inputs.objects = filter_predicted_objects(*planner_data_->predicted_objects, ego_data, params_);
115+
stopwatch.tic("filter_predicted_objects");
116+
inputs.objects = filter_predicted_objects(*planner_data_, ego_data, params_);
117+
const auto filter_predicted_objects_ms = stopwatch.toc("filter_predicted_objects");
117118
inputs.route_handler = planner_data_->route_handler_;
118119
inputs.lanelets = other_lanelets;
120+
stopwatch.tic("calculate_decisions");
119121
const auto decisions = calculate_decisions(inputs, params_, logger_);
120122
const auto calculate_decisions_us = stopwatch.toc("calculate_decisions");
121123
stopwatch.tic("calc_slowdown_points");
@@ -157,7 +159,7 @@ bool OutOfLaneModule::modifyPathVelocity(PathWithLaneId * path, StopReason * sto
157159
}
158160
if (point_to_insert) {
159161
prev_inserted_point_ = point_to_insert;
160-
RCLCPP_INFO(logger_, "Avoiding lane %lu", point_to_insert->slowdown.lane_to_avoid.id());
162+
RCLCPP_DEBUG(logger_, "Avoiding lane %lu", point_to_insert->slowdown.lane_to_avoid.id());
161163
debug_data_.slowdowns = {*point_to_insert};
162164
auto path_idx = motion_utils::findNearestSegmentIndex(
163165
path->points, point_to_insert->point.point.pose.position) +
@@ -187,12 +189,13 @@ bool OutOfLaneModule::modifyPathVelocity(PathWithLaneId * path, StopReason * sto
187189
"\tcalculate_lanelets = %2.0fus\n"
188190
"\tcalculate_path_footprints = %2.0fus\n"
189191
"\tcalculate_overlapping_ranges = %2.0fus\n"
192+
"\tfilter_pred_objects = %2.0fus\n"
190193
"\tcalculate_decisions = %2.0fus\n"
191194
"\tcalc_slowdown_points = %2.0fus\n"
192195
"\tinsert_slowdown_points = %2.0fus\n",
193196
total_time_us, calculate_lanelets_us, calculate_path_footprints_us,
194-
calculate_overlapping_ranges_us, calculate_decisions_us, calc_slowdown_points_us,
195-
insert_slowdown_points_us);
197+
calculate_overlapping_ranges_us, filter_predicted_objects_ms, calculate_decisions_us,
198+
calc_slowdown_points_us, insert_slowdown_points_us);
196199
return true;
197200
}
198201

planning/behavior_velocity_out_of_lane_module/src/types.hpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ struct PlannerParam
4747
double ego_min_velocity; // [m/s] minimum velocity of ego used to calculate its ttc or time range
4848

4949
bool objects_use_predicted_paths; // whether to use the objects' predicted paths
50-
double objects_min_vel; // [m/s] objects lower than this velocity will be ignored
51-
double objects_min_confidence; // minimum confidence to consider a predicted path
50+
bool objects_cut_predicted_paths_beyond_red_lights; // whether to cut predicted paths beyond red
51+
// lights' stop lines
52+
double objects_min_vel; // [m/s] objects lower than this velocity will be ignored
53+
double objects_min_confidence; // minimum confidence to consider a predicted path
5254
double objects_dist_buffer; // [m] distance buffer used to determine if a collision will occur in
5355
// the other lane
5456

0 commit comments

Comments
 (0)