Apollo 11.0
自动驾驶开放平台
lane_borrow_path_generic.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
45 const std::string& config_dir,
46 const std::string& name,
47 const std::shared_ptr<DependencyInjector>& injector) {
48 if (!Task::Init(config_dir, name, injector)) {
49 return false;
50 }
51 // Load the config this task.
52 return Task::LoadConfig<LaneBorrowPathGenericConfig>(&config_);
53}
54
55apollo::common::Status LaneBorrowPathGeneric::Process(Frame* frame, ReferenceLineInfo* reference_line_info) {
56 if (!config_.is_allow_lane_borrowing() || reference_line_info->path_reusable()) {
57 AINFO << "path reusable" << reference_line_info->path_reusable() << ",skip";
58 return Status::OK();
59 }
60 if (!IsNecessaryToBorrowLane()) {
61 decided_side_pass_direction_.clear();
62 auto* mutable_path_decider_status
63 = injector_->planning_context()->mutable_planning_status()->mutable_path_decider();
64 mutable_path_decider_status->set_left_borrow(false);
65 mutable_path_decider_status->set_right_borrow(false);
66 AINFO << "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
72 AINFO << "LaneBorrowPathGeneric, reference_line_info length: " << reference_line_info->reference_line().Length();
73
75 if (!DecidePathBounds(&candidate_path_boundaries)) {
76 AERROR << "Failed to decide path boundaries.";
77 return Status::OK();
78 }
79 if (!OptimizePath(candidate_path_boundaries, &candidate_path_data)) {
80 AERROR << "Failed to optimize path.";
81 return Status::OK();
82 }
83 if (!AssessPath(&candidate_path_data, reference_line_info->mutable_path_data())) {
84 AERROR << "Path assessment failed";
85 }
86
87 return Status::OK();
88}
89
90bool LaneBorrowPathGeneric::DecidePathBounds(std::vector<PathBoundary>* boundary) {
91 AINFO << "side pass direction size:" << decided_side_pass_direction_.size();
92 narrowest_width_.clear();
93 for (size_t i = 0; i < decided_side_pass_direction_.size(); i++) {
94 boundary->emplace_back();
95 auto& path_bound = boundary->back();
96 std::string blocking_obstacle_id = "";
97 std::string borrow_lane_type = "";
98 double path_narrowest_width = 0;
99 // 1. Initialize the path boundaries to be an indefinitely large area.
101 const std::string msg = "Failed to initialize path boundaries.";
102 AERROR << msg;
103 boundary->pop_back();
104 continue;
105 }
106 // 2. Decide a rough boundary based on lane info and ADC's position
107 if (!GetBoundaryFromNeighborLane(decided_side_pass_direction_[i], &path_bound, &borrow_lane_type)) {
108 AERROR << "Failed to decide a rough boundary based on lane and adc.";
109 boundary->pop_back();
110 continue;
111 }
112 // TODO(fengzhiqi): ADC buffer
113 if (config_.enable_extend_boundary_by_adc()) {
115 AERROR << "Failed to decide a rough boundary based on adc.";
116 boundary->pop_back();
117 continue;
118 }
119 }
120
121 std::string label;
122 if (decided_side_pass_direction_[i] == SidePassDirection::LEFT_BORROW) {
123 label = "regular/left" + borrow_lane_type;
124 } else {
125 label = "regular/right" + borrow_lane_type;
126 }
127 path_bound.set_label(label);
128
129 // path_bound.DebugString("after_neighbor_lane");
130 // 3. Fine-tune the boundary based on static obstacles
131 AINFO << "LaneBorrowPathGeneric, decided_side_pass_direction: " << decided_side_pass_direction_[i]
132 << ", boundary size: " << path_bound.size() << ", path_bound start end s: [ " << path_bound.front().s
133 << ", " << path_bound.back().s << "]";
134
135 PathBound temp_path_bound = path_bound;
136 LaneBorrowInfo lane_borrow_direction = decided_side_pass_direction_[i] == SidePassDirection::LEFT_BORROW
139 obs_sl_polygons_.clear();
140 GetSLPolygons(&obs_sl_polygons_, lane_borrow_direction);
145 &path_bound,
146 &blocking_obstacle_id,
147 &path_narrowest_width);
148 // path_bound.DebugString("after_obs");
149
150 // 3.2 Update boundary width nudge info
151 GetBoundaryFromNudgeDecision(decided_side_pass_direction_[i], &path_bound);
152 // path_bound.DebugString("after_undge_info");
153
154 // 3.3 Update boundary width Extra Path Bound
156
157 // 4. Append some extra path bound points to avoid zero-length path data.
158 int counter = 0;
159 while (!blocking_obstacle_id.empty() && path_bound.size() < temp_path_bound.size()
160 && counter < FLAGS_num_extra_tail_bound_point) {
161 path_bound.push_back(temp_path_bound[path_bound.size()]);
162 counter++;
163 }
164
165 // lane_borrow_status update
166 auto* lane_borrow_status = injector_->planning_context()->mutable_planning_status()->mutable_lane_borrow();
167 if (!blocking_obstacle_id.empty()) {
168 double current_time = ::apollo::cyber::Clock::NowInSeconds();
169 lane_borrow_status->set_block_obstacle_id(blocking_obstacle_id);
170 if (lane_borrow_status->lane_borrow_block()) {
171 lane_borrow_status->set_block_duration(
172 lane_borrow_status->block_duration() + current_time
173 - lane_borrow_status->last_block_timestamp());
174 } else {
175 lane_borrow_status->set_block_duration(0);
176 lane_borrow_status->set_lane_borrow_block(true);
177 }
178 lane_borrow_status->set_last_block_timestamp(current_time);
179 } else {
180 if (lane_borrow_status->lane_borrow_block()) {
181 lane_borrow_status->set_block_duration(0);
182 lane_borrow_status->set_lane_borrow_block(false);
183 lane_borrow_status->set_last_block_timestamp(0);
184 }
185 }
186
187 ADEBUG << "Completed generating path boundaries.";
188
189 path_bound.set_blocking_obstacle_id(blocking_obstacle_id);
190 RecordDebugInfo(path_bound, path_bound.label(), reference_line_info_);
191 narrowest_width_.emplace(label, path_narrowest_width);
192 }
193 return !boundary->empty();
194}
195
196bool LaneBorrowPathGeneric::OptimizePath(
197 const std::vector<PathBoundary>& path_boundaries,
198 std::vector<PathData>* candidate_path_data) {
199 const auto& config = config_.path_optimizer_config();
200 const ReferenceLine& reference_line = reference_line_info_->reference_line();
201 std::array<double, 3> end_state = {0.0, 0.0, 0.0};
202
203 for (const auto& path_boundary : path_boundaries) {
204 std::vector<double> opt_l, opt_dl, opt_ddl;
205 std::vector<std::pair<double, double>> ddl_bounds;
206 PathOptimizerUtil::CalculateAccBound(path_boundary, reference_line, &ddl_bounds);
207 const double jerk_bound = PathOptimizerUtil::EstimateJerkBoundary(std::fmax(init_sl_state_.first[1], 1e-12));
208 std::vector<double> ref_l;
209 std::vector<double> weight_ref_l;
210 bool is_left_side_pass = path_boundary.label().find("left") != std::string::npos;
212 path_boundary, config.path_reference_l_weight(), &ref_l, &weight_ref_l, is_left_side_pass);
213
214 bool res_opt = PathOptimizerUtil::OptimizePath(
216 end_state,
217 ref_l,
218 weight_ref_l,
219 path_boundary,
220 ddl_bounds,
221 jerk_bound,
222 config,
223 &opt_l,
224 &opt_dl,
225 &opt_ddl);
226 if (res_opt) {
227 auto frenet_frame_path = PathOptimizerUtil::ToPiecewiseJerkPath(
228 opt_l, opt_dl, opt_ddl, path_boundary.delta_s(), path_boundary.start_s());
229 PathData path_data;
230 path_data.SetReferenceLine(&reference_line);
231 path_data.SetFrenetPath(std::move(frenet_frame_path));
232 if (FLAGS_use_front_axe_center_in_path_planning) {
233 auto discretized_path
235 path_data.SetDiscretizedPath(discretized_path);
236 }
237 path_data.set_path_label(path_boundary.label());
238 path_data.set_blocking_obstacle_id(path_boundary.blocking_obstacle_id());
239 candidate_path_data->push_back(std::move(path_data));
240 AINFO << "Lane borrow: path labels [ " << path_boundary.label() << " ]";
241 AINFO << "dalta s: " << path_boundary.delta_s() << ", boundary size: " << path_boundary.size()
242 << ", frenet path size: " << candidate_path_data->back().frenet_frame_path().size();
243 }
244 }
245 if (candidate_path_data->empty()) {
246 return false;
247 }
248 return true;
249}
250
251bool LaneBorrowPathGeneric::AssessPath(std::vector<PathData>* candidate_path_data, PathData* final_path) {
252 std::vector<PathData> valid_path_data;
253 for (auto& curr_path_data : *candidate_path_data) {
255 SetPathInfo(&curr_path_data);
256 if (reference_line_info_->SDistanceToDestination() < FLAGS_path_trim_destination_threshold) {
258 }
259 if (curr_path_data.Empty()) {
260 AINFO << "lane borrow path is empty after trimed";
261 continue;
262 }
263 valid_path_data.push_back(curr_path_data);
264 }
265 }
266 if (valid_path_data.empty()) {
267 AINFO << "All lane borrow path are not valid";
268 return false;
269 }
270 auto* mutable_path_decider_status
271 = injector_->planning_context()->mutable_planning_status()->mutable_path_decider();
272 const Obstacle* blocking_obstacle = reference_line_info_->path_decision()->obstacles().Find(blocking_obstacle_id_);
273 if (valid_path_data.size() > 1) {
274 if (ComparePathData(
276 valid_path_data[0],
277 valid_path_data[1],
278 blocking_obstacle,
279 narrowest_width_)) {
280 *final_path = valid_path_data[0];
281 } else {
282 *final_path = valid_path_data[1];
283 }
284 } else {
285 *final_path = valid_path_data[0];
286 }
287 reference_line_info_->MutableCandidatePathData()->push_back(*final_path);
289 RecordDebugInfo(*final_path, final_path->path_label(), reference_line_info_);
290 return true;
291}
292
293bool LaneBorrowPathGeneric::GetBoundaryFromNeighborLane(
294 const SidePassDirection pass_direction,
295 PathBoundary* const path_bound,
296 std::string* borrow_lane_type) {
297 // Sanity checks.
298 CHECK_NOTNULL(path_bound);
299 ACHECK(!path_bound->empty());
300 const ReferenceLine& reference_line = reference_line_info_->reference_line();
301 double adc_lane_width = PathBoundsDeciderUtil::GetADCLaneWidth(reference_line, init_sl_state_.first[0]);
302 double offset_to_map = 0;
303 bool borrowing_reverse_lane = false;
304 reference_line.GetOffsetToMap(init_sl_state_.first[0], &offset_to_map);
305 // Go through every point, update the boundary based on lane info and
306 // ADC's position.
307 double past_lane_left_width = adc_lane_width / 2.0;
308 double past_lane_right_width = adc_lane_width / 2.0;
309 int path_blocked_idx = -1;
310 for (size_t i = 0; i < path_bound->size(); ++i) {
311 double curr_s = (*path_bound)[i].s;
312 // 1. Get the current lane width at current point.
313 double curr_lane_left_width = 0.0;
314 double curr_lane_right_width = 0.0;
315 double offset_to_lane_center = 0.0;
316 if (!reference_line.GetLaneWidth(curr_s, &curr_lane_left_width, &curr_lane_right_width)) {
317 AWARN << "Failed to get lane width at s = " << curr_s;
318 curr_lane_left_width = past_lane_left_width;
319 curr_lane_right_width = past_lane_right_width;
320 } else {
321 reference_line.GetOffsetToMap(curr_s, &offset_to_lane_center);
322 curr_lane_left_width += offset_to_lane_center;
323 curr_lane_right_width -= offset_to_lane_center;
324 past_lane_left_width = curr_lane_left_width;
325 past_lane_right_width = curr_lane_right_width;
326 }
327 // 2. Get the neighbor lane widths at the current point.
328 double curr_neighbor_lane_width = 0.0;
329 if (CheckLaneBoundaryType(*reference_line_info_, curr_s, pass_direction)) {
330 hdmap::Id neighbor_lane_id;
331 if (pass_direction == SidePassDirection::LEFT_BORROW) {
332 // Borrowing left neighbor lane.
335 curr_s,
336 &neighbor_lane_id,
337 &curr_neighbor_lane_width)) {
338 ADEBUG << "Borrow left forward neighbor lane." << neighbor_lane_id.id();
341 curr_s,
342 &neighbor_lane_id,
343 &curr_neighbor_lane_width)) {
344 borrowing_reverse_lane = true;
345 ADEBUG << "Borrow left reverse neighbor lane." << neighbor_lane_id.id();
346 }
347 } else if (pass_direction == SidePassDirection::RIGHT_BORROW) {
348 // Borrowing right neighbor lane.
351 curr_s,
352 &neighbor_lane_id,
353 &curr_neighbor_lane_width)) {
354 ADEBUG << "Borrow right forward neighbor lane." << neighbor_lane_id.id();
357 curr_s,
358 &neighbor_lane_id,
359 &curr_neighbor_lane_width)) {
360 borrowing_reverse_lane = true;
361 ADEBUG << "Borrow right reverse neighbor lane." << neighbor_lane_id.id();
362 } else {
363 AINFO << "There is no right neighbor lane.";
364 }
365 }
366 }
367 // 3. Calculate the proper boundary based on lane-width, ADC's position,
368 // and ADC's velocity.
369 double offset_to_map = 0.0;
370 reference_line.GetOffsetToMap(curr_s, &offset_to_map);
371
372 double curr_left_bound_lane = curr_lane_left_width
373 + (pass_direction == SidePassDirection::LEFT_BORROW ? curr_neighbor_lane_width : 0.0);
374
375 double curr_right_bound_lane = -curr_lane_right_width
376 - (pass_direction == SidePassDirection::RIGHT_BORROW ? curr_neighbor_lane_width : 0.0);
377 double curr_left_bound = 0.0;
378 double curr_right_bound = 0.0;
379 curr_left_bound = curr_left_bound_lane - offset_to_map;
380 curr_right_bound = curr_right_bound_lane - offset_to_map;
381
382 // 4. Update the boundary.
384 curr_left_bound, curr_right_bound, BoundType::LANE, BoundType::LANE, "", "", &path_bound->at(i))) {
385 path_blocked_idx = static_cast<int>(i);
386 }
387 if (path_blocked_idx != -1) {
388 break;
389 }
390 }
391 PathBoundsDeciderUtil::TrimPathBounds(path_blocked_idx, path_bound);
392 *borrow_lane_type = borrowing_reverse_lane ? "reverse" : "forward";
393 return true;
394}
395
396bool LaneBorrowPathGeneric::GetBoundaryFromNudgeDecision(
397 const SidePassDirection pass_direction,
398 PathBoundary* const path_bound) {
399 const auto& nudge_info = ParkDataCenter::Instance()->current_nudge_info(reference_line_info_->key());
400 bool is_use_nudge_key_points = FLAGS_enable_nudge_decider && nudge_info.is_enable()
401 && nudge_info.extra_nudge_key_points().size() > 1 && nudge_info.extra_nudge_key_points().at(0).size() > 1;
402 if (!is_use_nudge_key_points) {
403 AINFO << "GetBoundaryFromNudgeDecision, not use nudge key points";
404 return true;
405 }
406
407 double start_pt_s, end_pt_s;
408 int key_points_index = pass_direction == SidePassDirection::LEFT_BORROW ? 0 : 1;
409 start_pt_s = nudge_info.extra_nudge_key_points().at(key_points_index).front().s();
410 end_pt_s = nudge_info.extra_nudge_key_points().at(key_points_index).back().s();
411
412 if (pass_direction == SidePassDirection::LEFT_BORROW) {
413 for (size_t i = 1; i < path_bound->size(); ++i) {
414 auto& left_bound = path_bound->at(i).l_upper;
415 auto& right_bound = path_bound->at(i).l_lower;
416 double check_s = path_bound->at(i).s;
417 if (check_s < start_pt_s) {
418 continue;
419 } else if (check_s < end_pt_s) {
420 double nudge_l = 0;
421 if (nudge_info.GetInterpolatedNudgeL(true, check_s, &nudge_l)) {
422 right_bound.l = std::max(std::min(nudge_l, left_bound.l), right_bound.l);
423 path_bound->at(i).is_nudge_bound[RIGHT_INDEX] = true;
424 }
425 } else {
426 break;
427 }
428 }
429 } else {
430 for (size_t i = 1; i < path_bound->size(); ++i) {
431 auto& left_bound = path_bound->at(i).l_upper;
432 auto& right_bound = path_bound->at(i).l_lower;
433 double check_s = path_bound->at(i).s;
434 if (check_s < start_pt_s) {
435 continue;
436 } else if (check_s < end_pt_s) {
437 double nudge_l = 0;
438 if (nudge_info.GetInterpolatedNudgeL(false, check_s, &nudge_l)) {
439 left_bound.l = std::min(std::max(nudge_l, right_bound.l), left_bound.l);
440 path_bound->at(i).is_nudge_bound[LEFT_INDEX] = true;
441 }
442 } else {
443 break;
444 }
445 }
446 }
447 return true;
448}
449
450void LaneBorrowPathGeneric::UpdateSelfPathInfo() {
451 auto cur_path = reference_line_info_->path_data();
452 if (!cur_path.Empty() && cur_path.path_label().find("self") != std::string::npos
453 && cur_path.blocking_obstacle_id().empty() && IsNudgeFinish()) {
454 use_self_lane_ = std::max(use_self_lane_ + 1, 0);
455 use_self_lane_ = std::min(use_self_lane_, 10);
456 } else {
457 use_self_lane_ = std::min(use_self_lane_ - 1, 0);
458 use_self_lane_ = std::max(use_self_lane_, -10);
459 }
460 blocking_obstacle_id_ = cur_path.blocking_obstacle_id();
461}
462
463bool LaneBorrowPathGeneric::IsNudgeFinish() {
464 const auto& nudge_info = ParkDataCenter::Instance()->current_nudge_info(reference_line_info_->key());
465 return !nudge_info.is_enable() || nudge_info.extra_nudge_key_points().size() < 2;
466}
467
468bool LaneBorrowPathGeneric::IsNecessaryToBorrowLane() {
469 auto* mutable_path_decider_status
470 = injector_->planning_context()->mutable_planning_status()->mutable_path_decider();
471 UpdateSelfPathInfo();
472 is_in_path_lane_borrow_scenario_ = mutable_path_decider_status->is_in_path_lane_borrow_scenario();
473 decided_side_pass_direction_.clear();
474 if (mutable_path_decider_status->left_borrow()) {
475 decided_side_pass_direction_.push_back(SidePassDirection::LEFT_BORROW);
476 }
477 if (mutable_path_decider_status->right_borrow()) {
478 decided_side_pass_direction_.push_back(SidePassDirection::RIGHT_BORROW);
479 }
480 AINFO << "is_in_path_lane_borrow_scenario_: " << is_in_path_lane_borrow_scenario_
481 << ", use_self_lane_: " << use_self_lane_;
482 if (is_in_path_lane_borrow_scenario_) {
483 // If originally borrowing neighbor lane:
484 const Frame* last_frame = injector_->frame_history()->Latest();
485 bool last_frame_not_in_lane_borrow = nullptr != last_frame && nullptr != last_frame->DriveReferenceLineInfo()
486 && (last_frame->DriveReferenceLineInfo()->path_data().path_label().find("lane_change")
487 != std::string::npos);
488 if (use_self_lane_ >= 6 || last_frame_not_in_lane_borrow
489 || frame_->reference_line_info().size() != last_frame->reference_line_info().size()) {
490 // If have been able to use self-lane for some time, then switch to
491 // non-lane-borrowing.
492 is_in_path_lane_borrow_scenario_ = false;
493 decided_side_pass_direction_.clear();
494 AINFO << "Switch from LANE-BORROW path to SELF-LANE path.";
495 }
496 } else {
497 // If originally not borrowing neighbor lane:
498 AINFO << "Blocking obstacle ID[" << blocking_obstacle_id_ << "]";
499 // ADC requirements check for lane-borrowing:
500 // if (!HasSingleReferenceLine(*frame_)) {
501 // AINFO << "Not HasSingleReferenceLine.";
502 // return false;
503 // }
505 AINFO << "Current referenceline is lane change.";
506 return false;
507 }
508 if (!IsWithinSidePassingSpeedADC(*frame_)) {
509 AINFO << "Not IsWithinSidePassingSpeedADC.";
510 return false;
511 }
512
513 // Obstacle condition check for lane-borrowing:
514 if (!IsBlockingObstacleFarFromIntersection(*reference_line_info_, blocking_obstacle_id_)) {
515 AINFO << "Not IsBlockingObstacleFarFromIntersection.";
516 return false;
517 }
518 // if (!IsLongTermBlockingObstacle()) {
519 // AINFO << "Not IsLongTermBlockingObstacle.";
520 // return false;
521 // }
523 *reference_line_info_, blocking_obstacle_id_, config_.enable_nudge_destination_threshold())) {
524 AINFO << "Not IsBlockingObstacleWithinDestination.";
525 return false;
526 }
527 // if (!IsSidePassableObstacle(*reference_line_info_)) {
528 // AINFO << "Not IsSidePassableObstacle.";
529 // return false;
530 // }
531 if (!config_.enable_active_trigger() && blocking_obstacle_id_.empty()) {
532 AINFO << "Not nudge, no blocking_obstacle_id and not active trigger";
533 return false;
534 }
535
536 if (!IsEnableNudge(*reference_line_info_)) {
537 AINFO << "Not nudge, details in ObstacleNudgeDecider";
538 return false;
539 }
540
541 // switch to lane-borrowing
542 if (decided_side_pass_direction_.empty()) {
543 // first time init decided_side_pass_direction
544 bool left_borrowable;
545 bool right_borrowable;
546 CheckLaneBorrow(*reference_line_info_, &left_borrowable, &right_borrowable);
547 if (!left_borrowable && !right_borrowable) {
548 is_in_path_lane_borrow_scenario_ = false;
549 AINFO << "LEFT AND RIGHT LANE CAN NOT BORROW";
550 return false;
551 } else {
552 is_in_path_lane_borrow_scenario_ = true;
553 if (left_borrowable) {
554 decided_side_pass_direction_.push_back(SidePassDirection::LEFT_BORROW);
555 mutable_path_decider_status->set_left_borrow(true);
556 }
557 if (right_borrowable) {
558 decided_side_pass_direction_.push_back(SidePassDirection::RIGHT_BORROW);
559 mutable_path_decider_status->set_right_borrow(true);
560 }
561 }
562 }
563 use_self_lane_ = 0;
564 for (auto& lane_borrow_dir : decided_side_pass_direction_) {
565 AINFO << "lane_borrow_dir: " << lane_borrow_dir;
566 }
567 AINFO << "Switch from SELF-LANE path to LANE-BORROW path.";
568 }
569 mutable_path_decider_status->set_is_in_path_lane_borrow_scenario(is_in_path_lane_borrow_scenario_);
570 return is_in_path_lane_borrow_scenario_;
571}
572
573bool LaneBorrowPathGeneric::HasSingleReferenceLine(const Frame& frame) {
574 return frame.reference_line_info().size() == 1;
575}
576
577bool LaneBorrowPathGeneric::IsWithinSidePassingSpeedADC(const Frame& frame) {
578 return frame.PlanningStartPoint().v() < config_.lane_borrow_max_speed();
579}
580
581bool LaneBorrowPathGeneric::IsLongTermBlockingObstacle() {
582 if (std::abs(use_self_lane_) >= config_.long_term_blocking_obstacle_cycle_threshold()) {
583 ADEBUG << "The blocking obstacle is long-term existing.";
584 return true;
585 } else {
586 ADEBUG << "The blocking obstacle is not long-term existing.";
587 return false;
588 }
589}
590
591bool LaneBorrowPathGeneric::IsSidePassableObstacle(const ReferenceLineInfo& reference_line_info) {
592 const auto& path_decider_status = injector_->planning_context()->planning_status().path_decider();
593 if (blocking_obstacle_id_.empty()) {
594 AINFO << "There is no blocking obstacle.";
595 return false;
596 }
597 const Obstacle* blocking_obstacle = reference_line_info.path_decision().obstacles().Find(blocking_obstacle_id_);
598 if (blocking_obstacle == nullptr) {
599 AINFO << "Blocking obstacle is no longer there.";
600 return false;
601 }
602
603 return IsNonmovableObstacle(reference_line_info, *blocking_obstacle);
604}
605
606bool LaneBorrowPathGeneric::IsEnableNudge(const ReferenceLineInfo& reference_line_info) {
607 if (!FLAGS_enable_nudge_decider) {
608 return true;
609 }
610 // const auto& lane_follow_status =
611 // injector_->planning_context()->planning_status().lane_follow();
612 // if (!lane_follow_status.lane_follow_block()) {
613 // AINFO << "LaneBorrowPathGeneric::IsEnableNudge, lane_follow is not block, no
614 // need lane borrow"; return false;
615 // }
616 const auto& nudge_info = ParkDataCenter::Instance()->current_nudge_info(reference_line_info.key());
617 if (nudge_info.is_enable() && nudge_info.extra_nudge_key_points().size() > 1) {
618 AINFO << "LaneBorrowPathGeneric::IsEnableNudge, Lane Nudge is enable";
619 return true;
620 }
621 return false;
622}
623
624void LaneBorrowPathGeneric::CheckLaneBorrow(
625 const ReferenceLineInfo& reference_line_info,
626 bool* left_neighbor_lane_borrowable,
627 bool* right_neighbor_lane_borrowable) {
628 const ReferenceLine& reference_line = reference_line_info.reference_line();
629
630 *left_neighbor_lane_borrowable = true;
631 *right_neighbor_lane_borrowable = true;
632
633 static constexpr double kLookforwardDistance = 20.0;
634 double check_s = reference_line_info.AdcSlBoundary().end_s();
635 double lookforward_distance = std::min(check_s + kLookforwardDistance, reference_line.Length());
636
637 // chenck Nudge length
638 const auto& nudge_info = ParkDataCenter::Instance()->current_nudge_info(reference_line_info.key());
639 if (FLAGS_enable_nudge_decider && nudge_info.is_enable() && nudge_info.extra_nudge_key_points().size() > 1
640 && nudge_info.extra_nudge_key_points().at(0).size() > 1) {
641 double nudge_length = nudge_info.extra_nudge_key_points().at(0).back().s();
642 lookforward_distance = std::max(std::min(lookforward_distance, nudge_length), check_s + 10.0);
643 }
644
645 while (check_s < lookforward_distance) {
646 auto ref_point = reference_line.GetNearestReferencePoint(check_s);
647 if (ref_point.lane_waypoints().empty()) {
648 *left_neighbor_lane_borrowable = false;
649 *right_neighbor_lane_borrowable = false;
650 return;
651 }
652 auto ptr_lane_info = reference_line_info.LocateLaneInfo(check_s);
653 if (ptr_lane_info->lane().left_neighbor_forward_lane_id().empty()
654 && ptr_lane_info->lane().left_neighbor_reverse_lane_id().empty()) {
655 *left_neighbor_lane_borrowable = false;
656 }
657 if (ptr_lane_info->lane().right_neighbor_forward_lane_id().empty()
658 && ptr_lane_info->lane().right_neighbor_reverse_lane_id().empty()) {
659 *right_neighbor_lane_borrowable = false;
660 }
661 AINFO << "enable_ignore_boundary_type: " << config_.enable_ignore_boundary_type();
662 if (!config_.enable_ignore_boundary_type()) {
663 const auto waypoint = ref_point.lane_waypoints().front();
665
666 if (*left_neighbor_lane_borrowable) {
667 lane_boundary_type = hdmap::LeftBoundaryType(waypoint);
668 if (lane_boundary_type == hdmap::LaneBoundaryType::SOLID_YELLOW
669 || lane_boundary_type == hdmap::LaneBoundaryType::DOUBLE_YELLOW
670 || lane_boundary_type == hdmap::LaneBoundaryType::SOLID_WHITE) {
671 *left_neighbor_lane_borrowable = false;
672 }
673 AINFO << "s[" << check_s << "] left_lane_boundary_type["
674 << LaneBoundaryType_Type_Name(lane_boundary_type) << "]";
675 }
676 if (*right_neighbor_lane_borrowable) {
677 lane_boundary_type = hdmap::RightBoundaryType(waypoint);
678 if (lane_boundary_type == hdmap::LaneBoundaryType::SOLID_YELLOW
679 || lane_boundary_type == hdmap::LaneBoundaryType::SOLID_WHITE) {
680 *right_neighbor_lane_borrowable = false;
681 }
682 AINFO << "s[" << check_s << "] right_neighbor_lane_borrowable["
683 << LaneBoundaryType_Type_Name(lane_boundary_type) << "]";
684 }
685 }
686 check_s += 2.0;
687 }
688}
689
690bool LaneBorrowPathGeneric::CheckLaneBoundaryType(
691 const ReferenceLineInfo& reference_line_info,
692 const double check_s,
693 const SidePassDirection& lane_borrow_info) {
694 const ReferenceLine& reference_line = reference_line_info.reference_line();
695 auto ref_point = reference_line.GetNearestReferencePoint(check_s);
696 if (ref_point.lane_waypoints().empty()) {
697 return false;
698 }
699 if (!config_.enable_ignore_boundary_type()) {
700 const auto waypoint = ref_point.lane_waypoints().front();
702 if (lane_borrow_info == SidePassDirection::LEFT_BORROW) {
703 lane_boundary_type = hdmap::LeftBoundaryType(waypoint);
704 } else if (lane_borrow_info == SidePassDirection::RIGHT_BORROW) {
705 lane_boundary_type = hdmap::RightBoundaryType(waypoint);
706 }
707 if (lane_boundary_type == hdmap::LaneBoundaryType::SOLID_YELLOW
708 || lane_boundary_type == hdmap::LaneBoundaryType::SOLID_WHITE) {
709 return false;
710 }
711 }
712 return true;
713}
714
715void LaneBorrowPathGeneric::SetPathInfo(PathData* const path_data) {
716 std::vector<PathPointDecision> path_decision;
718 // Go through every path_point, and add in-lane/out-of-lane info.
719 const auto& discrete_path = path_data->discretized_path();
720 bool is_prev_point_out_lane = false;
721 SLBoundary ego_sl_boundary;
722 for (size_t i = 0; i < discrete_path.size(); ++i) {
723 if (!GetSLBoundary(*path_data, i, reference_line_info_, &ego_sl_boundary)) {
724 ADEBUG << "Unable to get SL-boundary of ego-vehicle.";
725 continue;
726 }
727 double lane_left_width = 0.0;
728 double lane_right_width = 0.0;
729 double middle_s = (ego_sl_boundary.start_s() + ego_sl_boundary.end_s()) / 2.0;
730 if (reference_line_info_->reference_line().GetLaneWidth(middle_s, &lane_left_width, &lane_right_width)) {
731 // Rough sl boundary estimate using single point lane width
732 double back_to_inlane_extra_buffer = 0.2;
733 double in_and_out_lane_hysteresis_buffer = is_prev_point_out_lane ? back_to_inlane_extra_buffer : 0.0;
734 // For lane-borrow path, as long as ADC is not on the lane of
735 // reference-line, it is out on other lanes. It might even be
736 // on reverse lane!
737 if (ego_sl_boundary.end_l() > lane_left_width + in_and_out_lane_hysteresis_buffer
738 || ego_sl_boundary.start_l() < -lane_right_width - in_and_out_lane_hysteresis_buffer) {
739 if (path_data->path_label().find("reverse") != std::string::npos) {
740 std::get<1>((path_decision)[i]) = PathData::PathPointType::OUT_ON_REVERSE_LANE;
741 } else if (path_data->path_label().find("forward") != std::string::npos) {
742 std::get<1>((path_decision)[i]) = PathData::PathPointType::OUT_ON_FORWARD_LANE;
743 } else {
744 std::get<1>((path_decision)[i]) = PathData::PathPointType::UNKNOWN;
745 }
746 if (!is_prev_point_out_lane) {
747 if (ego_sl_boundary.end_l() > lane_left_width + back_to_inlane_extra_buffer
748 || ego_sl_boundary.start_l() < -lane_right_width - back_to_inlane_extra_buffer) {
749 is_prev_point_out_lane = true;
750 }
751 }
752 } else {
753 // The path point is within the reference_line's lane.
754 std::get<1>((path_decision)[i]) = PathData::PathPointType::IN_LANE;
755 if (is_prev_point_out_lane) {
756 is_prev_point_out_lane = false;
757 }
758 }
759
760 } else {
761 AERROR << "reference line not ready when setting path point guide, middle_s" << middle_s << ",index" << i
762 << "path point" << discrete_path[i].DebugString();
763 break;
764 }
765 }
766 path_data->SetPathPointDecisionGuide(std::move(path_decision));
767}
768
769void LaneBorrowPathGeneric::GetSLPolygons(std::vector<SLPolygon>* polygons, LaneBorrowInfo lane_borrow_info) {
770 polygons->clear();
771 auto obstacles = reference_line_info_->path_decision()->obstacles();
772 const auto& nudge_info = ParkDataCenter::Instance()->current_nudge_info(reference_line_info_->key());
773 const double adc_back_edge_s = reference_line_info_->AdcSlBoundary().start_s();
774 for (const auto* obstacle : obstacles.Items()) {
776 continue;
777 }
778 // double check_dis = std::max(reference_line_info_->vehicle_state().linear_velocity() * 3.0, 10.0);
779
780 // if (nudge_info.IsObsIgnoreNudgeDecision(
781 // obstacle->Id(), obstacle->PerceptionSLBoundary().start_s(), check_dis)) {
782 // continue;
783 // }
784 if (obstacle->PerceptionSLBoundary().end_s() < adc_back_edge_s) {
785 continue;
786 }
787 const auto obstacle_sl = obstacle->PerceptionSLBoundary();
788 // AINFO << "GetSLPolygonsWithNudgeDecision: " << obstacle->Id();
789 polygons->emplace_back(obstacle_sl, obstacle->Id(), obstacle->Perception().type());
790 if (nudge_info.NeedCheckObsCollision(obstacle->Id())) {
791 if (lane_borrow_info == LaneBorrowInfo::LEFT_BORROW) {
792 polygons->back().SetNudgeInfo(SLPolygon::LEFT_NUDGE);
793 AINFO << "Set Obs " << obstacle->Id() << ", LEFT_NUDGE";
794 } else if (lane_borrow_info == LaneBorrowInfo::RIGHT_BORROW) {
795 polygons->back().SetNudgeInfo(SLPolygon::RIGHT_NUDGE);
796 AINFO << "Set Obs " << obstacle->Id() << ", RIGHT_NUDGE";
797 }
798 }
799 }
800 sort(polygons->begin(), polygons->end(), [](const SLPolygon& a, const SLPolygon& b) {
801 return a.MinS() < b.MinS();
802 });
803}
804
806 const ReferenceLineInfo& reference_line_info,
807 const PathData& lhs,
808 const PathData& rhs,
809 const Obstacle* blocking_obstacle,
810 const std::unordered_map<std::string, double>& narrowest_width) {
811 AINFO << "Comparing " << lhs.path_label() << " and " << rhs.path_label();
812 static constexpr double kNeighborPathLengthComparisonTolerance = 25.0;
813 double lhs_path_length = lhs.frenet_frame_path().back().s();
814 double rhs_path_length = rhs.frenet_frame_path().back().s();
815 // Select longer path.
816 // If roughly same length, then select self-lane path.
817 if (std::fabs(lhs_path_length - rhs_path_length) > kNeighborPathLengthComparisonTolerance) {
818 return lhs_path_length > rhs_path_length;
819 }
820 // If roughly same length, and must borrow neighbor lane,
821 // then prefer to borrow forward lane rather than reverse lane.
822 int lhs_on_reverse = ContainsOutOnReverseLane(lhs.path_point_decision_guide());
823 int rhs_on_reverse = ContainsOutOnReverseLane(rhs.path_point_decision_guide());
824 // TODO(jiacheng): make this a flag.
825 if (std::abs(lhs_on_reverse - rhs_on_reverse) > 6) {
826 AINFO << "ComparePathData, on_reverse: [left, right] : [ " << lhs_on_reverse << ", " << rhs_on_reverse << " ]";
827 return lhs_on_reverse < rhs_on_reverse;
828 }
829 // For two lane-borrow directions, based on ADC's position,
830 // select the more convenient one.
831 if (blocking_obstacle) {
832 // select left/right path based on blocking_obstacle's position
833 double obstacle_l = (blocking_obstacle->PerceptionSLBoundary().start_l()
834 + blocking_obstacle->PerceptionSLBoundary().end_l())
835 / 2;
836 ADEBUG << "ComparePathData, obstacle " << blocking_obstacle->Id() << ", l: " << obstacle_l;
837 SLPolygon blocking_obstacle_sl_polygon;
838 ParkDataCenter::Instance()
839 ->current_nudge_info(reference_line_info.key())
840 .GetFirstBlockSLPolygon(blocking_obstacle->Id(), &blocking_obstacle_sl_polygon);
841 if (!blocking_obstacle_sl_polygon.id().empty()) {
842 obstacle_l = (blocking_obstacle_sl_polygon.MaxL() + blocking_obstacle_sl_polygon.MinL()) / 2;
843 AINFO << "ComparePathData, obstacle in nudge_info " << blocking_obstacle_sl_polygon.id()
844 << ", l: " << obstacle_l;
845 if (obstacle_l > 0.3) {
846 return lhs.path_label().find("right") != std::string::npos;
847 } else if (obstacle_l < -0.3) {
848 return lhs.path_label().find("left") != std::string::npos;
849 }
850 }
851 } else {
852 // select left/right path based on ADC's position
853 double adc_l = lhs.frenet_frame_path().front().l();
854 AINFO << "ComparePathData, adc_l: " << adc_l;
855 if (adc_l < -1.0) {
856 AINFO << "adc_l < -1.0";
857 return lhs.path_label().find("right") != std::string::npos;
858 } else if (adc_l > 1.0) {
859 AINFO << "adc_l > 1.0";
860 return lhs.path_label().find("left") != std::string::npos;
861 }
862 }
863 // If same length, both neighbor lane are forward,
864 // then select the one that returns to in-lane earlier.
865 static constexpr double kBackToSelfLaneComparisonTolerance = 20.0;
866 int lhs_back_idx = GetBackToInLaneIndex(lhs.path_point_decision_guide());
867 int rhs_back_idx = GetBackToInLaneIndex(rhs.path_point_decision_guide());
868 double lhs_back_s = lhs.frenet_frame_path()[lhs_back_idx].s();
869 double rhs_back_s = rhs.frenet_frame_path()[rhs_back_idx].s();
870 if (std::fabs(lhs_back_s - rhs_back_s) > kBackToSelfLaneComparisonTolerance) {
871 AINFO << "ComparePathData, back_idx [ " << lhs_back_idx << ", " << rhs_back_idx << " ], bask_s [ " << lhs_back_s
872 << ", " << rhs_back_s << " ]";
873 return lhs_back_idx < rhs_back_idx;
874 }
875 // Compare the narrowest_width
876 if (narrowest_width.find(lhs.path_label()) != narrowest_width.end()
877 && narrowest_width.find(rhs.path_label()) != narrowest_width.end()) {
878 double lhs_w = narrowest_width.at(lhs.path_label());
879 double rhs_w = narrowest_width.at(rhs.path_label());
880 if ((lhs_w < 2.0 || rhs_w < 2.0) && std::fabs(lhs_w - rhs_w) > 1.5) {
881 AINFO << "ComparePathData, lhs_w: " << lhs_w << ", rhs_w: " << rhs_w << ", chose left: " << (lhs_w > rhs_w);
882 return lhs_w > rhs_w;
883 }
884 }
885 // If same length, both forward, back to inlane at same time,
886 // select the left one to side-pass.
887 bool lhs_on_leftlane = lhs.path_label().find("left") != std::string::npos;
888 AINFO << "ComparePathData, lhs_on_leftlane: " << lhs_on_leftlane;
889 return lhs_on_leftlane;
890}
891
892int ContainsOutOnReverseLane(const std::vector<PathPointDecision>& path_point_decision) {
893 int ret = 0;
894 for (const auto& curr_decision : path_point_decision) {
895 if (std::get<1>(curr_decision) == PathData::PathPointType::OUT_ON_REVERSE_LANE) {
896 ++ret;
897 }
898 }
899 return ret;
900}
901
902int GetBackToInLaneIndex(const std::vector<PathPointDecision>& path_point_decision) {
903 // ACHECK(!path_point_decision.empty());
904 // ACHECK(std::get<1>(path_point_decision.back()) ==
905 // PathData::PathPointType::IN_LANE);
906
907 for (int i = static_cast<int>(path_point_decision.size()) - 1; i >= 0; --i) {
908 if (std::get<1>(path_point_decision[i]) != PathData::PathPointType::IN_LANE) {
909 return i;
910 }
911 }
912 return 0;
913}
914
915} // namespace planning
916} // 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
static double NowInSeconds()
gets the current time in second.
Definition clock.cc:56
Frame holds all data for one planning cycle.
Definition frame.h:62
const std::list< ReferenceLineInfo > & reference_line_info() const
Definition frame.cc:123
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 UpdatePathBoundaryBySLPolygon(const ReferenceLineInfo &reference_line_info, std::vector< SLPolygon > *const sl_polygon, const SLState &init_sl_state, PathBoundary *const path_boundary, std::string *const blocked_id, double *const narrowest_width)
static bool ExtendBoundaryByADC(const ReferenceLineInfo &reference_line_info, const SLState &init_sl_state, const double extend_buffer, PathBoundary *const path_bound)
extend boundary to include adc
static bool AddExtraPathBound(const std::vector< SLPolygon > &sl_polygons, PathBoundary *const path_boundary, const SLState &init_sl_state, std::string *const blocked_id)
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 double GetADCLaneWidth(const ReferenceLine &reference_line, const double adc_frenet_s)
Get lane width in init_sl_state.
static bool IsWithinPathDeciderScopeObstacle(const Obstacle &obstacle)
Is obstacle should be considered in path decision
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 void UpdatePathRefWithBoundInSidePassDirection(const PathBoundary &path_boundary, double weight, std::vector< double > *ref_l, std::vector< double > *weight_ref_l, bool is_left_side_pass)
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.
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
std::vector< PathData > * MutableCandidatePathData()
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 ...
bool GetLaneWidth(const double s, double *const lane_left_width, double *const lane_right_width) const
std::string id() const
Definition sl_polygon.h:86
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)
bool IsBlockingObstacleWithinDestination(const ReferenceLineInfo &reference_line_info, const std::string &blocking_obstacle_id, const double threshold)
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)
bool IsBlockingObstacleFarFromIntersection(const ReferenceLineInfo &reference_line_info, const std::string &blocking_obstacle_id)
class register implement
Definition arena_queue.h:37
#define LEFT_INDEX
#define RIGHT_INDEX