Apollo 11.0
自动驾驶开放平台
st_obstacles_processor.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2019 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
22
23#include <algorithm>
24#include <unordered_set>
25
26#include "modules/common_msgs/basic_msgs/pnc_point.pb.h"
27#include "modules/common_msgs/planning_msgs/decision.pb.h"
28#include "cyber/common/log.h"
34
35namespace apollo {
36namespace planning {
37
44
45namespace {
46// ObsTEdge contains: (is_starting_t, t, s_min, s_max, obs_id).
47using ObsTEdge = std::tuple<int, double, double, double, std::string>;
48} // namespace
49
50void STObstaclesProcessor::Init(const double planning_distance,
51 const double planning_time,
52 const PathData& path_data,
53 PathDecision* const path_decision,
54 History* const history) {
55 planning_time_ = planning_time;
56 planning_distance_ = planning_distance;
57 path_data_ = path_data;
59 adc_path_init_s_ = path_data_.discretized_path().front().s();
60 path_decision_ = path_decision;
61 history_ = history;
62
63 obs_t_edges_.clear();
64 obs_t_edges_idx_ = 0;
65
66 obs_id_to_st_boundary_.clear();
67 obs_id_to_decision_.clear();
68 candidate_clear_zones_.clear();
69 obs_id_to_alternative_st_boundary_.clear();
70}
71
73 PathDecision* const path_decision) {
74 // Sanity checks.
75 if (path_decision == nullptr) {
76 const std::string msg = "path_decision is nullptr";
77 AERROR << msg;
78 return Status(ErrorCode::PLANNING_ERROR, msg);
79 }
80 if (planning_time_ < 0.0) {
81 const std::string msg = "Negative planning time.";
82 AERROR << msg;
83 return Status(ErrorCode::PLANNING_ERROR, msg);
84 }
85 if (planning_distance_ < 0.0) {
86 const std::string msg = "Negative planning distance.";
87 AERROR << msg;
88 return Status(ErrorCode::PLANNING_ERROR, msg);
89 }
90 if (path_data_.discretized_path().size() <= 1) {
91 const std::string msg = "Number of path points is too few.";
92 AERROR << msg;
93 return Status(ErrorCode::PLANNING_ERROR, msg);
94 }
95 obs_id_to_st_boundary_.clear();
96
97 // Some preprocessing to save the adc_low_road_right segments.
98 bool is_adc_low_road_right_beginning = true;
99 for (const auto& path_pt_info : path_data_.path_point_decision_guide()) {
100 double path_pt_s = 0.0;
101 PathData::PathPointType path_pt_type;
102 std::tie(path_pt_s, path_pt_type, std::ignore) = path_pt_info;
105 if (is_adc_low_road_right_beginning) {
106 adc_low_road_right_segments_.emplace_back(path_pt_s, path_pt_s);
107 is_adc_low_road_right_beginning = false;
108 } else {
109 adc_low_road_right_segments_.back().second = path_pt_s;
110 }
111 } else if (path_pt_type == PathData::PathPointType::IN_LANE) {
112 if (!is_adc_low_road_right_beginning) {
113 is_adc_low_road_right_beginning = true;
114 }
115 }
116 }
117
118 // Map obstacles into ST-graph.
119 // Go through every obstacle and plot them in ST-graph.
120 std::unordered_set<std::string> non_ignore_obstacles;
121 std::tuple<std::string, STBoundary, Obstacle*> closest_stop_obstacle;
122 std::get<0>(closest_stop_obstacle) = "NULL";
123 for (const auto* obs_item_ptr : path_decision->obstacles().Items()) {
124 // Sanity checks.
125 Obstacle* obs_ptr = path_decision->Find(obs_item_ptr->Id());
126 if (obs_ptr == nullptr) {
127 const std::string msg = "Null obstacle pointer.";
128 AERROR << msg;
129 return Status(ErrorCode::PLANNING_ERROR, msg);
130 }
131
132 // Draw the obstacle's st-boundary.
133 std::vector<STPoint> lower_points;
134 std::vector<STPoint> upper_points;
135 bool is_caution_obstacle = false;
136 double obs_caution_end_t = 0.0;
137 if (!ComputeObstacleSTBoundary(*obs_ptr, &lower_points, &upper_points,
138 &is_caution_obstacle, &obs_caution_end_t)) {
139 // Obstacle doesn't appear on ST-Graph.
140 continue;
141 }
142 auto boundary =
143 STBoundary::CreateInstanceAccurate(lower_points, upper_points);
144 boundary.set_id(obs_ptr->Id());
145 if (is_caution_obstacle) {
146 boundary.set_obstacle_road_right_ending_t(obs_caution_end_t);
147 }
148 // Update the trimmed obstacle into alternative st-bound storage
149 // for later uses.
150 while (lower_points.size() > 2 &&
151 lower_points.back().t() > obs_caution_end_t) {
152 lower_points.pop_back();
153 }
154 while (upper_points.size() > 2 &&
155 upper_points.back().t() > obs_caution_end_t) {
156 upper_points.pop_back();
157 }
158 auto alternative_boundary =
159 STBoundary::CreateInstanceAccurate(lower_points, upper_points);
160 alternative_boundary.set_id(obs_ptr->Id());
161 obs_id_to_alternative_st_boundary_[obs_ptr->Id()] = alternative_boundary;
162 ADEBUG << "Obstacle " << obs_ptr->Id()
163 << " has an alternative st-boundary with "
164 << lower_points.size() + upper_points.size() << " points.";
165
166 // Store all Keep-Clear zone together.
167 if (obs_item_ptr->Id().find("KC") != std::string::npos) {
168 candidate_clear_zones_.push_back(
169 make_tuple(obs_ptr->Id(), boundary, obs_ptr));
170 continue;
171 }
172
173 // Process all other obstacles than Keep-Clear zone.
174 if (obs_ptr->Trajectory().trajectory_point().empty()) {
175 // Obstacle is static.
176 if (std::get<0>(closest_stop_obstacle) == "NULL" ||
177 std::get<1>(closest_stop_obstacle).bottom_left_point().s() >
178 boundary.bottom_left_point().s()) {
179 // If this static obstacle is closer for ADC to stop, record it.
180 closest_stop_obstacle =
181 std::make_tuple(obs_ptr->Id(), boundary, obs_ptr);
182 }
183 } else {
184 // Obstacle is dynamic.
185 if (boundary.bottom_left_point().s() - adc_path_init_s_ <
187 boundary.bottom_left_point().t() > kTIgnoreThreshold) {
188 // Ignore obstacles that are behind.
189 // TODO(jiacheng): don't ignore if ADC is in dangerous segments.
190 continue;
191 }
192 obs_id_to_st_boundary_[obs_ptr->Id()] = boundary;
193 obs_ptr->set_path_st_boundary(boundary);
194 non_ignore_obstacles.insert(obs_ptr->Id());
195 ADEBUG << "Adding " << obs_ptr->Id() << " into the ST-graph.";
196 }
197 }
198 // For static obstacles, only retain the closest one (also considers
199 // Keep-Clear zone here).
200 // Note: We only need to check the overlapping between the closest obstacle
201 // and all the Keep-Clear zones. Because if there is another obstacle
202 // overlapping with a Keep-Clear zone, which results in an even closer
203 // stop fence, then that very Keep-Clear zone must also overlap with
204 // the closest obstacle. (Proof omitted here)
205 if (std::get<0>(closest_stop_obstacle) != "NULL") {
206 std::string closest_stop_obs_id;
207 STBoundary closest_stop_obs_boundary;
208 Obstacle* closest_stop_obs_ptr;
209 std::tie(closest_stop_obs_id, closest_stop_obs_boundary,
210 closest_stop_obs_ptr) = closest_stop_obstacle;
211 ADEBUG << "Closest obstacle ID = " << closest_stop_obs_id;
212 // Go through all Keep-Clear zones, and see if there is an even closer
213 // stop fence due to them.
214 if (!closest_stop_obs_ptr->IsVirtual()) {
215 for (const auto& clear_zone : candidate_clear_zones_) {
216 const auto& clear_zone_boundary = std::get<1>(clear_zone);
217 if (closest_stop_obs_boundary.min_s() >= clear_zone_boundary.min_s() &&
218 closest_stop_obs_boundary.min_s() <= clear_zone_boundary.max_s()) {
219 std::tie(closest_stop_obs_id, closest_stop_obs_boundary,
220 closest_stop_obs_ptr) = clear_zone;
221 ADEBUG << "Clear zone " << closest_stop_obs_id << " is closer.";
222 break;
223 }
224 }
225 }
226 obs_id_to_st_boundary_[closest_stop_obs_id] = closest_stop_obs_boundary;
227 closest_stop_obs_ptr->set_path_st_boundary(closest_stop_obs_boundary);
228 non_ignore_obstacles.insert(closest_stop_obs_id);
229 ADEBUG << "Adding " << closest_stop_obs_ptr->Id() << " into the ST-graph.";
230 ADEBUG << "min_s = " << closest_stop_obs_boundary.min_s();
231 }
232
233 // Set IGNORE decision for those that are not in ST-graph:
234 for (const auto* obs_item_ptr : path_decision->obstacles().Items()) {
235 Obstacle* obs_ptr = path_decision->Find(obs_item_ptr->Id());
236 if (non_ignore_obstacles.count(obs_ptr->Id()) == 0) {
237 ObjectDecisionType ignore_decision;
238 ignore_decision.mutable_ignore();
239 if (!obs_ptr->HasLongitudinalDecision()) {
240 obs_ptr->AddLongitudinalDecision("st_obstacle_processor",
241 ignore_decision);
242 }
243 if (!obs_ptr->HasLateralDecision()) {
244 obs_ptr->AddLateralDecision("st_obstacle_processor", ignore_decision);
245 }
246 }
247 }
248
249 // Preprocess the obstacles for sweep-line algorithms.
250 // Fetch every obstacle's beginning end ending t-edges only.
251 for (const auto& it : obs_id_to_st_boundary_) {
252 obs_t_edges_.emplace_back(true, it.second.min_t(),
253 it.second.bottom_left_point().s(),
254 it.second.upper_left_point().s(), it.first);
255 obs_t_edges_.emplace_back(false, it.second.max_t(),
256 it.second.bottom_right_point().s(),
257 it.second.upper_right_point().s(), it.first);
258 }
259 // Sort the edges.
260 std::sort(obs_t_edges_.begin(), obs_t_edges_.end(),
261 [](const ObsTEdge& lhs, const ObsTEdge& rhs) {
262 if (std::get<1>(lhs) != std::get<1>(rhs)) {
263 return std::get<1>(lhs) < std::get<1>(rhs);
264 } else {
265 return std::get<0>(lhs) > std::get<0>(rhs);
266 }
267 });
268
269 return Status::OK();
270}
271
272std::unordered_map<std::string, STBoundary>
273STObstaclesProcessor::GetAllSTBoundaries() {
274 return obs_id_to_st_boundary_;
275}
276
277bool STObstaclesProcessor::GetLimitingSpeedInfo(
278 double t, std::pair<double, double>* const limiting_speed_info) {
279 if (obs_id_to_decision_.empty()) {
280 // If no obstacle, then no speed limits.
281 return false;
282 }
283
284 double s_min = 0.0;
285 double s_max = planning_distance_;
286 for (auto it : obs_id_to_decision_) {
287 auto obs_id = it.first;
288 auto obs_decision = it.second;
289 auto obs_st_boundary = obs_id_to_st_boundary_[obs_id];
290 double obs_s_min = 0.0;
291 double obs_s_max = 0.0;
292 obs_st_boundary.GetBoundarySRange(t, &obs_s_max, &obs_s_min);
293 double obs_ds_lower = 0.0;
294 double obs_ds_upper = 0.0;
295 obs_st_boundary.GetBoundarySlopes(t, &obs_ds_upper, &obs_ds_lower);
296 if (obs_decision.has_yield() || obs_decision.has_stop()) {
297 if (obs_s_min <= s_max) {
298 s_max = obs_s_min;
299 limiting_speed_info->second = obs_ds_lower;
300 }
301 } else if (it.second.has_overtake()) {
302 if (obs_s_max >= s_min) {
303 s_min = obs_s_max;
304 limiting_speed_info->first = obs_ds_upper;
305 }
306 }
307 }
308 return s_min <= s_max;
309}
310
311bool STObstaclesProcessor::GetSBoundsFromDecisions(
312 double t, std::vector<std::pair<double, double>>* const available_s_bounds,
313 std::vector<std::vector<std::pair<std::string, ObjectDecisionType>>>* const
314 available_obs_decisions) {
315 // Sanity checks.
316 available_s_bounds->clear();
317 available_obs_decisions->clear();
318
319 // Gather any possible change in st-boundary situations.
320 ADEBUG << "There are " << obs_t_edges_.size() << " t-edges.";
321 std::vector<ObsTEdge> new_t_edges;
322 while (obs_t_edges_idx_ < static_cast<int>(obs_t_edges_.size()) &&
323 std::get<1>(obs_t_edges_[obs_t_edges_idx_]) <= t) {
324 if (std::get<0>(obs_t_edges_[obs_t_edges_idx_]) == 0 &&
325 std::get<1>(obs_t_edges_[obs_t_edges_idx_]) == t) {
326 break;
327 }
328 ADEBUG << "Seeing a new t-edge at t = "
329 << std::get<1>(obs_t_edges_[obs_t_edges_idx_]);
330 new_t_edges.push_back(obs_t_edges_[obs_t_edges_idx_]);
331 ++obs_t_edges_idx_;
332 }
333
334 // For st-boundaries that disappeared before t, remove them.
335 for (const auto& obs_t_edge : new_t_edges) {
336 if (std::get<0>(obs_t_edge) == 0) {
337 ADEBUG << "Obstacle id: " << std::get<4>(obs_t_edge)
338 << " is leaving st-graph.";
339 if (obs_id_to_decision_.count(std::get<4>(obs_t_edge)) != 0) {
340 obs_id_to_decision_.erase(std::get<4>(obs_t_edge));
341 }
342 }
343 }
344
345 // For overtaken obstacles, remove them if we are after
346 // their high right-of-road ending time (with a margin).
347 std::vector<std::string> obs_id_to_remove;
348 for (const auto& obs_id_to_decision_pair : obs_id_to_decision_) {
349 auto obs_id = obs_id_to_decision_pair.first;
350 auto obs_decision = obs_id_to_decision_pair.second;
351 auto obs_st_boundary = obs_id_to_st_boundary_[obs_id];
352 if (obs_decision.has_overtake() &&
353 obs_st_boundary.min_t() <= t - kOvertakenObsCautionTime &&
354 obs_st_boundary.obstacle_road_right_ending_t() <=
356 obs_id_to_remove.push_back(obs_id_to_decision_pair.first);
357 }
358 }
359 for (const auto& obs_id : obs_id_to_remove) {
360 obs_id_to_decision_.erase(obs_id);
361 // Change the displayed st-boundary to the alternative one:
362 if (obs_id_to_alternative_st_boundary_.count(obs_id) > 0) {
363 Obstacle* obs_ptr = path_decision_->Find(obs_id);
364 obs_id_to_st_boundary_[obs_id] =
365 obs_id_to_alternative_st_boundary_[obs_id];
366 obs_id_to_st_boundary_[obs_id].SetBoundaryType(
367 STBoundary::BoundaryType::OVERTAKE);
368 obs_ptr->set_path_st_boundary(obs_id_to_alternative_st_boundary_[obs_id]);
369 }
370 }
371
372 // Based on existing decisions, get the s-boundary.
373 double s_min = 0.0;
374 double s_max = planning_distance_;
375 for (auto it : obs_id_to_decision_) {
376 auto obs_id = it.first;
377 auto obs_decision = it.second;
378 auto obs_st_boundary = obs_id_to_st_boundary_[obs_id];
379 double obs_s_min = 0.0;
380 double obs_s_max = 0.0;
381 obs_st_boundary.GetBoundarySRange(t, &obs_s_max, &obs_s_min);
382 if (obs_decision.has_yield() || obs_decision.has_stop()) {
383 s_max = std::fmin(s_max, obs_s_min);
384 } else if (it.second.has_overtake()) {
385 s_min = std::fmax(s_min, obs_s_max);
386 }
387 }
388 if (s_min > s_max) {
389 return false;
390 }
391 ADEBUG << "S-boundary based on existing decisions = (" << s_min << ", "
392 << s_max << ")";
393
394 // For newly entering st_boundaries, determine possible new-boundaries.
395 // For apparent ones, make decisions directly.
396 std::vector<ObsTEdge> ambiguous_t_edges;
397 for (auto obs_t_edge : new_t_edges) {
398 ADEBUG << "For obstacle id: " << std::get<4>(obs_t_edge)
399 << ", its s-range = [" << std::get<2>(obs_t_edge) << ", "
400 << std::get<3>(obs_t_edge) << "]";
401 if (std::get<0>(obs_t_edge) == 1) {
402 if (std::get<2>(obs_t_edge) >= s_max) {
403 ADEBUG << " Apparently, it should be yielded.";
404 obs_id_to_decision_[std::get<4>(obs_t_edge)] =
405 DetermineObstacleDecision(std::get<2>(obs_t_edge),
406 std::get<3>(obs_t_edge), s_max);
407 obs_id_to_st_boundary_[std::get<4>(obs_t_edge)].SetBoundaryType(
408 STBoundary::BoundaryType::YIELD);
409 } else if (std::get<3>(obs_t_edge) <= s_min) {
410 ADEBUG << " Apparently, it should be overtaken.";
411 obs_id_to_decision_[std::get<4>(obs_t_edge)] =
412 DetermineObstacleDecision(std::get<2>(obs_t_edge),
413 std::get<3>(obs_t_edge), s_min);
414 obs_id_to_st_boundary_[std::get<4>(obs_t_edge)].SetBoundaryType(
415 STBoundary::BoundaryType::OVERTAKE);
416 } else {
417 ADEBUG << " It should be further analyzed.";
418 ambiguous_t_edges.push_back(obs_t_edge);
419 }
420 }
421 }
422 // For ambiguous ones, enumerate all decisions and corresponding bounds.
423 auto s_gaps = FindSGaps(ambiguous_t_edges, s_min, s_max);
424 if (s_gaps.empty()) {
425 return false;
426 }
427 for (auto s_gap : s_gaps) {
428 available_s_bounds->push_back(s_gap);
429 std::vector<std::pair<std::string, ObjectDecisionType>> obs_decisions;
430 for (auto obs_t_edge : ambiguous_t_edges) {
431 std::string obs_id = std::get<4>(obs_t_edge);
432 double obs_s_min = std::get<2>(obs_t_edge);
433 double obs_s_max = std::get<3>(obs_t_edge);
434 obs_decisions.emplace_back(
435 obs_id,
436 DetermineObstacleDecision(obs_s_min, obs_s_max,
437 (s_gap.first + s_gap.second) / 2.0));
438 }
439 available_obs_decisions->push_back(obs_decisions);
440 }
441
442 return true;
443}
444
445void STObstaclesProcessor::SetObstacleDecision(
446 const std::string& obs_id, const ObjectDecisionType& obs_decision) {
447 obs_id_to_decision_[obs_id] = obs_decision;
448 ObjectStatus object_status;
449 object_status.mutable_motion_type()->mutable_dynamic();
450 if (obs_decision.has_yield() || obs_decision.has_stop()) {
451 obs_id_to_st_boundary_[obs_id].SetBoundaryType(
452 STBoundary::BoundaryType::YIELD);
453 object_status.mutable_decision_type()->mutable_yield();
454 } else if (obs_decision.has_overtake()) {
455 obs_id_to_st_boundary_[obs_id].SetBoundaryType(
456 STBoundary::BoundaryType::OVERTAKE);
457 object_status.mutable_decision_type()->mutable_overtake();
458 }
459 history_->mutable_history_status()->SetObjectStatus(obs_id, object_status);
460}
461
462void STObstaclesProcessor::SetObstacleDecision(
463 const std::vector<std::pair<std::string, ObjectDecisionType>>&
464 obstacle_decisions) {
465 for (auto obs_decision : obstacle_decisions) {
466 SetObstacleDecision(obs_decision.first, obs_decision.second);
467 }
468}
469
471// Private helper functions.
472
473bool STObstaclesProcessor::ComputeObstacleSTBoundary(
474 const Obstacle& obstacle, std::vector<STPoint>* const lower_points,
475 std::vector<STPoint>* const upper_points, bool* const is_caution_obstacle,
476 double* const obs_caution_end_t) {
477 lower_points->clear();
478 upper_points->clear();
479 *is_caution_obstacle = false;
480 const auto& adc_path_points = path_data_.discretized_path();
481 const auto& obs_trajectory = obstacle.Trajectory();
482
483 if (obs_trajectory.trajectory_point().empty()) {
484 // Processing a static obstacle.
485 // Sanity checks.
486 if (!obstacle.IsStatic()) {
487 AWARN << "Non-static obstacle[" << obstacle.Id()
488 << "] has NO prediction trajectory."
489 << obstacle.Perception().ShortDebugString();
490 }
491 // Get the overlapping s between ADC path and obstacle's perception box.
492 const Box2d& obs_box = obstacle.PerceptionBoundingBox();
493 std::pair<double, double> overlapping_s;
494 if (GetOverlappingS(adc_path_points, obs_box, kADCSafetyLBuffer,
495 &overlapping_s)) {
496 lower_points->emplace_back(overlapping_s.first, 0.0);
497 lower_points->emplace_back(overlapping_s.first, planning_time_);
498 upper_points->emplace_back(overlapping_s.second, 0.0);
499 upper_points->emplace_back(overlapping_s.second, planning_time_);
500 }
501 *is_caution_obstacle = true;
502 *obs_caution_end_t = planning_time_;
503 } else {
504 // Processing a dynamic obstacle.
505 // Go through every occurrence of the obstacle at all timesteps, and
506 // figure out the overlapping s-max and s-min one by one.
507 bool is_obs_first_traj_pt = true;
508 for (const auto& obs_traj_pt : obs_trajectory.trajectory_point()) {
509 // TODO(jiacheng): Currently, if the obstacle overlaps with ADC at
510 // disjoint segments (happens very rarely), we merge them into one.
511 // In the future, this could be considered in greater details rather
512 // than being approximated.
513 const Box2d& obs_box = obstacle.GetBoundingBox(obs_traj_pt);
514 ADEBUG << obs_box.DebugString();
515 std::pair<double, double> overlapping_s;
516 if (GetOverlappingS(adc_path_points, obs_box, kADCSafetyLBuffer,
517 &overlapping_s)) {
518 ADEBUG << "Obstacle instance is overlapping with ADC path.";
519 lower_points->emplace_back(overlapping_s.first,
520 obs_traj_pt.relative_time());
521 upper_points->emplace_back(overlapping_s.second,
522 obs_traj_pt.relative_time());
523 if (is_obs_first_traj_pt) {
524 if (IsSWithinADCLowRoadRightSegment(overlapping_s.first) ||
525 IsSWithinADCLowRoadRightSegment(overlapping_s.second)) {
526 *is_caution_obstacle = true;
527 }
528 }
529 if ((*is_caution_obstacle)) {
530 if (IsSWithinADCLowRoadRightSegment(overlapping_s.first) ||
531 IsSWithinADCLowRoadRightSegment(overlapping_s.second)) {
532 *obs_caution_end_t = obs_traj_pt.relative_time();
533 }
534 }
535 }
536 is_obs_first_traj_pt = false;
537 }
538 if (lower_points->size() == 1) {
539 lower_points->emplace_back(lower_points->front().s(),
540 lower_points->front().t() + 0.1);
541 upper_points->emplace_back(upper_points->front().s(),
542 upper_points->front().t() + 0.1);
543 }
544 }
545
546 return (!lower_points->empty() && !upper_points->empty());
547}
548
549bool STObstaclesProcessor::GetOverlappingS(
550 const std::vector<PathPoint>& adc_path_points,
551 const Box2d& obstacle_instance, const double adc_l_buffer,
552 std::pair<double, double>* const overlapping_s) {
553 // Locate the possible range to search in details.
554 int pt_before_idx = GetSBoundingPathPointIndex(
555 adc_path_points, obstacle_instance, vehicle_param_.front_edge_to_center(),
556 true, 0, static_cast<int>(adc_path_points.size()) - 2);
557 ADEBUG << "The index before is " << pt_before_idx;
558 int pt_after_idx = GetSBoundingPathPointIndex(
559 adc_path_points, obstacle_instance, vehicle_param_.back_edge_to_center(),
560 false, 0, static_cast<int>(adc_path_points.size()) - 2);
561 ADEBUG << "The index after is " << pt_after_idx;
562 if (pt_before_idx == static_cast<int>(adc_path_points.size()) - 2) {
563 return false;
564 }
565 if (pt_after_idx == 0) {
566 return false;
567 }
568
569 if (pt_before_idx == -1) {
570 pt_before_idx = 0;
571 }
572 if (pt_after_idx == -1) {
573 pt_after_idx = static_cast<int>(adc_path_points.size()) - 2;
574 }
575 if (pt_before_idx >= pt_after_idx) {
576 return false;
577 }
578
579 // Detailed searching.
580 bool has_overlapping = false;
581 for (int i = pt_before_idx; i <= pt_after_idx; ++i) {
582 ADEBUG << "At ADC path index = " << i << " :";
583 if (IsADCOverlappingWithObstacle(adc_path_points[i], obstacle_instance,
584 adc_l_buffer)) {
585 overlapping_s->first = adc_path_points[std::max(i - 1, 0)].s();
586 has_overlapping = true;
587 ADEBUG << "There is overlapping.";
588 break;
589 }
590 }
591 if (!has_overlapping) {
592 return false;
593 }
594 for (int i = pt_after_idx; i >= pt_before_idx; --i) {
595 ADEBUG << "At ADC path index = " << i << " :";
596 if (IsADCOverlappingWithObstacle(adc_path_points[i], obstacle_instance,
597 adc_l_buffer)) {
598 overlapping_s->second = adc_path_points[i + 1].s();
599 ADEBUG << "There is overlapping.";
600 break;
601 }
602 }
603 return true;
604}
605
606int STObstaclesProcessor::GetSBoundingPathPointIndex(
607 const std::vector<PathPoint>& adc_path_points,
608 const Box2d& obstacle_instance, const double s_thresh, const bool is_before,
609 const int start_idx, const int end_idx) {
610 if (start_idx == end_idx) {
611 if (IsPathPointAwayFromObstacle(adc_path_points[start_idx],
612 adc_path_points[start_idx + 1],
613 obstacle_instance, s_thresh, is_before)) {
614 return start_idx;
615 } else {
616 return -1;
617 }
618 }
619
620 if (is_before) {
621 int mid_idx = (start_idx + end_idx - 1) / 2 + 1;
622 if (IsPathPointAwayFromObstacle(adc_path_points[mid_idx],
623 adc_path_points[mid_idx + 1],
624 obstacle_instance, s_thresh, is_before)) {
625 return GetSBoundingPathPointIndex(adc_path_points, obstacle_instance,
626 s_thresh, is_before, mid_idx, end_idx);
627 } else {
628 return GetSBoundingPathPointIndex(adc_path_points, obstacle_instance,
629 s_thresh, is_before, start_idx,
630 mid_idx - 1);
631 }
632 } else {
633 int mid_idx = (start_idx + end_idx) / 2;
634 if (IsPathPointAwayFromObstacle(adc_path_points[mid_idx],
635 adc_path_points[mid_idx + 1],
636 obstacle_instance, s_thresh, is_before)) {
637 return GetSBoundingPathPointIndex(adc_path_points, obstacle_instance,
638 s_thresh, is_before, start_idx,
639 mid_idx);
640 } else {
641 return GetSBoundingPathPointIndex(adc_path_points, obstacle_instance,
642 s_thresh, is_before, mid_idx + 1,
643 end_idx);
644 }
645 }
646}
647
648bool STObstaclesProcessor::IsPathPointAwayFromObstacle(
649 const PathPoint& path_point, const PathPoint& direction_point,
650 const Box2d& obs_box, const double s_thresh, const bool is_before) {
651 Vec2d path_pt(path_point.x(), path_point.y());
652 Vec2d dir_pt(direction_point.x(), direction_point.y());
653 LineSegment2d path_dir_lineseg(path_pt, dir_pt);
654 LineSegment2d normal_line_seg(path_pt, path_dir_lineseg.rotate(M_PI_2));
655
656 auto corner_points = obs_box.GetAllCorners();
657 for (const auto& corner_pt : corner_points) {
658 Vec2d normal_line_ft_pt;
659 normal_line_seg.GetPerpendicularFoot(corner_pt, &normal_line_ft_pt);
660 Vec2d path_dir_unit_vec = path_dir_lineseg.unit_direction();
661 Vec2d perpendicular_vec = corner_pt - normal_line_ft_pt;
662 double corner_pt_s_dist = path_dir_unit_vec.InnerProd(perpendicular_vec);
663 if (is_before && corner_pt_s_dist < s_thresh) {
664 return false;
665 }
666 if (!is_before && corner_pt_s_dist > -s_thresh) {
667 return false;
668 }
669 }
670 return true;
671}
672
673bool STObstaclesProcessor::IsADCOverlappingWithObstacle(
674 const PathPoint& adc_path_point, const Box2d& obs_box,
675 const double l_buffer) const {
676 // Convert reference point from center of rear axis to center of ADC.
677 Vec2d ego_center_map_frame((vehicle_param_.front_edge_to_center() -
678 vehicle_param_.back_edge_to_center()) *
679 0.5,
680 (vehicle_param_.left_edge_to_center() -
681 vehicle_param_.right_edge_to_center()) *
682 0.5);
683 ego_center_map_frame.SelfRotate(adc_path_point.theta());
684 ego_center_map_frame.set_x(ego_center_map_frame.x() + adc_path_point.x());
685 ego_center_map_frame.set_y(ego_center_map_frame.y() + adc_path_point.y());
686
687 // Compute the ADC bounding box.
688 Box2d adc_box(ego_center_map_frame, adc_path_point.theta(),
689 vehicle_param_.length(), vehicle_param_.width() + l_buffer * 2);
690
691 ADEBUG << " ADC box is: " << adc_box.DebugString();
692 ADEBUG << " Obs box is: " << obs_box.DebugString();
693
694 // Check whether ADC bounding box overlaps with obstacle bounding box.
695 return obs_box.HasOverlap(adc_box);
696}
697
698std::vector<std::pair<double, double>> STObstaclesProcessor::FindSGaps(
699 const std::vector<ObsTEdge>& obstacle_t_edges, double s_min, double s_max) {
700 std::vector<std::pair<double, int>> obs_s_edges;
701 for (auto obs_t_edge : obstacle_t_edges) {
702 obs_s_edges.emplace_back(std::get<2>(obs_t_edge), 1);
703 obs_s_edges.emplace_back(std::get<3>(obs_t_edge), 0);
704 }
705 // obs_s_edges.emplace_back(std::numeric_limits<double>::lowest(), 1);
706 obs_s_edges.emplace_back(s_min, 0);
707 obs_s_edges.emplace_back(s_max, 1);
708 // obs_s_edges.emplace_back(std::numeric_limits<double>::max(), 0);
709 std::sort(
710 obs_s_edges.begin(), obs_s_edges.end(),
711 [](const std::pair<double, int>& lhs, const std::pair<double, int>& rhs) {
712 if (lhs.first != rhs.first) {
713 return lhs.first < rhs.first;
714 } else {
715 return lhs.second > rhs.second;
716 }
717 });
718
719 std::vector<std::pair<double, double>> s_gaps;
720 int num_st_obs = 1;
721 double prev_open_s = 0.0;
722 for (auto obs_s_edge : obs_s_edges) {
723 if (obs_s_edge.second == 1) {
724 num_st_obs++;
725 if (num_st_obs == 1) {
726 s_gaps.emplace_back(prev_open_s, obs_s_edge.first);
727 }
728 } else {
729 num_st_obs--;
730 if (num_st_obs == 0) {
731 prev_open_s = obs_s_edge.first;
732 }
733 }
734 }
735
736 return s_gaps;
737}
738
739ObjectDecisionType STObstaclesProcessor::DetermineObstacleDecision(
740 const double obs_s_min, const double obs_s_max, const double s) const {
741 ObjectDecisionType decision;
742 if (s <= obs_s_min) {
743 decision.mutable_yield()->set_distance_s(0.0);
744 } else if (s >= obs_s_max) {
745 decision.mutable_overtake()->set_distance_s(0.0);
746 }
747 return decision;
748}
749
750bool STObstaclesProcessor::IsSWithinADCLowRoadRightSegment(
751 const double s) const {
752 for (const auto& seg : adc_low_road_right_segments_) {
753 if (s >= seg.first && s <= seg.second) {
754 return true;
755 }
756 }
757 return false;
758}
759
760} // namespace planning
761} // 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
static const VehicleConfig & GetConfig()
Get the current vehicle configuration.
Rectangular (undirected) bounding box in 2-D.
Definition box2d.h:52
std::string DebugString() const
Gets a human-readable description of the box
Definition box2d.cc:418
Implements a class of 2-dimensional vectors.
Definition vec2d.h:42
const std::vector< const T * > & Items() const
List all the items in the container.
This is the class that associates an Obstacle with its path properties.
Definition obstacle.h:62
const perception::PerceptionObstacle & Perception() const
Definition obstacle.h:102
void AddLongitudinalDecision(const std::string &decider_tag, const ObjectDecisionType &decision)
Definition obstacle.cc:646
void AddLateralDecision(const std::string &decider_tag, const ObjectDecisionType &decision)
Definition obstacle.cc:661
bool HasLongitudinalDecision() const
Definition obstacle.cc:636
const prediction::Trajectory & Trajectory() const
Definition obstacle.h:96
const std::string & Id() const
Definition obstacle.h:75
common::math::Box2d GetBoundingBox(const common::TrajectoryPoint &point) const
Definition obstacle.cc:159
bool HasLateralDecision() const
Definition obstacle.cc:631
void set_path_st_boundary(const STBoundary &boundary)
Definition obstacle.cc:698
const common::math::Box2d & PerceptionBoundingBox() const
Definition obstacle.h:90
const DiscretizedPath & discretized_path() const
Definition path_data.cc:90
const std::vector< std::tuple< double, PathPointType, double > > & path_point_decision_guide() const
Definition path_data.cc:99
PathDecision represents all obstacle decisions on one path.
const Obstacle * Find(const std::string &object_id) const
const IndexedList< std::string, Obstacle > & obstacles() const
static STBoundary CreateInstanceAccurate(const std::vector< STPoint > &lower_points, const std::vector< STPoint > &upper_points)
Wrapper of the constructor.
common::Status MapObstaclesToSTBoundaries(PathDecision *const path_decision)
void Init(const double planning_distance, const double planning_time, const PathData &path_data, PathDecision *const path_decision, History *const history)
Planning module main class.
Define the LineSegment2d class.
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AWARN
Definition log.h:43
Some util functions.
constexpr double kSIgnoreThreshold
constexpr double kOvertakenObsCautionTime
constexpr double kTIgnoreThreshold
class register implement
Definition arena_queue.h:37
optional VehicleParam vehicle_param
repeated apollo::common::TrajectoryPoint trajectory_point
Definition feature.proto:78
Defines the Vec2d class.