Apollo 10.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 std::vector<SLPolygon> obs_sl_polygons;
123 &obs_sl_polygons, init_sl_state_);
125 *reference_line_info_, &obs_sl_polygons, init_sl_state_,
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 RecordDebugInfo(*final_path, final_path->path_label(), reference_line_info_);
237 return true;
238}
239
240bool LaneBorrowPath::GetBoundaryFromNeighborLane(
241 const SidePassDirection pass_direction, PathBoundary* const path_bound,
242 std::string* borrow_lane_type) {
243 // Sanity checks.
244 CHECK_NOTNULL(path_bound);
245 ACHECK(!path_bound->empty());
246 const ReferenceLine& reference_line = reference_line_info_->reference_line();
247 double adc_lane_width = PathBoundsDeciderUtil::GetADCLaneWidth(
248 reference_line, init_sl_state_.first[0]);
249 double offset_to_map = 0;
250 bool borrowing_reverse_lane = false;
251 reference_line.GetOffsetToMap(init_sl_state_.first[0], &offset_to_map);
252 // Go through every point, update the boundary based on lane info and
253 // ADC's position.
254 double past_lane_left_width = adc_lane_width / 2.0;
255 double past_lane_right_width = adc_lane_width / 2.0;
256 int path_blocked_idx = -1;
257 for (size_t i = 0; i < path_bound->size(); ++i) {
258 double curr_s = (*path_bound)[i].s;
259 // 1. Get the current lane width at current point.
260 double curr_lane_left_width = 0.0;
261 double curr_lane_right_width = 0.0;
262 double offset_to_lane_center = 0.0;
263 if (!reference_line.GetLaneWidth(curr_s, &curr_lane_left_width,
264 &curr_lane_right_width)) {
265 AWARN << "Failed to get lane width at s = " << curr_s;
266 curr_lane_left_width = past_lane_left_width;
267 curr_lane_right_width = past_lane_right_width;
268 } else {
269 reference_line.GetOffsetToMap(curr_s, &offset_to_lane_center);
270 curr_lane_left_width += offset_to_lane_center;
271 curr_lane_right_width -= offset_to_lane_center;
272 past_lane_left_width = curr_lane_left_width;
273 past_lane_right_width = curr_lane_right_width;
274 }
275 // 2. Get the neighbor lane widths at the current point.
276 double curr_neighbor_lane_width = 0.0;
277 if (CheckLaneBoundaryType(*reference_line_info_, curr_s, pass_direction)) {
278 hdmap::Id neighbor_lane_id;
279 if (pass_direction == SidePassDirection::LEFT_BORROW) {
280 // Borrowing left neighbor lane.
283 &neighbor_lane_id, &curr_neighbor_lane_width)) {
284 ADEBUG << "Borrow left forward neighbor lane."
285 << neighbor_lane_id.id();
288 &neighbor_lane_id, &curr_neighbor_lane_width)) {
289 borrowing_reverse_lane = true;
290 ADEBUG << "Borrow left reverse neighbor lane."
291 << neighbor_lane_id.id();
292 } else {
293 ADEBUG << "There is no left neighbor lane.";
294 }
295 } else if (pass_direction == SidePassDirection::RIGHT_BORROW) {
296 // Borrowing right neighbor lane.
299 &neighbor_lane_id, &curr_neighbor_lane_width)) {
300 ADEBUG << "Borrow right forward neighbor lane."
301 << neighbor_lane_id.id();
304 &neighbor_lane_id, &curr_neighbor_lane_width)) {
305 borrowing_reverse_lane = true;
306 ADEBUG << "Borrow right reverse neighbor lane."
307 << neighbor_lane_id.id();
308 } else {
309 ADEBUG << "There is no right neighbor lane.";
310 }
311 }
312 }
313 // 3. Calculate the proper boundary based on lane-width, ADC's position,
314 // and ADC's velocity.
315 double offset_to_map = 0.0;
316 reference_line.GetOffsetToMap(curr_s, &offset_to_map);
317
318 double curr_left_bound_lane =
319 curr_lane_left_width + (pass_direction == SidePassDirection::LEFT_BORROW
320 ? curr_neighbor_lane_width
321 : 0.0);
322
323 double curr_right_bound_lane =
324 -curr_lane_right_width -
325 (pass_direction == SidePassDirection::RIGHT_BORROW
326 ? curr_neighbor_lane_width
327 : 0.0);
328 double curr_left_bound = 0.0;
329 double curr_right_bound = 0.0;
330 curr_left_bound = curr_left_bound_lane - offset_to_map;
331 curr_right_bound = curr_right_bound_lane - offset_to_map;
332
333 // 4. Update the boundary.
335 curr_left_bound, curr_right_bound, BoundType::LANE, BoundType::LANE,
336 "", "", &path_bound->at(i))) {
337 path_blocked_idx = static_cast<int>(i);
338 }
339 if (path_blocked_idx != -1) {
340 break;
341 }
342 }
343 PathBoundsDeciderUtil::TrimPathBounds(path_blocked_idx, path_bound);
344 *borrow_lane_type = borrowing_reverse_lane ? "reverse" : "forward";
345 return true;
346}
347void LaneBorrowPath::UpdateSelfPathInfo() {
348 auto cur_path = reference_line_info_->path_data();
349 if (!cur_path.Empty() &&
350 cur_path.path_label().find("self") != std::string::npos &&
351 cur_path.blocking_obstacle_id().empty()) {
352 use_self_lane_ = std::min(use_self_lane_ + 1, 10);
353 } else {
354 use_self_lane_ = 0;
355 }
356 blocking_obstacle_id_ = cur_path.blocking_obstacle_id();
357}
358bool LaneBorrowPath::IsNecessaryToBorrowLane() {
359 auto* mutable_path_decider_status = injector_->planning_context()
360 ->mutable_planning_status()
361 ->mutable_path_decider();
362 if (mutable_path_decider_status->is_in_path_lane_borrow_scenario()) {
363 UpdateSelfPathInfo();
364 // If originally borrowing neighbor lane:
365 if (use_self_lane_ >= 6) {
366 // If have been able to use self-lane for some time, then switch to
367 // non-lane-borrowing.
368 mutable_path_decider_status->set_is_in_path_lane_borrow_scenario(false);
369 decided_side_pass_direction_.clear();
370 AINFO << "Switch from LANE-BORROW path to SELF-LANE path.";
371 }
372 } else {
373 // If originally not borrowing neighbor lane:
374 AINFO << "Blocking obstacle ID["
375 << mutable_path_decider_status->front_static_obstacle_id() << "]";
376 // ADC requirements check for lane-borrowing:
377 if (!HasSingleReferenceLine(*frame_)) {
378 return false;
379 }
380 if (!IsWithinSidePassingSpeedADC(*frame_)) {
381 return false;
382 }
383
384 // Obstacle condition check for lane-borrowing:
385 if (!IsBlockingObstacleFarFromIntersection(*reference_line_info_)) {
386 return false;
387 }
388 if (!IsLongTermBlockingObstacle()) {
389 return false;
390 }
391 if (!IsBlockingObstacleWithinDestination(*reference_line_info_)) {
392 return false;
393 }
394 if (!IsSidePassableObstacle(*reference_line_info_)) {
395 return false;
396 }
397
398 // switch to lane-borrowing
399 if (decided_side_pass_direction_.empty()) {
400 // first time init decided_side_pass_direction
401 bool left_borrowable;
402 bool right_borrowable;
403 CheckLaneBorrow(*reference_line_info_, &left_borrowable,
404 &right_borrowable);
405 if (!left_borrowable && !right_borrowable) {
406 mutable_path_decider_status->set_is_in_path_lane_borrow_scenario(false);
407 AINFO << "LEFT AND RIGHT LANE CAN NOT BORROW";
408 return false;
409 } else {
410 mutable_path_decider_status->set_is_in_path_lane_borrow_scenario(true);
411 if (left_borrowable) {
412 decided_side_pass_direction_.push_back(
413 SidePassDirection::LEFT_BORROW);
414 }
415 if (right_borrowable) {
416 decided_side_pass_direction_.push_back(
417 SidePassDirection::RIGHT_BORROW);
418 }
419 }
420 }
421 use_self_lane_ = 0;
422 AINFO << "Switch from SELF-LANE path to LANE-BORROW path.";
423 }
424 return mutable_path_decider_status->is_in_path_lane_borrow_scenario();
425}
426
427bool LaneBorrowPath::HasSingleReferenceLine(const Frame& frame) {
428 return frame.reference_line_info().size() == 1;
429}
430
431bool LaneBorrowPath::IsWithinSidePassingSpeedADC(const Frame& frame) {
432 return frame.PlanningStartPoint().v() < config_.lane_borrow_max_speed();
433}
434
435bool LaneBorrowPath::IsLongTermBlockingObstacle() {
436 if (injector_->planning_context()
437 ->planning_status()
438 .path_decider()
439 .front_static_obstacle_cycle_counter() >=
441 ADEBUG << "The blocking obstacle is long-term existing.";
442 return true;
443 } else {
444 ADEBUG << "The blocking obstacle is not long-term existing.";
445 return false;
446 }
447}
448
449bool LaneBorrowPath::IsBlockingObstacleWithinDestination(
450 const ReferenceLineInfo& reference_line_info) {
451 const auto& path_decider_status =
452 injector_->planning_context()->planning_status().path_decider();
453 const std::string blocking_obstacle_id =
454 path_decider_status.front_static_obstacle_id();
455 if (blocking_obstacle_id.empty()) {
456 ADEBUG << "There is no blocking obstacle.";
457 return true;
458 }
459 const Obstacle* blocking_obstacle =
460 reference_line_info.path_decision().obstacles().Find(
461 blocking_obstacle_id);
462 if (blocking_obstacle == nullptr) {
463 ADEBUG << "Blocking obstacle is no longer there.";
464 return true;
465 }
466
467 double blocking_obstacle_s =
468 blocking_obstacle->PerceptionSLBoundary().start_s();
469 double adc_end_s = reference_line_info.AdcSlBoundary().end_s();
470 ADEBUG << "Blocking obstacle is at s = " << blocking_obstacle_s;
471 ADEBUG << "ADC is at s = " << adc_end_s;
472 ADEBUG << "Destination is at s = "
473 << reference_line_info.SDistanceToDestination() + adc_end_s;
474 if (blocking_obstacle_s - adc_end_s >
475 reference_line_info.SDistanceToDestination()) {
476 return false;
477 }
478 return true;
479}
480
481bool LaneBorrowPath::IsBlockingObstacleFarFromIntersection(
482 const ReferenceLineInfo& reference_line_info) {
483 const auto& path_decider_status =
484 injector_->planning_context()->planning_status().path_decider();
485 const std::string blocking_obstacle_id =
486 path_decider_status.front_static_obstacle_id();
487 if (blocking_obstacle_id.empty()) {
488 ADEBUG << "There is no blocking obstacle.";
489 return true;
490 }
491 const Obstacle* blocking_obstacle =
492 reference_line_info.path_decision().obstacles().Find(
493 blocking_obstacle_id);
494 if (blocking_obstacle == nullptr) {
495 ADEBUG << "Blocking obstacle is no longer there.";
496 return true;
497 }
498
499 // Get blocking obstacle's s.
500 double blocking_obstacle_s =
501 blocking_obstacle->PerceptionSLBoundary().end_s();
502 ADEBUG << "Blocking obstacle is at s = " << blocking_obstacle_s;
503 // Get intersection's s and compare with threshold.
504 const auto& first_encountered_overlaps =
505 reference_line_info.FirstEncounteredOverlaps();
506 for (const auto& overlap : first_encountered_overlaps) {
507 ADEBUG << overlap.first << ", " << overlap.second.DebugString();
508 if (overlap.first != ReferenceLineInfo::SIGNAL &&
509 overlap.first != ReferenceLineInfo::STOP_SIGN) {
510 continue;
511 }
512
513 auto distance = overlap.second.start_s - blocking_obstacle_s;
514 if (overlap.first == ReferenceLineInfo::SIGNAL ||
515 overlap.first == ReferenceLineInfo::STOP_SIGN) {
516 if (distance < kIntersectionClearanceDist) {
517 ADEBUG << "Too close to signal intersection (" << distance
518 << "m); don't SIDE_PASS.";
519 return false;
520 }
521 } else {
522 if (distance < kJunctionClearanceDist) {
523 ADEBUG << "Too close to overlap_type[" << overlap.first << "] ("
524 << distance << "m); don't SIDE_PASS";
525 return false;
526 }
527 }
528 }
529
530 return true;
531}
532
533bool LaneBorrowPath::IsSidePassableObstacle(
534 const ReferenceLineInfo& reference_line_info) {
535 const auto& path_decider_status =
536 injector_->planning_context()->planning_status().path_decider();
537 const std::string blocking_obstacle_id =
538 path_decider_status.front_static_obstacle_id();
539 if (blocking_obstacle_id.empty()) {
540 ADEBUG << "There is no blocking obstacle.";
541 return false;
542 }
543 const Obstacle* blocking_obstacle =
544 reference_line_info.path_decision().obstacles().Find(
545 blocking_obstacle_id);
546 if (blocking_obstacle == nullptr) {
547 ADEBUG << "Blocking obstacle is no longer there.";
548 return false;
549 }
550
551 return IsNonmovableObstacle(reference_line_info, *blocking_obstacle);
552}
553
554void LaneBorrowPath::CheckLaneBorrow(
555 const ReferenceLineInfo& reference_line_info,
556 bool* left_neighbor_lane_borrowable, bool* right_neighbor_lane_borrowable) {
557 const ReferenceLine& reference_line = reference_line_info.reference_line();
558
559 *left_neighbor_lane_borrowable = true;
560 *right_neighbor_lane_borrowable = true;
561
562 static constexpr double kLookforwardDistance = 100.0;
563 double check_s = reference_line_info.AdcSlBoundary().end_s();
564 const double lookforward_distance =
565 std::min(check_s + kLookforwardDistance, reference_line.Length());
566 while (check_s < lookforward_distance) {
567 auto ref_point = reference_line.GetNearestReferencePoint(check_s);
568 if (ref_point.lane_waypoints().empty()) {
569 *left_neighbor_lane_borrowable = false;
570 *right_neighbor_lane_borrowable = false;
571 return;
572 }
573 auto ptr_lane_info = reference_line_info.LocateLaneInfo(check_s);
574 if (ptr_lane_info->lane().left_neighbor_forward_lane_id().empty() &&
575 ptr_lane_info->lane().left_neighbor_reverse_lane_id().empty()) {
576 *left_neighbor_lane_borrowable = false;
577 }
578 if (ptr_lane_info->lane().right_neighbor_forward_lane_id().empty() &&
579 ptr_lane_info->lane().right_neighbor_reverse_lane_id().empty()) {
580 *right_neighbor_lane_borrowable = false;
581 }
582 const auto waypoint = ref_point.lane_waypoints().front();
583 hdmap::LaneBoundaryType::Type lane_boundary_type =
585
586 if (*left_neighbor_lane_borrowable) {
587 lane_boundary_type = hdmap::LeftBoundaryType(waypoint);
588 if (lane_boundary_type == hdmap::LaneBoundaryType::SOLID_YELLOW ||
589 lane_boundary_type == hdmap::LaneBoundaryType::DOUBLE_YELLOW ||
590 lane_boundary_type == hdmap::LaneBoundaryType::SOLID_WHITE) {
591 *left_neighbor_lane_borrowable = false;
592 }
593 ADEBUG << "s[" << check_s << "] left_lane_boundary_type["
594 << LaneBoundaryType_Type_Name(lane_boundary_type) << "]";
595 }
596 if (*right_neighbor_lane_borrowable) {
597 lane_boundary_type = hdmap::RightBoundaryType(waypoint);
598 if (lane_boundary_type == hdmap::LaneBoundaryType::SOLID_YELLOW ||
599 lane_boundary_type == hdmap::LaneBoundaryType::SOLID_WHITE) {
600 *right_neighbor_lane_borrowable = false;
601 }
602 ADEBUG << "s[" << check_s << "] right_neighbor_lane_borrowable["
603 << LaneBoundaryType_Type_Name(lane_boundary_type) << "]";
604 }
605 check_s += 2.0;
606 }
607}
608
609bool LaneBorrowPath::CheckLaneBoundaryType(
610 const ReferenceLineInfo& reference_line_info, const double check_s,
611 const SidePassDirection& lane_borrow_info) {
612 const ReferenceLine& reference_line = reference_line_info.reference_line();
613 auto ref_point = reference_line.GetNearestReferencePoint(check_s);
614 if (ref_point.lane_waypoints().empty()) {
615 return false;
616 }
617
618 const auto waypoint = ref_point.lane_waypoints().front();
619 hdmap::LaneBoundaryType::Type lane_boundary_type =
621 if (lane_borrow_info == SidePassDirection::LEFT_BORROW) {
622 lane_boundary_type = hdmap::LeftBoundaryType(waypoint);
623 } else if (lane_borrow_info == SidePassDirection::RIGHT_BORROW) {
624 lane_boundary_type = hdmap::RightBoundaryType(waypoint);
625 }
626 if (lane_boundary_type == hdmap::LaneBoundaryType::SOLID_YELLOW ||
627 lane_boundary_type == hdmap::LaneBoundaryType::SOLID_WHITE) {
628 return false;
629 }
630 return true;
631}
632
633void LaneBorrowPath::SetPathInfo(PathData* const path_data) {
634 std::vector<PathPointDecision> path_decision;
636 *path_data, PathData::PathPointType::IN_LANE, &path_decision);
637 // Go through every path_point, and add in-lane/out-of-lane info.
638 const auto& discrete_path = path_data->discretized_path();
639 bool is_prev_point_out_lane = false;
640 SLBoundary ego_sl_boundary;
641 for (size_t i = 0; i < discrete_path.size(); ++i) {
642 if (!GetSLBoundary(*path_data, i, reference_line_info_, &ego_sl_boundary)) {
643 ADEBUG << "Unable to get SL-boundary of ego-vehicle.";
644 continue;
645 }
646 double lane_left_width = 0.0;
647 double lane_right_width = 0.0;
648 double middle_s =
649 (ego_sl_boundary.start_s() + ego_sl_boundary.end_s()) / 2.0;
651 middle_s, &lane_left_width, &lane_right_width)) {
652 // Rough sl boundary estimate using single point lane width
653 double back_to_inlane_extra_buffer = 0.2;
654 double in_and_out_lane_hysteresis_buffer =
655 is_prev_point_out_lane ? back_to_inlane_extra_buffer : 0.0;
656 // For lane-borrow path, as long as ADC is not on the lane of
657 // reference-line, it is out on other lanes. It might even be
658 // on reverse lane!
659 if (ego_sl_boundary.end_l() >
660 lane_left_width + in_and_out_lane_hysteresis_buffer ||
661 ego_sl_boundary.start_l() <
662 -lane_right_width - in_and_out_lane_hysteresis_buffer) {
663 if (path_data->path_label().find("reverse") != std::string::npos) {
664 std::get<1>((path_decision)[i]) =
666 } else if (path_data->path_label().find("forward") !=
667 std::string::npos) {
668 std::get<1>((path_decision)[i]) =
670 } else {
671 std::get<1>((path_decision)[i]) = PathData::PathPointType::UNKNOWN;
672 }
673 if (!is_prev_point_out_lane) {
674 if (ego_sl_boundary.end_l() >
675 lane_left_width + back_to_inlane_extra_buffer ||
676 ego_sl_boundary.start_l() <
677 -lane_right_width - back_to_inlane_extra_buffer) {
678 is_prev_point_out_lane = true;
679 }
680 }
681 } else {
682 // The path point is within the reference_line's lane.
683 std::get<1>((path_decision)[i]) = PathData::PathPointType::IN_LANE;
684 if (is_prev_point_out_lane) {
685 is_prev_point_out_lane = false;
686 }
687 }
688
689 } else {
690 AERROR
691 << "reference line not ready when setting path point guide, middle_s"
692 << middle_s << ",index" << i << "path point"
693 << discrete_path[i].DebugString();
694 break;
695 }
696 }
697 path_data->SetPathPointDecisionGuide(std::move(path_decision));
698}
699
700bool ComparePathData(const PathData& lhs, const PathData& rhs,
701 const Obstacle* blocking_obstacle) {
702 ADEBUG << "Comparing " << lhs.path_label() << " and " << rhs.path_label();
703 static constexpr double kNeighborPathLengthComparisonTolerance = 25.0;
704 double lhs_path_length = lhs.frenet_frame_path().back().s();
705 double rhs_path_length = rhs.frenet_frame_path().back().s();
706 // Select longer path.
707 // If roughly same length, then select self-lane path.
708 if (std::fabs(lhs_path_length - rhs_path_length) >
709 kNeighborPathLengthComparisonTolerance) {
710 return lhs_path_length > rhs_path_length;
711 }
712 // If roughly same length, and must borrow neighbor lane,
713 // then prefer to borrow forward lane rather than reverse lane.
714 int lhs_on_reverse =
716 int rhs_on_reverse =
718 // TODO(jiacheng): make this a flag.
719 if (std::abs(lhs_on_reverse - rhs_on_reverse) > 6) {
720 return lhs_on_reverse < rhs_on_reverse;
721 }
722 // For two lane-borrow directions, based on ADC's position,
723 // select the more convenient one.
724 if (blocking_obstacle) {
725 // select left/right path based on blocking_obstacle's position
726 const double obstacle_l =
727 (blocking_obstacle->PerceptionSLBoundary().start_l() +
728 blocking_obstacle->PerceptionSLBoundary().end_l()) /
729 2;
730 ADEBUG << "obstacle[" << blocking_obstacle->Id() << "] l[" << obstacle_l
731 << "]";
732 return (obstacle_l > 0.0
733 ? (lhs.path_label().find("right") != std::string::npos)
734 : (lhs.path_label().find("left") != std::string::npos));
735 } else {
736 // select left/right path based on ADC's position
737 double adc_l = lhs.frenet_frame_path().front().l();
738 if (adc_l < -1.0) {
739 return lhs.path_label().find("right") != std::string::npos;
740 } else if (adc_l > 1.0) {
741 return lhs.path_label().find("left") != std::string::npos;
742 }
743 }
744 // If same length, both neighbor lane are forward,
745 // then select the one that returns to in-lane earlier.
746 static constexpr double kBackToSelfLaneComparisonTolerance = 20.0;
747 int lhs_back_idx = GetBackToInLaneIndex(lhs.path_point_decision_guide());
748 int rhs_back_idx = GetBackToInLaneIndex(rhs.path_point_decision_guide());
749 double lhs_back_s = lhs.frenet_frame_path()[lhs_back_idx].s();
750 double rhs_back_s = rhs.frenet_frame_path()[rhs_back_idx].s();
751 if (std::fabs(lhs_back_s - rhs_back_s) > kBackToSelfLaneComparisonTolerance) {
752 return lhs_back_idx < rhs_back_idx;
753 }
754 // If same length, both forward, back to inlane at same time,
755 // select the left one to side-pass.
756 bool lhs_on_leftlane = lhs.path_label().find("left") != std::string::npos;
757 return lhs_on_leftlane;
758}
759
761 const std::vector<PathPointDecision>& path_point_decision) {
762 int ret = 0;
763 for (const auto& curr_decision : path_point_decision) {
764 if (std::get<1>(curr_decision) ==
766 ++ret;
767 }
768 }
769 return ret;
770}
771
773 const std::vector<PathPointDecision>& path_point_decision) {
774 // ACHECK(!path_point_decision.empty());
775 // ACHECK(std::get<1>(path_point_decision.back()) ==
776 // PathData::PathPointType::IN_LANE);
777
778 for (int i = static_cast<int>(path_point_decision.size()) - 1; i >= 0; --i) {
779 if (std::get<1>(path_point_decision[i]) !=
781 return i;
782 }
783 }
784 return 0;
785}
786
787} // namespace planning
788} // 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
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
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