Apollo 11.0
自动驾驶开放平台
obstacle.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2017 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 <iomanip>
25#include <utility>
26
27#include "cyber/common/log.h"
34
35namespace apollo {
36namespace planning {
37
39using apollo::common::util::FindOrDie;
42
43namespace {
44const double kStBoundaryDeltaS = 0.2; // meters
45const double kStBoundarySparseDeltaS = 1.0; // meters
46const double kStBoundaryDeltaT = 0.05; // seconds
47} // namespace
48
49const std::unordered_map<ObjectDecisionType::ObjectTagCase, int,
50 Obstacle::ObjectTagCaseHash>
51 Obstacle::s_longitudinal_decision_safety_sorter_ = {
52 {ObjectDecisionType::kIgnore, 0},
53 {ObjectDecisionType::kOvertake, 100},
54 {ObjectDecisionType::kFollow, 300},
55 {ObjectDecisionType::kYield, 400},
56 {ObjectDecisionType::kStop, 500}};
57
58const std::unordered_map<ObjectDecisionType::ObjectTagCase, int,
59 Obstacle::ObjectTagCaseHash>
60 Obstacle::s_lateral_decision_safety_sorter_ = {
61 {ObjectDecisionType::kIgnore, 0}, {ObjectDecisionType::kNudge, 100}};
62
63Obstacle::Obstacle(const std::string& id,
64 const PerceptionObstacle& perception_obstacle,
65 const ObstaclePriority::Priority& obstacle_priority,
66 const bool is_static)
67 : id_(id),
68 perception_id_(perception_obstacle.id()),
69 perception_obstacle_(perception_obstacle),
70 perception_bounding_box_({perception_obstacle_.position().x(),
71 perception_obstacle_.position().y()},
72 perception_obstacle_.theta(),
73 perception_obstacle_.length(),
74 perception_obstacle_.width()) {
75 is_caution_level_obstacle_ = (obstacle_priority == ObstaclePriority::CAUTION);
76 std::vector<common::math::Vec2d> polygon_points;
77 if (FLAGS_use_navigation_mode ||
78 perception_obstacle.polygon_point_size() <= 2) {
79 perception_bounding_box_.GetAllCorners(&polygon_points);
80 } else {
81 ACHECK(perception_obstacle.polygon_point_size() > 2)
82 << "object " << id << "has less than 3 polygon points";
83 for (const auto& point : perception_obstacle.polygon_point()) {
84 polygon_points.emplace_back(point.x(), point.y());
85 }
86 }
88 &perception_polygon_))
89 << "object[" << id << "] polygon is not a valid convex hull.\n"
90 << perception_obstacle.DebugString();
91
92 is_static_ = (is_static || obstacle_priority == ObstaclePriority::IGNORE);
93 is_virtual_ = (perception_obstacle.id() < 0);
94 speed_ = std::hypot(perception_obstacle.velocity().x(),
95 perception_obstacle.velocity().y());
96}
97
98Obstacle::Obstacle(const std::string& id,
99 const PerceptionObstacle& perception_obstacle,
100 const prediction::Trajectory& trajectory,
101 const ObstaclePriority::Priority& obstacle_priority,
102 const bool is_static)
103 : Obstacle(id, perception_obstacle, obstacle_priority, is_static) {
104 trajectory_ = trajectory;
105 auto& trajectory_points = *trajectory_.mutable_trajectory_point();
106 double cumulative_s = 0.0;
107 if (trajectory_points.size() > 0) {
108 trajectory_points[0].mutable_path_point()->set_s(0.0);
109 }
110 for (int i = 1; i < trajectory_points.size(); ++i) {
111 const auto& prev = trajectory_points[i - 1];
112 const auto& cur = trajectory_points[i];
113 if (prev.relative_time() >= cur.relative_time()) {
114 AERROR << "prediction time is not increasing."
115 << "current point: " << cur.ShortDebugString()
116 << "previous point: " << prev.ShortDebugString();
117 }
118 cumulative_s +=
119 common::util::DistanceXY(prev.path_point(), cur.path_point());
120 trajectory_points[i].mutable_path_point()->set_s(cumulative_s);
121 }
122}
123
125 const double relative_time) const {
126 const auto& points = trajectory_.trajectory_point();
127 if (points.size() < 2) {
129 point.mutable_path_point()->set_x(perception_obstacle_.position().x());
130 point.mutable_path_point()->set_y(perception_obstacle_.position().y());
131 point.mutable_path_point()->set_z(perception_obstacle_.position().z());
132 point.mutable_path_point()->set_theta(perception_obstacle_.theta());
133 point.mutable_path_point()->set_s(0.0);
134 point.mutable_path_point()->set_kappa(0.0);
135 point.mutable_path_point()->set_dkappa(0.0);
136 point.mutable_path_point()->set_ddkappa(0.0);
137 point.set_v(0.0);
138 point.set_a(0.0);
139 point.set_relative_time(0.0);
140 return point;
141 } else {
142 auto comp = [](const common::TrajectoryPoint p, const double time) {
143 return p.relative_time() < time;
144 };
145
146 auto it_lower =
147 std::lower_bound(points.begin(), points.end(), relative_time, comp);
148
149 if (it_lower == points.begin()) {
150 return *points.begin();
151 } else if (it_lower == points.end()) {
152 return *points.rbegin();
153 }
155 *(it_lower - 1), *it_lower, relative_time);
156 }
157}
158
160 const common::TrajectoryPoint& point) const {
161 return common::math::Box2d({point.path_point().x(), point.path_point().y()},
162 point.path_point().theta(),
163 perception_obstacle_.length(),
164 perception_obstacle_.width());
165}
166
168 if (obstacle.length() <= 0.0) {
169 AERROR << "invalid obstacle length:" << obstacle.length();
170 return false;
171 }
172 if (obstacle.width() <= 0.0) {
173 AERROR << "invalid obstacle width:" << obstacle.width();
174 return false;
175 }
176 if (obstacle.height() <= 0.0) {
177 AERROR << "invalid obstacle height:" << obstacle.height();
178 return false;
179 }
180 if (obstacle.has_velocity()) {
181 if (std::isnan(obstacle.velocity().x()) ||
182 std::isnan(obstacle.velocity().y())) {
183 AERROR << "invalid obstacle velocity:"
184 << obstacle.velocity().DebugString();
185 return false;
186 }
187 }
188 for (auto pt : obstacle.polygon_point()) {
189 if (std::isnan(pt.x()) || std::isnan(pt.y())) {
190 AERROR << "invalid obstacle polygon point:" << pt.DebugString();
191 return false;
192 }
193 }
194 return true;
195}
196
197std::list<std::unique_ptr<Obstacle>> Obstacle::CreateObstacles(
198 const prediction::PredictionObstacles& predictions) {
199 std::list<std::unique_ptr<Obstacle>> obstacles;
200 for (const auto& prediction_obstacle : predictions.prediction_obstacle()) {
201 if (!IsValidPerceptionObstacle(prediction_obstacle.perception_obstacle())) {
202 AERROR << "Invalid perception obstacle: "
203 << prediction_obstacle.perception_obstacle().DebugString();
204 continue;
205 }
206 const auto perception_id =
207 std::to_string(prediction_obstacle.perception_obstacle().id());
208 if (prediction_obstacle.trajectory().empty()) {
209 obstacles.emplace_back(
210 new Obstacle(perception_id, prediction_obstacle.perception_obstacle(),
211 prediction_obstacle.priority().priority(),
212 prediction_obstacle.is_static()));
213 continue;
214 }
215
216 int trajectory_index = 0;
217 for (const auto& trajectory : prediction_obstacle.trajectory()) {
218 bool is_valid_trajectory = true;
219 for (const auto& point : trajectory.trajectory_point()) {
220 if (!IsValidTrajectoryPoint(point)) {
221 AERROR << "obj:" << perception_id
222 << " TrajectoryPoint: " << trajectory.ShortDebugString()
223 << " is NOT valid.";
224 is_valid_trajectory = false;
225 break;
226 }
227 }
228 if (!is_valid_trajectory) {
229 continue;
230 }
231
232 const std::string obstacle_id =
233 absl::StrCat(perception_id, "_", trajectory_index);
234 obstacles.emplace_back(
235 new Obstacle(obstacle_id, prediction_obstacle.perception_obstacle(),
236 trajectory, prediction_obstacle.priority().priority(),
237 prediction_obstacle.is_static()));
238 ++trajectory_index;
239 }
240 }
241 return obstacles;
242}
243
245 const std::string& id, const common::math::Box2d& obstacle_box) {
246 // create a "virtual" perception_obstacle
247 perception::PerceptionObstacle perception_obstacle;
248 // simulator needs a valid integer
249 size_t negative_id = std::hash<std::string>{}(id);
250 // set the first bit to 1 so negative_id became negative number
251 negative_id |= (0x1 << 31);
252 perception_obstacle.set_id(static_cast<int32_t>(negative_id));
253 perception_obstacle.mutable_position()->set_x(obstacle_box.center().x());
254 perception_obstacle.mutable_position()->set_y(obstacle_box.center().y());
255 perception_obstacle.set_theta(obstacle_box.heading());
256 perception_obstacle.mutable_velocity()->set_x(0);
257 perception_obstacle.mutable_velocity()->set_y(0);
258 perception_obstacle.set_length(obstacle_box.length());
259 perception_obstacle.set_width(obstacle_box.width());
260 perception_obstacle.set_height(FLAGS_virtual_stop_wall_height);
261 perception_obstacle.set_type(
263 perception_obstacle.set_tracking_time(1.0);
264
265 std::vector<common::math::Vec2d> corner_points;
266 obstacle_box.GetAllCorners(&corner_points);
267 for (const auto& corner_point : corner_points) {
268 auto* point = perception_obstacle.add_polygon_point();
269 point->set_x(corner_point.x());
270 point->set_y(corner_point.y());
271 }
272 auto* obstacle =
273 new Obstacle(id, perception_obstacle, ObstaclePriority::NORMAL, true);
274 obstacle->is_virtual_ = true;
275 return std::unique_ptr<Obstacle>(obstacle);
276}
277
279 return !((!point.has_path_point()) || std::isnan(point.path_point().x()) ||
280 std::isnan(point.path_point().y()) ||
281 std::isnan(point.path_point().z()) ||
282 std::isnan(point.path_point().kappa()) ||
283 std::isnan(point.path_point().s()) ||
284 std::isnan(point.path_point().dkappa()) ||
285 std::isnan(point.path_point().ddkappa()) || std::isnan(point.v()) ||
286 std::isnan(point.a()) || std::isnan(point.relative_time()));
287}
288
290 sl_boundary_ = sl_boundary;
291}
292
294 const common::VehicleParam& vehicle_param) const {
295 if (min_radius_stop_distance_ > 0) {
296 return min_radius_stop_distance_;
297 }
298 static constexpr double stop_distance_buffer = 0.5;
299 const double min_turn_radius = VehicleConfigHelper::MinSafeTurnRadius();
300 double lateral_diff =
301 vehicle_param.width() / 2.0 + std::max(std::fabs(sl_boundary_.start_l()),
302 std::fabs(sl_boundary_.end_l()));
303 const double kEpison = 1e-5;
304 lateral_diff = std::min(lateral_diff, min_turn_radius - kEpison);
305 double stop_distance =
306 std::sqrt(std::fabs(min_turn_radius * min_turn_radius -
307 (min_turn_radius - lateral_diff) *
308 (min_turn_radius - lateral_diff))) +
309 stop_distance_buffer;
310 stop_distance -= vehicle_param.front_edge_to_center();
311 stop_distance = std::min(stop_distance, FLAGS_max_stop_distance_obstacle);
312 stop_distance = std::max(stop_distance, FLAGS_min_stop_distance_obstacle);
313 return stop_distance;
314}
315
317 const double adc_start_s) {
318 const auto& adc_param =
319 VehicleConfigHelper::Instance()->GetConfig().vehicle_param();
320 const double half_adc_width = adc_param.width() / 2;
321 if (is_static_ || trajectory_.trajectory_point().empty()) {
322 std::vector<std::pair<STPoint, STPoint>> point_pairs;
323 double start_s = sl_boundary_.start_s();
324 double end_s = sl_boundary_.end_s();
325 if (end_s - start_s < kStBoundaryDeltaS) {
326 end_s = start_s + kStBoundaryDeltaS;
327 }
328 if (!reference_line.IsBlockRoad(perception_bounding_box_, half_adc_width)) {
329 return;
330 }
331 point_pairs.emplace_back(STPoint(start_s - adc_start_s, 0.0),
332 STPoint(end_s - adc_start_s, 0.0));
333 point_pairs.emplace_back(STPoint(start_s - adc_start_s, FLAGS_st_max_t),
334 STPoint(end_s - adc_start_s, FLAGS_st_max_t));
335 reference_line_st_boundary_ = STBoundary(point_pairs);
336 } else {
337 if (BuildTrajectoryStBoundary(reference_line, adc_start_s,
338 &reference_line_st_boundary_)) {
339 ADEBUG << "Found st_boundary for obstacle " << id_;
340 ADEBUG << "st_boundary: min_t = " << reference_line_st_boundary_.min_t()
341 << ", max_t = " << reference_line_st_boundary_.max_t()
342 << ", min_s = " << reference_line_st_boundary_.min_s()
343 << ", max_s = " << reference_line_st_boundary_.max_s();
344 } else {
345 ADEBUG << "No st_boundary for obstacle " << id_;
346 }
347 }
348}
349
350bool Obstacle::BuildTrajectoryStBoundary(const ReferenceLine& reference_line,
351 const double adc_start_s,
352 STBoundary* const st_boundary) {
353 if (!IsValidObstacle(perception_obstacle_)) {
354 AERROR << "Fail to build trajectory st boundary because object is not "
355 "valid. PerceptionObstacle: "
356 << perception_obstacle_.DebugString();
357 return false;
358 }
359 const double object_width = perception_obstacle_.width();
360 const double object_length = perception_obstacle_.length();
361 const auto& trajectory_points = trajectory_.trajectory_point();
362 if (trajectory_points.empty()) {
363 AWARN << "object " << id_ << " has no trajectory points";
364 return false;
365 }
366 const auto& adc_param =
367 VehicleConfigHelper::Instance()->GetConfig().vehicle_param();
368 const double adc_length = adc_param.length();
369 const double adc_half_length = adc_length / 2.0;
370 const double adc_width = adc_param.width();
371 common::math::Box2d min_box({0, 0}, 1.0, 1.0, 1.0);
372 common::math::Box2d max_box({0, 0}, 1.0, 1.0, 1.0);
373 std::vector<std::pair<STPoint, STPoint>> polygon_points;
374
375 SLBoundary last_sl_boundary;
376 int last_index = 0;
377
378 for (int i = 1; i < trajectory_points.size(); ++i) {
379 ADEBUG << "last_sl_boundary: " << last_sl_boundary.ShortDebugString();
380
381 const auto& first_traj_point = trajectory_points[i - 1];
382 const auto& second_traj_point = trajectory_points[i];
383 const auto& first_point = first_traj_point.path_point();
384 const auto& second_point = second_traj_point.path_point();
385
386 double object_moving_box_length =
387 object_length + common::util::DistanceXY(first_point, second_point);
388
389 common::math::Vec2d center((first_point.x() + second_point.x()) / 2.0,
390 (first_point.y() + second_point.y()) / 2.0);
391 common::math::Box2d object_moving_box(
392 center, first_point.theta(), object_moving_box_length, object_width);
393 SLBoundary object_boundary;
394 // NOTICE: this method will have errors when the reference line is not
395 // straight. Need double loop to cover all corner cases.
396 // roughly skip points that are too close to last_sl_boundary box
397 const double distance_xy =
398 common::util::DistanceXY(trajectory_points[last_index].path_point(),
399 trajectory_points[i].path_point());
400 if (last_sl_boundary.start_l() > distance_xy ||
401 last_sl_boundary.end_l() < -distance_xy) {
402 continue;
403 }
404
405 const double mid_s =
406 (last_sl_boundary.start_s() + last_sl_boundary.end_s()) / 2.0;
407 const double start_s = std::fmax(0.0, mid_s - 2.0 * distance_xy);
408 const double end_s = (i == 1) ? reference_line.Length()
409 : std::fmin(reference_line.Length(),
410 mid_s + 2.0 * distance_xy);
411
412 if (!reference_line.GetApproximateSLBoundary(object_moving_box, start_s,
413 end_s, &object_boundary)) {
414 AERROR << "failed to calculate boundary";
415 return false;
416 }
417
418 // update history record
419 last_sl_boundary = object_boundary;
420 last_index = i;
421
422 // skip if object is entirely on one side of reference line.
423 static constexpr double kSkipLDistanceFactor = 0.4;
424 const double skip_l_distance =
425 (object_boundary.end_s() - object_boundary.start_s()) *
426 kSkipLDistanceFactor +
427 adc_width / 2.0;
428
429 if (!IsCautionLevelObstacle() &&
430 (std::fmin(object_boundary.start_l(), object_boundary.end_l()) >
431 skip_l_distance ||
432 std::fmax(object_boundary.start_l(), object_boundary.end_l()) <
433 -skip_l_distance)) {
434 continue;
435 }
436
437 if (!IsCautionLevelObstacle() && object_boundary.end_s() < 0) {
438 // skip if behind reference line
439 continue;
440 }
441 static constexpr double kSparseMappingS = 20.0;
442 const double st_boundary_delta_s =
443 (std::fabs(object_boundary.start_s() - adc_start_s) > kSparseMappingS)
444 ? kStBoundarySparseDeltaS
445 : kStBoundaryDeltaS;
446 const double object_s_diff =
447 object_boundary.end_s() - object_boundary.start_s();
448 if (object_s_diff < st_boundary_delta_s) {
449 continue;
450 }
451 const double delta_t =
452 second_traj_point.relative_time() - first_traj_point.relative_time();
453 double low_s = std::max(object_boundary.start_s() - adc_half_length, 0.0);
454 bool has_low = false;
455 double high_s =
456 std::min(object_boundary.end_s() + adc_half_length, FLAGS_st_max_s);
457 bool has_high = false;
458 while (low_s + st_boundary_delta_s < high_s && !(has_low && has_high)) {
459 if (!has_low) {
460 auto low_ref = reference_line.GetReferencePoint(low_s);
461 has_low = object_moving_box.HasOverlap(
462 {low_ref, low_ref.heading(), adc_length,
463 adc_width + FLAGS_nonstatic_obstacle_nudge_l_buffer});
464 low_s += st_boundary_delta_s;
465 }
466 if (!has_high) {
467 auto high_ref = reference_line.GetReferencePoint(high_s);
468 has_high = object_moving_box.HasOverlap(
469 {high_ref, high_ref.heading(), adc_length,
470 adc_width + FLAGS_nonstatic_obstacle_nudge_l_buffer});
471 high_s -= st_boundary_delta_s;
472 }
473 }
474 if (has_low && has_high) {
475 low_s -= st_boundary_delta_s;
476 high_s += st_boundary_delta_s;
477 double low_t =
478 (first_traj_point.relative_time() +
479 std::fabs((low_s - object_boundary.start_s()) / object_s_diff) *
480 delta_t);
481 polygon_points.emplace_back(
482 std::make_pair(STPoint{low_s - adc_start_s, low_t},
483 STPoint{high_s - adc_start_s, low_t}));
484 double high_t =
485 (first_traj_point.relative_time() +
486 std::fabs((high_s - object_boundary.start_s()) / object_s_diff) *
487 delta_t);
488 if (high_t - low_t > 0.05) {
489 polygon_points.emplace_back(
490 std::make_pair(STPoint{low_s - adc_start_s, high_t},
491 STPoint{high_s - adc_start_s, high_t}));
492 }
493 }
494 }
495 if (!polygon_points.empty()) {
496 std::sort(polygon_points.begin(), polygon_points.end(),
497 [](const std::pair<STPoint, STPoint>& a,
498 const std::pair<STPoint, STPoint>& b) {
499 return a.first.t() < b.first.t();
500 });
501 auto last = std::unique(polygon_points.begin(), polygon_points.end(),
502 [](const std::pair<STPoint, STPoint>& a,
503 const std::pair<STPoint, STPoint>& b) {
504 return std::fabs(a.first.t() - b.first.t()) <
505 kStBoundaryDeltaT;
506 });
507 polygon_points.erase(last, polygon_points.end());
508 if (polygon_points.size() > 2) {
509 *st_boundary = STBoundary(polygon_points);
510 }
511 } else {
512 return false;
513 }
514 return true;
515}
516
518 return reference_line_st_boundary_;
519}
520
522 return path_st_boundary_;
523}
524
525const std::vector<std::string>& Obstacle::decider_tags() const {
526 return decider_tags_;
527}
528
529const std::vector<ObjectDecisionType>& Obstacle::decisions() const {
530 return decisions_;
531}
532
533bool Obstacle::IsLateralDecision(const ObjectDecisionType& decision) {
534 return decision.has_ignore() || decision.has_nudge();
535}
536
537bool Obstacle::IsLongitudinalDecision(const ObjectDecisionType& decision) {
538 return decision.has_ignore() || decision.has_stop() || decision.has_yield() ||
539 decision.has_follow() || decision.has_overtake();
540}
541
542ObjectDecisionType Obstacle::MergeLongitudinalDecision(
543 const ObjectDecisionType& lhs, const ObjectDecisionType& rhs) {
544 if (lhs.object_tag_case() == ObjectDecisionType::OBJECT_TAG_NOT_SET) {
545 return rhs;
546 }
547 if (rhs.object_tag_case() == ObjectDecisionType::OBJECT_TAG_NOT_SET) {
548 return lhs;
549 }
550 const auto lhs_val =
551 FindOrDie(s_longitudinal_decision_safety_sorter_, lhs.object_tag_case());
552 const auto rhs_val =
553 FindOrDie(s_longitudinal_decision_safety_sorter_, rhs.object_tag_case());
554 if (lhs_val < rhs_val) {
555 return rhs;
556 } else if (lhs_val > rhs_val) {
557 return lhs;
558 } else {
559 if (lhs.has_ignore()) {
560 return rhs;
561 } else if (lhs.has_stop()) {
562 return lhs.stop().distance_s() < rhs.stop().distance_s() ? lhs : rhs;
563 } else if (lhs.has_yield()) {
564 return lhs.yield().distance_s() < rhs.yield().distance_s() ? lhs : rhs;
565 } else if (lhs.has_follow()) {
566 return lhs.follow().distance_s() < rhs.follow().distance_s() ? lhs : rhs;
567 } else if (lhs.has_overtake()) {
568 return lhs.overtake().distance_s() > rhs.overtake().distance_s() ? lhs
569 : rhs;
570 } else {
571 DCHECK(false) << "Unknown decision";
572 }
573 }
574 return lhs; // stop compiler complaining
575}
576
577const ObjectDecisionType& Obstacle::LongitudinalDecision() const {
578 return longitudinal_decision_;
579}
580
581const ObjectDecisionType& Obstacle::LateralDecision() const {
582 return lateral_decision_;
583}
584
585bool Obstacle::IsIgnore() const {
587}
588
590 return longitudinal_decision_.has_ignore();
591}
592
594 return lateral_decision_.has_ignore();
595}
596
597ObjectDecisionType Obstacle::MergeLateralDecision(
598 const ObjectDecisionType& lhs, const ObjectDecisionType& rhs) {
599 if (lhs.object_tag_case() == ObjectDecisionType::OBJECT_TAG_NOT_SET) {
600 return rhs;
601 }
602 if (rhs.object_tag_case() == ObjectDecisionType::OBJECT_TAG_NOT_SET) {
603 return lhs;
604 }
605 const auto lhs_val =
606 FindOrDie(s_lateral_decision_safety_sorter_, lhs.object_tag_case());
607 const auto rhs_val =
608 FindOrDie(s_lateral_decision_safety_sorter_, rhs.object_tag_case());
609 if (lhs_val < rhs_val) {
610 return rhs;
611 } else if (lhs_val > rhs_val) {
612 return lhs;
613 } else {
614 if (lhs.has_ignore()) {
615 return rhs;
616 } else if (lhs.has_nudge()) {
617 DCHECK(lhs.nudge().type() == rhs.nudge().type())
618 << "could not merge left nudge and right nudge";
619 return std::fabs(lhs.nudge().distance_l()) >
620 std::fabs(rhs.nudge().distance_l())
621 ? lhs
622 : rhs;
623 }
624 }
625 DCHECK(false) << "Does not have rule to merge decision: "
626 << lhs.ShortDebugString()
627 << " and decision: " << rhs.ShortDebugString();
628 return lhs;
629}
630
632 return lateral_decision_.object_tag_case() !=
633 ObjectDecisionType::OBJECT_TAG_NOT_SET;
634}
635
637 return longitudinal_decision_.object_tag_case() !=
638 ObjectDecisionType::OBJECT_TAG_NOT_SET;
639}
640
645
646void Obstacle::AddLongitudinalDecision(const std::string& decider_tag,
647 const ObjectDecisionType& decision) {
648 DCHECK(IsLongitudinalDecision(decision))
649 << "Decision: " << decision.ShortDebugString()
650 << " is not a longitudinal decision";
651 longitudinal_decision_ =
652 MergeLongitudinalDecision(longitudinal_decision_, decision);
653 ADEBUG << decider_tag << " added obstacle " << Id()
654 << " longitudinal decision: " << decision.ShortDebugString()
655 << ". The merged decision is: "
656 << longitudinal_decision_.ShortDebugString();
657 decisions_.push_back(decision);
658 decider_tags_.push_back(decider_tag);
659}
660
661void Obstacle::AddLateralDecision(const std::string& decider_tag,
662 const ObjectDecisionType& decision) {
663 DCHECK(IsLateralDecision(decision))
664 << "Decision: " << decision.ShortDebugString()
665 << " is not a lateral decision";
666 lateral_decision_ = MergeLateralDecision(lateral_decision_, decision);
667 ADEBUG << decider_tag << " added obstacle " << Id()
668 << " a lateral decision: " << decision.ShortDebugString()
669 << ". The merged decision is: "
670 << lateral_decision_.ShortDebugString();
671 decisions_.push_back(decision);
672 decider_tags_.push_back(decider_tag);
673}
674
675std::string Obstacle::DebugString() const {
676 std::stringstream ss;
677 ss << "Obstacle id: " << id_;
678 for (size_t i = 0; i < decisions_.size(); ++i) {
679 ss << " decision: " << decisions_[i].DebugString() << ", made by "
680 << decider_tags_[i];
681 }
682 if (lateral_decision_.object_tag_case() !=
683 ObjectDecisionType::OBJECT_TAG_NOT_SET) {
684 ss << "lateral decision: " << lateral_decision_.ShortDebugString();
685 }
686 if (longitudinal_decision_.object_tag_case() !=
687 ObjectDecisionType::OBJECT_TAG_NOT_SET) {
688 ss << "longitudinal decision: "
689 << longitudinal_decision_.ShortDebugString();
690 }
691 return ss.str();
692}
693
695 return sl_boundary_;
696}
697
699 path_st_boundary_ = boundary;
700 path_st_boundary_initialized_ = true;
701}
702
704 path_st_boundary_.SetBoundaryType(type);
705}
706
707void Obstacle::EraseStBoundary() { path_st_boundary_ = STBoundary(); }
708
710 lateral_decision_.Clear();
711 longitudinal_decision_.Clear();
712 decider_tags_.clear();
713}
714
716 reference_line_st_boundary_ = boundary;
717}
718
720 const STBoundary::BoundaryType type) {
721 reference_line_st_boundary_.SetBoundaryType(type);
722}
723
725 reference_line_st_boundary_ = STBoundary();
726}
727
728bool Obstacle::IsValidObstacle(
729 const perception::PerceptionObstacle& perception_obstacle) {
730 const double object_width = perception_obstacle.width();
731 const double object_length = perception_obstacle.length();
732
733 const double kMinObjectDimension = 1.0e-6;
734 return !std::isnan(object_width) && !std::isnan(object_length) &&
735 object_width > kMinObjectDimension &&
736 object_length > kMinObjectDimension;
737}
738
739void Obstacle::CheckLaneBlocking(const ReferenceLine& reference_line) {
740 if (!IsStatic()) {
741 is_lane_blocking_ = false;
742 return;
743 }
744 DCHECK(sl_boundary_.has_start_s());
745 DCHECK(sl_boundary_.has_end_s());
746 DCHECK(sl_boundary_.has_start_l());
747 DCHECK(sl_boundary_.has_end_l());
748
749 if (sl_boundary_.start_l() * sl_boundary_.end_l() < 0.0) {
750 is_lane_blocking_ = true;
751 return;
752 }
753
754 const double driving_width = reference_line.GetDrivingWidth(sl_boundary_);
756
757 if (reference_line.IsOnLane(sl_boundary_) &&
758 driving_width <
759 vehicle_param.width() + FLAGS_static_obstacle_nudge_l_buffer) {
760 is_lane_blocking_ = true;
761 return;
762 }
763
764 is_lane_blocking_ = false;
765}
766
767void Obstacle::SetLaneChangeBlocking(const bool is_distance_clear) {
768 is_lane_change_blocking_ = is_distance_clear;
769}
770
771// input: obstacle trajectory point
772// ouput: obstacle polygon
774 const common::TrajectoryPoint& point) const {
775 double delta_heading =
776 point.path_point().theta() - perception_obstacle_.theta();
777 double cos_delta_heading = cos(delta_heading);
778 double sin_delta_heading = sin(delta_heading);
779 std::vector<common::math::Vec2d> polygon_point;
780 polygon_point.reserve(perception_polygon_.points().size());
781
782 for (auto& iter : perception_polygon_.points()) {
783 double relative_x = iter.x() - perception_obstacle_.position().x();
784 double relative_y = iter.y() - perception_obstacle_.position().y();
785 double x = relative_x * cos_delta_heading - relative_y * sin_delta_heading +
786 point.path_point().x();
787 double y = relative_x * sin_delta_heading + relative_y * cos_delta_heading +
788 point.path_point().y();
789 polygon_point.emplace_back(x, y);
790 }
791
792 common::math::Polygon2d trajectory_point_polygon(polygon_point);
793 return trajectory_point_polygon;
794}
795
797 if (perception_polygon_.points().size() < 1) {
798 return;
799 }
800
801 PrintCurves print_curve;
802 for (const auto& p : perception_polygon_.points()) {
803 print_curve.AddPoint(id_ + "_ObsPolygon", p.x(), p.y());
804 }
805 print_curve.AddPoint(id_ + "_ObsPolygon", perception_polygon_.points()[0].x(),
806 perception_polygon_.points()[0].y());
807 print_curve.PrintToLog();
808}
809
810} // namespace planning
811} // namespace apollo
@Brief This is a helper class that can load vehicle configurations.
static double MinSafeTurnRadius()
Get the safe turning radius when the vehicle is turning with maximum steering angle.
static const VehicleConfig & GetConfig()
Get the current vehicle configuration.
Rectangular (undirected) bounding box in 2-D.
Definition box2d.h:52
void GetAllCorners(std::vector< Vec2d > *const corners) const
Getter of the corners of the box
Definition box2d.cc:140
double width() const
Getter of the width
Definition box2d.h:130
const Vec2d & center() const
Getter of the center of the box
Definition box2d.h:106
double length() const
Getter of the length
Definition box2d.h:124
double heading() const
Getter of the heading
Definition box2d.h:148
The class of polygon in 2-D.
Definition polygon2d.h:42
static bool ComputeConvexHull(const std::vector< Vec2d > &points, Polygon2d *const polygon, bool check_area=true)
Compute the convex hull of a group of points.
Definition polygon2d.cc:261
const std::vector< Vec2d > & points() const
Get the vertices of the polygon.
Definition polygon2d.h:65
double y() const
Getter for y component
Definition vec2d.h:57
double x() const
Getter for x component
Definition vec2d.h:54
This is the class that associates an Obstacle with its path properties.
Definition obstacle.h:62
static bool IsLongitudinalDecision(const ObjectDecisionType &decision)
check if an ObjectDecisionType is a longitudinal decision.
Definition obstacle.cc:537
std::string DebugString() const
Definition obstacle.cc:675
const std::vector< std::string > & decider_tags() const
Definition obstacle.cc:525
const STBoundary & path_st_boundary() const
Definition obstacle.cc:521
const STBoundary & reference_line_st_boundary() const
Definition obstacle.cc:517
static bool IsLateralDecision(const ObjectDecisionType &decision)
check if an ObjectDecisionType is a lateral decision.
Definition obstacle.cc:533
void SetReferenceLineStBoundaryType(const STBoundary::BoundaryType type)
Definition obstacle.cc:719
bool IsLongitudinalIgnore() const
Definition obstacle.cc:589
const std::vector< ObjectDecisionType > & decisions() const
Definition obstacle.cc:529
void AddLongitudinalDecision(const std::string &decider_tag, const ObjectDecisionType &decision)
Definition obstacle.cc:646
const ObjectDecisionType & LateralDecision() const
return the merged lateral decision Lateral decision is one of {Nudge, Ignore}
Definition obstacle.cc:581
common::TrajectoryPoint GetPointAtTime(const double time) const
Definition obstacle.cc:124
static bool IsValidTrajectoryPoint(const common::TrajectoryPoint &point)
Definition obstacle.cc:278
double MinRadiusStopDistance(const common::VehicleParam &vehicle_param) const
Calculate stop distance with the obstacle using the ADC's minimum turning radius
Definition obstacle.cc:293
void PrintPolygonCurve() const
Definition obstacle.cc:796
void SetReferenceLineStBoundary(const STBoundary &boundary)
Definition obstacle.cc:715
void AddLateralDecision(const std::string &decider_tag, const ObjectDecisionType &decision)
Definition obstacle.cc:661
void CheckLaneBlocking(const ReferenceLine &reference_line)
Definition obstacle.cc:739
bool HasLongitudinalDecision() const
Definition obstacle.cc:636
const ObjectDecisionType & LongitudinalDecision() const
return the merged longitudinal decision Longitudinal decision is one of {Stop, Yield,...
Definition obstacle.cc:577
void SetLaneChangeBlocking(const bool is_distance_clear)
Definition obstacle.cc:767
const std::string & Id() const
Definition obstacle.h:75
bool IsCautionLevelObstacle() const
Definition obstacle.h:124
common::math::Box2d GetBoundingBox(const common::TrajectoryPoint &point) const
Definition obstacle.cc:159
void SetStBoundaryType(const STBoundary::BoundaryType type)
Definition obstacle.cc:703
bool IsLateralIgnore() const
Definition obstacle.cc:593
bool HasLateralDecision() const
Definition obstacle.cc:631
static std::unique_ptr< Obstacle > CreateStaticVirtualObstacles(const std::string &id, const common::math::Box2d &obstacle_box)
Definition obstacle.cc:244
static bool IsValidPerceptionObstacle(const perception::PerceptionObstacle &obstacle)
Definition obstacle.cc:167
bool HasNonIgnoreDecision() const
Definition obstacle.cc:641
void BuildReferenceLineStBoundary(const ReferenceLine &reference_line, const double adc_start_s)
Definition obstacle.cc:316
void set_path_st_boundary(const STBoundary &boundary)
Definition obstacle.cc:698
const SLBoundary & PerceptionSLBoundary() const
Definition obstacle.cc:694
static std::list< std::unique_ptr< Obstacle > > CreateObstacles(const prediction::PredictionObstacles &predictions)
This is a helper function that can create obstacles from prediction data.
Definition obstacle.cc:197
void SetPerceptionSlBoundary(const SLBoundary &sl_boundary)
Definition obstacle.cc:289
common::math::Polygon2d GetObstacleTrajectoryPolygon(const common::TrajectoryPoint &point) const
Definition obstacle.cc:773
bool IsIgnore() const
Check if this object can be safely ignored.
Definition obstacle.cc:585
void AddPoint(std::string key, double x, double y)
add point to curve key
bool GetApproximateSLBoundary(const common::math::Box2d &box, const double start_s, const double end_s, SLBoundary *const sl_boundary) const
bool IsOnLane(const common::SLPoint &sl_point) const
: check if a box/point is on lane along reference line
ReferencePoint GetReferencePoint(const double s) const
double GetDrivingWidth(const SLBoundary &sl_boundary) const
bool IsBlockRoad(const common::math::Box2d &box2d, double gap) const
Check if a box is blocking the road surface.
void SetBoundaryType(const BoundaryType &boundary_type)
Planning module main class.
Linear interpolation functions.
#define ACHECK(cond)
Definition log.h:80
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AWARN
Definition log.h:43
Some map util functions.
Some util functions.
SLPoint InterpolateUsingLinearApproximation(const SLPoint &p0, const SLPoint &p1, const double w)
double DistanceXY(const U &u, const V &v)
calculate the distance beteween Point u and Point v, which are all have member function x() and y() i...
Definition util.h:97
class register implement
Definition arena_queue.h:37
optional VehicleParam vehicle_param
repeated apollo::common::Point3D polygon_point
optional apollo::common::Point3D velocity
optional apollo::common::Point3D position
repeated apollo::common::TrajectoryPoint trajectory_point
Definition feature.proto:78