16 #ifndef NAV2_SMAC_PLANNER__SMAC_PLANNER_HYBRID_IMPL_HPP_
17 #define NAV2_SMAC_PLANNER__SMAC_PLANNER_HYBRID_IMPL_HPP_
27 #include "nav2_smac_planner/smac_planner_hybrid.hpp"
28 #include "nav2_ros_common/tf2_factories.hpp"
32 namespace nav2_smac_planner
35 using namespace std::chrono;
36 using rcl_interfaces::msg::ParameterType;
37 using std::placeholders::_1;
39 template<
typename NodeT>
42 _collision_checker(nullptr, 1, nullptr),
45 _costmap_ros(nullptr),
46 _costmap_downsampler(nullptr)
50 template<
typename NodeT>
54 _logger,
"Destroying plugin %s of type SmacPlannerHybrid",
58 template<
typename NodeT>
60 const nav2::LifecycleNode::WeakPtr & parent,
61 std::string name, nav2::TransformBuffer::SharedPtr,
62 std::shared_ptr<nav2_costmap_2d::Costmap2DROS> costmap_ros)
65 auto node = parent.lock();
66 _logger = node->get_logger();
67 _clock = node->get_clock();
68 _costmap = costmap_ros->getCostmap();
69 _costmap_ros = costmap_ros;
71 _global_frame = costmap_ros->getGlobalFrameID();
73 RCLCPP_INFO(_logger,
"Configuring %s of type SmacPlannerHybrid", name.c_str());
75 int angle_quantizations;
76 double analytic_expansion_max_length_m;
80 _downsample_costmap = node->declare_or_get_parameter(name +
".downsample_costmap",
false);
81 _downsampling_factor = node->declare_or_get_parameter(name +
".downsampling_factor", 1);
83 angle_quantizations = node->declare_or_get_parameter(name +
".angle_quantization_bins", 72);
84 _angle_bin_size = 2.0 * M_PI / angle_quantizations;
85 _angle_quantizations =
static_cast<unsigned int>(angle_quantizations);
87 _tolerance =
static_cast<float>(node->declare_or_get_parameter(name +
".tolerance", 0.25));
88 _allow_unknown = node->declare_or_get_parameter(name +
".allow_unknown",
true);
89 _max_iterations = node->declare_or_get_parameter(name +
".max_iterations", 1000000);
90 _max_on_approach_iterations =
91 node->declare_or_get_parameter(name +
".max_on_approach_iterations", 1000);
92 _terminal_checking_interval =
93 node->declare_or_get_parameter(name +
".terminal_checking_interval", 5000);
94 smooth_path = node->declare_or_get_parameter(name +
".smooth_path",
true);
96 _minimum_turning_radius_global_coords =
97 node->declare_or_get_parameter(name +
".minimum_turning_radius", 0.4);
98 _search_info.allow_primitive_interpolation =
99 node->declare_or_get_parameter(name +
".allow_primitive_interpolation",
true);
100 _search_info.cache_obstacle_heuristic =
101 node->declare_or_get_parameter(name +
".cache_obstacle_heuristic",
false);
102 _search_info.reverse_penalty =
103 node->declare_or_get_parameter(name +
".reverse_penalty", 2.0);
104 _search_info.change_penalty =
105 node->declare_or_get_parameter(name +
".change_penalty", 0.0);
106 _search_info.non_straight_penalty =
107 node->declare_or_get_parameter(name +
".non_straight_penalty", 1.2);
108 _search_info.cost_penalty =
109 node->declare_or_get_parameter(name +
".cost_penalty", 2.0);
110 _search_info.retrospective_penalty =
111 node->declare_or_get_parameter(name +
".retrospective_penalty", 0.015);
112 _search_info.analytic_expansion_ratio =
113 node->declare_or_get_parameter(name +
".analytic_expansion_ratio", 3.5);
114 _search_info.analytic_expansion_max_cost =
115 node->declare_or_get_parameter(name +
".analytic_expansion_max_cost", 200.0);
116 _search_info.analytic_expansion_max_cost_override =
117 node->declare_or_get_parameter(name +
".analytic_expansion_max_cost_override",
false);
118 _search_info.use_quadratic_cost_penalty =
119 node->declare_or_get_parameter(name +
".use_quadratic_cost_penalty",
false);
120 _search_info.downsample_obstacle_heuristic =
121 node->declare_or_get_parameter(name +
".downsample_obstacle_heuristic",
true);
123 analytic_expansion_max_length_m =
124 node->declare_or_get_parameter(name +
".analytic_expansion_max_length", 3.0);
125 _search_info.analytic_expansion_max_length =
126 analytic_expansion_max_length_m / _costmap->getResolution();
128 _max_planning_time = node->declare_or_get_parameter(name +
".max_planning_time", 5.0);
129 _lookup_table_size = node->declare_or_get_parameter(name +
".lookup_table_size", 20.0);
131 _debug_visualizations = node->declare_or_get_parameter(name +
".debug_visualizations",
false);
133 _motion_model_for_search =
134 node->declare_or_get_parameter(name +
".motion_model_for_search", std::string(
"DUBIN"));
136 std::string goal_heading_type =
137 node->declare_or_get_parameter(name +
".goal_heading_mode", std::string(
"DEFAULT"));
138 _goal_heading_mode = fromStringToGH(goal_heading_type);
140 _coarse_search_resolution =
141 node->declare_or_get_parameter(name +
".coarse_search_resolution", 1);
143 if (_goal_heading_mode == GoalHeadingMode::UNKNOWN) {
144 std::string error_msg =
"Unable to get GoalHeader type. Given '" + goal_heading_type +
"' "
145 "Valid options are DEFAULT, BIDIRECTIONAL, ALL_DIRECTION. ";
149 _motion_model = fromString(_motion_model_for_search);
151 if (_motion_model == MotionModel::UNKNOWN) {
154 "Unable to get MotionModel search type. Given '%s', "
155 "valid options are MOORE, VON_NEUMANN, DUBIN, REEDS_SHEPP, STATE_LATTICE.",
156 _motion_model_for_search.c_str());
159 if (_max_on_approach_iterations <= 0) {
161 _logger,
"On approach iteration selected as <= 0, "
162 "disabling tolerance and on approach iterations.");
163 _max_on_approach_iterations = std::numeric_limits<int>::max();
166 if (_max_iterations <= 0) {
168 _logger,
"maximum iteration selected as <= 0, "
169 "disabling maximum iterations.");
170 _max_iterations = std::numeric_limits<int>::max();
173 if (_coarse_search_resolution <= 0) {
175 _logger,
"coarse iteration resolution selected as <= 0, "
176 "disabling coarse iteration resolution search for goal heading"
179 _coarse_search_resolution = 1;
182 if (_angle_quantizations % _coarse_search_resolution != 0) {
183 std::string error_msg =
"coarse iteration should be an increment"
184 " of the number of angular bins configured";
188 if (_minimum_turning_radius_global_coords < _costmap->getResolution() * _downsampling_factor) {
190 _logger,
"Min turning radius cannot be less than the search grid cell resolution!");
191 _minimum_turning_radius_global_coords = _costmap->getResolution() * _downsampling_factor;
195 if (!_downsample_costmap) {
196 _downsampling_factor = 1;
198 _search_info.minimum_turning_radius =
199 _minimum_turning_radius_global_coords / (_costmap->getResolution() * _downsampling_factor);
201 static_cast<float>(_lookup_table_size) /
202 static_cast<float>(_costmap->getResolution() * _downsampling_factor);
205 _lookup_table_dim =
static_cast<float>(
static_cast<int>(_lookup_table_dim));
208 if (
static_cast<int>(_lookup_table_dim) % 2 == 0) {
211 "Even sized heuristic lookup table size set %f, increasing size by 1 to make odd",
213 _lookup_table_dim += 1.0;
218 _collision_checker.setFootprint(
219 _costmap_ros->getRobotFootprint(),
220 _costmap_ros->getUseRadius(),
221 findCircumscribedCost(_costmap_ros));
224 _a_star = std::make_unique<AStarAlgorithm<NodeT>>(_motion_model, _search_info);
228 _max_on_approach_iterations,
229 _terminal_checking_interval,
232 _angle_quantizations);
236 params.
get(node, name);
238 _smoother = std::make_unique<Smoother>(params);
239 _smoother->initialize(_minimum_turning_radius_global_coords);
243 _costmap_downsampler = std::make_unique<CostmapDownsampler>();
244 std::string topic_name =
"downsampled_costmap";
245 _costmap_downsampler->on_configure(
246 node, _global_frame, topic_name, _costmap, _downsampling_factor);
248 _raw_plan_publisher = node->create_publisher<nav_msgs::msg::Path>(
"unsmoothed_plan");
250 if (_debug_visualizations) {
251 _expansions_publisher = node->create_publisher<geometry_msgs::msg::PoseArray>(
"expansions");
252 _planned_footprints_publisher = node->create_publisher<visualization_msgs::msg::MarkerArray>(
253 "planned_footprints");
254 _smoothed_footprints_publisher =
255 node->create_publisher<visualization_msgs::msg::MarkerArray>(
256 "smoothed_footprints");
260 _logger,
"Configured plugin %s of type SmacPlannerHybrid with "
261 "maximum iterations %i, max on approach iterations %i, and %s. Tolerance %.2f."
262 "Using motion model: %s.",
263 _name.c_str(), _max_iterations, _max_on_approach_iterations,
264 _allow_unknown ?
"allowing unknown traversal" :
"not allowing unknown traversal",
265 _tolerance, toString(_motion_model).c_str());
268 template<
typename NodeT>
272 _logger,
"Activating plugin %s of type SmacPlannerHybrid",
274 _raw_plan_publisher->on_activate();
275 if (_debug_visualizations) {
276 _expansions_publisher->on_activate();
277 _planned_footprints_publisher->on_activate();
278 _smoothed_footprints_publisher->on_activate();
280 if (_costmap_downsampler) {
281 _costmap_downsampler->on_activate();
283 auto node = _node.lock();
285 _post_set_params_handler = node->add_post_set_parameters_callback(
288 this, std::placeholders::_1));
289 _on_set_params_handler = node->add_on_set_parameters_callback(
292 this, std::placeholders::_1));
295 auto resolution_remote_cb = [
this](
const rclcpp::Parameter & p) {
296 updateParametersCallback(
297 {rclcpp::Parameter(
"resolution", rclcpp::ParameterValue(p.as_double()))});
299 _remote_param_subscriber = std::make_shared<rclcpp::ParameterEventHandler>(_node.lock());
300 _remote_resolution_handler = _remote_param_subscriber->add_parameter_callback(
301 "resolution", resolution_remote_cb,
"global_costmap/global_costmap");
304 template<
typename NodeT>
308 _logger,
"Deactivating plugin %s of type SmacPlannerHybrid",
310 _raw_plan_publisher->on_deactivate();
311 if (_debug_visualizations) {
312 _expansions_publisher->on_deactivate();
313 _planned_footprints_publisher->on_deactivate();
314 _smoothed_footprints_publisher->on_deactivate();
316 if (_costmap_downsampler) {
317 _costmap_downsampler->on_deactivate();
320 auto node = _node.lock();
321 if (_post_set_params_handler && node) {
322 node->remove_post_set_parameters_callback(_post_set_params_handler.get());
324 _post_set_params_handler.reset();
325 if (_on_set_params_handler && node) {
326 node->remove_on_set_parameters_callback(_on_set_params_handler.get());
328 _on_set_params_handler.reset();
331 template<
typename NodeT>
335 _logger,
"Cleaning up plugin %s of type SmacPlannerHybrid",
339 if (_costmap_downsampler) {
340 _costmap_downsampler->on_cleanup();
341 _costmap_downsampler.reset();
343 _raw_plan_publisher.reset();
344 if (_debug_visualizations) {
345 _expansions_publisher.reset();
346 _planned_footprints_publisher.reset();
347 _smoothed_footprints_publisher.reset();
351 template<
typename NodeT>
353 const geometry_msgs::msg::PoseStamped & start,
354 const geometry_msgs::msg::PoseStamped & goal,
355 const std::vector<geometry_msgs::msg::PoseStamped> & viapoints,
356 std::function<
bool()> cancel_checker)
358 if (!viapoints.empty()) {
359 RCLCPP_WARN(_logger,
"Received %zu viapoints, but this planner ignores them",
363 std::lock_guard<std::mutex> lock_reinit(_mutex);
364 steady_clock::time_point a = steady_clock::now();
366 std::unique_lock<nav2_costmap_2d::Costmap2D::mutex_t> lock(*(_costmap->getMutex()));
370 if (_downsample_costmap && _downsampling_factor > 1) {
371 costmap = _costmap_downsampler->downsample(_downsampling_factor);
372 _collision_checker.setCostmap(costmap);
376 _collision_checker.setFootprint(
377 _costmap_ros->getRobotFootprint(),
378 _costmap_ros->getUseRadius(),
379 findCircumscribedCost(_costmap_ros));
380 _a_star->setCollisionChecker(&_collision_checker);
383 float mx_start, my_start, mx_goal, my_goal;
385 start.pose.position.x,
386 start.pose.position.y,
391 "Start Coordinates of(" + std::to_string(start.pose.position.x) +
", " +
392 std::to_string(start.pose.position.y) +
") was outside bounds");
395 double start_orientation_bin = std::round(tf2::getYaw(start.pose.orientation) / _angle_bin_size);
396 while (start_orientation_bin < 0.0) {
397 start_orientation_bin +=
static_cast<float>(_angle_quantizations);
400 if (start_orientation_bin >=
static_cast<float>(_angle_quantizations)) {
401 start_orientation_bin -=
static_cast<float>(_angle_quantizations);
403 unsigned int start_orientation_bin_int =
404 static_cast<unsigned int>(start_orientation_bin);
405 _a_star->setStart(mx_start, my_start, start_orientation_bin_int);
409 goal.pose.position.x,
410 goal.pose.position.y,
415 "Goal Coordinates of(" + std::to_string(goal.pose.position.x) +
", " +
416 std::to_string(goal.pose.position.y) +
") was outside bounds");
418 double goal_orientation_bin = std::round(tf2::getYaw(goal.pose.orientation) / _angle_bin_size);
419 while (goal_orientation_bin < 0.0) {
420 goal_orientation_bin +=
static_cast<float>(_angle_quantizations);
423 if (goal_orientation_bin >=
static_cast<float>(_angle_quantizations)) {
424 goal_orientation_bin -=
static_cast<float>(_angle_quantizations);
426 unsigned int goal_orientation_bin_int =
427 static_cast<unsigned int>(goal_orientation_bin);
429 mx_goal, my_goal,
static_cast<unsigned int>(goal_orientation_bin_int),
430 _goal_heading_mode, _coarse_search_resolution);
433 nav_msgs::msg::Path plan;
434 plan.header.stamp = _clock->now();
435 plan.header.frame_id = _global_frame;
436 geometry_msgs::msg::PoseStamped pose;
437 pose.header = plan.header;
438 pose.pose.position.z = 0.0;
439 pose.pose.orientation.x = 0.0;
440 pose.pose.orientation.y = 0.0;
441 pose.pose.orientation.z = 0.0;
442 pose.pose.orientation.w = 1.0;
445 if (std::floor(mx_start) == std::floor(mx_goal) &&
446 std::floor(my_start) == std::floor(my_goal) &&
447 start_orientation_bin_int == goal_orientation_bin_int)
449 pose.pose = start.pose;
450 pose.pose.orientation = goal.pose.orientation;
451 plan.poses.push_back(pose);
454 if (_raw_plan_publisher->get_subscription_count() > 0) {
455 auto msg = std::make_unique<nav_msgs::msg::Path>(plan);
456 _raw_plan_publisher->publish(std::move(msg));
463 typename NodeT::CoordinateVector path;
464 int num_iterations = 0;
466 std::unique_ptr<std::vector<std::tuple<float, float, float>>> expansions =
nullptr;
467 if (_debug_visualizations) {
468 expansions = std::make_unique<std::vector<std::tuple<float, float, float>>>();
471 if (!_a_star->createPath(
472 path, num_iterations,
473 _tolerance /
static_cast<float>(costmap->
getResolution()), cancel_checker, expansions.get()))
475 if (_debug_visualizations) {
476 auto msg = std::make_unique<geometry_msgs::msg::PoseArray>();
477 geometry_msgs::msg::Pose msg_pose;
478 msg->header.stamp = _clock->now();
479 msg->header.frame_id = _global_frame;
480 for (
auto & e : *expansions) {
481 msg_pose.position.x = std::get<0>(e);
482 msg_pose.position.y = std::get<1>(e);
483 msg_pose.orientation = getWorldOrientation(std::get<2>(e));
484 msg->poses.push_back(msg_pose);
486 _expansions_publisher->publish(std::move(msg));
490 if (num_iterations == 1) {
494 if (num_iterations < _a_star->getMaxIterations()) {
502 plan.poses.reserve(path.size());
503 for (
int i = path.size() - 1; i >= 0; --i) {
504 pose.pose = getWorldCoords(path[i].x, path[i].y, costmap);
505 pose.pose.orientation = getWorldOrientation(path[i].theta);
506 plan.poses.push_back(pose);
510 if (_raw_plan_publisher->get_subscription_count() > 0) {
511 auto msg = std::make_unique<nav_msgs::msg::Path>(plan);
512 _raw_plan_publisher->publish(std::move(msg));
515 if (_debug_visualizations) {
517 auto now = _clock->now();
518 auto msg = std::make_unique<geometry_msgs::msg::PoseArray>();
519 geometry_msgs::msg::Pose msg_pose;
520 msg->header.stamp = now;
521 msg->header.frame_id = _global_frame;
522 for (
auto & e : *expansions) {
523 msg_pose.position.x = std::get<0>(e);
524 msg_pose.position.y = std::get<1>(e);
525 msg_pose.orientation = getWorldOrientation(std::get<2>(e));
526 msg->poses.push_back(msg_pose);
528 _expansions_publisher->publish(std::move(msg));
530 if (_planned_footprints_publisher->get_subscription_count() > 0) {
532 auto marker_array = std::make_unique<visualization_msgs::msg::MarkerArray>();
533 visualization_msgs::msg::Marker clear_all_marker;
534 clear_all_marker.action = visualization_msgs::msg::Marker::DELETEALL;
535 marker_array->markers.push_back(clear_all_marker);
536 _planned_footprints_publisher->publish(std::move(marker_array));
539 marker_array = std::make_unique<visualization_msgs::msg::MarkerArray>();
540 for (
size_t i = 0; i < plan.poses.size(); i++) {
541 const std::vector<geometry_msgs::msg::Point> edge =
542 transformFootprintToEdges(plan.poses[i].pose, _costmap_ros->getRobotFootprint());
543 marker_array->markers.push_back(createMarker(edge, i, _global_frame, now));
545 _planned_footprints_publisher->publish(std::move(marker_array));
550 steady_clock::time_point b = steady_clock::now();
551 duration<double> time_span = duration_cast<duration<double>>(b - a);
552 double time_remaining = _max_planning_time -
static_cast<double>(time_span.count());
554 #ifdef BENCHMARK_TESTING
555 std::cout <<
"It took " << time_span.count() * 1000 <<
556 " milliseconds with " << num_iterations <<
" iterations." << std::endl;
560 if (_smoother && num_iterations > 1) {
565 _costmap_ros->getUseRadius() ? std::vector<geometry_msgs::msg::Point>() :
566 _costmap_ros->getRobotFootprint());
569 #ifdef BENCHMARK_TESTING
570 steady_clock::time_point c = steady_clock::now();
571 duration<double> time_span2 = duration_cast<duration<double>>(c - b);
572 std::cout <<
"It took " << time_span2.count() * 1000 <<
573 " milliseconds to smooth path." << std::endl;
576 if (_debug_visualizations) {
577 if (_smoothed_footprints_publisher->get_subscription_count() > 0) {
579 auto marker_array = std::make_unique<visualization_msgs::msg::MarkerArray>();
580 visualization_msgs::msg::Marker clear_all_marker;
581 clear_all_marker.action = visualization_msgs::msg::Marker::DELETEALL;
582 marker_array->markers.push_back(clear_all_marker);
583 _smoothed_footprints_publisher->publish(std::move(marker_array));
586 marker_array = std::make_unique<visualization_msgs::msg::MarkerArray>();
587 auto now = _clock->now();
588 for (
size_t i = 0; i < plan.poses.size(); i++) {
589 const std::vector<geometry_msgs::msg::Point> edge =
590 transformFootprintToEdges(plan.poses[i].pose, _costmap_ros->getRobotFootprint());
591 marker_array->markers.push_back(createMarker(edge, i, _global_frame, now));
593 _smoothed_footprints_publisher->publish(std::move(marker_array));
600 template<
typename NodeT>
601 rcl_interfaces::msg::SetParametersResult
603 const std::vector<rclcpp::Parameter> & parameters)
605 rcl_interfaces::msg::SetParametersResult result;
606 result.successful =
true;
607 for (
const auto & parameter : parameters) {
608 const auto & param_type = parameter.get_type();
609 const auto & param_name = parameter.get_name();
610 if (param_name.find(_name +
".") != 0) {
613 if (param_type == ParameterType::PARAMETER_DOUBLE) {
614 if (parameter.as_double() < 0.0) {
616 _logger,
"The value of parameter '%s' is incorrectly set to %f, "
617 "it should be >=0. Ignoring parameter update.",
618 param_name.c_str(), parameter.as_double());
619 result.successful =
false;
620 }
else if (param_name == _name +
".minimum_turning_radius" &&
621 parameter.as_double() < _costmap->getResolution() * _downsampling_factor)
624 _logger,
"The value of parameter minimum_turning_radius is incorrectly set to %f, "
625 "it should be >= costmap resolution * downsampling factor (%f). "
626 "Ignoring parameter update.",
627 parameter.as_double(),
628 _costmap->getResolution() * _downsampling_factor);
629 result.successful =
false;
631 }
else if (param_type == ParameterType::PARAMETER_INTEGER) {
632 if (parameter.as_int() <= 0 && (param_name != _name +
".max_on_approach_iterations" &&
633 param_name != _name +
".max_iterations"))
636 _logger,
"The value of parameter '%s' is incorrectly set to %ld, "
637 "it should be >0. Ignoring parameter update.",
638 param_name.c_str(), parameter.as_int());
639 result.successful =
false;
640 }
else if (param_name == _name +
".angle_quantization_bins") {
641 unsigned int angle_quantizations =
static_cast<unsigned int>(parameter.as_int());
642 if (angle_quantizations % _coarse_search_resolution != 0) {
645 "The value of parameter angle_quantization_bins is incorrectly set to %u, "
646 "it should be an increment of the coarse_search_resolution (%u). "
647 "Ignoring parameter update.",
649 _coarse_search_resolution);
650 result.successful =
false;
652 }
else if (param_name == _name +
".coarse_search_resolution") {
653 if (_angle_quantizations %
static_cast<unsigned int>(parameter.as_int()) != 0) {
656 "The value of parameter coarse_search_resolution is incorrectly set to %ld, "
657 "it should be an increment of the angle_quantization_bins (%u). "
658 "Ignoring parameter update.",
660 _angle_quantizations);
661 result.successful =
false;
664 }
else if (param_type == ParameterType::PARAMETER_STRING) {
665 if (param_name == _name +
".motion_model_for_search") {
666 MotionModel motion_model = fromString(parameter.as_string());
667 if (motion_model == MotionModel::UNKNOWN) {
670 "Unable to get MotionModel search type. Given '%s', "
671 "valid options are MOORE, VON_NEUMANN, DUBIN, REEDS_SHEPP, STATE_LATTICE. "
672 "Ignoring parameter update.",
673 parameter.as_string().c_str());
674 result.successful =
false;
676 }
else if (param_name == _name +
".goal_heading_mode") {
677 GoalHeadingMode goal_heading_mode = fromStringToGH(parameter.as_string());
678 if (goal_heading_mode == GoalHeadingMode::UNKNOWN) {
681 "Unable to get GoalHeader type. Given '%s' Valid options are DEFAULT, "
682 "BIDIRECTIONAL, ALL_DIRECTION. Ignoring parameter update.",
683 parameter.as_string().c_str());
684 result.successful =
false;
692 template<
typename NodeT>
695 const std::vector<rclcpp::Parameter> & parameters)
697 std::lock_guard<std::mutex> lock_reinit(_mutex);
699 bool reinit_collision_checker =
false;
700 bool reinit_a_star =
false;
701 bool reinit_lookup_table =
false;
702 bool reinit_downsampler =
false;
703 bool reinit_smoother =
false;
705 for (
auto parameter : parameters) {
706 const auto & param_type = parameter.get_type();
707 const auto & param_name = parameter.get_name();
708 if (param_name.find(_name +
".") != 0 && param_name !=
"resolution") {
711 if (param_type == ParameterType::PARAMETER_DOUBLE) {
712 if (param_name == _name +
".max_planning_time") {
713 reinit_a_star =
true;
714 _max_planning_time = parameter.as_double();
715 }
else if (param_name == _name +
".tolerance") {
716 _tolerance =
static_cast<float>(parameter.as_double());
717 }
else if (param_name == _name +
".lookup_table_size") {
718 reinit_a_star =
true;
719 reinit_lookup_table =
true;
720 _lookup_table_size = parameter.as_double();
721 }
else if (param_name == _name +
".minimum_turning_radius") {
722 reinit_a_star =
true;
723 reinit_lookup_table =
true;
725 reinit_smoother =
true;
727 _minimum_turning_radius_global_coords =
static_cast<float>(parameter.as_double());
728 }
else if (param_name == _name +
".reverse_penalty") {
729 reinit_a_star =
true;
730 _search_info.reverse_penalty =
static_cast<float>(parameter.as_double());
731 }
else if (param_name == _name +
".change_penalty") {
732 reinit_a_star =
true;
733 _search_info.change_penalty =
static_cast<float>(parameter.as_double());
734 }
else if (param_name == _name +
".non_straight_penalty") {
735 reinit_a_star =
true;
736 _search_info.non_straight_penalty =
static_cast<float>(parameter.as_double());
737 }
else if (param_name == _name +
".cost_penalty") {
738 reinit_a_star =
true;
739 _search_info.cost_penalty =
static_cast<float>(parameter.as_double());
740 }
else if (param_name == _name +
".analytic_expansion_ratio") {
741 reinit_a_star =
true;
742 _search_info.analytic_expansion_ratio =
static_cast<float>(parameter.as_double());
743 }
else if (param_name == _name +
".analytic_expansion_max_length") {
744 reinit_a_star =
true;
745 _search_info.analytic_expansion_max_length =
746 static_cast<float>(parameter.as_double()) / _costmap->getResolution();
747 }
else if (param_name == _name +
".analytic_expansion_max_cost") {
748 reinit_a_star =
true;
749 _search_info.analytic_expansion_max_cost =
static_cast<float>(parameter.as_double());
750 }
else if (param_name ==
"resolution") {
753 RCLCPP_INFO(_logger,
"Costmap resolution changed. Reinitializing SmacPlannerHybrid.");
754 reinit_collision_checker =
true;
755 reinit_a_star =
true;
756 reinit_lookup_table =
true;
757 reinit_downsampler =
true;
758 reinit_smoother =
true;
760 }
else if (param_type == ParameterType::PARAMETER_BOOL) {
761 if (param_name == _name +
".downsample_costmap") {
762 reinit_downsampler =
true;
763 _downsample_costmap = parameter.as_bool();
764 }
else if (param_name == _name +
".allow_unknown") {
765 reinit_a_star =
true;
766 _allow_unknown = parameter.as_bool();
767 }
else if (param_name == _name +
".cache_obstacle_heuristic") {
768 reinit_a_star =
true;
769 _search_info.cache_obstacle_heuristic = parameter.as_bool();
770 }
else if (param_name == _name +
".allow_primitive_interpolation") {
771 _search_info.allow_primitive_interpolation = parameter.as_bool();
772 reinit_a_star =
true;
773 }
else if (param_name == _name +
".smooth_path") {
774 if (parameter.as_bool()) {
775 reinit_smoother =
true;
779 }
else if (param_name == _name +
".analytic_expansion_max_cost_override") {
780 _search_info.analytic_expansion_max_cost_override = parameter.as_bool();
781 reinit_a_star =
true;
783 }
else if (param_type == ParameterType::PARAMETER_INTEGER) {
784 if (param_name == _name +
".downsampling_factor") {
785 reinit_a_star =
true;
786 reinit_lookup_table =
true;
787 reinit_downsampler =
true;
788 _downsampling_factor = parameter.as_int();
789 }
else if (param_name == _name +
".max_iterations") {
790 reinit_a_star =
true;
791 _max_iterations = parameter.as_int();
792 if (_max_iterations <= 0) {
794 _logger,
"maximum iteration selected as <= 0, "
795 "disabling maximum iterations.");
796 _max_iterations = std::numeric_limits<int>::max();
798 }
else if (param_name == _name +
".max_on_approach_iterations") {
799 reinit_a_star =
true;
800 _max_on_approach_iterations = parameter.as_int();
801 if (_max_on_approach_iterations <= 0) {
803 _logger,
"On approach iteration selected as <= 0, "
804 "disabling tolerance and on approach iterations.");
805 _max_on_approach_iterations = std::numeric_limits<int>::max();
807 }
else if (param_name == _name +
".terminal_checking_interval") {
808 reinit_a_star =
true;
809 _terminal_checking_interval = parameter.as_int();
810 }
else if (param_name == _name +
".angle_quantization_bins") {
811 reinit_collision_checker =
true;
812 reinit_a_star =
true;
813 reinit_lookup_table =
true;
814 int angle_quantizations = parameter.as_int();
815 _angle_bin_size = 2.0 * M_PI / angle_quantizations;
816 _angle_quantizations =
static_cast<unsigned int>(angle_quantizations);
817 }
else if (param_name == _name +
".coarse_search_resolution") {
818 _coarse_search_resolution = parameter.as_int();
820 }
else if (param_type == ParameterType::PARAMETER_STRING) {
821 if (param_name == _name +
".motion_model_for_search") {
822 reinit_a_star =
true;
823 reinit_lookup_table =
true;
824 _motion_model = fromString(parameter.as_string());
825 }
else if (param_name == _name +
".goal_heading_mode") {
826 std::string goal_heading_type = parameter.as_string();
827 GoalHeadingMode goal_heading_mode = fromStringToGH(goal_heading_type);
830 "GoalHeadingMode type set to '%s'.",
831 goal_heading_type.c_str());
832 _goal_heading_mode = goal_heading_mode;
838 if (reinit_a_star || reinit_downsampler || reinit_collision_checker || reinit_smoother) {
840 if (!_downsample_costmap) {
841 _downsampling_factor = 1;
843 _search_info.minimum_turning_radius =
844 _minimum_turning_radius_global_coords / (_costmap->getResolution() * _downsampling_factor);
846 static_cast<float>(_lookup_table_size) /
847 static_cast<float>(_costmap->getResolution() * _downsampling_factor);
850 _lookup_table_dim =
static_cast<float>(
static_cast<int>(_lookup_table_dim));
853 if (
static_cast<int>(_lookup_table_dim) % 2 == 0) {
856 "Even sized heuristic lookup table size set %f, increasing size by 1 to make odd",
858 _lookup_table_dim += 1.0;
861 auto node = _node.lock();
865 if (reinit_lookup_table) {
866 _a_star = std::make_unique<AStarAlgorithm<NodeT>>(_motion_model, _search_info);
868 _a_star->setSearchInfo(_search_info);
873 _max_on_approach_iterations,
874 _terminal_checking_interval,
877 _angle_quantizations);
881 if (reinit_downsampler) {
882 if (_downsample_costmap && _downsampling_factor > 1) {
883 std::string topic_name =
"downsampled_costmap";
884 _costmap_downsampler = std::make_unique<CostmapDownsampler>();
885 _costmap_downsampler->on_configure(
886 node, _global_frame, topic_name, _costmap, _downsampling_factor);
887 _costmap_downsampler->on_activate();
892 if (reinit_collision_checker) {
894 _collision_checker.setFootprint(
895 _costmap_ros->getRobotFootprint(),
896 _costmap_ros->getUseRadius(),
897 findCircumscribedCost(_costmap_ros));
901 if (reinit_smoother) {
903 params.
get(node, _name);
904 _smoother = std::make_unique<Smoother>(params);
905 _smoother->initialize(_minimum_turning_radius_global_coords);
A 2D costmap provides a mapping between points in the world and their associated "costs".
double getResolution() const
Accessor for the resolution of the costmap.
bool worldToMapContinuous(double wx, double wy, float &mx, float &my) const
Convert from world coordinates to map coordinates.
A costmap grid collision checker.
A templated hybrid-A* planner that allows custom node types.
void activate() override
Activate lifecycle node.
void deactivate() override
Deactivate lifecycle node.
void cleanup() override
Cleanup lifecycle node.
rcl_interfaces::msg::SetParametersResult validateParameterUpdatesCallback(const std::vector< rclcpp::Parameter > ¶meters)
Validate incoming parameter updates before applying them. This callback is triggered when one or more...
SmacPlannerHybridT()
constructor
~SmacPlannerHybridT()
destructor
void configure(const nav2::LifecycleNode::WeakPtr &parent, std::string name, nav2::TransformBuffer::SharedPtr tf, std::shared_ptr< nav2_costmap_2d::Costmap2DROS > costmap_ros) override
Configuring plugin.
nav_msgs::msg::Path createPlan(const geometry_msgs::msg::PoseStamped &start, const geometry_msgs::msg::PoseStamped &goal, const std::vector< geometry_msgs::msg::PoseStamped > &viapoints, std::function< bool()> cancel_checker) override
Creating a plan from start and goal poses.
void updateParametersCallback(const std::vector< rclcpp::Parameter > ¶meters)
Apply parameter updates after validation This callback is executed when parameters have been successf...
Parameters for the smoother cost function.
void get(nav2::LifecycleNode::SharedPtr node, const std::string &name)
Get params from ROS parameter.