Apollo 11.0
自动驾驶开放平台
navi_planner.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 <memory>
25#include <utility>
26
27#include "absl/strings/str_cat.h"
28
29#include "cyber/common/log.h"
30#include "cyber/time/clock.h"
45
50namespace apollo {
51namespace planning {
52
61
62namespace {
63constexpr uint32_t KDestLanePriority = 0;
64constexpr double kPathOptimizationFallbackClost = 2e4;
65constexpr double kSpeedOptimizationFallbackClost = 2e4;
66constexpr double kStraightForwardLineCost = 10.0;
67} // namespace
68
69void NaviPlanner::RegisterTasks() {
70 task_factory_.Register(NAVI_PATH_DECIDER,
71 []() -> NaviTask* { return new NaviPathDecider(); });
72 task_factory_.Register(NAVI_SPEED_DECIDER,
73 []() -> NaviTask* { return new NaviSpeedDecider(); });
74}
75
76Status NaviPlanner::Init(const std::shared_ptr<DependencyInjector>& injector,
77 const std::string& config_path) {
78 Planner::Init(injector, config_path);
79 // NaviPlanner is only used in navigation mode based on the real-time relative
80 // map.
81 if (!FLAGS_use_navigation_mode) {
82 const std::string msg = "NaviPlanner is only used in navigation mode.";
83 AERROR << msg;
84 return Status(ErrorCode::PLANNING_ERROR, msg);
85 }
86
87 AINFO << "In NaviPlanner::Init()";
88 RegisterTasks();
89 PlannerNaviConfig planner_conf;
90 LoadConfig<PlannerNaviConfig>(config_path, &planner_conf);
91 for (const auto task : planner_conf.task()) {
92 tasks_.emplace_back(
93 task_factory_.CreateObject(static_cast<NaviTaskType>(task)));
94 AINFO << "Created task:" << tasks_.back()->Name();
95 }
96 for (auto& task : tasks_) {
97 if (!task->Init(planner_conf)) {
98 const std::string msg =
99 absl::StrCat("Init task[", task->Name(), "] failed.");
100 AERROR << msg;
101 return Status(ErrorCode::PLANNING_ERROR, msg);
102 }
103 }
104 return Status::OK();
105}
106
107Status NaviPlanner::Plan(const TrajectoryPoint& planning_init_point,
108 Frame* frame, ADCTrajectory* ptr_computed_trajectory) {
109 // NaviPlanner is only used in navigation mode based on the real-time relative
110 // map.
111 if (!FLAGS_use_navigation_mode) {
112 const std::string msg = "NaviPlanner is only used in navigation mode.";
113 AERROR << msg;
114 return Status(ErrorCode::PLANNING_ERROR, msg);
115 }
116
117 size_t success_line_count = 0;
118 for (auto& reference_line_info : *frame->mutable_reference_line_info()) {
119 uint32_t priority = reference_line_info.GetPriority();
120 reference_line_info.SetCost(priority * kStraightForwardLineCost);
121 if (priority != KDestLanePriority) {
122 reference_line_info.SetDrivable(false);
123 continue;
124 }
125 auto status =
126 PlanOnReferenceLine(planning_init_point, frame, &reference_line_info);
127
128 if (status.ok() && reference_line_info.IsDrivable()) {
129 success_line_count += 1;
130 } else {
131 reference_line_info.SetDrivable(false);
132 AERROR << "Failed to plan on reference line "
133 << reference_line_info.Lanes().Id();
134 }
135 ADEBUG << "ref line info: " << reference_line_info.Lanes().Id()
136 << " priority : " << reference_line_info.GetPriority()
137 << " cost : " << reference_line_info.Cost()
138 << " driveable : " << reference_line_info.IsDrivable();
139 }
140
141 if (success_line_count > 0) {
142 return Status::OK();
143 }
144
145 return Status(ErrorCode::PLANNING_ERROR,
146 "Failed to plan on any reference line.");
147}
148
150 const TrajectoryPoint& planning_init_point, Frame* frame,
151 ReferenceLineInfo* reference_line_info) {
152 if (!reference_line_info->IsChangeLanePath() &&
153 reference_line_info->IsNeighborLanePath()) {
154 reference_line_info->AddCost(kStraightForwardLineCost);
155 }
156 ADEBUG << "planning start point:" << planning_init_point.DebugString();
157 auto* heuristic_speed_data = reference_line_info->mutable_speed_data();
158 auto speed_profile =
159 GenerateInitSpeedProfile(planning_init_point, reference_line_info);
160 if (speed_profile.empty()) {
161 speed_profile = GenerateSpeedHotStart(planning_init_point);
162 ADEBUG << "Using dummy hot start for speed vector";
163 }
164 *heuristic_speed_data = SpeedData(speed_profile);
165
166 auto ret = Status::OK();
167
168 for (auto& task : tasks_) {
169 const double start_timestamp = Clock::NowInSeconds();
170 ret = task->Execute(frame, reference_line_info);
171 if (!ret.ok()) {
172 AERROR << "Failed to run tasks[" << task->Name()
173 << "], Error message: " << ret.error_message();
174 break;
175 }
176 const double end_timestamp = Clock::NowInSeconds();
177 const double time_diff_ms = (end_timestamp - start_timestamp) * 1000;
178
179 ADEBUG << "after task " << task->Name() << ":"
180 << reference_line_info->PathSpeedDebugString();
181 ADEBUG << task->Name() << " time spend: " << time_diff_ms << " ms.";
182
183 RecordDebugInfo(reference_line_info, task->Name(), time_diff_ms);
184 }
185
186 RecordObstacleDebugInfo(reference_line_info);
187
188 if (reference_line_info->path_data().Empty()) {
189 ADEBUG << "Path fallback.";
190 GenerateFallbackPathProfile(reference_line_info,
191 reference_line_info->mutable_path_data());
192 reference_line_info->AddCost(kPathOptimizationFallbackClost);
193 }
194
195 if (!ret.ok() || reference_line_info->speed_data().empty()) {
196 ADEBUG << "Speed fallback.";
197 GenerateFallbackSpeedProfile(reference_line_info->mutable_speed_data());
198 reference_line_info->AddCost(kSpeedOptimizationFallbackClost);
199 }
200
201 DiscretizedTrajectory trajectory;
202 if (!reference_line_info->CombinePathAndSpeedProfile(
203 planning_init_point.relative_time(),
204 planning_init_point.path_point().s(), &trajectory)) {
205 const std::string msg = "Fail to aggregate planning trajectory.";
206 AERROR << msg;
207 return Status(ErrorCode::PLANNING_ERROR, msg);
208 }
209
210 for (const auto* obstacle :
211 reference_line_info->path_decision()->obstacles().Items()) {
212 if (obstacle->IsVirtual()) {
213 continue;
214 }
215 if (!obstacle->IsStatic()) {
216 continue;
217 }
218 if (obstacle->LongitudinalDecision().has_stop()) {
219 static constexpr double kRefrenceLineStaticObsCost = 1e3;
220 reference_line_info->AddCost(kRefrenceLineStaticObsCost);
221 }
222 }
223
224 if (FLAGS_enable_trajectory_check) {
225 if (ConstraintChecker::ValidTrajectory(trajectory) !=
227 const std::string msg = "Current planning trajectory is not valid.";
228 AERROR << msg;
229 return Status(ErrorCode::PLANNING_ERROR, msg);
230 }
231 }
232
233 reference_line_info->SetTrajectory(trajectory);
234 reference_line_info->SetDrivable(true);
235 return Status::OK();
236}
237
238void NaviPlanner::RecordObstacleDebugInfo(
239 ReferenceLineInfo* reference_line_info) {
240 if (!FLAGS_enable_record_debug) {
241 ADEBUG << "Skip record debug info";
242 return;
243 }
244 auto ptr_debug = reference_line_info->mutable_debug();
245
246 const auto path_decision = reference_line_info->path_decision();
247 for (const auto obstacle : path_decision->obstacles().Items()) {
248 auto obstacle_debug = ptr_debug->mutable_planning_data()->add_obstacle();
249 obstacle_debug->set_id(obstacle->Id());
250 obstacle_debug->mutable_sl_boundary()->CopyFrom(
251 obstacle->PerceptionSLBoundary());
252 const auto& decider_tags = obstacle->decider_tags();
253 const auto& decisions = obstacle->decisions();
254 if (decider_tags.size() != decisions.size()) {
255 AERROR << "decider_tags size: " << decider_tags.size()
256 << " different from decisions size:" << decisions.size();
257 }
258 for (size_t i = 0; i < decider_tags.size(); ++i) {
259 auto decision_tag = obstacle_debug->add_decision_tag();
260 decision_tag->set_decider_tag(decider_tags[i]);
261 decision_tag->mutable_decision()->CopyFrom(decisions[i]);
262 }
263 }
264}
265
266void NaviPlanner::RecordDebugInfo(ReferenceLineInfo* reference_line_info,
267 const std::string& name,
268 const double time_diff_ms) {
269 if (!FLAGS_enable_record_debug) {
270 ADEBUG << "Skip record debug info";
271 return;
272 }
273 if (reference_line_info == nullptr) {
274 AERROR << "Reference line info is null.";
275 return;
276 }
277
278 auto ptr_latency_stats = reference_line_info->mutable_latency_stats();
279
280 auto ptr_stats = ptr_latency_stats->add_task_stats();
281 ptr_stats->set_name(name);
282 ptr_stats->set_time_ms(time_diff_ms);
283}
284
285std::vector<SpeedPoint> NaviPlanner::GenerateInitSpeedProfile(
286 const TrajectoryPoint& planning_init_point,
287 const ReferenceLineInfo* reference_line_info) {
288 std::vector<SpeedPoint> speed_profile;
289 const auto* last_frame = injector_->frame_history()->Latest();
290 if (!last_frame) {
291 AWARN << "last frame is empty";
292 return speed_profile;
293 }
294 const ReferenceLineInfo* last_reference_line_info =
295 last_frame->DriveReferenceLineInfo();
296 if (!last_reference_line_info) {
297 ADEBUG << "last reference line info is empty";
298 return speed_profile;
299 }
300 if (!reference_line_info->IsStartFrom(*last_reference_line_info)) {
301 ADEBUG << "Current reference line is not started previous drived line";
302 return speed_profile;
303 }
304 const auto& last_speed_data = last_reference_line_info->speed_data();
305
306 if (!last_speed_data.empty()) {
307 const auto& last_init_point = last_frame->PlanningStartPoint().path_point();
308 Vec2d last_xy_point(last_init_point.x(), last_init_point.y());
309 SLPoint last_sl_point;
310 if (!last_reference_line_info->reference_line().XYToSL(last_xy_point,
311 &last_sl_point)) {
312 AERROR << "Fail to transfer xy to sl when init speed profile";
313 }
314
315 Vec2d xy_point(planning_init_point.path_point().x(),
316 planning_init_point.path_point().y());
317 SLPoint sl_point;
318 if (!last_reference_line_info->reference_line().XYToSL(xy_point,
319 &sl_point)) {
320 AERROR << "Fail to transfer xy to sl when init speed profile";
321 }
322
323 double s_diff = sl_point.s() - last_sl_point.s();
324 double start_time = 0.0;
325 double start_s = 0.0;
326 bool is_updated_start = false;
327 for (const auto& speed_point : last_speed_data) {
328 if (speed_point.s() < s_diff) {
329 continue;
330 }
331 if (!is_updated_start) {
332 start_time = speed_point.t();
333 start_s = speed_point.s();
334 is_updated_start = true;
335 }
336 speed_profile.push_back(PointFactory::ToSpeedPoint(
337 speed_point.s() - start_s, speed_point.t() - start_time,
338 speed_point.v(), speed_point.a(), speed_point.da()));
339 }
340 }
341 return speed_profile;
342}
343
344// This is a dummy simple hot start, need refine later
345std::vector<SpeedPoint> NaviPlanner::GenerateSpeedHotStart(
346 const TrajectoryPoint& planning_init_point) {
347 std::vector<SpeedPoint> hot_start_speed_profile;
348 double s = 0.0;
349 double t = 0.0;
350 double v = common::math::Clamp(planning_init_point.v(), 5.0,
351 FLAGS_planning_upper_speed_limit);
352 while (t < FLAGS_trajectory_time_length) {
353 hot_start_speed_profile.push_back(PointFactory::ToSpeedPoint(s, t, v));
354 t += FLAGS_trajectory_time_min_interval;
355 s += v * FLAGS_trajectory_time_min_interval;
356 }
357 return hot_start_speed_profile;
358}
359
360void NaviPlanner::GenerateFallbackPathProfile(
361 const ReferenceLineInfo* reference_line_info, PathData* path_data) {
362 auto adc_point = injector_->ego_info()->start_point();
363 double adc_s = reference_line_info->AdcSlBoundary().end_s();
364 const double max_s = 150.0;
365 const double unit_s = 1.0;
366
367 // projection of adc point onto reference line
368 const auto& adc_ref_point =
369 reference_line_info->reference_line().GetReferencePoint(0.5 * adc_s);
370
371 DCHECK(adc_point.has_path_point());
372 const double dx = adc_point.path_point().x() - adc_ref_point.x();
373 const double dy = adc_point.path_point().y() - adc_ref_point.y();
374
375 std::vector<common::PathPoint> path_points;
376 for (double s = adc_s; s < max_s; s += unit_s) {
377 const auto& ref_point =
378 reference_line_info->reference_line().GetReferencePoint(s);
379 path_points.push_back(PointFactory::ToPathPoint(
380 ref_point.x() + dx, ref_point.y() + dy, 0.0, s, ref_point.heading(),
381 ref_point.kappa(), ref_point.dkappa()));
382 }
383 path_data->SetReferenceLine(&(reference_line_info->reference_line()));
384 path_data->SetDiscretizedPath(DiscretizedPath(std::move(path_points)));
385}
386
387void NaviPlanner::GenerateFallbackSpeedProfile(SpeedData* speed_data) {
388 const auto& start_point = injector_->ego_info()->start_point();
389 *speed_data =
390 GenerateStopProfileFromPolynomial(start_point.v(), start_point.a());
391 if (speed_data->empty()) {
392 *speed_data = GenerateStopProfile(start_point.v(), start_point.a());
393 }
394}
395
396SpeedData NaviPlanner::GenerateStopProfile(const double init_speed,
397 const double init_acc) const {
398 AERROR << "Slowing down the car.";
399 SpeedData speed_data;
400
401 const double kFixedJerk = -1.0;
402 const double first_point_acc = std::fmin(0.0, init_acc);
403
404 const double max_t = 3.0;
405 const double unit_t = 0.02;
406
407 double pre_s = 0.0;
408 const double t_mid =
409 (FLAGS_slowdown_profile_deceleration - first_point_acc) / kFixedJerk;
410 const double s_mid = init_speed * t_mid +
411 0.5 * first_point_acc * t_mid * t_mid +
412 1.0 / 6.0 * kFixedJerk * t_mid * t_mid * t_mid;
413 const double v_mid =
414 init_speed + first_point_acc * t_mid + 0.5 * kFixedJerk * t_mid * t_mid;
415
416 for (double t = 0.0; t < max_t; t += unit_t) {
417 double s = 0.0;
418 double v = 0.0;
419 if (t <= t_mid) {
420 s = std::fmax(pre_s, init_speed * t + 0.5 * first_point_acc * t * t +
421 1.0 / 6.0 * kFixedJerk * t * t * t);
422 v = std::fmax(
423 0.0, init_speed + first_point_acc * t + 0.5 * kFixedJerk * t * t);
424 const double a = first_point_acc + kFixedJerk * t;
425 speed_data.AppendSpeedPoint(s, t, v, a, 0.0);
426 pre_s = s;
427 } else {
428 s = std::fmax(pre_s, s_mid + v_mid * (t - t_mid) +
429 0.5 * FLAGS_slowdown_profile_deceleration *
430 (t - t_mid) * (t - t_mid));
431 v = std::fmax(0.0,
432 v_mid + (t - t_mid) * FLAGS_slowdown_profile_deceleration);
433 speed_data.AppendSpeedPoint(s, t, v, FLAGS_slowdown_profile_deceleration,
434 0.0);
435 }
436 pre_s = s;
437 }
438 return speed_data;
439}
440
441SpeedData NaviPlanner::GenerateStopProfileFromPolynomial(
442 const double init_speed, const double init_acc) const {
443 AERROR << "Slowing down the car with polynomial.";
444 static constexpr double kMaxT = 4.0;
445 for (double t = 2.0; t <= kMaxT; t += 0.5) {
446 for (double s = 0.0; s < 50.0; s += 1.0) {
447 QuinticPolynomialCurve1d curve(0.0, init_speed, init_acc, s, 0.0, 0.0, t);
448 if (!IsValidProfile(curve)) {
449 continue;
450 }
451 static constexpr double kUnitT = 0.02;
452 SpeedData speed_data;
453 for (double curve_t = 0.0; curve_t <= t; curve_t += kUnitT) {
454 const double curve_s = curve.Evaluate(0, curve_t);
455 const double curve_v = curve.Evaluate(1, curve_t);
456 const double curve_a = curve.Evaluate(2, curve_t);
457 const double curve_da = curve.Evaluate(3, curve_t);
458 speed_data.AppendSpeedPoint(curve_s, curve_t, curve_v, curve_a,
459 curve_da);
460 }
461 return speed_data;
462 }
463 }
464 return SpeedData();
465}
466
467bool NaviPlanner::IsValidProfile(const QuinticPolynomialCurve1d& curve) const {
468 for (double evaluate_t = 0.1; evaluate_t <= curve.ParamLength();
469 evaluate_t += 0.2) {
470 const double v = curve.Evaluate(1, evaluate_t);
471 const double a = curve.Evaluate(2, evaluate_t);
472 static constexpr double kEpsilon = 1e-3;
473 if (v < -kEpsilon || a < -5.0) {
474 return false;
475 }
476 }
477 return true;
478}
479
480} // namespace planning
481} // 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
Implements a class of 2-dimensional vectors.
Definition vec2d.h:42
static SpeedPoint ToSpeedPoint(const double s, const double t, const double v=0, const double a=0, const double da=0)
static PathPoint ToPathPoint(const double x, const double y, const double z=0, const double s=0, const double theta=0, const double kappa=0, const double dkappa=0, const double ddkappa=0)
a singleton clock that can be used to get the current timestamp.
Definition clock.h:39
static double NowInSeconds()
gets the current time in second.
Definition clock.cc:56
static Result ValidTrajectory(const DiscretizedTrajectory &trajectory)
Frame holds all data for one planning cycle.
Definition frame.h:62
std::list< ReferenceLineInfo > * mutable_reference_line_info()
Definition frame.cc:127
const std::vector< const T * > & Items() const
List all the items in the container.
common::Status Plan(const common::TrajectoryPoint &planning_init_point, Frame *frame, ADCTrajectory *ptr_computed_trajectory) override
Override function Plan in parent class Planner.
common::Status Init(const std::shared_ptr< DependencyInjector > &injector, const std::string &config_path="") override
common::Status PlanOnReferenceLine(const common::TrajectoryPoint &planning_init_point, Frame *frame, ReferenceLineInfo *reference_line_info) override
Override function Plan in parent class Planner.
const IndexedList< std::string, Obstacle > & obstacles() const
virtual apollo::common::Status Init(const std::shared_ptr< DependencyInjector > &injector, const std::string &config_path="")
Definition planner.h:54
std::shared_ptr< DependencyInjector > injector_
Definition planner.h:79
ReferenceLineInfo holds all data for one reference line.
void SetTrajectory(const DiscretizedTrajectory &trajectory)
void SetDrivable(bool drivable)
Set if the vehicle can drive following this reference line A planner need to set this value to true i...
bool CombinePathAndSpeedProfile(const double relative_time, const double start_s, DiscretizedTrajectory *discretized_trajectory)
bool IsNeighborLanePath() const
Check if the current reference line is the neighbor of the vehicle current position
planning_internal::Debug * mutable_debug()
bool IsChangeLanePath() const
Check if the current reference line is a change lane reference line, i.e., ADC's current position is ...
Planning module main class.
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
T Clamp(const T value, T bound1, T bound2)
Clamp a value between two bounds.
Definition math_utils.h:155
class register implement
Definition arena_queue.h:37
This file provides the declaration of the class "NaviSpeedDecider".
This file provides the declaration of the class "NaviPathDecider".
This file provides the declaration of the class "NaviPlanner".
This file provides the declaration of the class "NaviSpeedDecider".
Some string util functions.