24#include <unordered_set>
39 planner_open_space_config_.CopyFrom(open_space_conf);
40 reed_shepp_generator_ = std::make_unique<ReedShepp>(vehicle_param_, planner_open_space_config_);
41 grid_a_star_heuristic_generator_ = std::make_unique<GridSearch>(planner_open_space_config_);
48 / std::tan(max_steer_angle_ * 2 / (next_node_num_ / 2 - 1));
49 if (arc_length_ < std::sqrt(2) * xy_grid_resolution_) {
50 arc_length_ = std::sqrt(2) * xy_grid_resolution_;
52 AINFO <<
"arc_length" << arc_length_;
53 delta_t_ = planner_open_space_config_.
delta_t();
73 planner_warm_start_config_.CopyFrom(warm_start_conf);
74 reed_shepp_generator_ = std::make_unique<ReedShepp>(vehicle_param_, planner_warm_start_config_);
75 grid_a_star_heuristic_generator_ = std::make_unique<GridSearch>(planner_warm_start_config_);
79 max_kappa_ = std::tan(max_steer_angle_) / vehicle_param_.
wheel_base();
80 step_size_ = planner_warm_start_config_.
step_size();
82 arc_length_ = std::sqrt(2) * xy_grid_resolution_;
83 AINFO <<
"arc_length" << arc_length_;
84 delta_t_ = FLAGS_open_space_delta_t;
91 acc_weight_ = FLAGS_open_space_acc_weight;
92 jerk_weight_ = FLAGS_open_space_jerk_weight;
93 kappa_penalty_weight_ = FLAGS_open_space_kappa_weight;
94 ref_s_weight_ = FLAGS_open_space_reference_s_weight;
95 ref_v_weight_ = FLAGS_open_space_reference_v_weight;
96 max_forward_v_ = FLAGS_open_space_max_forward_v;
97 max_reverse_v_ = FLAGS_open_space_max_reverse_v;
98 max_forward_acc_ = FLAGS_open_space_max_forward_acc;
99 max_reverse_acc_ = FLAGS_open_space_max_reverse_acc;
100 max_acc_jerk_ = FLAGS_open_space_max_jerk;
105bool HybridAStar::AnalyticExpansion(
106 std::shared_ptr<Node3d> current_node,
107 std::shared_ptr<Node3d>* candidate_final_node) {
108 std::shared_ptr<ReedSheppPath> reeds_shepp_to_check = std::make_shared<ReedSheppPath>();
109 if (!reed_shepp_generator_->ShortestRSP(current_node, end_node_, reeds_shepp_to_check)) {
112 if (!RSPCheck(reeds_shepp_to_check)) {
116 *candidate_final_node = LoadRSPinCS(reeds_shepp_to_check, current_node);
120bool HybridAStar::RSPCheck(
const std::shared_ptr<ReedSheppPath> reeds_shepp_to_end) {
121 std::shared_ptr<Node3d> node = std::shared_ptr<Node3d>(
new Node3d(
122 reeds_shepp_to_end->x,
123 reeds_shepp_to_end->y,
124 reeds_shepp_to_end->phi,
126 planner_warm_start_config_));
127 return ValidityCheck(node) && RSPLengthCheck(reeds_shepp_to_end);
130bool HybridAStar::RSPLengthCheck(
const std::shared_ptr<ReedSheppPath> reeds_shepp_path) {
131 for (
int i = 0; i < reeds_shepp_path->segs_lengths.size(); i++) {
132 if (reeds_shepp_path->segs_types[i] !=
'S') {
133 double dist = std::fabs(reeds_shepp_path->segs_lengths[i]) / max_kappa_ * reeds_shepp_path->radius;
138 double dist = std::fabs(reeds_shepp_path->segs_lengths[i]) / max_kappa_;
147bool HybridAStar::ValidityCheck(std::shared_ptr<Node3d> node) {
149 CHECK_GT(node->GetStepSize(), 0U);
151 if (obstacles_linesegments_vec_.empty()) {
155 size_t node_step_size = node->GetStepSize();
156 const auto& traversed_x = node->GetXs();
157 const auto& traversed_y = node->GetYs();
158 const auto& traversed_phi = node->GetPhis();
162 size_t check_start_index = 0;
163 if (node_step_size == 1) {
164 check_start_index = 0;
166 check_start_index = 1;
169 for (
size_t i = check_start_index; i < node_step_size; ++i) {
170 if (traversed_x[i] > XYbounds_[1] || traversed_x[i] < XYbounds_[0] || traversed_y[i] > XYbounds_[3]
171 || traversed_y[i] < XYbounds_[2]) {
174 Box2d bounding_box =
Node3d::GetBoundingBox(vehicle_param_, traversed_x[i], traversed_y[i], traversed_phi[i]);
175 for (
const auto& obstacle_linesegments : obstacles_linesegments_vec_) {
176 for (
const common::math::LineSegment2d& linesegment : obstacle_linesegments) {
177 if (bounding_box.HasOverlap(linesegment)) {
178 ADEBUG <<
"collision start at x: " << linesegment.start().x();
179 ADEBUG <<
"collision start at y: " << linesegment.start().y();
180 ADEBUG <<
"collision end at x: " << linesegment.end().x();
181 ADEBUG <<
"collision end at y: " << linesegment.end().y();
190std::shared_ptr<Node3d> HybridAStar::LoadRSPinCS(
191 const std::shared_ptr<ReedSheppPath> reeds_shepp_to_end,
192 std::shared_ptr<Node3d> current_node) {
193 std::shared_ptr<Node3d> end_node = std::shared_ptr<Node3d>(
new Node3d(
194 reeds_shepp_to_end->x,
195 reeds_shepp_to_end->y,
196 reeds_shepp_to_end->phi,
198 planner_warm_start_config_));
199 end_node->SetPre(current_node);
200 end_node->SetTrajCost(current_node->GetTrajCost() + reeds_shepp_to_end->cost);
204double HybridAStar::GetSoftBoundaryCost(
const std::shared_ptr<ReedSheppPath>& reeds_shepp_to_end) {
208 for (
int i = 0; i < reeds_shepp_to_end->x.size(); i++) {
210 x = reeds_shepp_to_end->x[i];
211 y = reeds_shepp_to_end->y[i];
212 point_cost = soft_boundary_penalty_ / (grid_a_star_heuristic_generator_->GetObstacleDistance(x, y) + 1e-6);
213 AINFO <<
"reedsheep point cost: " << point_cost;
216 AINFO <<
"reedsheep soft cost: " << cost;
220std::shared_ptr<Node3d> HybridAStar::Next_node_generator(std::shared_ptr<Node3d> current_node,
size_t next_node_index) {
221 double steering = 0.0;
222 double traveled_distance = 0.0;
223 if (next_node_index <
static_cast<double>(next_node_num_) / 2) {
224 steering = -max_steer_angle_
225 + (2 * max_steer_angle_ / (
static_cast<double>(next_node_num_) / 2 - 1))
226 *
static_cast<double>(next_node_index);
227 traveled_distance = step_size_;
229 size_t index = next_node_index - next_node_num_ / 2;
230 steering = -max_steer_angle_
231 + (2 * max_steer_angle_ / (
static_cast<double>(next_node_num_) / 2 - 1)) *
static_cast<double>(index);
232 traveled_distance = -step_size_;
236 std::vector<double> intermediate_x;
237 std::vector<double> intermediate_y;
238 std::vector<double> intermediate_phi;
239 double last_x = current_node->GetX();
240 double last_y = current_node->GetY();
241 double last_phi = current_node->GetPhi();
242 intermediate_x.push_back(last_x);
243 intermediate_y.push_back(last_y);
244 intermediate_phi.push_back(last_phi);
245 for (
size_t i = 0; i < arc_length_ / step_size_; ++i) {
246 const double next_phi = last_phi + traveled_distance / vehicle_param_.
wheel_base() * std::tan(steering);
247 const double next_x = last_x + traveled_distance * std::cos((last_phi + next_phi) / 2.0);
248 const double next_y = last_y + traveled_distance * std::sin((last_phi + next_phi) / 2.0);
249 intermediate_x.push_back(next_x);
250 intermediate_y.push_back(next_y);
257 if (intermediate_x.back() > XYbounds_[1] || intermediate_x.back() < XYbounds_[0]
258 || intermediate_y.back() > XYbounds_[3] || intermediate_y.back() < XYbounds_[2]) {
261 std::shared_ptr<Node3d> next_node = std::shared_ptr<Node3d>(
262 new Node3d(intermediate_x, intermediate_y, intermediate_phi, XYbounds_, planner_warm_start_config_));
263 next_node->SetPre(current_node);
264 next_node->SetDirec(traveled_distance > 0.0);
265 next_node->SetSteer(steering);
266 int dir = traveled_distance > 0.0 ? 1 : -1;
267 next_node->SetTravelDist(
268 current_node->GetDirec() == next_node->GetDirec() ? current_node->GetTravelDist() + arc_length_ * dir
269 : arc_length_ * dir);
273void HybridAStar::CalculateNodeCost(std::shared_ptr<Node3d> current_node, std::shared_ptr<Node3d> next_node) {
274 next_node->SetTrajCost(current_node->GetTrajCost() + TrajCost(current_node, next_node));
276 double optimal_path_cost = 0.0;
277 optimal_path_cost += HoloObstacleHeuristic(next_node);
278 next_node->SetHeuCost(optimal_path_cost);
281double HybridAStar::TrajCost(std::shared_ptr<Node3d> current_node, std::shared_ptr<Node3d> next_node) {
283 double piecewise_cost = 0.0;
284 if (next_node->GetDirec()) {
285 piecewise_cost +=
static_cast<double>(next_node->GetStepSize() - 1) * step_size_ * traj_forward_penalty_;
287 piecewise_cost +=
static_cast<double>(next_node->GetStepSize() - 1) * step_size_ * traj_back_penalty_;
289 AINFO <<
"traj cost: " << piecewise_cost;
290 if (current_node->GetDirec() != next_node->GetDirec()) {
291 piecewise_cost += traj_gear_switch_penalty_;
292 if (std::fabs(current_node->GetTravelDist()) < traj_expected_shortest_length_) {
293 piecewise_cost += traj_short_length_penalty_;
296 piecewise_cost += traj_steer_penalty_ * std::abs(next_node->GetSteer());
297 AINFO <<
"steer pos: " << traj_steer_penalty_ * std::abs(next_node->GetSteer());
298 piecewise_cost += traj_steer_change_penalty_ * std::abs(next_node->GetSteer() - current_node->GetSteer());
299 AINFO <<
"steer change: "
300 << traj_steer_change_penalty_ * std::abs(next_node->GetSteer() - current_node->GetSteer());
302 piecewise_cost += soft_boundary_penalty_
303 / (grid_a_star_heuristic_generator_->GetObstacleDistance(current_node->GetX(), current_node->GetY())
315 return piecewise_cost;
318double HybridAStar::HoloObstacleHeuristic(std::shared_ptr<Node3d> next_node) {
319 return grid_a_star_heuristic_generator_->CheckDpMap(next_node->GetX(), next_node->GetY());
322bool HybridAStar::GetResult(HybridAStartResult* result) {
323 std::shared_ptr<Node3d> current_node = final_node_;
324 std::vector<double> hybrid_a_x;
325 std::vector<double> hybrid_a_y;
326 std::vector<double> hybrid_a_phi;
327 AINFO <<
"switch node:" << current_node->GetXs().back() <<
", " << current_node->GetYs().back();
328 AINFO <<
"switch node:" << current_node->GetXs().front() <<
", " << current_node->GetYs().front();
329 AINFO <<
"cost: " << final_node_->GetCost() <<
"," << final_node_->GetTrajCost();
330 while (current_node->GetPreNode() !=
nullptr) {
331 std::vector<double> x = current_node->GetXs();
332 std::vector<double> y = current_node->GetYs();
333 std::vector<double> phi = current_node->GetPhis();
334 if (x.empty() || y.empty() || phi.empty()) {
335 AERROR <<
"result size check failed";
338 if (x.size() != y.size() || x.size() != phi.size()) {
339 AERROR <<
"states sizes are not equal";
342 std::reverse(x.begin(), x.end());
343 std::reverse(y.begin(), y.end());
344 std::reverse(phi.begin(), phi.end());
348 hybrid_a_x.insert(hybrid_a_x.end(), x.begin(), x.end());
349 hybrid_a_y.insert(hybrid_a_y.end(), y.begin(), y.end());
350 hybrid_a_phi.insert(hybrid_a_phi.end(), phi.begin(), phi.end());
351 current_node = current_node->GetPreNode();
353 hybrid_a_x.push_back(current_node->GetX());
354 hybrid_a_y.push_back(current_node->GetY());
355 hybrid_a_phi.push_back(current_node->GetPhi());
356 std::reverse(hybrid_a_x.begin(), hybrid_a_x.end());
357 std::reverse(hybrid_a_y.begin(), hybrid_a_y.end());
358 std::reverse(hybrid_a_phi.begin(), hybrid_a_phi.end());
359 (*result).x = hybrid_a_x;
360 (*result).y = hybrid_a_y;
361 (*result).phi = hybrid_a_phi;
363 if (!GetTemporalProfile(result)) {
364 AERROR <<
"GetSpeedProfile from Hybrid Astar path fails";
368 if (result->x.size() != result->y.size() || result->x.size() != result->v.size()
369 || result->x.size() != result->phi.size()) {
370 AERROR <<
"state sizes not equal, " <<
"result->x.size(): " << result->x.size() <<
"result->y.size()"
371 << result->y.size() <<
"result->phi.size()" << result->phi.size() <<
"result->v.size()"
375 if (result->a.size() != result->steer.size() || result->x.size() - result->a.size() != 1) {
376 AERROR <<
"control sizes not equal or not right";
377 AERROR <<
" acceleration size: " << result->a.size();
378 AERROR <<
" steer size: " << result->steer.size();
379 AERROR <<
" x size: " << result->x.size();
385bool HybridAStar::GenerateSpeedAcceleration(HybridAStartResult* result) {
386 AINFO <<
"GenerateSpeedAcceleration";
388 if (result->x.size() < 2 || result->y.size() < 2 || result->phi.size() < 2) {
389 AERROR <<
"result size check when generating speed and acceleration fail";
392 const size_t x_size = result->x.size();
396 result->v.push_back(0.0);
397 for (
size_t i = 1; i + 1 < x_size; ++i) {
398 double discrete_v = (((result->x[i + 1] - result->x[i]) / delta_t_) * std::cos(result->phi[i])
399 + ((result->x[i] - result->x[i - 1]) / delta_t_) * std::cos(result->phi[i]))
401 + (((result->y[i + 1] - result->y[i]) / delta_t_) * std::sin(result->phi[i])
402 + ((result->y[i] - result->y[i - 1]) / delta_t_) * std::sin(result->phi[i]))
404 result->v.push_back(discrete_v);
406 result->v.push_back(0.0);
409 for (
size_t i = 0; i + 1 < x_size; ++i) {
410 const double discrete_a = (result->v[i + 1] - result->v[i]) / delta_t_;
411 result->a.push_back(discrete_a);
415 for (
size_t i = 0; i + 1 < x_size; ++i) {
416 double discrete_steer = (result->phi[i + 1] - result->phi[i]) * vehicle_param_.
wheel_base() / step_size_;
417 if (result->v[i] > 0.0) {
418 discrete_steer = std::atan(discrete_steer);
420 discrete_steer = std::atan(-discrete_steer);
422 result->steer.push_back(discrete_steer);
427bool HybridAStar::GenerateSCurveSpeedAcceleration(HybridAStartResult* result) {
428 AINFO <<
"GenerateSCurveSpeedAcceleration";
430 CHECK_NOTNULL(result);
431 if (result->x.size() < 2 || result->y.size() < 2 || result->phi.size() < 2) {
432 AERROR <<
"result size check when generating speed and acceleration fail";
435 if (result->x.size() != result->y.size() || result->x.size() != result->phi.size()) {
436 AERROR <<
"result sizes not equal";
441 double init_heading = result->phi.front();
442 const Vec2d init_tracking_vector(result->x[1] - result->x[0], result->y[1] - result->y[0]);
446 size_t path_points_size = result->x.size();
448 double accumulated_s = 0.0;
449 result->accumulated_s.clear();
450 auto last_x = result->x.front();
451 auto last_y = result->y.front();
452 for (
size_t i = 0; i < path_points_size; ++i) {
453 double x_diff = result->x[i] - last_x;
454 double y_diff = result->y[i] - last_y;
455 accumulated_s += std::sqrt(x_diff * x_diff + y_diff * y_diff);
456 result->accumulated_s.push_back(accumulated_s);
457 last_x = result->x[i];
458 last_y = result->y[i];
461 const double init_v = 0.0;
462 const double init_a = 0.0;
467 SpeedData speed_data;
470 const double path_length = result->accumulated_s.back();
471 const double total_t = std::max(
472 gear ? 1.5 * (max_forward_v_ * max_forward_v_ + path_length * max_forward_acc_)
473 / (max_forward_acc_ * max_forward_v_)
474 : 1.5 * (max_reverse_v_ * max_reverse_v_ + path_length * max_reverse_acc_)
475 / (max_reverse_acc_ * max_reverse_v_),
477 if (total_t + delta_t_ >= delta_t_ * std::numeric_limits<size_t>::max()) {
478 AERROR <<
"Number of knots overflow. total_t: " << total_t <<
", delta_t: " << delta_t_;
481 const size_t num_of_knots =
static_cast<size_t>(total_t / delta_t_) + 1;
483 PiecewiseJerkSpeedProblem piecewise_jerk_problem(num_of_knots, delta_t_, {0.0, std::abs(init_v), std::abs(init_a)});
486 std::vector<std::pair<double, double>> x_bounds(num_of_knots, {0.0, path_length});
488 const double max_v = gear ? max_forward_v_ : max_reverse_v_;
489 const double max_acc = gear ? max_forward_acc_ : max_reverse_acc_;
491 const auto upper_dx = std::fmax(max_v, std::abs(init_v));
492 std::vector<std::pair<double, double>> dx_bounds(num_of_knots, {0.0, upper_dx});
493 std::vector<std::pair<double, double>> ddx_bounds(num_of_knots, {-max_acc, max_acc});
495 x_bounds[num_of_knots - 1] = std::make_pair(path_length, path_length);
496 dx_bounds[num_of_knots - 1] = std::make_pair(0.0, 0.0);
497 ddx_bounds[num_of_knots - 1] = std::make_pair(0.0, 0.0);
500 std::vector<double> x_ref(num_of_knots, path_length);
501 piecewise_jerk_problem.set_x_ref(ref_s_weight_, std::move(x_ref));
502 piecewise_jerk_problem.set_dx_ref(ref_v_weight_, max_v * 0.8);
503 piecewise_jerk_problem.set_weight_ddx(acc_weight_);
504 piecewise_jerk_problem.set_weight_dddx(jerk_weight_);
505 piecewise_jerk_problem.set_x_bounds(std::move(x_bounds));
506 piecewise_jerk_problem.set_dx_bounds(std::move(dx_bounds));
507 piecewise_jerk_problem.set_ddx_bounds(std::move(ddx_bounds));
508 piecewise_jerk_problem.set_dddx_bound(max_acc_jerk_);
511 if (!piecewise_jerk_problem.Optimize()) {
512 AERROR <<
"Piecewise jerk speed optimizer failed!";
517 const std::vector<double>& s = piecewise_jerk_problem.opt_x();
518 const std::vector<double>& ds = piecewise_jerk_problem.opt_dx();
519 const std::vector<double>& dds = piecewise_jerk_problem.opt_ddx();
522 speed_data.AppendSpeedPoint(s[0], 0.0, ds[0], dds[0], 0.0);
523 const double kEpislon = 1.0e-6;
524 const double sEpislon = 1.0e-6;
525 for (
size_t i = 1; i < num_of_knots; ++i) {
526 if (s[i - 1] - s[i] > kEpislon) {
527 ADEBUG <<
"unexpected decreasing s in speed smoothing at time " <<
static_cast<double>(i) * delta_t_
528 <<
"with total time " << total_t;
531 speed_data.AppendSpeedPoint(
532 s[i], delta_t_ *
static_cast<double>(i), ds[i], dds[i], (dds[i] - dds[i - 1]) / delta_t_);
534 if (path_length - s[i] < sEpislon) {
540 DiscretizedPath path_data;
541 for (
size_t i = 0; i < path_points_size; ++i) {
542 common::PathPoint path_point;
543 path_point.set_x(result->x[i]);
544 path_point.set_y(result->y[i]);
545 path_point.set_theta(result->phi[i]);
546 path_point.set_s(result->accumulated_s[i]);
547 path_data.push_back(std::move(path_point));
550 HybridAStartResult combined_result;
553 const double kDenseTimeResoltuion = 0.5;
554 const double time_horizon = speed_data.TotalTime() + kDenseTimeResoltuion * 1.0e-6;
555 if (path_data.empty()) {
556 AERROR <<
"path data is empty";
559 for (
double cur_rel_time = 0.0; cur_rel_time < time_horizon; cur_rel_time += kDenseTimeResoltuion) {
560 common::SpeedPoint speed_point;
561 if (!speed_data.EvaluateByTime(cur_rel_time, &speed_point)) {
562 AERROR <<
"Fail to get speed point with relative time " << cur_rel_time;
566 if (speed_point.s() > path_data.Length()
567 || (speed_point.v() < 0.05 && speed_point.s() > path_data.Length() / 2)) {
571 common::PathPoint path_point = path_data.Evaluate(speed_point.s());
573 combined_result.x.push_back(path_point.x());
574 combined_result.y.push_back(path_point.y());
575 combined_result.phi.push_back(path_point.theta());
576 combined_result.accumulated_s.push_back(path_point.s());
578 combined_result.v.push_back(-speed_point.v());
579 combined_result.a.push_back(-speed_point.a());
581 combined_result.v.push_back(speed_point.v());
582 combined_result.a.push_back(speed_point.a());
586 combined_result.a.pop_back();
589 path_points_size = combined_result.x.size();
592 for (
size_t i = 0; i + 1 < path_points_size; ++i) {
593 double discrete_steer = (combined_result.phi[i + 1] - combined_result.phi[i]) * vehicle_param_.
wheel_base()
594 / (combined_result.accumulated_s[i + 1] - combined_result.accumulated_s[i]);
595 discrete_steer = gear ? std::atan(discrete_steer) :
std::atan(-discrete_steer);
596 combined_result.steer.push_back(discrete_steer);
599 *result = combined_result;
605 std::vector<HybridAStartResult>* partitioned_result) {
606 const auto& x = result.
x;
607 const auto& y = result.
y;
608 const auto& phi = result.
phi;
609 if (x.size() != y.size() || x.size() != phi.size()) {
610 AERROR <<
"states sizes are not equal when do trajectory partitioning of "
611 "Hybrid A Star result";
615 size_t horizon = x.size();
616 partitioned_result->clear();
617 partitioned_result->emplace_back();
618 auto* current_traj = &(partitioned_result->back());
619 double heading_angle = phi.front();
620 const Vec2d init_tracking_vector(x[1] - x[0], y[1] - y[0]);
621 double tracking_angle = init_tracking_vector.
Angle();
623 AINFO << x[0] <<
" " << y[0] <<
" " << phi[0];
624 for (
size_t i = 0; i < horizon - 1; ++i) {
625 heading_angle = phi[i];
626 const Vec2d tracking_vector(x[i + 1] - x[i], y[i + 1] - y[i]);
627 tracking_angle = tracking_vector.
Angle();
629 if (gear != current_gear) {
630 current_traj->x.push_back(x[i]);
631 current_traj->y.push_back(y[i]);
632 current_traj->phi.push_back(phi[i]);
633 partitioned_result->emplace_back();
634 current_traj = &(partitioned_result->back());
637 current_traj->x.push_back(x[i]);
638 current_traj->y.push_back(y[i]);
639 current_traj->phi.push_back(phi[i]);
641 AINFO << x.back() <<
" " << y.back() <<
" " << phi.back();
642 current_traj->x.push_back(x.back());
643 current_traj->y.push_back(y.back());
644 current_traj->phi.push_back(phi.back());
646 const auto start_timestamp = std::chrono::system_clock::now();
649 for (
auto& result : *partitioned_result) {
650 if (FLAGS_use_s_curve_speed_smooth) {
651 if (!GenerateSCurveSpeedAcceleration(&result)) {
652 AERROR <<
"GenerateSCurveSpeedAcceleration fail";
656 if (!GenerateSpeedAcceleration(&result)) {
657 AERROR <<
"GenerateSpeedAcceleration fail";
663 const auto end_timestamp = std::chrono::system_clock::now();
664 std::chrono::duration<double> diff = end_timestamp - start_timestamp;
665 ADEBUG <<
"speed profile total time: " << diff.count() * 1000.0 <<
" ms.";
670 std::vector<HybridAStartResult> partitioned_results;
672 AERROR <<
"TrajectoryPartition fail";
675 ADEBUG <<
"PARTION SIZE " << partitioned_results.size();
676 HybridAStartResult stitched_result;
677 for (
const auto& result : partitioned_results) {
678 std::copy(result.
x.begin(), result.
x.end() - 1, std::back_inserter(stitched_result.x));
679 std::copy(result.
y.begin(), result.
y.end() - 1, std::back_inserter(stitched_result.y));
680 std::copy(result.
phi.begin(), result.
phi.end() - 1, std::back_inserter(stitched_result.phi));
681 std::copy(result.
v.begin(), result.
v.end() - 1, std::back_inserter(stitched_result.v));
682 std::copy(result.
a.begin(), result.
a.end(), std::back_inserter(stitched_result.a));
683 std::copy(result.
steer.begin(), result.
steer.end(), std::back_inserter(stitched_result.steer));
685 stitched_result.x.push_back(partitioned_results.back().x.back());
686 stitched_result.y.push_back(partitioned_results.back().y.back());
687 stitched_result.phi.push_back(partitioned_results.back().phi.back());
688 stitched_result.v.push_back(partitioned_results.back().v.back());
689 *result = stitched_result;
700 const std::vector<double>& XYbounds,
701 const std::vector<std::vector<common::math::Vec2d>>& obstacles_vertices_vec,
703 const std::vector<std::vector<common::math::Vec2d>>& soft_boundary_vertices_vec,
704 bool reeds_sheep_last_straight) {
705 reed_shepp_generator_->reeds_sheep_last_straight_ = reeds_sheep_last_straight;
709 open_pq_ =
decltype(open_pq_)();
710 final_node_ =
nullptr;
712 std::vector<std::vector<common::math::LineSegment2d>> obstacles_linesegments_vec;
713 for (
const auto& obstacle_vertices : obstacles_vertices_vec) {
714 size_t vertices_num = obstacle_vertices.size();
715 std::vector<common::math::LineSegment2d> obstacle_linesegments;
716 for (
size_t i = 0; i < vertices_num - 1; ++i) {
719 obstacle_linesegments.emplace_back(line_segment);
721 obstacles_linesegments_vec.emplace_back(obstacle_linesegments);
723 obstacles_linesegments_vec_ = std::move(obstacles_linesegments_vec);
724 std::vector<std::vector<common::math::LineSegment2d>> soft_boundary_linesegments_vec;
725 for (
const auto& soft_boundary_vertices : soft_boundary_vertices_vec) {
726 size_t vertices_num = soft_boundary_vertices.size();
727 std::vector<common::math::LineSegment2d> soft_boundary_linesegments;
728 for (
size_t i = 0; i < vertices_num - 1; ++i) {
731 soft_boundary_linesegments.emplace_back(line_segment);
733 soft_boundary_linesegments_vec.emplace_back(soft_boundary_linesegments);
735 soft_boundary_linesegments_vec_ = std::move(soft_boundary_linesegments_vec);
736 for (
size_t i = 0; i < obstacles_linesegments_vec_.size(); i++) {
737 for (
auto linesg : obstacles_linesegments_vec_[i]) {
738 std::string name = std::to_string(i) +
"roi_boundary";
739 print_curves.
AddPoint(name, linesg.start());
740 print_curves.
AddPoint(name, linesg.end());
743 Vec2d sposition(sx, sy);
744 Vec2d svec_to_center(
747 Vec2d scenter(sposition + svec_to_center.
rotate(sphi));
750 Vec2d eposition(ex, ey);
751 print_curves.
AddPoint(
"end_position", eposition);
752 Vec2d evec_to_center(
755 Vec2d ecenter(eposition + evec_to_center.
rotate(ephi));
758 XYbounds_ = XYbounds;
760 start_node_.reset(
new Node3d({sx}, {sy}, {sphi}, XYbounds_, planner_warm_start_config_));
761 end_node_.reset(
new Node3d({ex}, {ey}, {ephi}, XYbounds_, planner_warm_start_config_));
762 AINFO <<
"start node" << sx <<
"," << sy <<
"," << sphi;
763 AINFO <<
"end node " << ex <<
"," << ey <<
"," << ephi;
764 if (!ValidityCheck(start_node_)) {
765 AERROR <<
"start_node in collision with obstacles";
766 AERROR << start_node_->GetX() <<
"," << start_node_->GetY() <<
"," << start_node_->GetPhi();
770 if (!ValidityCheck(end_node_)) {
771 AERROR <<
"end_node in collision with obstacles";
776 grid_a_star_heuristic_generator_->GenerateDpMap(
777 ex, ey, XYbounds_, obstacles_linesegments_vec_, soft_boundary_linesegments_vec_);
780 open_set_.insert(start_node_->GetIndex());
781 open_pq_.emplace(start_node_, start_node_->GetCost());
783 size_t explored_node_num = 0;
784 size_t available_result_num = 0;
785 auto best_explored_num = explored_node_num;
786 auto best_available_result_num = available_result_num;
788 double heuristic_time = 0.0;
789 double rs_time = 0.0;
790 double node_generator_time = 0.0;
791 double validity_check_time = 0.0;
793 size_t desired_explored_num = std::min(
795 static constexpr int kMaxNodeNum = 200000;
796 std::vector<std::shared_ptr<Node3d>> candidate_final_nodes;
797 while (!open_pq_.empty() && open_pq_.size() < kMaxNodeNum && available_result_num < desired_explored_num
798 && explored_node_num < max_explored_num) {
799 std::shared_ptr<Node3d> current_node = open_pq_.top().first;
800 if (current_node->GetPreNode() !=
nullptr) {
801 AINFO <<
"print_open_pq:" <<
"(" << current_node->GetPreNode()->GetX() <<
", "
802 << current_node->GetPreNode()->GetY() <<
")" <<
";" <<
"(" << current_node->GetX() <<
", "
803 << current_node->GetY() <<
");";
807 std::shared_ptr<Node3d> final_node =
nullptr;
808 if (AnalyticExpansion(current_node, &final_node)) {
809 if (final_node_ ==
nullptr || final_node_->GetTrajCost() > final_node->GetTrajCost()) {
810 final_node_ = final_node;
811 best_explored_num = explored_node_num + 1;
812 best_available_result_num = available_result_num + 1;
814 available_result_num++;
818 rs_time += rs_end_time - rs_start_time;
819 close_set_.insert(current_node->GetIndex());
822 && available_result_num > 0) {
826 size_t begin_index = 0;
827 size_t end_index = next_node_num_;
828 std::unordered_set<std::string> temp_set;
829 for (
size_t i = begin_index; i < end_index; ++i) {
831 std::shared_ptr<Node3d> next_node = Next_node_generator(current_node, i);
835 if (next_node ==
nullptr) {
839 if (close_set_.count(next_node->GetIndex()) > 0) {
844 if (!ValidityCheck(next_node)) {
848 if (open_set_.count(next_node->GetIndex()) == 0) {
850 CalculateNodeCost(current_node, next_node);
852 heuristic_time += end_time - start_time;
853 temp_set.insert(next_node->GetIndex());
854 open_pq_.emplace(next_node, next_node->GetCost());
857 open_set_.insert(temp_set.begin(), temp_set.end());
860 if (final_node_ ==
nullptr) {
861 AERROR <<
"Hybird A* cannot find a valid path";
866 AINFO <<
"open_pq_.empty()" << (open_pq_.empty() ?
"true" :
"false");
867 AINFO <<
"open_pq_.size()" << open_pq_.size();
868 AINFO <<
"desired_explored_num" << desired_explored_num;
869 AINFO <<
"min cost is : " << final_node_->GetTrajCost();
870 AINFO <<
"max_explored_num is " << max_explored_num;
871 AINFO <<
"explored node num is " << explored_node_num <<
"available_result_num " << available_result_num;
872 AINFO <<
"best_explored_num is " << best_explored_num <<
"best_available_result_num is "
873 << best_available_result_num;
874 AINFO <<
"cal node time is " << heuristic_time <<
"validity_check_time " << validity_check_time
875 <<
"node_generator_time " << node_generator_time;
876 AINFO <<
"reed shepp time is " << rs_time;
879 print_curves.
AddPoint(
"rs_point", final_node_->GetXs().front(), final_node_->GetYs().front());
880 if (!GetResult(result)) {
881 AERROR <<
"GetResult failed";
885 for (
size_t i = 0; i < result->
x.size(); i++) {
886 print_curves.
AddPoint(
"warm_path", result->
x[i], result->
y[i]);
Rectangular (undirected) bounding box in 2-D.
void GetAllCorners(std::vector< Vec2d > *const corners) const
Getter of the corners of the box
Implements a class of 2-dimensional vectors.
Vec2d rotate(const double angle) const
rotate the vector by angle.
double Angle() const
Gets the angle between the vector and the positive x semi-axis
a singleton clock that can be used to get the current timestamp.
static double NowInSeconds()
gets the current time in second.
HybridAStar(const PlannerOpenSpaceConfig &open_space_conf)
bool TrajectoryPartition(const HybridAStartResult &result, std::vector< HybridAStartResult > *partitioned_result)
bool Plan(double sx, double sy, double sphi, double ex, double ey, double ephi, const std::vector< double > &XYbounds, const std::vector< std::vector< common::math::Vec2d > > &obstacles_vertices_vec, HybridAStartResult *result, const std::vector< std::vector< common::math::Vec2d > > &soft_boundary_vertices_vec={}, bool reeds_sheep_last_straight=false)
static apollo::common::math::Box2d GetBoundingBox(const common::VehicleParam &vehicle_param_, const double x, const double y, const double phi)
void AddPoint(std::string key, double x, double y)
add point to curve key
Planning module main class.
double NormalizeAngle(const double angle)
Normalize angle to [-PI, PI).
optional double max_steer_angle
optional double left_edge_to_center
optional double back_edge_to_center
optional double steer_ratio
optional double front_edge_to_center
optional double wheel_base
optional double right_edge_to_center
std::vector< double > steer
std::vector< double > phi
optional double max_forward_v
optional double max_forward_acc
optional double max_acc_jerk
optional double max_reverse_acc
optional double max_reverse_v
optional SpeedOptimizerConfig s_curve_config
optional WarmStartConfig warm_start_config
optional IterativeAnchoringConfig iterative_anchoring_smoother_config
optional double jerk_weight
optional double ref_v_weight
optional double kappa_penalty_weight
optional double acc_weight
optional double ref_s_weight
optional double traj_short_length_penalty
optional double traj_back_penalty
optional double phi_grid_resolution
optional int32 max_explored_num
optional double traj_steer_penalty
optional double step_size
optional int32 desired_explored_num
optional double traj_steer_change_penalty
optional double astar_max_search_time
optional double xy_grid_resolution
optional double traj_gear_switch_penalty
optional uint64 next_node_num
optional double traj_kappa_contraint_ratio
optional double traj_forward_penalty
optional double traj_expected_shortest_length
optional double soft_boundary_penalty