Apollo 11.0
自动驾驶开放平台
navigation_lane.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2018 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
23
24#include <algorithm>
25#include <limits>
26#include <string>
27
28#include "absl/strings/str_cat.h"
29#include "cyber/common/log.h"
33#include "modules/common_msgs/map_msgs/map_lane.pb.h"
35
36namespace apollo {
37namespace relative_map {
38
43using apollo::common::util::operator+;
45
46namespace {
58bool CreateSingleLaneMap(
59 const NaviPathTuple &navi_path_tuple, const MapGenerationParam &map_config,
60 const perception::PerceptionObstacles &perception_obstacles,
61 hdmap::Map *const hdmap,
62 google::protobuf::Map<std::string, NavigationPath> *const navigation_path) {
63 CHECK_NOTNULL(hdmap);
64 CHECK_NOTNULL(navigation_path);
65
66 const auto &navi_path = std::get<3>(navi_path_tuple);
67 const auto &path = navi_path->path();
68 if (path.path_point_size() < 2) {
69 AERROR << "The path length of line index is invalid";
70 return false;
71 }
72 auto *lane = hdmap->add_lane();
73 lane->mutable_id()->set_id(
74 absl::StrCat(navi_path->path_priority(), "_", path.name()));
75 (*navigation_path)[lane->id().id()] = *navi_path;
76 // lane types
77 lane->set_type(Lane::CITY_DRIVING);
78 lane->set_turn(Lane::NO_TURN);
79
80 // speed limit
81 lane->set_speed_limit(map_config.default_speed_limit());
82
83 // center line
84 auto *curve_segment = lane->mutable_central_curve()->add_segment();
85 curve_segment->set_heading(path.path_point(0).theta());
86 auto *line_segment = curve_segment->mutable_line_segment();
87
88 // left boundary
89 hdmap::LineSegment *left_segment = nullptr;
90 if (FLAGS_relative_map_generate_left_boundray) {
91 auto *left_boundary = lane->mutable_left_boundary();
92 auto *left_boundary_type = left_boundary->add_boundary_type();
93 left_boundary->set_virtual_(false);
94 left_boundary_type->set_s(0.0);
95 left_boundary_type->add_types(
96 perception_obstacles.lane_marker().left_lane_marker().lane_type());
97 left_segment =
98 left_boundary->mutable_curve()->add_segment()->mutable_line_segment();
99 }
100
101 // right boundary
102 auto *right_boundary = lane->mutable_right_boundary();
103 auto *right_boundary_type = right_boundary->add_boundary_type();
104 right_boundary->set_virtual_(false);
105 right_boundary_type->set_s(0.0);
106 right_boundary_type->add_types(
107 perception_obstacles.lane_marker().right_lane_marker().lane_type());
108 auto *right_segment =
109 right_boundary->mutable_curve()->add_segment()->mutable_line_segment();
110
111 const double lane_left_width = std::get<1>(navi_path_tuple);
112 const double lane_right_width = std::get<2>(navi_path_tuple);
113
114 for (const auto &path_point : path.path_point()) {
115 auto *point = line_segment->add_point();
116 point->set_x(path_point.x());
117 point->set_y(path_point.y());
118 point->set_z(path_point.z());
119 if (FLAGS_relative_map_generate_left_boundray) {
120 auto *left_sample = lane->add_left_sample();
121 left_sample->set_s(path_point.s());
122 left_sample->set_width(lane_left_width);
123 left_segment->add_point()->CopyFrom(
124 *point + lane_left_width *
125 Vec2d::CreateUnitVec2d(path_point.theta() + M_PI_2));
126 }
127
128 auto *right_sample = lane->add_right_sample();
129 right_sample->set_s(path_point.s());
130 right_sample->set_width(lane_right_width);
131 right_segment->add_point()->CopyFrom(
132 *point +
133 lane_right_width * Vec2d::CreateUnitVec2d(path_point.theta() - M_PI_2));
134 }
135 return true;
136}
137} // namespace
138
140 : config_(config) {}
141
143 config_ = config;
144}
145
147 common::VehicleStateProvider *vehicle_state_provider) {
148 vehicle_state_provider_ = vehicle_state_provider;
149}
150
152 const NavigationInfo &navigation_path) {
153 navigation_info_ = navigation_path;
154 last_project_index_map_.clear();
155 navigation_path_list_.clear();
156 current_navi_path_tuple_ = std::make_tuple(-1, -1.0, -1.0, nullptr);
157 if (FLAGS_enable_cyclic_rerouting) {
158 UpdateStitchIndexInfo();
159 }
160}
161
163 navigation_path_list_.clear();
164 current_navi_path_tuple_ = std::make_tuple(-1, -1.0, -1.0, nullptr);
165
166 // original_pose is in world coordination: ENU
167 original_pose_ = vehicle_state_provider_->original_pose();
168
169 int navigation_line_num = navigation_info_.navigation_path_size();
170 const auto &lane_marker = perception_obstacles_.lane_marker();
171
172 auto generate_path_on_perception_func = [this, &lane_marker]() {
173 auto current_navi_path = std::make_shared<NavigationPath>();
174 auto *path = current_navi_path->mutable_path();
175 ConvertLaneMarkerToPath(lane_marker, path);
176 current_navi_path->set_path_priority(0);
177 double left_width = perceived_left_width_ > 0.0 ? perceived_left_width_
178 : default_left_width_;
179 double right_width = perceived_right_width_ > 0.0 ? perceived_right_width_
180 : default_right_width_;
181 current_navi_path_tuple_ =
182 std::make_tuple(0, left_width, right_width, current_navi_path);
183 };
184
185 ADEBUG << "Beginning of NavigationLane::GeneratePath().";
186 ADEBUG << "navigation_line_num: " << navigation_line_num;
187
188 // priority: merge > navigation line > perception lane marker
190 navigation_line_num > 0) {
191 // Generate multiple navigation paths based on navigation lines.
192 // Don't worry about efficiency because the total number of navigation lines
193 // will not exceed 10 at most.
194 for (int i = 0; i < navigation_line_num; ++i) {
195 auto current_navi_path = std::make_shared<NavigationPath>();
196 auto *path = current_navi_path->mutable_path();
197 if (ConvertNavigationLineToPath(i, path)) {
198 current_navi_path->set_path_priority(
199 navigation_info_.navigation_path(i).path_priority());
200 navigation_path_list_.emplace_back(
201 i, default_left_width_, default_right_width_, current_navi_path);
202 }
203 }
204
205 // If no navigation path is generated based on navigation lines, we generate
206 // one where the vehicle is located based on perceived lane markers.
207 if (navigation_path_list_.empty()) {
208 generate_path_on_perception_func();
209 return true;
210 }
211
212 // Sort navigation paths from left to right according to the vehicle's
213 // direction.
214 // In the FLU vehicle coordinate system, the y-coordinate on the left side
215 // of the vehicle is positive, and the right value is negative. Therefore,
216 // the navigation paths can be sorted from left to right according to its
217 // y-coordinate.
218 navigation_path_list_.sort(
219 [](const NaviPathTuple &left, const NaviPathTuple &right) {
220 double left_y = std::get<3>(left)->path().path_point(0).y();
221 double right_y = std::get<3>(right)->path().path_point(0).y();
222 return left_y > right_y;
223 });
224
225 // Get which navigation path the vehicle is currently on.
226 double min_d = std::numeric_limits<double>::max();
227 for (const auto &navi_path_tuple : navigation_path_list_) {
228 int current_line_index = std::get<0>(navi_path_tuple);
229 ADEBUG << "Current navigation path index is: " << current_line_index;
230 double current_d = std::numeric_limits<double>::max();
231 auto item_iter = last_project_index_map_.find(current_line_index);
232 if (item_iter != last_project_index_map_.end()) {
233 current_d = item_iter->second.second;
234 }
235 if (current_d < min_d) {
236 min_d = current_d;
237 current_navi_path_tuple_ = navi_path_tuple;
238 }
239 }
240
241 // Merge current navigation path where the vehicle is located with perceived
242 // lane markers.
243 auto *path = std::get<3>(current_navi_path_tuple_)->mutable_path();
244 MergeNavigationLineAndLaneMarker(std::get<0>(current_navi_path_tuple_),
245 path);
246
247 // Set the width for the navigation path which the vehicle is currently on.
248 double left_width = perceived_left_width_ > 0.0 ? perceived_left_width_
249 : default_left_width_;
250 double right_width = perceived_right_width_ > 0.0 ? perceived_right_width_
251 : default_right_width_;
252 if (!IsFloatEqual(left_width, default_left_width_) &&
253 !IsFloatEqual(right_width, default_right_width_)) {
254 left_width = left_width > default_left_width_ ? left_width - min_d
255 : left_width + min_d;
256 right_width = right_width > default_right_width_ ? right_width - min_d
257 : right_width + min_d;
258 }
259
260 ADEBUG << "The left width of current lane is: " << left_width
261 << " and the right width of current lane is: " << right_width;
262
263 std::get<1>(current_navi_path_tuple_) = left_width;
264 std::get<2>(current_navi_path_tuple_) = right_width;
265 auto curr_navi_path_iter = std::find_if(
266 std::begin(navigation_path_list_), std::end(navigation_path_list_),
267 [this](const NaviPathTuple &item) {
268 return std::get<0>(item) == std::get<0>(current_navi_path_tuple_);
269 });
270 if (curr_navi_path_iter != std::end(navigation_path_list_)) {
271 std::get<1>(*curr_navi_path_iter) = left_width;
272 std::get<2>(*curr_navi_path_iter) = right_width;
273 }
274
275 // Set the width between each navigation path and its adjacent path.
276 // The reason for using average of multiple points is to prevent too much
277 // interference from a singularity.
278 // If current navigation path is the path which the vehicle is currently
279 // on, the current lane width uses the perceived width.
280 int average_point_size = 5;
281 for (auto iter = navigation_path_list_.begin();
282 iter != navigation_path_list_.end(); ++iter) {
283 const auto &curr_path = std::get<3>(*iter)->path();
284
285 // Left neighbor
286 auto prev_iter = std::prev(iter);
287 if (prev_iter != navigation_path_list_.end()) {
288 const auto &prev_path = std::get<3>(*prev_iter)->path();
289 average_point_size = std::min(
290 average_point_size,
291 std::min(curr_path.path_point_size(), prev_path.path_point_size()));
292 double lateral_distance_sum = 0.0;
293 for (int i = 0; i < average_point_size; ++i) {
294 lateral_distance_sum +=
295 fabs(curr_path.path_point(i).y() - prev_path.path_point(i).y());
296 }
297 double width = lateral_distance_sum /
298 static_cast<double>(average_point_size) / 2.0;
299 width = common::math::Clamp(width, config_.min_lane_half_width(),
300 config_.max_lane_half_width());
301
302 auto &curr_left_width = std::get<1>(*iter);
303 auto &prev_right_width = std::get<2>(*prev_iter);
304 if (std::get<0>(*iter) == std::get<0>(current_navi_path_tuple_)) {
305 prev_right_width = 2.0 * width - curr_left_width;
306 } else {
307 curr_left_width = width;
308 prev_right_width = width;
309 }
310 }
311 // Right neighbor
312 auto next_iter = std::next(iter);
313 if (next_iter != navigation_path_list_.end()) {
314 const auto &next_path = std::get<3>(*next_iter)->path();
315 average_point_size = std::min(
316 average_point_size,
317 std::min(curr_path.path_point_size(), next_path.path_point_size()));
318 double lateral_distance_sum = 0.0;
319 for (int i = 0; i < average_point_size; ++i) {
320 lateral_distance_sum +=
321 fabs(curr_path.path_point(i).y() - next_path.path_point(i).y());
322 }
323 double width = lateral_distance_sum /
324 static_cast<double>(average_point_size) / 2.0;
325 width = common::math::Clamp(width, config_.min_lane_half_width(),
326 config_.max_lane_half_width());
327
328 auto &curr_right_width = std::get<2>(*iter);
329 auto &next_left_width = std::get<1>(*next_iter);
330 if (std::get<0>(*iter) == std::get<0>(current_navi_path_tuple_)) {
331 next_left_width = 2.0 * width - curr_right_width;
332 } else {
333 next_left_width = width;
334 curr_right_width = width;
335 }
336 }
337 }
338
339 return true;
340 }
341
342 // Generate a navigation path where the vehicle is located based on perceived
343 // lane markers.
344 generate_path_on_perception_func();
345 return true;
346}
347
348double NavigationLane::EvaluateCubicPolynomial(const double c0, const double c1,
349 const double c2, const double c3,
350 const double x) const {
351 return ((c3 * x + c2) * x + c1) * x + c0;
352}
353
354void NavigationLane::MergeNavigationLineAndLaneMarker(
355 const int line_index, common::Path *const path) {
356 CHECK_NOTNULL(path);
357
358 // If the size of "path" points is smaller than 2, it indicates that a
359 // navigation path needs to be generated firstly.
360 if (path->path_point_size() < 2) {
361 path->Clear();
362 ConvertNavigationLineToPath(line_index, path);
363 }
364
365 // If the size of "path" points is still smaller than 2, just generate a
366 // navigation path based on perceived lane markers.
367 if (path->path_point_size() < 2) {
368 path->Clear();
369 ConvertLaneMarkerToPath(perception_obstacles_.lane_marker(), path);
370 return;
371 }
372
373 common::Path lane_marker_path;
374 ConvertLaneMarkerToPath(perception_obstacles_.lane_marker(),
375 &lane_marker_path);
376
377 // If the size of lane marker path points is smaller than 2, merging is not
378 // required.
379 if (lane_marker_path.path_point_size() < 2) {
380 return;
381 }
382
383 int lane_marker_index = 0;
384 double navigation_line_weight = 1.0 - config_.lane_marker_weight();
385 for (int i = 0; i < path->path_point_size(); ++i) {
386 auto *point = path->mutable_path_point(i);
387 double s = point->s();
388 auto lane_maker_point = GetPathPointByS(lane_marker_path, lane_marker_index,
389 s, &lane_marker_index);
390 // For the beginning and ending portions of a navigation path beyond the
391 // perceived path, only the y-coordinates in the FLU coordinate system are
392 // used for merging.
393 const int marker_size = lane_marker_path.path_point_size();
394 if (lane_marker_index < 0 || lane_marker_index > (marker_size - 1)) {
395 point->set_y(navigation_line_weight * point->y() +
396 (1 - navigation_line_weight) * lane_maker_point.y());
397 lane_marker_index = 0;
398 continue;
399 }
401 *point, lane_maker_point, navigation_line_weight,
402 1 - navigation_line_weight);
403 }
404}
405
406common::PathPoint NavigationLane::GetPathPointByS(const common::Path &path,
407 const int start_index,
408 const double s,
409 int *const matched_index) {
410 CHECK_NOTNULL(matched_index);
411 const int size = path.path_point_size();
412
413 if (start_index < 0 || s < path.path_point(start_index).s()) {
414 *matched_index = -1;
415 return path.path_point(0);
416 }
417
418 if (s > path.path_point(size - 1).s() || start_index > (size - 1)) {
419 *matched_index = size;
420 return path.path_point(size - 1);
421 }
422
423 static constexpr double kEpsilon = 1e-9;
424 if (std::fabs(path.path_point(start_index).s() - s) < kEpsilon) {
425 *matched_index = start_index;
426 return path.path_point(start_index);
427 }
428 int i = start_index;
429 while (i + 1 < size && path.path_point(i + 1).s() < s) {
430 ++i;
431 }
432 *matched_index = i;
433
434 // x, y, z, theta, kappa, s, dkappa, ddkappa
435 const double r = (s - path.path_point(i).s()) /
436 (path.path_point(i + 1).s() - path.path_point(i).s());
438 path.path_point(i), path.path_point(i + 1), 1 - r, r);
439 return p;
440}
441
442bool NavigationLane::ConvertNavigationLineToPath(const int line_index,
443 common::Path *const path) {
444 CHECK_NOTNULL(path);
445 if (!navigation_info_.navigation_path(line_index).has_path() ||
446 navigation_info_.navigation_path(line_index).path().path_point_size() ==
447 0) {
448 // path is empty
449 return false;
450 }
451 path->set_name(absl::StrCat("Path from navigation line index ", line_index));
452 const auto &navigation_path =
453 navigation_info_.navigation_path(line_index).path();
454 auto proj_index_pair = UpdateProjectionIndex(navigation_path, line_index);
455 // Can't find a proper projection index in the "line_index" lane according to
456 // current vehicle position.
457 int current_project_index = proj_index_pair.first;
458 if (current_project_index < 0 ||
459 current_project_index >= navigation_path.path_point_size()) {
460 AERROR << "Invalid projection index " << current_project_index
461 << " in line " << line_index;
462 last_project_index_map_.erase(line_index);
463 return false;
464 } else {
465 last_project_index_map_[line_index] = proj_index_pair;
466 }
467
468 // offset between the current vehicle state and navigation line
469 const double dx = -original_pose_.position().x();
470 const double dy = -original_pose_.position().y();
471 auto enu_to_flu_func = [this, dx, dy](const double enu_x, const double enu_y,
472 const double enu_theta, double *flu_x,
473 double *flu_y, double *flu_theta) {
474 if (flu_x != nullptr && flu_y != nullptr) {
475 Eigen::Vector2d flu_coordinate = common::math::RotateVector2d(
476 {enu_x + dx, enu_y + dy}, -original_pose_.heading());
477
478 *flu_x = flu_coordinate.x();
479 *flu_y = flu_coordinate.y();
480 }
481
482 if (flu_theta != nullptr) {
483 *flu_theta = common::math::NormalizeAngle(
484 common::math::NormalizeAngle(enu_theta) - original_pose_.heading());
485 }
486 };
487
488 auto gen_navi_path_loop_func =
489 [this, &navigation_path, &enu_to_flu_func](
490 const int start, const int end, const double ref_s_base,
491 const double max_length, common::Path *path) {
492 CHECK_NOTNULL(path);
493 const double ref_s = navigation_path.path_point(start).s();
494 for (int i = start; i < end; ++i) {
495 auto *point = path->add_path_point();
496 point->CopyFrom(navigation_path.path_point(i));
497
498 double flu_x = 0.0;
499 double flu_y = 0.0;
500 double flu_theta = 0.0;
501 enu_to_flu_func(point->x(), point->y(), point->theta(), &flu_x,
502 &flu_y, &flu_theta);
503
504 point->set_x(flu_x);
505 point->set_y(flu_y);
506 point->set_theta(flu_theta);
507 const double accumulated_s =
508 navigation_path.path_point(i).s() - ref_s + ref_s_base;
509 point->set_s(accumulated_s);
510
511 if (accumulated_s > max_length) {
512 break;
513 }
514 }
515 };
516
517 double dist = navigation_path.path_point().rbegin()->s() -
518 navigation_path.path_point(current_project_index).s();
519 // Stitch current position to the beginning for a cyclic/circular route.
520 if (FLAGS_enable_cyclic_rerouting &&
521 dist < config_.max_len_from_navigation_line()) {
522 auto item_iter = stitch_index_map_.find(line_index);
523 if (item_iter != stitch_index_map_.end()) {
524 int stitch_start_index =
525 std::max(item_iter->second.first, item_iter->second.second);
526 stitch_start_index = std::max(current_project_index, stitch_start_index);
527 stitch_start_index =
528 std::min(navigation_path.path_point_size() - 1, stitch_start_index);
529
530 int stitch_end_index =
531 std::min(item_iter->second.first, item_iter->second.second);
532 stitch_end_index = std::max(0, stitch_end_index);
533 stitch_end_index = std::min(current_project_index, stitch_end_index);
534
535 ADEBUG << "The stitch_start_index is: " << stitch_start_index << "; "
536 << "the stitch_end_index is: " << stitch_end_index << "; "
537 << "the current_project_index is: " << current_project_index
538 << " for the navigation line: " << line_index;
539
540 double length = navigation_path.path_point(stitch_start_index).s() -
541 navigation_path.path_point(current_project_index).s();
542 gen_navi_path_loop_func(std::max(0, current_project_index - 3),
543 stitch_start_index + 1, 0.0, length, path);
544 if (length > config_.max_len_from_navigation_line()) {
545 return true;
546 }
547 gen_navi_path_loop_func(stitch_end_index,
548 navigation_path.path_point_size(), length,
549 config_.max_len_from_navigation_line(), path);
550 return true;
551 }
552 }
553
554 if (dist < 20) {
555 return false;
556 }
557 gen_navi_path_loop_func(std::max(0, current_project_index - 3),
558 navigation_path.path_point_size(), 0.0,
559 config_.max_len_from_navigation_line(), path);
560 return true;
561}
562
563// project adc_state_ onto path
564ProjIndexPair NavigationLane::UpdateProjectionIndex(const common::Path &path,
565 const int line_index) {
566 if (path.path_point_size() < 2) {
567 return std::make_pair(-1, std::numeric_limits<double>::max());
568 }
569
570 double min_d = std::numeric_limits<double>::max();
571 const int path_size = path.path_point_size();
572 int current_project_index = 0;
573 auto item_iter = last_project_index_map_.find(line_index);
574 if (item_iter != last_project_index_map_.end()) {
575 current_project_index = std::max(0, item_iter->second.first);
576 }
577
578 // A lambda expression for checking the distance between the vehicle's initial
579 // position and the starting point of the current navigation line.
580 auto check_distance_func = [this, &path, &path_size](
581 const int project_index,
582 double *project_distance) {
583 // Convert the starting point of the current navigation line from the
584 // ENU coordinates to the FLU coordinates. For the multi-lane situation,
585 // the distance in the Y-axis direction can be appropriately enlarged,
586 // but the distance in the X-axis direction should be small.
587
588 // flu_x = (enu_x - x_shift) * cos(angle) + (enu_y - y_shift) *
589 // sin(angle)
590 // flu_y = (enu_y - y_shift) * cos(angle) - (enu_x - x_shift) *
591 // sin(angle)
592 if (project_index < 0 || project_index > path_size - 1) {
593 return false;
594 }
595 double enu_x = path.path_point(project_index).x();
596 double enu_y = path.path_point(project_index).y();
597 double x_shift = original_pose_.position().x();
598 double y_shift = original_pose_.position().y();
599 double cos_angle = std::cos(original_pose_.heading());
600 double sin_angle = std::sin(original_pose_.heading());
601 double flu_x =
602 (enu_x - x_shift) * cos_angle + (enu_y - y_shift) * sin_angle;
603 double flu_y =
604 (enu_y - y_shift) * cos_angle - (enu_x - x_shift) * sin_angle;
605
606 if (project_distance != nullptr) {
607 *project_distance = std::fabs(flu_y);
608 }
609
610 if (std::fabs(flu_x) < config_.max_distance_to_navigation_line() / 2.0 &&
611 std::fabs(flu_y) < config_.max_distance_to_navigation_line() * 2.0) {
612 return true;
613 }
614 return false;
615 };
616
617 int index = 0;
618 for (int i = current_project_index; i + 1 < path_size; ++i) {
619 const double d = DistanceXY(original_pose_.position(), path.path_point(i));
620 if (d < min_d) {
621 min_d = d;
622 index = i;
623 }
624 const double kMaxDistance = 50.0;
625 if (current_project_index != 0 && d > kMaxDistance) {
626 break;
627 }
628 }
629
630 if (check_distance_func(index, &min_d)) {
631 if (FLAGS_enable_cyclic_rerouting) {
632 // We create a condition here that sets the "current_project_index" to
633 // 0, should the vehicle reach the end point of a cyclic/circular
634 // route. For cyclic/circular navigation lines where the distance
635 // between their start and end points is very small, it is tedious
636 // and unnecessary to re-send navigation lines every time.
637 auto item_iter = stitch_index_map_.find(line_index);
638 if (item_iter != stitch_index_map_.end()) {
639 int start_index =
640 std::max(item_iter->second.first, item_iter->second.second);
641 int end_index =
642 std::min(item_iter->second.first, item_iter->second.second);
643 int index_diff = index - start_index;
644 if (index_diff >= 0) {
645 index = std::min(end_index + index_diff, start_index);
646 min_d = DistanceXY(original_pose_.position(), path.path_point(index));
647 }
648 }
649 }
650 return std::make_pair(index, min_d);
651 }
652
653 return std::make_pair(-1, std::numeric_limits<double>::max());
654}
655
656double NavigationLane::GetKappa(const double c1, const double c2,
657 const double c3, const double x) {
658 const double dy = 3 * c3 * x * x + 2 * c2 * x + c1;
659 const double d2y = 6 * c3 * x + 2 * c2;
660 return d2y / std::pow((1 + dy * dy), 1.5);
661}
662
663void NavigationLane::ConvertLaneMarkerToPath(
664 const perception::LaneMarkers &lane_marker, common::Path *const path) {
665 CHECK_NOTNULL(path);
666
667 path->set_name("Path from lane markers.");
668 const auto &left_lane = lane_marker.left_lane_marker();
669 const auto &right_lane = lane_marker.right_lane_marker();
670
671 double path_c0 = (left_lane.c0_position() + right_lane.c0_position()) / 2.0;
672
673 double path_c1 =
674 (left_lane.c1_heading_angle() + right_lane.c1_heading_angle()) / 2.0;
675
676 double path_c2 = (left_lane.c2_curvature() + right_lane.c2_curvature()) / 2.0;
677
678 double path_c3 = (left_lane.c3_curvature_derivative() +
679 right_lane.c3_curvature_derivative()) /
680 2.0;
681
682 const double current_speed =
683 vehicle_state_provider_->vehicle_state().linear_velocity();
684 double path_range =
685 current_speed * config_.ratio_navigation_lane_len_to_speed();
686 if (path_range <= config_.min_len_for_navigation_lane()) {
687 path_range = config_.min_len_for_navigation_lane();
688 } else {
689 path_range = config_.max_len_for_navigation_lane();
690 }
691
692 const double unit_z = 1.0;
693 const double start_s = -2.0;
694 double accumulated_s = start_s;
695 for (double z = start_s; z <= path_range; z += unit_z) {
696 double x1 = z;
697 double y1 = 0;
698 if (left_lane.view_range() > config_.min_view_range_to_use_lane_marker() ||
699 right_lane.view_range() > config_.min_view_range_to_use_lane_marker()) {
700 y1 = EvaluateCubicPolynomial(path_c0, path_c1, path_c2, path_c3, z);
701 }
702 auto *point = path->add_path_point();
703 point->set_x(x1);
704 point->set_y(y1);
705
706 if (path->path_point_size() > 1) {
707 auto &pre_point = path->path_point(path->path_point_size() - 2);
708 accumulated_s += std::hypot(x1 - pre_point.x(), y1 - pre_point.y());
709 }
710 point->set_s(accumulated_s);
711 point->set_theta(
712 std::atan2(3 * path_c3 * x1 * x1 + 2 * path_c2 * x1 + path_c1, 1));
713 point->set_kappa(GetKappa(path_c1, path_c2, path_c3, x1));
714
715 const double k1 = GetKappa(path_c1, path_c2, path_c3, x1 - 0.0001);
716 const double k2 = GetKappa(path_c1, path_c2, path_c3, x1 + 0.0001);
717 point->set_dkappa((k2 - k1) / 0.0002);
718 }
719
720 perceived_left_width_ = std::fabs(left_lane.c0_position());
721 perceived_right_width_ = std::fabs(right_lane.c0_position());
722 // If the perceived lane width is incorrect, use the default lane width
723 // directly.
724 double perceived_lane_width = perceived_left_width_ + perceived_right_width_;
725 if (perceived_lane_width < 2.0 * config_.min_lane_half_width() ||
726 perceived_lane_width > 2.0 * config_.max_lane_half_width()) {
727 perceived_left_width_ = default_left_width_;
728 perceived_right_width_ = default_right_width_;
729 }
730}
731
733 MapMsg *const map_msg) const {
734 auto *navigation_path = map_msg->mutable_navigation_path();
735 auto *hdmap = map_msg->mutable_hdmap();
736 auto *lane_marker = map_msg->mutable_lane_marker();
737
738 lane_marker->CopyFrom(perception_obstacles_.lane_marker());
739
740 // If no navigation path is generated based on navigation lines, we try to
741 // create map with "current_navi_path_tuple_" which is generated based on
742 // perceived lane markers.
743 if (navigation_path_list_.empty()) {
744 if (std::get<3>(current_navi_path_tuple_) != nullptr) {
745 FLAGS_relative_map_generate_left_boundray = true;
746 return CreateSingleLaneMap(current_navi_path_tuple_, map_config,
747 perception_obstacles_, hdmap, navigation_path);
748 } else {
749 return false;
750 }
751 }
752
753 int fail_num = 0;
754 FLAGS_relative_map_generate_left_boundray = true;
755 for (auto iter = navigation_path_list_.cbegin();
756 iter != navigation_path_list_.cend(); ++iter) {
757 std::size_t index = std::distance(navigation_path_list_.cbegin(), iter);
758 if (!CreateSingleLaneMap(*iter, map_config, perception_obstacles_, hdmap,
759 navigation_path)) {
760 AWARN << "Failed to generate lane: " << index;
761 ++fail_num;
762 FLAGS_relative_map_generate_left_boundray = true;
763 continue;
764 }
765 FLAGS_relative_map_generate_left_boundray = false;
766
767 // The left border of the middle lane uses the right border of the left
768 // lane.
769 int lane_index = static_cast<int>(index) - fail_num;
770 if (lane_index > 0) {
771 auto *left_boundary =
772 hdmap->mutable_lane(lane_index)->mutable_left_boundary();
773 left_boundary->CopyFrom(hdmap->lane(lane_index - 1).right_boundary());
774 auto *left_sample =
775 hdmap->mutable_lane(lane_index)->mutable_left_sample();
776 left_sample->CopyFrom(hdmap->lane(lane_index - 1).right_sample());
777 }
778 }
779
780 int lane_num = hdmap->lane_size();
781 ADEBUG << "The Lane number is: " << lane_num;
782
783 // Set road boundary
784 auto *road = hdmap->add_road();
785 road->mutable_id()->set_id("road_" + hdmap->lane(0).id().id());
786 auto *section = road->add_section();
787 for (int i = 0; i < lane_num; ++i) {
788 auto *lane_id = section->add_lane_id();
789 lane_id->CopyFrom(hdmap->lane(0).id());
790 }
791 auto *outer_polygon = section->mutable_boundary()->mutable_outer_polygon();
792 auto *left_edge = outer_polygon->add_edge();
794 left_edge->mutable_curve()->CopyFrom(hdmap->lane(0).left_boundary().curve());
795
796 auto *right_edge = outer_polygon->add_edge();
798 right_edge->mutable_curve()->CopyFrom(
799 hdmap->lane(lane_num - 1).right_boundary().curve());
800
801 // Set neighbor information for each lane
802 if (lane_num < 2) {
803 return true;
804 }
805 for (int i = 0; i < lane_num; ++i) {
806 auto *lane = hdmap->mutable_lane(i);
807 if (i > 0) {
808 lane->add_left_neighbor_forward_lane_id()->CopyFrom(
809 hdmap->lane(i - 1).id());
810 ADEBUG << "Left neighbor is: " << hdmap->lane(i - 1).id().id();
811 }
812 if (i < lane_num - 1) {
813 lane->add_right_neighbor_forward_lane_id()->CopyFrom(
814 hdmap->lane(i + 1).id());
815 ADEBUG << "Right neighbor is: " << hdmap->lane(i + 1).id().id();
816 }
817 }
818 return true;
819}
820
821void NavigationLane::UpdateStitchIndexInfo() {
822 stitch_index_map_.clear();
823
824 int navigation_line_num = navigation_info_.navigation_path_size();
825 if (navigation_line_num <= 0) {
826 return;
827 }
828
829 static constexpr int kMinPathPointSize = 10;
830 for (int i = 0; i < navigation_line_num; ++i) {
831 const auto &navigation_path = navigation_info_.navigation_path(i).path();
832 if (!navigation_info_.navigation_path(i).has_path() ||
833 navigation_path.path_point_size() < kMinPathPointSize) {
834 continue;
835 }
836
837 double min_distance = std::numeric_limits<double>::max();
838 StitchIndexPair min_index_pair = std::make_pair(-1, -1);
839
840 int path_size = navigation_path.path_point_size();
841 const double start_s = navigation_path.path_point(0).s();
842 const double end_s = navigation_path.path_point(path_size - 1).s();
843 for (int m = 0; m < path_size; ++m) {
844 double forward_s = navigation_path.path_point(m).s() - start_s;
845 if (forward_s > config_.max_len_from_navigation_line()) {
846 break;
847 }
848
849 for (int n = path_size - 1; n >= 0; --n) {
850 double reverse_s = end_s - navigation_path.path_point(n).s();
851 if (reverse_s > config_.max_len_from_navigation_line()) {
852 break;
853 }
854 if (m == n) {
855 break;
856 }
857
858 double current_distance = DistanceXY(navigation_path.path_point(m),
859 navigation_path.path_point(n));
860 if (current_distance < min_distance) {
861 min_distance = current_distance;
862 min_index_pair = std::make_pair(m, n);
863 }
864 }
865 }
866
867 if (min_distance < config_.min_lane_half_width()) {
868 AINFO << "The stitching pair is: (" << min_index_pair.first << ", "
869 << min_index_pair.second << ") for the navigation line: " << i;
870 stitch_index_map_[i] = min_index_pair;
871 }
872 }
873}
874
875} // namespace relative_map
876} // namespace apollo
const localization::Pose & original_pose() const
Implements a class of 2-dimensional vectors.
Definition vec2d.h:42
static Vec2d CreateUnitVec2d(const double angle)
Creates a unit-vector with a given angle to the positive x semi-axis
Definition vec2d.cc:29
void SetConfig(const NavigationLaneConfig &config)
Set the configuration information required by the NavigationLane.
bool GeneratePath()
Generate a suitable path (i.e.
void SetVehicleStateProvider(common::VehicleStateProvider *vehicle_state_provider)
bool CreateMap(const MapGenerationParam &map_config, MapMsg *const map_msg) const
Generate a real-time relative map of approximately 250 m in length based on several navigation line s...
void UpdateNavigationInfo(const NavigationInfo &navigation_info)
Update navigation line information.
Math-related util functions.
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
#define AWARN
Definition log.h:43
Some util functions.
T Clamp(const T value, T bound1, T bound2)
Clamp a value between two bounds.
Definition math_utils.h:155
double NormalizeAngle(const double angle)
Normalize angle to [-PI, PI).
Definition math_utils.cc:53
Eigen::Vector2d RotateVector2d(const Eigen::Vector2d &v_in, const double theta)
Definition math_utils.cc:82
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
std::enable_if<!std::numeric_limits< T >::is_integer, bool >::type IsFloatEqual(T x, T y, int ulp=2)
Definition util.h:123
PathPoint GetWeightedAverageOfTwoPathPoints(const PathPoint &p1, const PathPoint &p2, const double w1, const double w2)
Definition util.cc:34
std::tuple< int, double, double, std::shared_ptr< NavigationPath > > NaviPathTuple
std::pair< int, double > ProjIndexPair
std::pair< int, int > StitchIndexPair
class register implement
Definition arena_queue.h:37
This file provides the declaration of the class NavigationLane.
optional double heading
Definition pose.proto:48
optional apollo::common::PointENU position
Definition pose.proto:26
repeated NavigationPath navigation_path
optional apollo::common::Path path
Defines the Vec2d class.