Apollo 11.0
自动驾驶开放平台
lane_borrow_path.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2023 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
18
19#include <algorithm>
20#include <functional>
21#include <memory>
22#include <string>
23#include <tuple>
24#include <utility>
25#include <vector>
26
34
35namespace apollo {
36namespace planning {
37
43
44constexpr double kIntersectionClearanceDist = 20.0;
45constexpr double kJunctionClearanceDist = 15.0;
46
47bool LaneBorrowPath::Init(const std::string& config_dir,
48 const std::string& name,
49 const std::shared_ptr<DependencyInjector>& injector) {
50 if (!Task::Init(config_dir, name, injector)) {
51 return false;
52 }
53 // Load the config this task.
54 return Task::LoadConfig<LaneBorrowPathConfig>(&config_);
55}
56
57apollo::common::Status LaneBorrowPath::Process(
58 Frame* frame, ReferenceLineInfo* reference_line_info) {
59 if (!config_.is_allow_lane_borrowing() ||
60 reference_line_info->path_reusable()) {
61 ADEBUG << "path reusable" << reference_line_info->path_reusable()
62 << ",skip";
63 return Status::OK();
64 }
65 if (!IsNecessaryToBorrowLane()) {
66 ADEBUG << "No need to borrow lane";
67 return Status::OK();
68 }
69 std::vector<PathBoundary> candidate_path_boundaries;
70 std::vector<PathData> candidate_path_data;
71
73 if (!DecidePathBounds(&candidate_path_boundaries)) {
74 return Status::OK();
75 }
76 if (!OptimizePath(candidate_path_boundaries, &candidate_path_data)) {
77 return Status::OK();
78 }
79 if (AssessPath(&candidate_path_data,
80 reference_line_info->mutable_path_data())) {
81 ADEBUG << "lane borrow path success";
82 }
83
84 return Status::OK();
85}
86
87bool LaneBorrowPath::DecidePathBounds(std::vector<PathBoundary>* boundary) {
88 for (size_t i = 0; i < decided_side_pass_direction_.size(); i++) {
89 boundary->emplace_back();
90 auto& path_bound = boundary->back();
91 std::string blocking_obstacle_id = "";
92 std::string borrow_lane_type = "";
93 double path_narrowest_width = 0;
94 // 1. Initialize the path boundaries to be an indefinitely large area.
96 &path_bound, init_sl_state_)) {
97 const std::string msg = "Failed to initialize path boundaries.";
98 AERROR << msg;
99 boundary->pop_back();
100 continue;
101 }
102 // 2. Decide a rough boundary based on lane info and ADC's position
103 if (!GetBoundaryFromNeighborLane(decided_side_pass_direction_[i],
104 &path_bound, &borrow_lane_type)) {
105 AERROR << "Failed to decide a rough boundary based on lane and adc.";
106 boundary->pop_back();
107 continue;
108 }
109
110 std::string label;
111 if (decided_side_pass_direction_[i] == SidePassDirection::LEFT_BORROW) {
112 label = "regular/left" + borrow_lane_type;
113 } else {
114 label = "regular/right" + borrow_lane_type;
115 }
116 path_bound.set_label(label);
117
118 // path_bound.DebugString("after_neighbor_lane");
119 // 3. Fine-tune the boundary based on static obstacles
120 PathBound temp_path_bound = path_bound;
121 obs_sl_polygons_.clear();
126 &path_bound, &blocking_obstacle_id, &path_narrowest_width)) {
127 const std::string msg =
128 "Failed to decide fine tune the boundaries after "
129 "taking into consideration all static obstacles.";
130 AERROR << msg;
131 boundary->pop_back();
132 continue;
133 }
134 // path_bound.DebugString("after_obs");
135 // 4. Append some extra path bound points to avoid zero-length path data.
136 int counter = 0;
137 while (!blocking_obstacle_id.empty() &&
138 path_bound.size() < temp_path_bound.size() &&
139 counter < FLAGS_num_extra_tail_bound_point) {
140 path_bound.push_back(temp_path_bound[path_bound.size()]);
141 counter++;
142 }
143 ADEBUG << "Completed generating path boundaries.";
144
145 path_bound.set_blocking_obstacle_id(blocking_obstacle_id);
146 RecordDebugInfo(path_bound, path_bound.label(), reference_line_info_);
147 }
148 return !boundary->empty();
149}
150bool LaneBorrowPath::OptimizePath(
151 const std::vector<PathBoundary>& path_boundaries,
152 std::vector<PathData>* candidate_path_data) {
153 const auto& config = config_.path_optimizer_config();
154 const ReferenceLine& reference_line = reference_line_info_->reference_line();
155 std::array<double, 3> end_state = {0.0, 0.0, 0.0};
156
157 for (const auto& path_boundary : path_boundaries) {
158 std::vector<double> opt_l, opt_dl, opt_ddl;
159 std::vector<std::pair<double, double>> ddl_bounds;
160 PathOptimizerUtil::CalculateAccBound(path_boundary, reference_line,
161 &ddl_bounds);
162 const double jerk_bound = PathOptimizerUtil::EstimateJerkBoundary(
163 std::fmax(init_sl_state_.first[1], 1e-12));
164 std::vector<double> ref_l;
165 std::vector<double> weight_ref_l;
167 path_boundary, config.path_reference_l_weight(), &ref_l, &weight_ref_l);
168
169 bool res_opt = PathOptimizerUtil::OptimizePath(
170 init_sl_state_, end_state, ref_l, weight_ref_l, path_boundary,
171 ddl_bounds, jerk_bound, config, &opt_l, &opt_dl, &opt_ddl);
172 if (res_opt) {
173 auto frenet_frame_path = PathOptimizerUtil::ToPiecewiseJerkPath(
174 opt_l, opt_dl, opt_ddl, path_boundary.delta_s(),
175 path_boundary.start_s());
176 PathData path_data;
177 path_data.SetReferenceLine(&reference_line);
178 path_data.SetFrenetPath(std::move(frenet_frame_path));
179 if (FLAGS_use_front_axe_center_in_path_planning) {
180 auto discretized_path = DiscretizedPath(
182 path_data));
183 path_data.SetDiscretizedPath(discretized_path);
184 }
185 path_data.set_path_label(path_boundary.label());
186 path_data.set_blocking_obstacle_id(path_boundary.blocking_obstacle_id());
187 candidate_path_data->push_back(std::move(path_data));
188 }
189 }
190 if (candidate_path_data->empty()) {
191 return false;
192 }
193 return true;
194}
195
196bool LaneBorrowPath::AssessPath(std::vector<PathData>* candidate_path_data,
197 PathData* final_path) {
198 std::vector<PathData> valid_path_data;
199 for (auto& curr_path_data : *candidate_path_data) {
201 curr_path_data)) {
202 SetPathInfo(&curr_path_data);
204 FLAGS_path_trim_destination_threshold) {
206 }
207 if (curr_path_data.Empty()) {
208 AINFO << "lane borrow path is empty after trimed";
209 continue;
210 }
211 valid_path_data.push_back(curr_path_data);
212 }
213 }
214 if (valid_path_data.empty()) {
215 AINFO << "All lane borrow path are not valid";
216 return false;
217 }
218 auto* mutable_path_decider_status = injector_->planning_context()
219 ->mutable_planning_status()
220 ->mutable_path_decider();
221 const std::string blocking_obstacle_id =
222 mutable_path_decider_status->front_static_obstacle_id();
223 const Obstacle* blocking_obstacle =
225 blocking_obstacle_id);
226 if (valid_path_data.size() > 1) {
227 if (ComparePathData(valid_path_data[0], valid_path_data[1],
228 blocking_obstacle)) {
229 *final_path = valid_path_data[0];
230 } else {
231 *final_path = valid_path_data[1];
232 }
233 } else {
234 *final_path = valid_path_data[0];
235 }
236 // move obs_sl_polygon to reference_line_info, it will be empty, do not use it
238 RecordDebugInfo(*final_path, final_path->path_label(), reference_line_info_);
239 return true;
240}
241
242bool LaneBorrowPath::GetBoundaryFromNeighborLane(
243 const SidePassDirection pass_direction, PathBoundary* const path_bound,
244 std::string* borrow_lane_type) {
245 // Sanity checks.
246 CHECK_NOTNULL(path_bound);
247 ACHECK(!path_bound->empty());
248 const ReferenceLine& reference_line = reference_line_info_->reference_line();
249 double adc_lane_width = PathBoundsDeciderUtil::GetADCLaneWidth(
250 reference_line, init_sl_state_.first[0]);
251 double offset_to_map = 0;
252 bool borrowing_reverse_lane = false;
253 reference_line.GetOffsetToMap(init_sl_state_.first[0], &offset_to_map);
254 // Go through every point, update the boundary based on lane info and
255 // ADC's position.
256 double past_lane_left_width = adc_lane_width / 2.0;
257 double past_lane_right_width = adc_lane_width / 2.0;
258 int path_blocked_idx = -1;
259 for (size_t i = 0; i < path_bound->size(); ++i) {
260 double curr_s = (*path_bound)[i].s;
261 // 1. Get the current lane width at current point.
262 double curr_lane_left_width = 0.0;
263 double curr_lane_right_width = 0.0;
264 double offset_to_lane_center = 0.0;
265 if (!reference_line.GetLaneWidth(curr_s, &curr_lane_left_width,
266 &curr_lane_right_width)) {
267 AWARN << "Failed to get lane width at s = " << curr_s;
268 curr_lane_left_width = past_lane_left_width;
269 curr_lane_right_width = past_lane_right_width;
270 } else {
271 reference_line.GetOffsetToMap(curr_s, &offset_to_lane_center);
272 curr_lane_left_width += offset_to_lane_center;
273 curr_lane_right_width -= offset_to_lane_center;
274 past_lane_left_width = curr_lane_left_width;
275 past_lane_right_width = curr_lane_right_width;
276 }
277 // 2. Get the neighbor lane widths at the current point.
278 double curr_neighbor_lane_width = 0.0;
279 if (CheckLaneBoundaryType(*reference_line_info_, curr_s, pass_direction)) {
280 hdmap::Id neighbor_lane_id;
281 if (pass_direction == SidePassDirection::LEFT_BORROW) {
282 // Borrowing left neighbor lane.
285 &neighbor_lane_id, &curr_neighbor_lane_width)) {
286 ADEBUG << "Borrow left forward neighbor lane."
287 << neighbor_lane_id.id();
290 &neighbor_lane_id, &curr_neighbor_lane_width)) {
291 borrowing_reverse_lane = true;
292 ADEBUG << "Borrow left reverse neighbor lane."
293 << neighbor_lane_id.id();
294 } else {
295 ADEBUG << "There is no left neighbor lane.";
296 }
297 } else if (pass_direction == SidePassDirection::RIGHT_BORROW) {
298 // Borrowing right neighbor lane.
301 &neighbor_lane_id, &curr_neighbor_lane_width)) {
302 ADEBUG << "Borrow right forward neighbor lane."
303 << neighbor_lane_id.id();
306 &neighbor_lane_id, &curr_neighbor_lane_width)) {
307 borrowing_reverse_lane = true;
308 ADEBUG << "Borrow right reverse neighbor lane."
309 << neighbor_lane_id.id();
310 } else {
311 ADEBUG << "There is no right neighbor lane.";
312 }
313 }
314 }
315 // 3. Calculate the proper boundary based on lane-width, ADC's position,
316 // and ADC's velocity.
317 double offset_to_map = 0.0;
318 reference_line.GetOffsetToMap(curr_s, &offset_to_map);
319
320 double curr_left_bound_lane =
321 curr_lane_left_width + (pass_direction == SidePassDirection::LEFT_BORROW
322 ? curr_neighbor_lane_width
323 : 0.0);
324
325 double curr_right_bound_lane =
326 -curr_lane_right_width -
327 (pass_direction == SidePassDirection::RIGHT_BORROW
328 ? curr_neighbor_lane_width
329 : 0.0);
330 double curr_left_bound = 0.0;
331 double curr_right_bound = 0.0;
332 curr_left_bound = curr_left_bound_lane - offset_to_map;
333 curr_right_bound = curr_right_bound_lane - offset_to_map;
334
335 // 4. Update the boundary.
337 curr_left_bound, curr_right_bound, BoundType::LANE, BoundType::LANE,
338 "", "", &path_bound->at(i))) {
339 path_blocked_idx = static_cast<int>(i);
340 }
341 if (path_blocked_idx != -1) {
342 break;
343 }
344 }
345 PathBoundsDeciderUtil::TrimPathBounds(path_blocked_idx, path_bound);
346 *borrow_lane_type = borrowing_reverse_lane ? "reverse" : "forward";
347 return true;
348}
349void LaneBorrowPath::UpdateSelfPathInfo() {
350 auto cur_path = reference_line_info_->path_data();
351 if (!cur_path.Empty() &&
352 cur_path.path_label().find("self") != std::string::npos &&
353 cur_path.blocking_obstacle_id().empty()) {
354 use_self_lane_ = std::min(use_self_lane_ + 1, 10);
355 } else {
356 use_self_lane_ = 0;
357 }
358 blocking_obstacle_id_ = cur_path.blocking_obstacle_id();
359}
360bool LaneBorrowPath::IsNecessaryToBorrowLane() {
361 auto* mutable_path_decider_status = injector_->planning_context()
362 ->mutable_planning_status()
363 ->mutable_path_decider();
364 if (mutable_path_decider_status->is_in_path_lane_borrow_scenario()) {
365 UpdateSelfPathInfo();
366 // If originally borrowing neighbor lane:
367 if (use_self_lane_ >= 6) {
368 // If have been able to use self-lane for some time, then switch to
369 // non-lane-borrowing.
370 mutable_path_decider_status->set_is_in_path_lane_borrow_scenario(false);
371 decided_side_pass_direction_.clear();
372 AINFO << "Switch from LANE-BORROW path to SELF-LANE path.";
373 }
374 } else {
375 // If originally not borrowing neighbor lane:
376 AINFO << "Blocking obstacle ID["
377 << mutable_path_decider_status->front_static_obstacle_id() << "]";
378 // ADC requirements check for lane-borrowing:
379 if (!HasSingleReferenceLine(*frame_)) {
380 return false;
381 }
382 if (!IsWithinSidePassingSpeedADC(*frame_)) {
383 return false;
384 }
385
386 // Obstacle condition check for lane-borrowing:
387 if (!IsBlockingObstacleFarFromIntersection(*reference_line_info_)) {
388 return false;
389 }
390 if (!IsLongTermBlockingObstacle()) {
391 return false;
392 }
393 if (!IsBlockingObstacleWithinDestination(*reference_line_info_)) {
394 return false;
395 }
396 if (!IsSidePassableObstacle(*reference_line_info_)) {
397 return false;
398 }
399
400 // switch to lane-borrowing
401 if (decided_side_pass_direction_.empty()) {
402 // first time init decided_side_pass_direction
403 bool left_borrowable;
404 bool right_borrowable;
405 CheckLaneBorrow(*reference_line_info_, &left_borrowable,
406 &right_borrowable);
407 if (!left_borrowable && !right_borrowable) {
408 mutable_path_decider_status->set_is_in_path_lane_borrow_scenario(false);
409 AINFO << "LEFT AND RIGHT LANE CAN NOT BORROW";
410 return false;
411 } else {
412 mutable_path_decider_status->set_is_in_path_lane_borrow_scenario(true);
413 if (left_borrowable) {
414 decided_side_pass_direction_.push_back(
415 SidePassDirection::LEFT_BORROW);
416 }
417 if (right_borrowable) {
418 decided_side_pass_direction_.push_back(
419 SidePassDirection::RIGHT_BORROW);
420 }
421 }
422 }
423 use_self_lane_ = 0;
424 AINFO << "Switch from SELF-LANE path to LANE-BORROW path.";
425 }
426 return mutable_path_decider_status->is_in_path_lane_borrow_scenario();
427}
428
429bool LaneBorrowPath::HasSingleReferenceLine(const Frame& frame) {
430 return frame.reference_line_info().size() == 1;
431}
432
433bool LaneBorrowPath::IsWithinSidePassingSpeedADC(const Frame& frame) {
434 return frame.PlanningStartPoint().v() < config_.lane_borrow_max_speed();
435}
436
437bool LaneBorrowPath::IsLongTermBlockingObstacle() {
438 if (injector_->planning_context()
439 ->planning_status()
440 .path_decider()
441 .front_static_obstacle_cycle_counter() >=
443 ADEBUG << "The blocking obstacle is long-term existing.";
444 return true;
445 } else {
446 ADEBUG << "The blocking obstacle is not long-term existing.";
447 return false;
448 }
449}
450
451bool LaneBorrowPath::IsBlockingObstacleWithinDestination(
452 const ReferenceLineInfo& reference_line_info) {
453 const auto& path_decider_status =
454 injector_->planning_context()->planning_status().path_decider();
455 const std::string blocking_obstacle_id =
456 path_decider_status.front_static_obstacle_id();
457 if (blocking_obstacle_id.empty()) {
458 ADEBUG << "There is no blocking obstacle.";
459 return true;
460 }
461 const Obstacle* blocking_obstacle =
462 reference_line_info.path_decision().obstacles().Find(
463 blocking_obstacle_id);
464 if (blocking_obstacle == nullptr) {
465 ADEBUG << "Blocking obstacle is no longer there.";
466 return true;
467 }
468
469 double blocking_obstacle_s =
470 blocking_obstacle->PerceptionSLBoundary().start_s();
471 double adc_end_s = reference_line_info.AdcSlBoundary().end_s();
472 ADEBUG << "Blocking obstacle is at s = " << blocking_obstacle_s;
473 ADEBUG << "ADC is at s = " << adc_end_s;
474 ADEBUG << "Destination is at s = "
475 << reference_line_info.SDistanceToDestination() + adc_end_s;
476 if (blocking_obstacle_s - adc_end_s >
477 reference_line_info.SDistanceToDestination()) {
478 return false;
479 }
480 return true;
481}
482
483bool LaneBorrowPath::IsBlockingObstacleFarFromIntersection(
484 const ReferenceLineInfo& reference_line_info) {
485 const auto& path_decider_status =
486 injector_->planning_context()->planning_status().path_decider();
487 const std::string blocking_obstacle_id =
488 path_decider_status.front_static_obstacle_id();
489 if (blocking_obstacle_id.empty()) {
490 ADEBUG << "There is no blocking obstacle.";
491 return true;
492 }
493 const Obstacle* blocking_obstacle =
494 reference_line_info.path_decision().obstacles().Find(
495 blocking_obstacle_id);
496 if (blocking_obstacle == nullptr) {
497 ADEBUG << "Blocking obstacle is no longer there.";
498 return true;
499 }
500
501 // Get blocking obstacle's s.
502 double blocking_obstacle_s =
503 blocking_obstacle->PerceptionSLBoundary().end_s();
504 ADEBUG << "Blocking obstacle is at s = " << blocking_obstacle_s;
505 // Get intersection's s and compare with threshold.
506 const auto& first_encountered_overlaps =
507 reference_line_info.FirstEncounteredOverlaps();
508 for (const auto& overlap : first_encountered_overlaps) {
509 ADEBUG << overlap.first << ", " << overlap.second.DebugString();
510 if (overlap.first != ReferenceLineInfo::SIGNAL &&
511 overlap.first != ReferenceLineInfo::STOP_SIGN) {
512 continue;
513 }
514
515 auto distance = overlap.second.start_s - blocking_obstacle_s;
516 if (overlap.first == ReferenceLineInfo::SIGNAL ||
517 overlap.first == ReferenceLineInfo::STOP_SIGN) {
518 if (distance < kIntersectionClearanceDist) {
519 ADEBUG << "Too close to signal intersection (" << distance
520 << "m); don't SIDE_PASS.";
521 return false;
522 }
523 } else {
524 if (distance < kJunctionClearanceDist) {
525 ADEBUG << "Too close to overlap_type[" << overlap.first << "] ("
526 << distance << "m); don't SIDE_PASS";
527 return false;
528 }
529 }
530 }
531
532 return true;
533}
534
535bool LaneBorrowPath::IsSidePassableObstacle(
536 const ReferenceLineInfo& reference_line_info) {
537 const auto& path_decider_status =
538 injector_->planning_context()->planning_status().path_decider();
539 const std::string blocking_obstacle_id =
540 path_decider_status.front_static_obstacle_id();
541 if (blocking_obstacle_id.empty()) {
542 ADEBUG << "There is no blocking obstacle.";
543 return false;
544 }
545 const Obstacle* blocking_obstacle =
546 reference_line_info.path_decision().obstacles().Find(
547 blocking_obstacle_id);
548 if (blocking_obstacle == nullptr) {
549 ADEBUG << "Blocking obstacle is no longer there.";
550 return false;
551 }
552
553 return IsNonmovableObstacle(reference_line_info, *blocking_obstacle);
554}
555
556void LaneBorrowPath::CheckLaneBorrow(
557 const ReferenceLineInfo& reference_line_info,
558 bool* left_neighbor_lane_borrowable, bool* right_neighbor_lane_borrowable) {
559 const ReferenceLine& reference_line = reference_line_info.reference_line();
560
561 *left_neighbor_lane_borrowable = true;
562 *right_neighbor_lane_borrowable = true;
563
564 static constexpr double kLookforwardDistance = 100.0;
565 double check_s = reference_line_info.AdcSlBoundary().end_s();
566 const double lookforward_distance =
567 std::min(check_s + kLookforwardDistance, reference_line.Length());
568 while (check_s < lookforward_distance) {
569 auto ref_point = reference_line.GetNearestReferencePoint(check_s);
570 if (ref_point.lane_waypoints().empty()) {
571 *left_neighbor_lane_borrowable = false;
572 *right_neighbor_lane_borrowable = false;
573 return;
574 }
575 auto ptr_lane_info = reference_line_info.LocateLaneInfo(check_s);
576 if (ptr_lane_info->lane().left_neighbor_forward_lane_id().empty() &&
577 ptr_lane_info->lane().left_neighbor_reverse_lane_id().empty()) {
578 *left_neighbor_lane_borrowable = false;
579 }
580 if (ptr_lane_info->lane().right_neighbor_forward_lane_id().empty() &&
581 ptr_lane_info->lane().right_neighbor_reverse_lane_id().empty()) {
582 *right_neighbor_lane_borrowable = false;
583 }
584 const auto waypoint = ref_point.lane_waypoints().front();
585 hdmap::LaneBoundaryType::Type lane_boundary_type =
587
588 if (*left_neighbor_lane_borrowable) {
589 lane_boundary_type = hdmap::LeftBoundaryType(waypoint);
590 if (lane_boundary_type == hdmap::LaneBoundaryType::SOLID_YELLOW ||
591 lane_boundary_type == hdmap::LaneBoundaryType::DOUBLE_YELLOW ||
592 lane_boundary_type == hdmap::LaneBoundaryType::SOLID_WHITE) {
593 *left_neighbor_lane_borrowable = false;
594 }
595 ADEBUG << "s[" << check_s << "] left_lane_boundary_type["
596 << LaneBoundaryType_Type_Name(lane_boundary_type) << "]";
597 }
598 if (*right_neighbor_lane_borrowable) {
599 lane_boundary_type = hdmap::RightBoundaryType(waypoint);
600 if (lane_boundary_type == hdmap::LaneBoundaryType::SOLID_YELLOW ||
601 lane_boundary_type == hdmap::LaneBoundaryType::SOLID_WHITE) {
602 *right_neighbor_lane_borrowable = false;
603 }
604 ADEBUG << "s[" << check_s << "] right_neighbor_lane_borrowable["
605 << LaneBoundaryType_Type_Name(lane_boundary_type) << "]";
606 }
607 check_s += 2.0;
608 }
609}
610
611bool LaneBorrowPath::CheckLaneBoundaryType(
612 const ReferenceLineInfo& reference_line_info, const double check_s,
613 const SidePassDirection& lane_borrow_info) {
614 const ReferenceLine& reference_line = reference_line_info.reference_line();
615 auto ref_point = reference_line.GetNearestReferencePoint(check_s);
616 if (ref_point.lane_waypoints().empty()) {
617 return false;
618 }
619
620 const auto waypoint = ref_point.lane_waypoints().front();
621 hdmap::LaneBoundaryType::Type lane_boundary_type =
623 if (lane_borrow_info == SidePassDirection::LEFT_BORROW) {
624 lane_boundary_type = hdmap::LeftBoundaryType(waypoint);
625 } else if (lane_borrow_info == SidePassDirection::RIGHT_BORROW) {
626 lane_boundary_type = hdmap::RightBoundaryType(waypoint);
627 }
628 if (lane_boundary_type == hdmap::LaneBoundaryType::SOLID_YELLOW ||
629 lane_boundary_type == hdmap::LaneBoundaryType::SOLID_WHITE) {
630 return false;
631 }
632 return true;
633}
634
635void LaneBorrowPath::SetPathInfo(PathData* const path_data) {
636 std::vector<PathPointDecision> path_decision;
638 *path_data, PathData::PathPointType::IN_LANE, &path_decision);
639 // Go through every path_point, and add in-lane/out-of-lane info.
640 const auto& discrete_path = path_data->discretized_path();
641 bool is_prev_point_out_lane = false;
642 SLBoundary ego_sl_boundary;
643 for (size_t i = 0; i < discrete_path.size(); ++i) {
644 if (!GetSLBoundary(*path_data, i, reference_line_info_, &ego_sl_boundary)) {
645 ADEBUG << "Unable to get SL-boundary of ego-vehicle.";
646 continue;
647 }
648 double lane_left_width = 0.0;
649 double lane_right_width = 0.0;
650 double middle_s =
651 (ego_sl_boundary.start_s() + ego_sl_boundary.end_s()) / 2.0;
653 middle_s, &lane_left_width, &lane_right_width)) {
654 // Rough sl boundary estimate using single point lane width
655 double back_to_inlane_extra_buffer = 0.2;
656 double in_and_out_lane_hysteresis_buffer =
657 is_prev_point_out_lane ? back_to_inlane_extra_buffer : 0.0;
658 // For lane-borrow path, as long as ADC is not on the lane of
659 // reference-line, it is out on other lanes. It might even be
660 // on reverse lane!
661 if (ego_sl_boundary.end_l() >
662 lane_left_width + in_and_out_lane_hysteresis_buffer ||
663 ego_sl_boundary.start_l() <
664 -lane_right_width - in_and_out_lane_hysteresis_buffer) {
665 if (path_data->path_label().find("reverse") != std::string::npos) {
666 std::get<1>((path_decision)[i]) =
668 } else if (path_data->path_label().find("forward") !=
669 std::string::npos) {
670 std::get<1>((path_decision)[i]) =
672 } else {
673 std::get<1>((path_decision)[i]) = PathData::PathPointType::UNKNOWN;
674 }
675 if (!is_prev_point_out_lane) {
676 if (ego_sl_boundary.end_l() >
677 lane_left_width + back_to_inlane_extra_buffer ||
678 ego_sl_boundary.start_l() <
679 -lane_right_width - back_to_inlane_extra_buffer) {
680 is_prev_point_out_lane = true;
681 }
682 }
683 } else {
684 // The path point is within the reference_line's lane.
685 std::get<1>((path_decision)[i]) = PathData::PathPointType::IN_LANE;
686 if (is_prev_point_out_lane) {
687 is_prev_point_out_lane = false;
688 }
689 }
690
691 } else {
692 AERROR
693 << "reference line not ready when setting path point guide, middle_s"
694 << middle_s << ",index" << i << "path point"
695 << discrete_path[i].DebugString();
696 break;
697 }
698 }
699 path_data->SetPathPointDecisionGuide(std::move(path_decision));
700}
701
702bool ComparePathData(const PathData& lhs, const PathData& rhs,
703 const Obstacle* blocking_obstacle) {
704 ADEBUG << "Comparing " << lhs.path_label() << " and " << rhs.path_label();
705 static constexpr double kNeighborPathLengthComparisonTolerance = 25.0;
706 double lhs_path_length = lhs.frenet_frame_path().back().s();
707 double rhs_path_length = rhs.frenet_frame_path().back().s();
708 // Select longer path.
709 // If roughly same length, then select self-lane path.
710 if (std::fabs(lhs_path_length - rhs_path_length) >
711 kNeighborPathLengthComparisonTolerance) {
712 return lhs_path_length > rhs_path_length;
713 }
714 // If roughly same length, and must borrow neighbor lane,
715 // then prefer to borrow forward lane rather than reverse lane.
716 int lhs_on_reverse =
718 int rhs_on_reverse =
720 // TODO(jiacheng): make this a flag.
721 if (std::abs(lhs_on_reverse - rhs_on_reverse) > 6) {
722 return lhs_on_reverse < rhs_on_reverse;
723 }
724 // For two lane-borrow directions, based on ADC's position,
725 // select the more convenient one.
726 if (blocking_obstacle) {
727 // select left/right path based on blocking_obstacle's position
728 const double obstacle_l =
729 (blocking_obstacle->PerceptionSLBoundary().start_l() +
730 blocking_obstacle->PerceptionSLBoundary().end_l()) /
731 2;
732 ADEBUG << "obstacle[" << blocking_obstacle->Id() << "] l[" << obstacle_l
733 << "]";
734 return (obstacle_l > 0.0
735 ? (lhs.path_label().find("right") != std::string::npos)
736 : (lhs.path_label().find("left") != std::string::npos));
737 } else {
738 // select left/right path based on ADC's position
739 double adc_l = lhs.frenet_frame_path().front().l();
740 if (adc_l < -1.0) {
741 return lhs.path_label().find("right") != std::string::npos;
742 } else if (adc_l > 1.0) {
743 return lhs.path_label().find("left") != std::string::npos;
744 }
745 }
746 // If same length, both neighbor lane are forward,
747 // then select the one that returns to in-lane earlier.
748 static constexpr double kBackToSelfLaneComparisonTolerance = 20.0;
749 int lhs_back_idx = GetBackToInLaneIndex(lhs.path_point_decision_guide());
750 int rhs_back_idx = GetBackToInLaneIndex(rhs.path_point_decision_guide());
751 double lhs_back_s = lhs.frenet_frame_path()[lhs_back_idx].s();
752 double rhs_back_s = rhs.frenet_frame_path()[rhs_back_idx].s();
753 if (std::fabs(lhs_back_s - rhs_back_s) > kBackToSelfLaneComparisonTolerance) {
754 return lhs_back_idx < rhs_back_idx;
755 }
756 // If same length, both forward, back to inlane at same time,
757 // select the left one to side-pass.
758 bool lhs_on_leftlane = lhs.path_label().find("left") != std::string::npos;
759 return lhs_on_leftlane;
760}
761
763 const std::vector<PathPointDecision>& path_point_decision) {
764 int ret = 0;
765 for (const auto& curr_decision : path_point_decision) {
766 if (std::get<1>(curr_decision) ==
768 ++ret;
769 }
770 }
771 return ret;
772}
773
775 const std::vector<PathPointDecision>& path_point_decision) {
776 // ACHECK(!path_point_decision.empty());
777 // ACHECK(std::get<1>(path_point_decision.back()) ==
778 // PathData::PathPointType::IN_LANE);
779
780 for (int i = static_cast<int>(path_point_decision.size()) - 1; i >= 0; --i) {
781 if (std::get<1>(path_point_decision[i]) !=
783 return i;
784 }
785 }
786 return 0;
787}
788
789} // namespace planning
790} // namespace apollo
A general class to denote the return status of an API call.
Definition status.h:43
static Status OK()
generate a success status.
Definition status.h:60
@Brief This is a helper class that can load vehicle configurations.
Rectangular (undirected) bounding box in 2-D.
Definition box2d.h:52
The class of polygon in 2-D.
Definition polygon2d.h:42
Implements a class of 2-dimensional vectors.
Definition vec2d.h:42
Frame holds all data for one planning cycle.
Definition frame.h:62
T * Find(const I id)
Find object by id in the container
bool Init(const std::string &config_dir, const std::string &name, const std::shared_ptr< DependencyInjector > &injector) override
This is the class that associates an Obstacle with its path properties.
Definition obstacle.h:62
const std::string & Id() const
Definition obstacle.h:75
const SLBoundary & PerceptionSLBoundary() const
Definition obstacle.cc:694
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 void TrimTailingOutLanePoints(PathData *const path_data)
Trim the points at tail of path which away from lane
static bool IsValidRegularPath(const ReferenceLineInfo &reference_line_info, const PathData &path_data)
Check if the generated path is valid
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 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...
const std::string & path_label() const
Definition path_data.cc:264
const FrenetFramePath & frenet_frame_path() const
Definition path_data.cc:94
const std::vector< std::tuple< double, PathPointType, double > > & path_point_decision_guide() const
Definition path_data.cc:99
const IndexedList< std::string, Obstacle > & obstacles() const
void RecordDebugInfo(const PathBound &path_boundaries, const std::string &debug_name, ReferenceLineInfo *const reference_line_info)
add path_boundary debug info for PnC monitor
bool GetSLBoundary(const PathData &path_data, int point_index, const ReferenceLineInfo *reference_line_info, SLBoundary *const sl_boundary)
get sl boundary of the point on PathData
std::vector< SLPolygon > obs_sl_polygons_
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.
static void UpdatePathRefWithBound(const PathBoundary &path_boundary, double weight, std::vector< double > *ref_l, std::vector< double > *weight_ref_l)
If ref_l is below or above path boundary, will update its values and weights
ReferenceLineInfo holds all data for one reference line.
bool GetNeighborLaneInfo(const ReferenceLineInfo::LaneType lane_type, const double s, hdmap::Id *ptr_lane_id, double *ptr_lane_width) const
std::vector< SLPolygon > * mutable_obs_sl_polygons()
const ReferenceLine & reference_line() const
bool GetLaneWidth(const double s, double *const lane_left_width, double *const lane_right_width) const
std::shared_ptr< DependencyInjector > injector_
Definition task.h:59
ReferenceLineInfo * reference_line_info_
Definition task.h:58
virtual bool Init(const std::string &config_dir, const std::string &name, const std::shared_ptr< DependencyInjector > &injector)
Definition task.cc:40
Planning module main class.
#define ACHECK(cond)
Definition log.h:80
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
#define AWARN
Definition log.h:43
LaneBoundaryType::Type LeftBoundaryType(const LaneWaypoint &waypoint)
get left boundary type at a waypoint.
Definition path.cc:75
LaneBoundaryType::Type RightBoundaryType(const LaneWaypoint &waypoint)
get left boundary type at a waypoint.
Definition path.cc:92
int GetBackToInLaneIndex(const std::vector< PathPointDecision > &path_point_decision)
constexpr double kJunctionClearanceDist
constexpr double kIntersectionClearanceDist
int ContainsOutOnReverseLane(const std::vector< PathPointDecision > &path_point_decision)
std::vector< PathBoundPoint > PathBound
bool IsNonmovableObstacle(const ReferenceLineInfo &reference_line_info, const Obstacle &obstacle)
bool ComparePathData(const PathData &lhs, const PathData &rhs, const Obstacle *blocking_obstacle)
class register implement
Definition arena_queue.h:37
optional PiecewiseJerkPathConfig path_optimizer_config