27#include "modules/common_msgs/basic_msgs/pnc_point.pb.h"
50bool CheckOverlapOnDpStGraph(
const std::vector<const STBoundary*>& boundaries,
51 const StGraphPoint& p1,
const StGraphPoint& p2) {
52 if (FLAGS_use_st_drivable_boundary) {
55 for (
const auto* boundary : boundaries) {
60 if (boundary->HasOverlap({p1.point(), p2.point()})) {
70 const std::vector<const Obstacle*>& obstacles,
72 : st_graph_data_(st_graph_data),
73 gridded_path_time_graph_config_(dp_config),
74 obstacles_(obstacles),
75 init_point_(init_point),
76 dp_st_cost_(dp_config, st_graph_data_.total_time_by_conf(),
77 st_graph_data_.path_length(), obstacles,
78 st_graph_data_.st_drivable_boundary(), init_point_) {
80 unit_t_ = gridded_path_time_graph_config_.
unit_t();
82 dense_unit_s_ = gridded_path_time_graph_config_.
dense_unit_s();
83 sparse_unit_s_ = gridded_path_time_graph_config_.
sparse_unit_s();
96 static constexpr double kBounadryEpsilon = 1e-2;
103 if (boundary->IsPointInBoundary({0.0, 0.0}) ||
104 (std::fabs(boundary->min_t()) < kBounadryEpsilon &&
105 std::fabs(boundary->min_s()) < kBounadryEpsilon)) {
106 dimension_t_ =
static_cast<uint32_t
>(std::ceil(
107 total_length_t_ /
static_cast<double>(unit_t_))) +
109 std::vector<SpeedPoint> speed_profile;
111 for (uint32_t i = 0; i < dimension_t_; ++i, t += unit_t_) {
119 if (!InitCostTable().ok()) {
120 const std::string msg =
"Initialize cost table failed.";
122 return Status(ErrorCode::PLANNING_ERROR, msg);
125 if (!InitSpeedLimitLookUp().ok()) {
126 const std::string msg =
"Initialize speed limit lookup table failed.";
128 return Status(ErrorCode::PLANNING_ERROR, msg);
131 if (!CalculateTotalCost().ok()) {
132 const std::string msg =
"Calculate total cost failed.";
134 return Status(ErrorCode::PLANNING_ERROR, msg);
137 if (!RetrieveSpeedProfile(speed_data).ok()) {
138 const std::string msg =
"Retrieve best speed profile failed.";
140 return Status(ErrorCode::PLANNING_ERROR, msg);
145Status GriddedPathTimeGraph::InitCostTable() {
150 if (unit_t_ < kDoubleEpsilon) {
151 const std::string msg =
"unit_t is smaller than the kDoubleEpsilon.";
153 return Status(ErrorCode::PLANNING_ERROR, msg);
157 if (dense_dimension_s_ < 1) {
158 const std::string msg =
"dense_dimension_s is at least 1.";
160 return Status(ErrorCode::PLANNING_ERROR, msg);
163 dimension_t_ =
static_cast<uint32_t
>(std::ceil(
164 total_length_t_ /
static_cast<double>(unit_t_))) +
167 double sparse_length_s =
169 static_cast<double>(dense_dimension_s_ - 1) * dense_unit_s_;
170 sparse_dimension_s_ =
171 sparse_length_s > std::numeric_limits<double>::epsilon()
172 ?
static_cast<uint32_t
>(std::ceil(sparse_length_s / sparse_unit_s_))
175 sparse_length_s > std::numeric_limits<double>::epsilon()
177 :
static_cast<uint32_t
>(std::ceil(total_length_s_ / dense_unit_s_)) +
179 dimension_s_ = dense_dimension_s_ + sparse_dimension_s_;
182 if (dimension_t_ < 1 || dimension_s_ < 1) {
183 const std::string msg =
"Dp st cost table size incorrect.";
185 return Status(ErrorCode::PLANNING_ERROR, msg);
188 cost_table_ = std::vector<std::vector<StGraphPoint>>(
189 dimension_t_, std::vector<StGraphPoint>(dimension_s_, StGraphPoint()));
192 for (uint32_t i = 0; i < cost_table_.size(); ++i, curr_t += unit_t_) {
193 auto& cost_table_i = cost_table_[i];
195 for (uint32_t j = 0; j < dense_dimension_s_; ++j, curr_s += dense_unit_s_) {
196 cost_table_i[j].Init(i, j, STPoint(curr_s, curr_t));
197 debug.AddPoint(
"dp_node_points", curr_t, curr_s);
199 curr_s =
static_cast<double>(dense_dimension_s_ - 1) * dense_unit_s_ +
201 for (uint32_t j = dense_dimension_s_; j < cost_table_i.size();
202 ++j, curr_s += sparse_unit_s_) {
203 cost_table_i[j].Init(i, j, STPoint(curr_s, curr_t));
204 debug.AddPoint(
"dp_node_points", curr_t, curr_s);
208 const auto& cost_table_0 = cost_table_[0];
209 spatial_distance_by_index_ = std::vector<double>(cost_table_0.size(), 0.0);
210 for (uint32_t i = 0; i < cost_table_0.size(); ++i) {
211 spatial_distance_by_index_[i] = cost_table_0[i].point().s();
216Status GriddedPathTimeGraph::InitSpeedLimitLookUp() {
217 speed_limit_by_index_.clear();
219 speed_limit_by_index_.resize(dimension_s_);
220 const auto& speed_limit = st_graph_data_.
speed_limit();
222 for (uint32_t i = 0; i < dimension_s_; ++i) {
223 speed_limit_by_index_[i] =
224 speed_limit.GetSpeedLimitByS(cost_table_[0][i].point().s());
229Status GriddedPathTimeGraph::CalculateTotalCost() {
233 size_t next_highest_row = 0;
234 size_t next_lowest_row = 0;
236 for (
size_t c = 0; c < cost_table_.size(); ++c) {
237 size_t highest_row = 0;
238 size_t lowest_row = cost_table_.back().size() - 1;
240 int count =
static_cast<int>(next_highest_row) -
241 static_cast<int>(next_lowest_row) + 1;
243 std::vector<std::future<void>> results;
244 for (
size_t r = next_lowest_row; r <= next_highest_row; ++r) {
245 auto msg = std::make_shared<StGraphMessage>(c, r);
246 if (gridded_path_time_graph_config_
247 .enable_multi_thread_in_dp_st_graph()) {
249 cyber::Async(&GriddedPathTimeGraph::CalculateCostAt,
this, msg));
251 CalculateCostAt(msg);
254 if (gridded_path_time_graph_config_
255 .enable_multi_thread_in_dp_st_graph()) {
256 for (
auto& result : results) {
262 for (
size_t r = next_lowest_row; r <= next_highest_row; ++r) {
263 const auto& cost_cr = cost_table_[c][r];
264 if (cost_cr.total_cost() < std::numeric_limits<double>::infinity()) {
267 GetRowRange(cost_cr, &h_r, &l_r);
268 highest_row = std::max(highest_row, h_r);
269 lowest_row = std::min(lowest_row, l_r);
272 next_highest_row = highest_row;
273 next_lowest_row = lowest_row;
279void GriddedPathTimeGraph::GetRowRange(
const StGraphPoint& point,
280 size_t* next_highest_row,
281 size_t* next_lowest_row) {
287 double acc_coeff = 0.5;
288 if (!point.pre_point()) {
289 v0 = init_point_.
v();
291 v0 = point.GetOptimalSpeed();
294 const auto max_s_size = dimension_s_ - 1;
295 const double t_squared = unit_t_ * unit_t_;
296 const double s_upper_bound = v0 * unit_t_ +
297 acc_coeff * max_acceleration_ * t_squared +
299 const auto next_highest_itr =
300 std::lower_bound(spatial_distance_by_index_.begin(),
301 spatial_distance_by_index_.end(), s_upper_bound);
302 if (next_highest_itr == spatial_distance_by_index_.end()) {
303 *next_highest_row = max_s_size;
306 std::distance(spatial_distance_by_index_.begin(), next_highest_itr);
309 const double s_lower_bound =
310 std::fmax(0.0, v0 * unit_t_ + acc_coeff * max_deceleration_ * t_squared) +
312 const auto next_lowest_itr =
313 std::lower_bound(spatial_distance_by_index_.begin(),
314 spatial_distance_by_index_.end(), s_lower_bound);
315 if (next_lowest_itr == spatial_distance_by_index_.end()) {
316 *next_lowest_row = max_s_size;
319 std::distance(spatial_distance_by_index_.begin(), next_lowest_itr);
323void GriddedPathTimeGraph::CalculateCostAt(
324 const std::shared_ptr<StGraphMessage>& msg) {
325 const uint32_t c = msg->c;
326 const uint32_t r = msg->r;
327 auto& cost_cr = cost_table_[c][r];
330 if (cost_cr.obstacle_cost() > std::numeric_limits<double>::max()) {
336 const auto& cost_init = cost_table_[0][0];
338 DCHECK_EQ(r, 0U) <<
"Incorrect. Row should be 0 with col = 0. row: " << r;
339 cost_cr.SetTotalCost(0.0);
340 cost_cr.SetOptimalSpeed(init_point_.
v());
344 const double speed_limit = speed_limit_by_index_[r];
345 const double cruise_speed = st_graph_data_.
cruise_speed();
348 const double min_s_consider_speed = dense_unit_s_ * dimension_t_;
352 2 * (cost_cr.point().s() / unit_t_ - init_point_.
v()) / unit_t_;
353 if (acc < max_deceleration_ || acc > max_acceleration_) {
358 cost_cr.point().s() > min_s_consider_speed) {
362 if (CheckOverlapOnDpStGraph(st_graph_data_.
st_boundaries(), cost_cr,
366 cost_cr.SetTotalCost(
367 cost_cr.obstacle_cost() + cost_cr.spatial_potential_cost() +
368 cost_init.total_cost() +
369 CalculateEdgeCostForSecondCol(r, speed_limit, cruise_speed));
370 cost_cr.SetPrePoint(cost_init);
371 cost_cr.SetOptimalSpeed(init_point_.
v() + acc * unit_t_);
375 static constexpr double kSpeedRangeBuffer = 0.20;
376 const double pre_lowest_s =
377 cost_cr.point().s() -
378 FLAGS_planning_upper_speed_limit * (1 + kSpeedRangeBuffer) * unit_t_;
379 const auto pre_lowest_itr =
380 std::lower_bound(spatial_distance_by_index_.begin(),
381 spatial_distance_by_index_.end(), pre_lowest_s);
383 if (pre_lowest_itr == spatial_distance_by_index_.end()) {
384 r_low = dimension_s_ - 1;
386 r_low =
static_cast<uint32_t
>(
387 std::distance(spatial_distance_by_index_.begin(), pre_lowest_itr));
389 const uint32_t r_pre_size = r - r_low + 1;
390 const auto& pre_col = cost_table_[c - 1];
391 double curr_speed_limit = speed_limit;
394 for (uint32_t i = 0; i < r_pre_size; ++i) {
395 uint32_t r_pre = r - i;
396 if (std::isinf(pre_col[r_pre].total_cost()) ||
397 pre_col[r_pre].pre_point() ==
nullptr) {
406 const double curr_a =
408 ((cost_cr.point().s() - pre_col[r_pre].point().s()) / unit_t_ -
409 pre_col[r_pre].GetOptimalSpeed()) /
411 if (curr_a < max_deceleration_ || curr_a > max_acceleration_) {
415 if (pre_col[r_pre].GetOptimalSpeed() + curr_a * unit_t_ <
417 cost_cr.point().s() > min_s_consider_speed) {
423 if (CheckOverlapOnDpStGraph(st_graph_data_.
st_boundaries(), cost_cr,
428 std::fmin(curr_speed_limit, speed_limit_by_index_[r_pre]);
429 const double cost = cost_cr.obstacle_cost() +
430 cost_cr.spatial_potential_cost() +
431 pre_col[r_pre].total_cost() +
432 CalculateEdgeCostForThirdCol(
433 r, r_pre, curr_speed_limit, cruise_speed);
435 if (cost < cost_cr.total_cost()) {
436 cost_cr.SetTotalCost(cost);
437 cost_cr.SetPrePoint(pre_col[r_pre]);
438 cost_cr.SetOptimalSpeed(pre_col[r_pre].GetOptimalSpeed() +
445 for (uint32_t i = 0; i < r_pre_size; ++i) {
446 uint32_t r_pre = r - i;
447 if (std::isinf(pre_col[r_pre].total_cost()) ||
448 pre_col[r_pre].pre_point() ==
nullptr) {
455 const double curr_a =
457 ((cost_cr.point().s() - pre_col[r_pre].point().s()) / unit_t_ -
458 pre_col[r_pre].GetOptimalSpeed()) /
460 if (curr_a > max_acceleration_ || curr_a < max_deceleration_) {
464 if (pre_col[r_pre].GetOptimalSpeed() + curr_a * unit_t_ < -
kDoubleEpsilon &&
465 cost_cr.point().s() > min_s_consider_speed) {
469 if (CheckOverlapOnDpStGraph(st_graph_data_.
st_boundaries(), cost_cr,
474 uint32_t r_prepre = pre_col[r_pre].pre_point()->index_s();
475 const StGraphPoint& prepre_graph_point = cost_table_[c - 2][r_prepre];
476 if (std::isinf(prepre_graph_point.total_cost())) {
480 if (!prepre_graph_point.pre_point()) {
483 const STPoint& triple_pre_point = prepre_graph_point.pre_point()->point();
484 const STPoint& prepre_point = prepre_graph_point.point();
485 const STPoint& pre_point = pre_col[r_pre].point();
486 const STPoint& curr_point = cost_cr.point();
488 std::fmin(curr_speed_limit, speed_limit_by_index_[r_pre]);
489 double cost = cost_cr.obstacle_cost() + cost_cr.spatial_potential_cost() +
490 pre_col[r_pre].total_cost() +
491 CalculateEdgeCost(triple_pre_point, prepre_point, pre_point,
492 curr_point, curr_speed_limit, cruise_speed);
494 if (cost < cost_cr.total_cost()) {
495 cost_cr.SetTotalCost(cost);
496 cost_cr.SetPrePoint(pre_col[r_pre]);
497 cost_cr.SetOptimalSpeed(pre_col[r_pre].GetOptimalSpeed() +
503Status GriddedPathTimeGraph::RetrieveSpeedProfile(SpeedData*
const speed_data) {
504 double min_cost = std::numeric_limits<double>::infinity();
505 const StGraphPoint* best_end_point =
nullptr;
506 PrintPoints debug(
"dp_node_edge");
507 for (
const auto& points_vec : cost_table_) {
508 for (
const auto& pt : points_vec) {
509 debug.AddPoint(pt.point().t(), pt.point().s());
514 for (
const StGraphPoint& cur_point : cost_table_.back()) {
515 if (!std::isinf(cur_point.total_cost()) &&
516 cur_point.total_cost() < min_cost) {
517 best_end_point = &cur_point;
518 min_cost = cur_point.total_cost();
522 for (
const auto& row : cost_table_) {
523 const StGraphPoint& cur_point = row.back();
524 if (!std::isinf(cur_point.total_cost()) &&
525 cur_point.total_cost() < min_cost) {
526 best_end_point = &cur_point;
527 min_cost = cur_point.total_cost();
531 if (best_end_point ==
nullptr) {
532 const std::string msg =
"Fail to find the best feasible trajectory.";
534 return Status(ErrorCode::PLANNING_ERROR, msg);
537 std::vector<SpeedPoint> speed_profile;
538 const StGraphPoint* cur_point = best_end_point;
539 PrintPoints debug_res(
"dp_result");
540 while (cur_point !=
nullptr) {
541 ADEBUG <<
"Time: " << cur_point->point().t();
542 ADEBUG <<
"S: " << cur_point->point().s();
543 ADEBUG <<
"V: " << cur_point->GetOptimalSpeed();
544 SpeedPoint speed_point;
545 debug_res.AddPoint(cur_point->point().t(), cur_point->point().s());
546 speed_point.set_s(cur_point->point().s());
547 speed_point.set_t(cur_point->point().t());
548 speed_profile.push_back(speed_point);
549 cur_point = cur_point->pre_point();
553 std::reverse(speed_profile.begin(), speed_profile.end());
555 static constexpr double kEpsilon = std::numeric_limits<double>::epsilon();
556 if (speed_profile.front().t() > kEpsilon ||
557 speed_profile.front().s() > kEpsilon) {
558 const std::string msg =
"Fail to retrieve speed profile.";
560 return Status(ErrorCode::PLANNING_ERROR, msg);
563 for (
size_t i = 0; i + 1 < speed_profile.size(); ++i) {
564 const double v = (speed_profile[i + 1].s() - speed_profile[i].s()) /
565 (speed_profile[i + 1].t() - speed_profile[i].t() + 1e-3);
566 speed_profile[i].set_v(v);
569 *speed_data = SpeedData(speed_profile);
573double GriddedPathTimeGraph::CalculateEdgeCost(
574 const STPoint& first,
const STPoint& second,
const STPoint& third,
575 const STPoint& forth,
const double speed_limit,
const double cruise_speed) {
576 return dp_st_cost_.
GetSpeedCost(third, forth, speed_limit, cruise_speed) +
581double GriddedPathTimeGraph::CalculateEdgeCostForSecondCol(
582 const uint32_t row,
const double speed_limit,
const double cruise_speed) {
583 double init_speed = init_point_.
v();
584 double init_acc = init_point_.
a();
585 const STPoint& pre_point = cost_table_[0][0].point();
586 const STPoint& curr_point = cost_table_[1][row].point();
587 return dp_st_cost_.
GetSpeedCost(pre_point, curr_point, speed_limit,
595double GriddedPathTimeGraph::CalculateEdgeCostForThirdCol(
596 const uint32_t curr_row,
const uint32_t pre_row,
const double speed_limit,
597 const double cruise_speed) {
598 double init_speed = init_point_.
v();
599 const STPoint& first = cost_table_[0][0].point();
600 const STPoint& second = cost_table_[1][pre_row].point();
601 const STPoint& third = cost_table_[2][curr_row].point();
602 return dp_st_cost_.
GetSpeedCost(second, third, speed_limit, cruise_speed) +
A general class to denote the return status of an API call.
static Status OK()
generate a success status.
static SpeedPoint ToSpeedPoint(const double s, const double t, const double v=0, const double a=0, const double da=0)
double GetSpatialPotentialCost(const StGraphPoint &point)
double GetAccelCostByTwoPoints(const double pre_speed, const STPoint &first, const STPoint &second)
double GetJerkCostByThreePoints(const double first_speed, const STPoint &first_point, const STPoint &second_point, const STPoint &third_point)
double GetJerkCostByTwoPoints(const double pre_speed, const double pre_acc, const STPoint &pre_point, const STPoint &curr_point)
double GetSpeedCost(const STPoint &first, const STPoint &second, const double speed_limit, const double cruise_speed) const
double GetJerkCostByFourPoints(const STPoint &first, const STPoint &second, const STPoint &third, const STPoint &fourth)
double GetAccelCostByThreePoints(const STPoint &first, const STPoint &second, const STPoint &third)
double GetObstacleCost(const StGraphPoint &point)
common::Status Search(SpeedData *const speed_data)
GriddedPathTimeGraph(const StGraphData &st_graph_data, const DpStSpeedOptimizerConfig &dp_config, const std::vector< const Obstacle * > &obstacles, const common::TrajectoryPoint &init_point)
const SpeedLimit & speed_limit() const
const std::vector< const STBoundary * > & st_boundaries() const
double path_length() const
double cruise_speed() const
double total_time_by_conf() const
Planning module main class.
const double kDoubleEpsilon
optional double max_deceleration
optional double max_acceleration
optional double dense_unit_s
optional double max_deceleration
optional double max_acceleration
optional double sparse_unit_s
optional int32 dense_dimension_s