27#include "absl/strings/str_cat.h"
63constexpr uint32_t KDestLanePriority = 0;
64constexpr double kPathOptimizationFallbackClost = 2e4;
65constexpr double kSpeedOptimizationFallbackClost = 2e4;
66constexpr double kStraightForwardLineCost = 10.0;
69void NaviPlanner::RegisterTasks() {
71 []() -> NaviTask* {
return new NaviPathDecider(); });
73 []() -> NaviTask* {
return new NaviSpeedDecider(); });
77 const std::string& config_path) {
81 if (!FLAGS_use_navigation_mode) {
82 const std::string msg =
"NaviPlanner is only used in navigation mode.";
84 return Status(ErrorCode::PLANNING_ERROR, msg);
87 AINFO <<
"In NaviPlanner::Init()";
90 LoadConfig<PlannerNaviConfig>(config_path, &planner_conf);
91 for (
const auto task : planner_conf.
task()) {
93 task_factory_.CreateObject(
static_cast<NaviTaskType>(task)));
94 AINFO <<
"Created task:" << tasks_.back()->Name();
96 for (
auto& task : tasks_) {
97 if (!task->Init(planner_conf)) {
98 const std::string msg =
99 absl::StrCat(
"Init task[", task->Name(),
"] failed.");
101 return Status(ErrorCode::PLANNING_ERROR, msg);
111 if (!FLAGS_use_navigation_mode) {
112 const std::string msg =
"NaviPlanner is only used in navigation mode.";
114 return Status(ErrorCode::PLANNING_ERROR, msg);
117 size_t success_line_count = 0;
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);
128 if (status.ok() && reference_line_info.IsDrivable()) {
129 success_line_count += 1;
131 reference_line_info.SetDrivable(
false);
132 AERROR <<
"Failed to plan on reference line "
133 << reference_line_info.Lanes().Id();
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();
141 if (success_line_count > 0) {
145 return Status(ErrorCode::PLANNING_ERROR,
146 "Failed to plan on any reference line.");
154 reference_line_info->
AddCost(kStraightForwardLineCost);
156 ADEBUG <<
"planning start point:" << planning_init_point.DebugString();
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";
164 *heuristic_speed_data =
SpeedData(speed_profile);
168 for (
auto& task : tasks_) {
170 ret = task->Execute(frame, reference_line_info);
172 AERROR <<
"Failed to run tasks[" << task->Name()
173 <<
"], Error message: " << ret.error_message();
177 const double time_diff_ms = (end_timestamp - start_timestamp) * 1000;
179 ADEBUG <<
"after task " << task->Name() <<
":"
181 ADEBUG << task->Name() <<
" time spend: " << time_diff_ms <<
" ms.";
183 RecordDebugInfo(reference_line_info, task->Name(), time_diff_ms);
186 RecordObstacleDebugInfo(reference_line_info);
189 ADEBUG <<
"Path fallback.";
190 GenerateFallbackPathProfile(reference_line_info,
192 reference_line_info->
AddCost(kPathOptimizationFallbackClost);
195 if (!ret.ok() || reference_line_info->
speed_data().empty()) {
196 ADEBUG <<
"Speed fallback.";
198 reference_line_info->
AddCost(kSpeedOptimizationFallbackClost);
204 planning_init_point.
path_point().
s(), &trajectory)) {
205 const std::string msg =
"Fail to aggregate planning trajectory.";
207 return Status(ErrorCode::PLANNING_ERROR, msg);
210 for (
const auto* obstacle :
212 if (obstacle->IsVirtual()) {
215 if (!obstacle->IsStatic()) {
218 if (obstacle->LongitudinalDecision().has_stop()) {
219 static constexpr double kRefrenceLineStaticObsCost = 1e3;
220 reference_line_info->
AddCost(kRefrenceLineStaticObsCost);
224 if (FLAGS_enable_trajectory_check) {
227 const std::string msg =
"Current planning trajectory is not valid.";
229 return Status(ErrorCode::PLANNING_ERROR, msg);
238void NaviPlanner::RecordObstacleDebugInfo(
240 if (!FLAGS_enable_record_debug) {
241 ADEBUG <<
"Skip record debug info";
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();
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]);
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";
273 if (reference_line_info ==
nullptr) {
274 AERROR <<
"Reference line info is null.";
278 auto ptr_latency_stats = reference_line_info->mutable_latency_stats();
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);
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();
291 AWARN <<
"last frame is empty";
292 return speed_profile;
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;
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;
304 const auto& last_speed_data = last_reference_line_info->speed_data();
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,
312 AERROR <<
"Fail to transfer xy to sl when init speed profile";
315 Vec2d xy_point(planning_init_point.path_point().x(),
316 planning_init_point.path_point().y());
318 if (!last_reference_line_info->reference_line().XYToSL(xy_point,
320 AERROR <<
"Fail to transfer xy to sl when init speed profile";
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) {
331 if (!is_updated_start) {
332 start_time = speed_point.t();
333 start_s = speed_point.s();
334 is_updated_start =
true;
337 speed_point.s() - start_s, speed_point.t() - start_time,
338 speed_point.v(), speed_point.a(), speed_point.da()));
341 return speed_profile;
345std::vector<SpeedPoint> NaviPlanner::GenerateSpeedHotStart(
346 const TrajectoryPoint& planning_init_point) {
347 std::vector<SpeedPoint> hot_start_speed_profile;
351 FLAGS_planning_upper_speed_limit);
352 while (t < FLAGS_trajectory_time_length) {
354 t += FLAGS_trajectory_time_min_interval;
355 s += v * FLAGS_trajectory_time_min_interval;
357 return hot_start_speed_profile;
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;
368 const auto& adc_ref_point =
369 reference_line_info->reference_line().GetReferencePoint(0.5 * adc_s);
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();
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);
380 ref_point.x() + dx, ref_point.y() + dy, 0.0, s, ref_point.heading(),
381 ref_point.kappa(), ref_point.dkappa()));
383 path_data->SetReferenceLine(&(reference_line_info->reference_line()));
384 path_data->SetDiscretizedPath(DiscretizedPath(std::move(path_points)));
387void NaviPlanner::GenerateFallbackSpeedProfile(SpeedData* speed_data) {
388 const auto& start_point =
injector_->ego_info()->start_point();
390 GenerateStopProfileFromPolynomial(start_point.v(), start_point.a());
391 if (speed_data->empty()) {
392 *speed_data = GenerateStopProfile(start_point.v(), start_point.a());
396SpeedData NaviPlanner::GenerateStopProfile(
const double init_speed,
397 const double init_acc)
const {
398 AERROR <<
"Slowing down the car.";
399 SpeedData speed_data;
401 const double kFixedJerk = -1.0;
402 const double first_point_acc = std::fmin(0.0, init_acc);
404 const double max_t = 3.0;
405 const double unit_t = 0.02;
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;
414 init_speed + first_point_acc * t_mid + 0.5 * kFixedJerk * t_mid * t_mid;
416 for (
double t = 0.0; t < max_t; t += unit_t) {
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);
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);
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));
432 v_mid + (t - t_mid) * FLAGS_slowdown_profile_deceleration);
433 speed_data.AppendSpeedPoint(s, t, v, FLAGS_slowdown_profile_deceleration,
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)) {
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,
467bool NaviPlanner::IsValidProfile(
const QuinticPolynomialCurve1d& curve)
const {
468 for (
double evaluate_t = 0.1; evaluate_t <= curve.ParamLength();
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) {
A general class to denote the return status of an API call.
static Status OK()
generate a success status.
Implements a class of 2-dimensional vectors.
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.
static double NowInSeconds()
gets the current time in second.
static Result ValidTrajectory(const DiscretizedTrajectory &trajectory)
Frame holds all data for one planning cycle.
std::list< ReferenceLineInfo > * mutable_reference_line_info()
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="")
std::shared_ptr< DependencyInjector > injector_
ReferenceLineInfo holds all data for one reference line.
PathDecision * path_decision()
void SetTrajectory(const DiscretizedTrajectory &trajectory)
void AddCost(double cost)
void SetDrivable(bool drivable)
Set if the vehicle can drive following this reference line A planner need to set this value to true i...
const SpeedData & speed_data() const
SpeedData * mutable_speed_data()
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
const PathData & path_data() const
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 ...
PathData * mutable_path_data()
std::string PathSpeedDebugString() const
Planning module main class.
Math-related util functions.
T Clamp(const T value, T bound1, T bound2)
Clamp a value between two bounds.
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.
optional double relative_time
optional PathPoint path_point
repeated NaviTaskType task