42 const std::shared_ptr<DependencyInjector>& injector) {
47 return Task::LoadConfig<PullOverPathConfig>(&config_);
56 std::vector<PathBoundary> candidate_path_boundaries;
57 std::vector<PathData> candidate_path_data;
61 if (!DecidePathBounds(&candidate_path_boundaries)) {
64 if (!OptimizePath(candidate_path_boundaries, &candidate_path_data)) {
67 if (AssessPath(&candidate_path_data,
69 ADEBUG <<
"pull-over path success";
75bool PullOverPath::DecidePathBounds(std::vector<PathBoundary>* boundary) {
76 auto* pull_over_status =
injector_->planning_context()
77 ->mutable_planning_status()
78 ->mutable_pull_over();
79 const bool plan_pull_over_path = pull_over_status->plan_pull_over_path();
80 if (!plan_pull_over_path) {
83 boundary->emplace_back();
84 auto& path_bound = boundary->back();
85 double path_narrowest_width = 0;
89 AERROR <<
"Failed to initialize path boundaries.";
93 AERROR <<
"Failed to decide a rough boundary based on road boundary.";
102 AERROR <<
"ADC is outside road boundary already. Cannot generate pull-over "
106 bool is_pull_over_right =
true;
108 double adc_to_left_bound =
110 double adc_to_right_bound =
112 is_pull_over_right = adc_to_left_bound > adc_to_right_bound;
114 is_pull_over_right =
false;
116 is_pull_over_right =
true;
119 UpdatePullOverBoundaryByLaneBoundary(is_pull_over_right, &path_bound);
122 std::string blocking_obstacle_id =
"";
124 std::vector<SLPolygon> obs_sl_polygons;
129 &blocking_obstacle_id, &path_narrowest_width)) {
130 AERROR <<
"Failed to decide fine tune the boundaries after "
131 "taking into consideration all static obstacles.";
136 if (pull_over_status->has_position()) {
139 pull_over_status->position().y(), path_bound);
143 pull_over_status->Clear();
144 pull_over_status->set_plan_pull_over_path(
true);
145 std::tuple<double, double, double, int> pull_over_configuration;
146 if (!SearchPullOverPosition(path_bound, &pull_over_configuration)) {
147 AERROR <<
"Failed to find a proper pull-over position.";
150 const auto& vehicle_param =
152 curr_idx = std::get<3>(pull_over_configuration);
154 pull_over_status->mutable_position()->set_x(
155 std::get<0>(pull_over_configuration));
156 pull_over_status->mutable_position()->set_y(
157 std::get<1>(pull_over_configuration));
158 pull_over_status->mutable_position()->set_z(0.0);
159 pull_over_status->set_theta(std::get<2>(pull_over_configuration));
160 pull_over_status->set_length_front(vehicle_param.front_edge_to_center());
161 pull_over_status->set_length_back(vehicle_param.back_edge_to_center());
162 pull_over_status->set_width_left(vehicle_param.width() / 2.0);
163 pull_over_status->set_width_right(vehicle_param.width() / 2.0);
165 AINFO <<
"Pull Over: x[" << std::fixed << pull_over_status->position().x()
166 <<
"] y[" << pull_over_status->position().y() <<
"] theta["
167 << pull_over_status->theta() <<
"]";
170 while (
static_cast<int>(path_bound.size()) - 1 >
171 curr_idx + FLAGS_num_extra_tail_bound_point) {
172 path_bound.pop_back();
174 for (
size_t idx = curr_idx + 1; idx < path_bound.size(); ++idx) {
175 path_bound[idx].l_lower.l = path_bound[curr_idx].l_lower.l;
176 path_bound[idx].l_upper.l = path_bound[curr_idx].l_upper.l;
181bool PullOverPath::OptimizePath(
182 const std::vector<PathBoundary>& path_boundaries,
183 std::vector<PathData>* candidate_path_data) {
186 std::array<double, 3> end_state = {0.0, 0.0, 0.0};
188 for (
const auto& path_boundary : path_boundaries) {
189 size_t path_boundary_size = path_boundary.boundary().size();
190 if (path_boundary_size <= 1U) {
191 AERROR <<
"Get invalid path boundary with size: " << path_boundary_size;
194 std::vector<double> opt_l, opt_dl, opt_ddl;
195 std::vector<std::pair<double, double>> ddl_bounds;
198 const auto& pull_over_status =
199 injector_->planning_context()->planning_status().pull_over();
200 std::vector<double> weight_ref_l(path_boundary_size,
201 path_config.path_reference_l_weight());
202 std::vector<double> ref_l(path_boundary_size, 0);
203 if (pull_over_status.has_position() &&
204 pull_over_status.position().has_x() &&
205 pull_over_status.position().has_y()) {
206 common::SLPoint pull_over_sl;
207 reference_line.XYToSL(pull_over_status.position(), &pull_over_sl);
208 end_state[0] = pull_over_sl.l();
209 ref_l.assign(path_boundary_size, end_state[0]);
218 ddl_bounds, jerk_bound, path_config, &opt_l, &opt_dl, &opt_ddl);
221 opt_l, opt_dl, opt_ddl, path_boundary.delta_s(),
222 path_boundary.start_s());
224 path_data.SetReferenceLine(&reference_line);
225 path_data.SetFrenetPath(std::move(frenet_frame_path));
226 if (FLAGS_use_front_axe_center_in_path_planning) {
227 auto discretized_path = DiscretizedPath(
230 path_data.SetDiscretizedPath(discretized_path);
232 path_data.set_path_label(path_boundary.label());
233 path_data.set_blocking_obstacle_id(path_boundary.blocking_obstacle_id());
234 candidate_path_data->push_back(std::move(path_data));
237 if (candidate_path_data->empty()) {
243bool PullOverPath::AssessPath(std::vector<PathData>* candidate_path_data,
244 PathData* final_path) {
245 PathData& curr_path_data = candidate_path_data->back();
250 AINFO <<
"Lane follow path is invalid";
254 std::vector<PathPointDecision> path_decision;
257 curr_path_data.SetPathPointDecisionGuide(std::move(path_decision));
259 if (curr_path_data.Empty()) {
260 AINFO <<
"Lane follow path is empty after trimed";
263 *final_path = curr_path_data;
265 curr_path_data.blocking_obstacle_id());
267 ->mutable_planning_data()
268 ->mutable_pull_over();
269 const auto& pull_over_status =
270 injector_->planning_context()->planning_status().pull_over();
271 pull_over_debug->mutable_position()->CopyFrom(pull_over_status.position());
272 pull_over_debug->set_theta(pull_over_status.theta());
273 pull_over_debug->set_length_front(pull_over_status.length_front());
274 pull_over_debug->set_length_back(pull_over_status.length_back());
275 pull_over_debug->set_width_left(pull_over_status.width_left());
276 pull_over_debug->set_width_right(pull_over_status.width_right());
280bool PullOverPath::GetBoundaryFromRoads(
281 const ReferenceLineInfo& reference_line_info,
282 PathBoundary*
const path_bound) {
284 CHECK_NOTNULL(path_bound);
285 ACHECK(!path_bound->empty());
286 const ReferenceLine& reference_line = reference_line_info.reference_line();
290 double past_road_left_width = adc_lane_width / 2.0;
291 double past_road_right_width = adc_lane_width / 2.0;
292 int path_blocked_idx = -1;
293 for (
size_t i = 0; i < path_bound->size(); ++i) {
295 double curr_s = (*path_bound)[i].s;
296 double curr_road_left_width = 0.0;
297 double curr_road_right_width = 0.0;
298 double refline_offset_to_lane_center = 0.0;
299 reference_line.GetOffsetToMap(curr_s, &refline_offset_to_lane_center);
300 if (!reference_line.GetRoadWidth(curr_s, &curr_road_left_width,
301 &curr_road_right_width)) {
302 AWARN <<
"Failed to get lane width at s = " << curr_s;
303 curr_road_left_width = past_road_left_width;
304 curr_road_right_width = past_road_right_width;
306 curr_road_left_width += refline_offset_to_lane_center;
307 curr_road_right_width -= refline_offset_to_lane_center;
308 past_road_left_width = curr_road_left_width;
309 past_road_right_width = curr_road_right_width;
311 double curr_left_bound = curr_road_left_width;
312 double curr_right_bound = -curr_road_right_width;
313 ADEBUG <<
"At s = " << curr_s
314 <<
", left road bound = " << curr_road_left_width
315 <<
", right road bound = " << curr_road_right_width
316 <<
", offset from refline to lane-center = "
317 << refline_offset_to_lane_center;
322 "",
"", &path_bound->at(i))) {
323 path_blocked_idx =
static_cast<int>(i);
325 if (path_blocked_idx != -1) {
334void PullOverPath::UpdatePullOverBoundaryByLaneBoundary(
335 bool is_pull_over_right, PathBoundary*
const path_bound) {
337 for (
size_t i = 0; i < path_bound->size(); ++i) {
338 const double curr_s = (*path_bound)[i].s;
339 double left_bound = 3.0;
340 double right_bound = 3.0;
341 double curr_lane_left_width = 0.0;
342 double curr_lane_right_width = 0.0;
343 if (reference_line.GetLaneWidth(curr_s, &curr_lane_left_width,
344 &curr_lane_right_width)) {
345 double offset_to_lane_center = 0.0;
347 left_bound = curr_lane_left_width + offset_to_lane_center;
348 right_bound = curr_lane_right_width + offset_to_lane_center;
350 ADEBUG <<
"left_bound[" << left_bound <<
"] right_bound[" << right_bound
352 if (is_pull_over_right) {
353 (*path_bound)[i].l_upper.l = left_bound;
355 (*path_bound)[i].l_lower.l = right_bound;
360bool PullOverPath::SearchPullOverPosition(
362 std::tuple<double, double, double, int>*
const pull_over_configuration) {
364 bool search_backward =
false;
366 double pull_over_s = 0.0;
368 if (!FindNearestPullOverS(&pull_over_s)) {
369 AERROR <<
"Failed to find emergency_pull_over s";
372 search_backward =
false;
374 if (!FindDestinationPullOverS(path_bound, &pull_over_s)) {
375 AERROR <<
"Failed to find pull_over s upon destination arrival";
378 search_backward =
true;
384 if (search_backward) {
386 idx =
static_cast<int>(path_bound.size()) - 1;
387 while (idx >= 0 && path_bound[idx].s > pull_over_s) {
392 while (idx <
static_cast<int>(path_bound.size()) &&
393 path_bound[idx].s < pull_over_s) {
397 if (idx < 0 || idx >=
static_cast<int>(path_bound.size())) {
398 AERROR <<
"Failed to find path_bound index for pull over s";
401 constexpr double kPulloverLonSearchCoeff = 1.5;
402 constexpr double kPulloverLatSearchCoeff = 1.25;
404 const double pull_over_space_length =
405 kPulloverLonSearchCoeff *
407 FLAGS_obstacle_lon_start_buffer - FLAGS_obstacle_lon_end_buffer;
408 const double pull_over_space_width =
409 (kPulloverLatSearchCoeff - 1.0) *
411 const double adc_half_width =
416 bool has_a_feasible_window =
false;
417 while ((search_backward && idx >= 0 &&
418 path_bound[idx].s - path_bound.front().s > pull_over_space_length) ||
419 (!search_backward && idx <
static_cast<int>(path_bound.size()) &&
420 path_bound.back().s - path_bound[idx].s > pull_over_space_length)) {
422 bool is_feasible_window =
true;
425 double pt_ref_line_s = path_bound[idx].s;
426 double pt_ref_line_l = 0.0;
427 common::SLPoint pt_sl;
428 pt_sl.set_s(pt_ref_line_s);
429 pt_sl.set_l(pt_ref_line_l);
430 common::math::Vec2d pt_xy;
432 common::PointENU hdmap_point;
433 hdmap_point.set_x(pt_xy.x());
434 hdmap_point.set_y(pt_xy.y());
435 ADEBUG <<
"Pull-over position might be around (" << pt_xy.x() <<
", "
437 std::vector<std::shared_ptr<const JunctionInfo>> junctions;
439 if (!junctions.empty()) {
440 AWARN <<
"Point is in PNC-junction.";
441 idx = search_backward ? idx - 1 : idx + 1;
445 while ((search_backward && j >= 0 &&
446 path_bound[idx].s - path_bound[j].s < pull_over_space_length) ||
447 (!search_backward && j <
static_cast<int>(path_bound.size()) &&
448 path_bound[j].s - path_bound[idx].s < pull_over_space_length)) {
449 double curr_s = path_bound[j].s;
450 double curr_right_bound = std::fabs(path_bound[j].l_lower.l);
451 double curr_road_left_width = 0;
452 double curr_road_right_width = 0;
454 curr_s, &curr_road_left_width, &curr_road_right_width);
455 ADEBUG <<
"s[" << curr_s <<
"] curr_road_left_width["
456 << curr_road_left_width <<
"] curr_road_right_width["
457 << curr_road_right_width <<
"]";
458 if (curr_road_right_width - (curr_right_bound + adc_half_width) >
460 AERROR <<
"Not close enough to road-edge. Not feasible for pull-over.";
461 is_feasible_window =
false;
464 const double right_bound = path_bound[j].l_lower.l;
465 const double left_bound = path_bound[j].l_upper.l;
466 ADEBUG <<
"left_bound[" << left_bound <<
"] right_bound[" << right_bound
468 if (left_bound - right_bound < pull_over_space_width) {
469 AERROR <<
"Not wide enough to fit ADC. Not feasible for pull-over.";
470 is_feasible_window =
false;
474 j = search_backward ? j - 1 : j + 1;
479 if (is_feasible_window) {
480 has_a_feasible_window =
true;
484 const auto& vehicle_param =
486 const double back_clear_to_total_length_ratio =
487 (0.5 * (kPulloverLonSearchCoeff - 1.0) * vehicle_param.length() +
488 vehicle_param.back_edge_to_center()) /
489 vehicle_param.
length() / kPulloverLonSearchCoeff;
493 if (!search_backward) {
497 auto pull_over_idx =
static_cast<size_t>(
498 back_clear_to_total_length_ratio *
static_cast<double>(end_idx) +
499 (1.0 - back_clear_to_total_length_ratio) *
500 static_cast<double>(start_idx));
502 const auto& pull_over_point = path_bound[pull_over_idx];
503 const double pull_over_s = pull_over_point.s;
504 const double pull_over_l =
505 pull_over_point.l_lower.l + pull_over_space_width / 2.0;
506 common::SLPoint pull_over_sl_point;
507 pull_over_sl_point.set_s(pull_over_s);
508 pull_over_sl_point.set_l(pull_over_l);
510 common::math::Vec2d pull_over_xy_point;
511 reference_line.SLToXY(pull_over_sl_point, &pull_over_xy_point);
512 const double pull_over_x = pull_over_xy_point.x();
513 const double pull_over_y = pull_over_xy_point.y();
518 const auto& reference_point =
519 reference_line.GetReferencePoint(pull_over_s);
520 double pull_over_theta = reference_point.heading();
527 point, 5.0, pull_over_theta, M_PI_2, &lane, &s, &l) == 0) {
528 pull_over_theta = lane->Heading(s);
530 *pull_over_configuration =
531 std::make_tuple(pull_over_x, pull_over_y, pull_over_theta,
532 static_cast<int>(pull_over_idx));
536 idx = search_backward ? idx - 1 : idx + 1;
539 return has_a_feasible_window;
542bool PullOverPath::FindNearestPullOverS(
double* pull_over_s) {
544 const double min_turn_radius = common::VehicleConfigHelper::Instance()
548 const double adjust_factor =
550 const double pull_over_distance = min_turn_radius * 2 * adjust_factor;
551 *pull_over_s = adc_end_s + pull_over_distance;
555bool PullOverPath::FindDestinationPullOverS(
const PathBound& path_bound,
556 double* pull_over_s) {
559 common::SLPoint destination_sl;
561 reference_line.
XYToSL(routing_end.pose(), &destination_sl);
562 const double destination_s = destination_sl.s();
566 ADEBUG <<
"Destination s[" << destination_s <<
"] adc_end_s[" << adc_end_s
568 if (destination_s - adc_end_s <
570 AERROR <<
"Destination is too close to ADC. distance["
571 << destination_s - adc_end_s <<
"]";
576 const double destination_to_pathend_buffer =
578 if (destination_s + destination_to_pathend_buffer >= path_bound.back().s) {
579 AERROR <<
"Destination is not within path_bounds search scope";
583 *pull_over_s = destination_s;
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.
static const VehicleConfig & GetConfig()
Get the current vehicle configuration.
static PointENU ToPointENU(const double x, const double y, const double z=0)
static const HDMap & BaseMap()
int GetJunctions(const apollo::common::PointENU &point, double distance, std::vector< JunctionInfoConstPtr > *junctions) const
get all junctions in certain range
Frame holds all data for one planning cycle.
const LocalView & local_view() const
static void InitPathPointDecision(const PathData &path_data, const PathData::PathPointType type, std::vector< PathPointDecision > *const path_point_decision)
Init path_point_decision as type
static bool IsValidRegularPath(const ReferenceLineInfo &reference_line_info, const PathData &path_data)
Check if the generated path is valid
static void ConvertBoundarySAxisFromLaneCenterToRefLine(const ReferenceLineInfo &reference_line_info, PathBoundary *const path_bound)
static bool GetBoundaryFromStaticObstacles(const ReferenceLineInfo &reference_line_info, std::vector< SLPolygon > *const sl_polygons, const SLState &init_sl_state, PathBoundary *const path_boundaries, std::string *const blocking_obstacle_id, double *const narrowest_width)
Refine the boundary based on static obstacles.
static int IsPointWithinPathBound(const ReferenceLineInfo &reference_line_info, const double x, const double y, const PathBound &path_bound)
static void TrimPathBounds(const int path_blocked_idx, PathBoundary *const path_boundaries)
static bool UpdatePathBoundaryWithBuffer(double left_bound, double right_bound, BoundType left_type, BoundType right_type, std::string left_id, std::string right_id, PathBoundPoint *const bound_point)
Update the path_boundary at "idx" It also checks if ADC is blocked (lmax < lmin).
static void GetSLPolygons(const ReferenceLineInfo &reference_line_info, std::vector< SLPolygon > *polygons, const SLState &init_sl_state)
static double GetADCLaneWidth(const ReferenceLine &reference_line, const double adc_frenet_s)
Get lane width in init_sl_state.
static bool InitPathBoundary(const ReferenceLineInfo &reference_line_info, PathBoundary *const path_bound, SLState init_sl_state)
Starting from ADC's current position, increment until the path length, and set lateral bounds to be i...
void RecordDebugInfo(const PathBound &path_boundaries, const std::string &debug_name, ReferenceLineInfo *const reference_line_info)
add path_boundary debug info for PnC monitor
void GetStartPointSLState()
calculate init sl state by planning start point, result will store in init_sl_state_
static std::vector< common::PathPoint > ConvertPathPointRefFromFrontAxeToRearAxe(const PathData &path_data)
static void CalculateAccBound(const PathBoundary &path_boundary, const ReferenceLine &reference_line, std::vector< std::pair< double, double > > *ddl_bounds)
calculate ddl bound by referenceline kappa and adc lat accleration
static FrenetFramePath ToPiecewiseJerkPath(const std::vector< double > &x, const std::vector< double > &dx, const std::vector< double > &ddx, const double delta_s, const double start_s)
Data format tramform from raw data to FrenetFramePath
static double EstimateJerkBoundary(const double vehicle_speed)
Calculation of jerk boundary based on vehicle kinematics model.
static bool OptimizePath(const SLState &init_state, const std::array< double, 3 > &end_state, std::vector< double > l_ref, std::vector< double > l_ref_weight, const PathBoundary &path_boundary, const std::vector< std::pair< double, double > > &ddl_bounds, double dddl_bound, const PiecewiseJerkPathConfig &config, std::vector< double > *x, std::vector< double > *dx, std::vector< double > *ddx)
Piecewise jerk path optimizer.
bool Init(const std::string &config_dir, const std::string &name, const std::shared_ptr< DependencyInjector > &injector) override
ReferenceLineInfo holds all data for one reference line.
void SetBlockingObstacle(const std::string &blocking_obstacle_id)
const ReferenceLine & reference_line() const
const PathData & path_data() const
planning_internal::Debug * mutable_debug()
const SLBoundary & AdcSlBoundary() const
bool IsChangeLanePath() const
Check if the current reference line is a change lane reference line, i.e., ADC's current position is ...
PathData * mutable_path_data()
bool GetRoadWidth(const double s, double *const road_left_width, double *const road_right_width) const
bool SLToXY(const common::SLPoint &sl_point, common::math::Vec2d *const xy_point) 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.
bool GetOffsetToMap(const double s, double *l_offset) const
std::shared_ptr< DependencyInjector > injector_
ReferenceLineInfo * reference_line_info_
virtual bool Init(const std::string &config_dir, const std::string &name, const std::shared_ptr< DependencyInjector > &injector)
Planning module main class.
std::shared_ptr< const LaneInfo > LaneInfoConstPtr
std::vector< PathBoundPoint > PathBound
optional VehicleParam vehicle_param
std::shared_ptr< routing::LaneWaypoint > end_lane_way_point
optional PullOverPosition pull_over_position
optional double pull_over_approach_lon_distance_adjust_factor
optional double pull_over_destination_to_pathend_buffer
optional double pull_over_road_edge_buffer
optional double pull_over_weight
optional double pull_over_destination_to_adc_buffer
optional PullOverDirection pull_over_direction
optional PiecewiseJerkPathConfig path_optimizer_config