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 if (trajectory.trajectory_point().empty()) {
218 bool box_check_collision =
false;
222 if (!obstacle.IsStatic()) {
223 AWARN <<
"Non-static obstacle[" << obstacle.Id()
224 <<
"] has NO prediction trajectory."
225 << obstacle.Perception().ShortDebugString();
228 const Box2d& obs_box = obstacle.PerceptionBoundingBox();
230 for (
const auto& curr_point_on_path : path_points) {
231 if (curr_point_on_path.s() > planning_max_distance_) {
234 if (CheckOverlap(curr_point_on_path, obs_box, l_buffer)) {
235 box_check_collision =
true;
240 if (box_check_collision) {
243 const double backward_distance = 0;
244 const double forward_distance = obs_box.length();
246 for (
const auto& curr_point_on_path : path_points) {
247 if (curr_point_on_path.s() > planning_max_distance_) {
250 const Polygon2d& obs_polygon = obstacle.PerceptionPolygon();
251 if (CheckOverlap(curr_point_on_path, obs_polygon, l_buffer)) {
254 std::fmax(0.0, curr_point_on_path.s() + backward_distance);
255 double high_s = std::fmin(planning_max_distance_,
256 curr_point_on_path.s() + forward_distance);
257 AINFO <<
"check colllision for obstacle[" << obstacle.Id()
258 <<
"], at: " << curr_point_on_path.DebugString();
262 lower_points->emplace_back(
264 lower_points->emplace_back(
267 upper_points->emplace_back(
269 upper_points->emplace_back(
279 const int default_num_point = 50;
280 DiscretizedPath discretized_path;
281 if (path_points.size() > 2 * default_num_point) {
282 const auto ratio = path_points.size() / default_num_point;
283 std::vector<PathPoint> sampled_path_points;
284 for (
size_t i = 0; i < path_points.size(); ++i) {
285 if (i % ratio == 0) {
286 sampled_path_points.push_back(path_points[i]);
289 discretized_path = DiscretizedPath(std::move(sampled_path_points));
291 discretized_path = DiscretizedPath(path_points);
295 double trajectory_time_interval =
296 obstacle.Trajectory().trajectory_point()[1].relative_time();
297 int trajectory_step =
298 std::min(FLAGS_trajectory_check_collision_time_step,
299 std::max(vehicle_param_.
width() / obstacle.speed() /
300 trajectory_time_interval,
302 bool trajectory_point_collision_status =
false;
303 int previous_index = 0;
305 for (
int i = 0; i < trajectory.trajectory_point_size();
306 i = std::min(i + trajectory_step,
307 trajectory.trajectory_point_size() - 1)) {
308 const auto& trajectory_point = trajectory.trajectory_point(i);
309 Polygon2d obstacle_shape =
310 obstacle.GetObstacleTrajectoryPolygon(trajectory_point);
312 double trajectory_point_time = trajectory_point.relative_time();
313 static constexpr double kNegtiveTimeThreshold = -1.0;
314 if (trajectory_point_time < kNegtiveTimeThreshold) {
317 bool collision = CheckOverlapWithTrajectoryPoint(
318 discretized_path, obstacle_shape, upper_points, lower_points,
319 l_buffer, default_num_point, obstacle_length, obstacle_width,
320 trajectory_point_time);
321 if ((trajectory_point_collision_status ^ collision) && i != 0) {
324 while ((trajectory_point_collision_status ^ collision) &&
325 index > previous_index) {
326 const auto& point = trajectory.trajectory_point(index);
327 trajectory_point_time = point.relative_time();
328 obstacle_shape = obstacle.GetObstacleTrajectoryPolygon(point);
329 collision = CheckOverlapWithTrajectoryPoint(
330 discretized_path, obstacle_shape, upper_points, lower_points,
331 l_buffer, default_num_point, obstacle_length, obstacle_width,
332 trajectory_point_time);
335 trajectory_point_collision_status = !trajectory_point_collision_status;
337 if (i == trajectory.trajectory_point_size() - 1)
break;
343 std::sort(lower_points->begin(), lower_points->end(),
344 [](
const STPoint& a,
const STPoint& b) { return a.t() < b.t(); });
345 std::sort(upper_points->begin(), upper_points->end(),
346 [](
const STPoint& a,
const STPoint& b) { return a.t() < b.t(); });
347 DCHECK_EQ(lower_points->size(), upper_points->size());
348 return (lower_points->size() > 1 && upper_points->size() > 1);
351bool STBoundaryMapper::CheckOverlapWithTrajectoryPoint(
352 const DiscretizedPath& discretized_path,
const Polygon2d& obstacle_shape,
353 std::vector<STPoint>* upper_points, std::vector<STPoint>* lower_points,
354 const double l_buffer,
int default_num_point,
const double obstacle_length,
355 const double obstacle_width,
const double trajectory_point_time)
const {
358 discretized_path.Length());
360 for (
double path_s = 0.0; path_s < path_len; path_s += step_length) {
361 const auto curr_adc_path_point =
362 discretized_path.Evaluate(path_s + discretized_path.front().s());
363 if (CheckOverlap(curr_adc_path_point, obstacle_shape, l_buffer)) {
366 const double backward_distance = 0.0;
367 const double forward_distance = vehicle_param_.
length() +
368 vehicle_param_.
width() + obstacle_length +
370 const double default_min_step = 0.1;
371 const double fine_tuning_step_length = std::fmin(
372 default_min_step, discretized_path.Length() / default_num_point);
374 bool find_low =
false;
375 bool find_high =
false;
376 double low_s = std::fmax(0.0, path_s + backward_distance);
378 std::fmin(discretized_path.Length(), path_s + forward_distance);
382 while (low_s < high_s) {
383 if (find_low && find_high) {
387 const auto& point_low =
388 discretized_path.Evaluate(low_s + discretized_path.front().s());
389 if (!CheckOverlap(point_low, obstacle_shape, l_buffer)) {
390 low_s += fine_tuning_step_length;
396 const auto& point_high =
397 discretized_path.Evaluate(high_s + discretized_path.front().s());
398 if (!CheckOverlap(point_high, obstacle_shape, l_buffer)) {
399 high_s -= fine_tuning_step_length;
405 if (find_high && find_low) {
406 lower_points->emplace_back(
408 trajectory_point_time);
409 upper_points->emplace_back(
411 trajectory_point_time);
419void STBoundaryMapper::ComputeSTBoundaryWithDecision(
420 Obstacle* obstacle,
const ObjectDecisionType& decision)
const {
421 DCHECK(decision.has_follow() || decision.has_yield() ||
422 decision.has_overtake())
423 <<
"decision is " << decision.DebugString()
424 <<
", but it must be follow or yield or overtake.";
426 std::vector<STPoint> lower_points;
427 std::vector<STPoint> upper_points;
429 if (FLAGS_use_st_drivable_boundary &&
430 obstacle->is_path_st_boundary_initialized()) {
431 const auto& path_st_boundary = obstacle->path_st_boundary();
432 lower_points = path_st_boundary.lower_points();
433 upper_points = path_st_boundary.upper_points();
436 &upper_points, &lower_points)) {
445 double characteristic_length = 0.0;
446 if (decision.has_follow()) {
447 characteristic_length = std::fabs(decision.follow().distance_s());
448 AINFO <<
"characteristic_length: " << characteristic_length;
452 }
else if (decision.has_yield()) {
453 characteristic_length = std::fabs(decision.yield().distance_s());
457 }
else if (decision.has_overtake()) {
458 characteristic_length = std::fabs(decision.overtake().distance_s());
461 DCHECK(
false) <<
"Obj decision should be either yield or overtake: "
462 << decision.DebugString();
464 boundary.SetBoundaryType(b_type);
465 boundary.set_id(obstacle->Id());
466 boundary.SetCharacteristicLength(characteristic_length);
467 obstacle->set_path_st_boundary(boundary);
470bool STBoundaryMapper::CheckOverlap(
const PathPoint& path_point,
471 const Box2d& obs_box,
472 const double l_buffer)
const {
480 ego_center_map_frame.SelfRotate(path_point.theta());
481 ego_center_map_frame.set_x(ego_center_map_frame.x() + path_point.x());
482 ego_center_map_frame.set_y(ego_center_map_frame.y() + path_point.y());
485 Box2d adc_box(ego_center_map_frame, path_point.theta(),
486 vehicle_param_.
length(), vehicle_param_.
width() + l_buffer * 2);
489 return obs_box.HasOverlap(adc_box);
492bool STBoundaryMapper::CheckOverlap(
const PathPoint& path_point,
493 const Polygon2d& obs_polygon,
494 const double l_buffer)
const {
502 ego_center_map_frame.SelfRotate(path_point.theta());
503 ego_center_map_frame.set_x(ego_center_map_frame.x() + path_point.x());
504 ego_center_map_frame.set_y(ego_center_map_frame.y() + path_point.y());
507 Box2d adc_box(ego_center_map_frame, path_point.theta(),
508 vehicle_param_.
length(), vehicle_param_.
width() + l_buffer * 2);
511 Polygon2d adc_polygon(adc_box);
512 return obs_polygon.HasOverlap(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