28#include "modules/common_msgs/basic_msgs/pnc_point.pb.h"
29#include "modules/common_msgs/planning_msgs/decision.pb.h"
54 const PathData& path_data,
const double planning_distance,
55 const double planning_time,
56 const std::shared_ptr<DependencyInjector>& injector)
57 : speed_bounds_config_(config),
58 reference_line_(reference_line),
59 path_data_(path_data),
61 planning_max_distance_(planning_distance),
62 planning_max_time_(planning_time),
63 injector_(injector) {}
67 CHECK_GT(planning_max_time_, 0.0);
69 AERROR <<
"Fail to get params because of too few path points. path points "
72 return Status(ErrorCode::PLANNING_ERROR,
73 "Fail to get params because of too few path points");
78 ObjectDecisionType stop_decision;
79 double min_stop_s = std::numeric_limits<double>::max();
80 for (
const auto* ptr_obstacle_item : path_decision->
obstacles().
Items()) {
81 Obstacle* ptr_obstacle = path_decision->
Find(ptr_obstacle_item->Id());
82 ACHECK(ptr_obstacle !=
nullptr);
92 if (decision.has_stop()) {
96 reference_line_.
XYToSL(decision.stop().stop_point(), &stop_sl_point);
97 const double stop_s = stop_sl_point.
s();
99 if (stop_s < min_stop_s) {
100 stop_obstacle = ptr_obstacle;
102 stop_decision = decision;
104 }
else if (decision.has_follow() || decision.has_overtake() ||
105 decision.has_yield()) {
108 ComputeSTBoundaryWithDecision(ptr_obstacle, decision);
109 }
else if (!decision.has_ignore()) {
111 AWARN <<
"No mapping for decision: " << decision.DebugString();
115 bool success = MapStopDecision(stop_obstacle, stop_decision);
117 const std::string msg =
"Fail to MapStopDecision.";
119 return Status(ErrorCode::PLANNING_ERROR, msg);
126bool STBoundaryMapper::MapStopDecision(
127 Obstacle* stop_obstacle,
const ObjectDecisionType& stop_decision)
const {
128 DCHECK(stop_decision.has_stop()) <<
"Must have stop decision";
130 reference_line_.
XYToSL(stop_decision.stop().stop_point(), &stop_sl_point);
132 double st_stop_s = 0.0;
133 const double stop_ref_s =
140 PathPoint stop_point;
144 st_stop_s = stop_point.s();
147 const double s_min = std::fmax(0.0, st_stop_s);
148 const double s_max = std::fmax(
149 s_min, std::fmax(planning_max_distance_, reference_line_.
Length()));
151 std::vector<std::pair<STPoint, STPoint>> point_pairs;
152 point_pairs.emplace_back(STPoint(s_min, 0.0), STPoint(s_max, 0.0));
153 point_pairs.emplace_back(
154 STPoint(s_min, planning_max_time_),
156 planning_max_time_));
157 auto boundary = STBoundary(point_pairs);
159 boundary.SetCharacteristicLength(speed_bounds_config_.
boundary_buffer());
160 boundary.set_id(stop_obstacle->
Id());
166 if (FLAGS_use_st_drivable_boundary) {
169 std::vector<STPoint> lower_points;
170 std::vector<STPoint> upper_points;
173 &upper_points, &lower_points)) {
178 boundary.set_id(obstacle->Id());
181 const auto& prev_st_boundary = obstacle->path_st_boundary();
182 const auto& ref_line_st_boundary = obstacle->reference_line_st_boundary();
183 if (!prev_st_boundary.IsEmpty()) {
184 boundary.SetBoundaryType(prev_st_boundary.boundary_type());
185 }
else if (!ref_line_st_boundary.IsEmpty()) {
186 boundary.SetBoundaryType(ref_line_st_boundary.boundary_type());
189 obstacle->set_path_st_boundary(boundary);
192bool STBoundaryMapper::GetOverlapBoundaryPoints(
193 const std::vector<PathPoint>& path_points,
const Obstacle& obstacle,
194 std::vector<STPoint>* upper_points,
195 std::vector<STPoint>* lower_points)
const {
197 DCHECK(upper_points->empty());
198 DCHECK(lower_points->empty());
199 if (path_points.empty()) {
200 AERROR <<
"No points in path_data_.discretized_path().";
204 const auto* planning_status = injector_->planning_context()
205 ->mutable_planning_status()
206 ->mutable_change_lane();
211 : FLAGS_nonstatic_obstacle_nudge_l_buffer;
214 const auto& trajectory = obstacle.Trajectory();
215 const double obstacle_length = obstacle.Perception().length();
216 const double obstacle_width = obstacle.Perception().width();
217 PrintCurves print_path_collision;
218 if (trajectory.trajectory_point().empty()) {
219 bool box_check_collision =
false;
223 if (!obstacle.IsStatic()) {
224 AWARN <<
"Non-static obstacle[" << obstacle.Id()
225 <<
"] has NO prediction trajectory."
226 << obstacle.Perception().ShortDebugString();
229 const Box2d& obs_box = obstacle.PerceptionBoundingBox();
231 for (
const auto& curr_point_on_path : path_points) {
232 if (curr_point_on_path.s() > planning_max_distance_) {
235 if (CheckOverlap(curr_point_on_path, obs_box, l_buffer)) {
236 box_check_collision =
true;
241 if (box_check_collision) {
244 const double backward_distance = 0;
245 const double forward_distance = obs_box.length();
247 for (
const auto& curr_point_on_path : path_points) {
248 if (curr_point_on_path.s() > planning_max_distance_) {
251 const Polygon2d& obs_polygon = obstacle.PerceptionPolygon();
252 Polygon2d ego_collision_polygon;
253 if (CheckOverlap(curr_point_on_path, obs_polygon, l_buffer, &ego_collision_polygon)) {
256 std::fmax(0.0, curr_point_on_path.s() + backward_distance);
257 double high_s = std::fmin(planning_max_distance_,
258 curr_point_on_path.s() + forward_distance);
259 AINFO <<
"check colllision for obstacle[" << obstacle.Id()
260 <<
"], at: " << curr_point_on_path.DebugString();
261 for (
const auto& point : ego_collision_polygon.points()) {
262 print_path_collision.AddPoint(obstacle.Id() +
"_collision_path_point",
263 point.x(), point.y());
265 print_path_collision.AddPoint(obstacle.Id() +
"_collision_path_point", ego_collision_polygon.points().front().x(), ego_collision_polygon.points().front().y());
269 lower_points->emplace_back(low_s - speed_bounds_config_.
point_extension(), 0.0);
270 lower_points->emplace_back(low_s - speed_bounds_config_.
point_extension(), planning_max_time_);
271 upper_points->emplace_back(high_s + speed_bounds_config_.
point_extension(), 0.0);
272 upper_points->emplace_back(high_s + speed_bounds_config_.
point_extension(), planning_max_time_);
276 print_path_collision.PrintToLog();
281 const int default_num_point = 50;
282 DiscretizedPath discretized_path;
283 if (path_points.size() > 2 * default_num_point) {
284 const auto ratio = path_points.size() / default_num_point;
285 std::vector<PathPoint> sampled_path_points;
286 for (
size_t i = 0; i < path_points.size(); ++i) {
287 if (i % ratio == 0) {
288 sampled_path_points.push_back(path_points[i]);
291 discretized_path = DiscretizedPath(std::move(sampled_path_points));
293 discretized_path = DiscretizedPath(path_points);
297 double trajectory_time_interval =
298 obstacle.Trajectory().trajectory_point()[1].relative_time();
299 int trajectory_step =
300 std::min(FLAGS_trajectory_check_collision_time_step,
301 std::max(vehicle_param_.
width() / obstacle.speed() /
302 trajectory_time_interval,
304 bool trajectory_point_collision_status =
false;
305 int previous_index = 0;
307 for (
int i = 0; i < trajectory.trajectory_point_size();
308 i = std::min(i + trajectory_step,
309 trajectory.trajectory_point_size() - 1)) {
310 const auto& trajectory_point = trajectory.trajectory_point(i);
311 Polygon2d obstacle_shape =
312 obstacle.GetObstacleTrajectoryPolygon(trajectory_point);
314 double trajectory_point_time = trajectory_point.relative_time();
315 static constexpr double kNegtiveTimeThreshold = -1.0;
316 if (trajectory_point_time < kNegtiveTimeThreshold) {
319 bool collision = CheckOverlapWithTrajectoryPoint(
320 discretized_path, obstacle_shape, upper_points, lower_points,
321 l_buffer, default_num_point, obstacle_length, obstacle_width,
322 trajectory_point_time);
323 if ((trajectory_point_collision_status ^ collision) && i != 0) {
326 while ((trajectory_point_collision_status ^ collision) &&
327 index > previous_index) {
328 const auto& point = trajectory.trajectory_point(index);
329 trajectory_point_time = point.relative_time();
330 obstacle_shape = obstacle.GetObstacleTrajectoryPolygon(point);
331 collision = CheckOverlapWithTrajectoryPoint(
332 discretized_path, obstacle_shape, upper_points, lower_points,
333 l_buffer, default_num_point, obstacle_length, obstacle_width,
334 trajectory_point_time);
337 trajectory_point_collision_status = !trajectory_point_collision_status;
339 if (i == trajectory.trajectory_point_size() - 1)
break;
345 std::sort(lower_points->begin(), lower_points->end(),
346 [](
const STPoint& a,
const STPoint& b) { return a.t() < b.t(); });
347 std::sort(upper_points->begin(), upper_points->end(),
348 [](
const STPoint& a,
const STPoint& b) { return a.t() < b.t(); });
349 DCHECK_EQ(lower_points->size(), upper_points->size());
350 return (lower_points->size() > 1 && upper_points->size() > 1);
353bool STBoundaryMapper::CheckOverlapWithTrajectoryPoint(
354 const DiscretizedPath& discretized_path,
const Polygon2d& obstacle_shape,
355 std::vector<STPoint>* upper_points, std::vector<STPoint>* lower_points,
356 const double l_buffer,
int default_num_point,
const double obstacle_length,
357 const double obstacle_width,
const double trajectory_point_time)
const {
360 discretized_path.Length());
362 for (
double path_s = 0.0; path_s < path_len; path_s += step_length) {
363 const auto curr_adc_path_point =
364 discretized_path.Evaluate(path_s + discretized_path.front().s());
365 if (CheckOverlap(curr_adc_path_point, obstacle_shape, l_buffer)) {
368 const double backward_distance = 0.0;
369 const double forward_distance = vehicle_param_.
length() +
370 vehicle_param_.
width() + obstacle_length +
372 const double default_min_step = 0.1;
373 const double fine_tuning_step_length = std::fmin(
374 default_min_step, discretized_path.Length() / default_num_point);
376 bool find_low =
false;
377 bool find_high =
false;
378 double low_s = std::fmax(0.0, path_s + backward_distance);
380 std::fmin(discretized_path.Length(), path_s + forward_distance);
384 while (low_s < high_s) {
385 if (find_low && find_high) {
389 const auto& point_low =
390 discretized_path.Evaluate(low_s + discretized_path.front().s());
391 if (!CheckOverlap(point_low, obstacle_shape, l_buffer)) {
392 low_s += fine_tuning_step_length;
398 const auto& point_high =
399 discretized_path.Evaluate(high_s + discretized_path.front().s());
400 if (!CheckOverlap(point_high, obstacle_shape, l_buffer)) {
401 high_s -= fine_tuning_step_length;
407 if (find_high && find_low) {
408 lower_points->emplace_back(
410 trajectory_point_time);
411 upper_points->emplace_back(
413 trajectory_point_time);
421void STBoundaryMapper::ComputeSTBoundaryWithDecision(
422 Obstacle* obstacle,
const ObjectDecisionType& decision)
const {
423 DCHECK(decision.has_follow() || decision.has_yield() ||
424 decision.has_overtake())
425 <<
"decision is " << decision.DebugString()
426 <<
", but it must be follow or yield or overtake.";
428 std::vector<STPoint> lower_points;
429 std::vector<STPoint> upper_points;
431 if (FLAGS_use_st_drivable_boundary &&
432 obstacle->is_path_st_boundary_initialized()) {
433 const auto& path_st_boundary = obstacle->path_st_boundary();
434 lower_points = path_st_boundary.lower_points();
435 upper_points = path_st_boundary.upper_points();
438 &upper_points, &lower_points)) {
447 double characteristic_length = 0.0;
448 if (decision.has_follow()) {
449 characteristic_length = std::fabs(decision.follow().distance_s());
450 AINFO <<
"characteristic_length: " << characteristic_length;
454 }
else if (decision.has_yield()) {
455 characteristic_length = std::fabs(decision.yield().distance_s());
459 }
else if (decision.has_overtake()) {
460 characteristic_length = std::fabs(decision.overtake().distance_s());
463 DCHECK(
false) <<
"Obj decision should be either yield or overtake: "
464 << decision.DebugString();
466 boundary.SetBoundaryType(b_type);
467 boundary.set_id(obstacle->Id());
468 boundary.SetCharacteristicLength(characteristic_length);
469 obstacle->set_path_st_boundary(boundary);
472bool STBoundaryMapper::CheckOverlap(
const PathPoint& path_point,
473 const Box2d& obs_box,
474 const double l_buffer)
const {
482 ego_center_map_frame.SelfRotate(path_point.theta());
483 ego_center_map_frame.set_x(ego_center_map_frame.x() + path_point.x());
484 ego_center_map_frame.set_y(ego_center_map_frame.y() + path_point.y());
487 Box2d adc_box(ego_center_map_frame, path_point.theta(),
488 vehicle_param_.
length(), vehicle_param_.
width() + l_buffer * 2);
491 return obs_box.HasOverlap(adc_box);
494bool STBoundaryMapper::CheckOverlap(
const PathPoint& path_point,
495 const Polygon2d& obs_polygon,
496 const double l_buffer,
497 Polygon2d* collision_ego_polygon)
const {
505 ego_center_map_frame.SelfRotate(path_point.theta());
506 ego_center_map_frame.set_x(ego_center_map_frame.x() + path_point.x());
507 ego_center_map_frame.set_y(ego_center_map_frame.y() + path_point.y());
510 Box2d adc_box(ego_center_map_frame, path_point.theta(),
511 vehicle_param_.
length(), vehicle_param_.
width() + l_buffer * 2);
515 Polygon2d adc_polygon(adc_box);
516 if (obs_polygon.HasOverlap(adc_polygon)) {
517 if (collision_ego_polygon !=
nullptr) {
518 *collision_ego_polygon = adc_polygon;
A general class to denote the return status of an API call.
static Status OK()
generate a success status.
@Brief This is a helper class that can load vehicle configurations.
Rectangular (undirected) bounding box in 2-D.
The class of polygon in 2-D.
Implements a class of 2-dimensional vectors.
const std::vector< const T * > & Items() const
List all the items in the container.
This is the class that associates an Obstacle with its path properties.
bool HasLongitudinalDecision() const
const ObjectDecisionType & LongitudinalDecision() const
return the merged longitudinal decision Longitudinal decision is one of {Stop, Yield,...
const std::string & Id() const
void set_path_st_boundary(const STBoundary &boundary)
const FrenetFramePath & frenet_frame_path() const
bool GetPathPointWithRefS(const double ref_s, common::PathPoint *const path_point) const
const DiscretizedPath & discretized_path() const
PathDecision represents all obstacle decisions on one path.
const Obstacle * Find(const std::string &object_id) const
const IndexedList< std::string, Obstacle > & obstacles() const
bool XYToSL(const common::math::Vec2d &xy_point, common::SLPoint *const sl_point, double warm_start_s=-1.0) const
Transvert Cartesian coordinates to Frenet.
common::Status ComputeSTBoundary(PathDecision *path_decision) const
STBoundaryMapper(const SpeedBoundsDeciderConfig &config, const ReferenceLine &reference_line, const PathData &path_data, const double planning_distance, const double planning_time, const std::shared_ptr< DependencyInjector > &injector)
static STBoundary CreateInstance(const std::vector< STPoint > &lower_points, const std::vector< STPoint > &upper_points)
Wrapper of the constructor (old).
STBoundary ExpandByS(const double s) const
Planning module main class.
Define the LineSegment2d class.
Some string util functions.
optional double left_edge_to_center
optional double back_edge_to_center
optional double front_edge_to_center
optional double right_edge_to_center
optional double lane_change_obstacle_nudge_l_buffer
optional double boundary_buffer
optional double point_extension
optional double max_trajectory_len