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;
79 _downsample_costmap = node->declare_or_get_parameter(name +
".downsample_costmap",
false);
80 _downsampling_factor = node->declare_or_get_parameter(name +
".downsampling_factor", 1);
82 angle_quantizations = node->declare_or_get_parameter(name +
".angle_quantization_bins", 72);
83 _angle_bin_size = 2.0 * M_PI / angle_quantizations;
84 _angle_quantizations =
static_cast<unsigned int>(angle_quantizations);
86 _tolerance =
static_cast<float>(node->declare_or_get_parameter(name +
".tolerance", 0.25));
87 _allow_unknown = node->declare_or_get_parameter(name +
".allow_unknown",
true);
88 _max_iterations = node->declare_or_get_parameter(name +
".max_iterations", 1000000);
89 _max_on_approach_iterations =
90 node->declare_or_get_parameter(name +
".max_on_approach_iterations", 1000);
91 _terminal_checking_interval =
92 node->declare_or_get_parameter(name +
".terminal_checking_interval", 5000);
93 smooth_path = node->declare_or_get_parameter(name +
".smooth_path",
true);
95 _minimum_turning_radius_global_coords =
96 node->declare_or_get_parameter(name +
".minimum_turning_radius", 0.4);
97 _search_info.allow_primitive_interpolation =
98 node->declare_or_get_parameter(name +
".allow_primitive_interpolation",
true);
99 _search_info.cache_obstacle_heuristic =
100 node->declare_or_get_parameter(name +
".cache_obstacle_heuristic",
false);
101 _search_info.reverse_penalty =
102 node->declare_or_get_parameter(name +
".reverse_penalty", 2.0);
103 _search_info.change_penalty =
104 node->declare_or_get_parameter(name +
".change_penalty", 0.0);
105 _search_info.non_straight_penalty =
106 node->declare_or_get_parameter(name +
".non_straight_penalty", 1.2);
107 _search_info.cost_penalty =
108 node->declare_or_get_parameter(name +
".cost_penalty", 2.0);
109 _search_info.retrospective_penalty =
110 node->declare_or_get_parameter(name +
".retrospective_penalty", 0.015);
111 _search_info.analytic_expansion_ratio =
112 node->declare_or_get_parameter(name +
".analytic_expansion_ratio", 3.5);
113 _search_info.analytic_expansion_max_cost =
114 node->declare_or_get_parameter(name +
".analytic_expansion_max_cost", 200.0);
115 _search_info.analytic_expansion_max_cost_override =
116 node->declare_or_get_parameter(name +
".analytic_expansion_max_cost_override",
false);
117 _search_info.use_quadratic_cost_penalty =
118 node->declare_or_get_parameter(name +
".use_quadratic_cost_penalty",
false);
119 _search_info.downsample_obstacle_heuristic =
120 node->declare_or_get_parameter(name +
".downsample_obstacle_heuristic",
true);
122 _analytic_expansion_max_length_m =
123 node->declare_or_get_parameter(name +
".analytic_expansion_max_length", 3.0);
125 _max_planning_time = node->declare_or_get_parameter(name +
".max_planning_time", 5.0);
126 _lookup_table_size = node->declare_or_get_parameter(name +
".lookup_table_size", 20.0);
128 _debug_visualizations = node->declare_or_get_parameter(name +
".debug_visualizations",
false);
130 _motion_model_for_search =
131 node->declare_or_get_parameter(name +
".motion_model_for_search", std::string(
"DUBIN"));
133 std::string goal_heading_type =
134 node->declare_or_get_parameter(name +
".goal_heading_mode", std::string(
"DEFAULT"));
135 _goal_heading_mode = fromStringToGH(goal_heading_type);
137 _coarse_search_resolution =
138 node->declare_or_get_parameter(name +
".coarse_search_resolution", 1);
140 if (_goal_heading_mode == GoalHeadingMode::UNKNOWN) {
141 std::string error_msg =
"Unable to get GoalHeader type. Given '" + goal_heading_type +
"' "
142 "Valid options are DEFAULT, BIDIRECTIONAL, ALL_DIRECTION. ";
146 _motion_model = fromString(_motion_model_for_search);
148 if (_motion_model == MotionModel::UNKNOWN) {
151 "Unable to get MotionModel search type. Given '%s', "
152 "valid options are MOORE, VON_NEUMANN, DUBIN, REEDS_SHEPP, STATE_LATTICE.",
153 _motion_model_for_search.c_str());
156 if (_max_on_approach_iterations <= 0) {
158 _logger,
"On approach iteration selected as <= 0, "
159 "disabling tolerance and on approach iterations.");
160 _max_on_approach_iterations = std::numeric_limits<int>::max();
163 if (_max_iterations <= 0) {
165 _logger,
"maximum iteration selected as <= 0, "
166 "disabling maximum iterations.");
167 _max_iterations = std::numeric_limits<int>::max();
170 if (_coarse_search_resolution <= 0) {
172 _logger,
"coarse iteration resolution selected as <= 0, "
173 "disabling coarse iteration resolution search for goal heading"
176 _coarse_search_resolution = 1;
179 if (angle_quantizations <= 0 || angle_quantizations > 1024) {
180 std::string error_msg =
"angle_quantization_bins must be in [1, 1024]";
184 if (_angle_quantizations % _coarse_search_resolution != 0) {
185 std::string error_msg =
"coarse iteration should be an increment"
186 " of the number of angular bins configured";
190 if (_analytic_expansion_max_length_m < 0.0 ||
191 _analytic_expansion_max_length_m > 1000.0)
193 std::string error_msg =
"analytic_expansion_max_length must be in [0.0, 1000.0]";
197 if (_lookup_table_size < 0.0 || _lookup_table_size > 20.0) {
198 std::string error_msg =
"lookup_table_size must be in [0.0, 20.0]";
202 if (_minimum_turning_radius_global_coords < _costmap->getResolution() * _downsampling_factor) {
204 _logger,
"Min turning radius cannot be less than the search grid cell resolution!");
205 _minimum_turning_radius_global_coords = _costmap->getResolution() * _downsampling_factor;
209 if (!_downsample_costmap) {
210 _downsampling_factor = 1;
212 updateSearchResolution(_costmap->getResolution() * _downsampling_factor);
216 _collision_checker.setFootprint(
217 _costmap_ros->getRobotFootprint(),
218 _costmap_ros->getUseRadius(),
219 findCircumscribedCost(_costmap_ros));
222 _a_star = std::make_unique<AStarAlgorithm<NodeT>>(_motion_model, _search_info);
226 _max_on_approach_iterations,
227 _terminal_checking_interval,
230 _angle_quantizations);
234 params.
get(node, name);
236 _smoother = std::make_unique<Smoother>(params);
237 _smoother->initialize(_minimum_turning_radius_global_coords);
241 _costmap_downsampler = std::make_unique<CostmapDownsampler>();
242 std::string topic_name =
"downsampled_costmap";
243 _costmap_downsampler->on_configure(
244 node, _global_frame, topic_name, _costmap, _downsampling_factor);
246 _raw_plan_publisher = node->create_publisher<nav_msgs::msg::Path>(
"unsmoothed_plan");
248 if (_debug_visualizations) {
249 _expansions_publisher = node->create_publisher<geometry_msgs::msg::PoseArray>(
"expansions");
250 _planned_footprints_publisher = node->create_publisher<visualization_msgs::msg::MarkerArray>(
251 "planned_footprints");
252 _smoothed_footprints_publisher =
253 node->create_publisher<visualization_msgs::msg::MarkerArray>(
254 "smoothed_footprints");
258 _logger,
"Configured plugin %s of type SmacPlannerHybrid with "
259 "maximum iterations %i, max on approach iterations %i, and %s. Tolerance %.2f."
260 "Using motion model: %s.",
261 _name.c_str(), _max_iterations, _max_on_approach_iterations,
262 _allow_unknown ?
"allowing unknown traversal" :
"not allowing unknown traversal",
263 _tolerance, toString(_motion_model).c_str());
266 template<
typename NodeT>
270 _logger,
"Activating plugin %s of type SmacPlannerHybrid",
272 _raw_plan_publisher->on_activate();
273 if (_debug_visualizations) {
274 _expansions_publisher->on_activate();
275 _planned_footprints_publisher->on_activate();
276 _smoothed_footprints_publisher->on_activate();
278 if (_costmap_downsampler) {
279 _costmap_downsampler->on_activate();
281 auto node = _node.lock();
283 _post_set_params_handler = node->add_post_set_parameters_callback(
286 this, std::placeholders::_1));
287 _on_set_params_handler = node->add_on_set_parameters_callback(
290 this, std::placeholders::_1));
293 template<
typename NodeT>
297 _logger,
"Deactivating plugin %s of type SmacPlannerHybrid",
299 _raw_plan_publisher->on_deactivate();
300 if (_debug_visualizations) {
301 _expansions_publisher->on_deactivate();
302 _planned_footprints_publisher->on_deactivate();
303 _smoothed_footprints_publisher->on_deactivate();
305 if (_costmap_downsampler) {
306 _costmap_downsampler->on_deactivate();
309 auto node = _node.lock();
310 if (_post_set_params_handler && node) {
311 node->remove_post_set_parameters_callback(_post_set_params_handler.get());
313 _post_set_params_handler.reset();
314 if (_on_set_params_handler && node) {
315 node->remove_on_set_parameters_callback(_on_set_params_handler.get());
317 _on_set_params_handler.reset();
320 template<
typename NodeT>
324 _logger,
"Cleaning up plugin %s of type SmacPlannerHybrid",
328 if (_costmap_downsampler) {
329 _costmap_downsampler->on_cleanup();
330 _costmap_downsampler.reset();
332 _raw_plan_publisher.reset();
333 if (_debug_visualizations) {
334 _expansions_publisher.reset();
335 _planned_footprints_publisher.reset();
336 _smoothed_footprints_publisher.reset();
340 template<
typename NodeT>
343 _search_resolution = resolution;
344 _search_info.minimum_turning_radius =
345 std::max(_minimum_turning_radius_global_coords / resolution, 1.0);
346 _search_info.analytic_expansion_max_length = _analytic_expansion_max_length_m / resolution;
348 static_cast<float>(_lookup_table_size) /
349 static_cast<float>(resolution);
352 _lookup_table_dim =
static_cast<float>(
static_cast<int>(_lookup_table_dim));
355 if (
static_cast<int>(_lookup_table_dim) % 2 == 0) {
358 "Even sized heuristic lookup table size set %f, increasing size by 1 to make odd",
360 _lookup_table_dim += 1.0;
364 template<
typename NodeT>
366 const geometry_msgs::msg::PoseStamped & start,
367 const geometry_msgs::msg::PoseStamped & goal,
368 const std::vector<geometry_msgs::msg::PoseStamped> & viapoints,
369 std::function<
bool()> cancel_checker)
371 if (!viapoints.empty()) {
372 RCLCPP_WARN(_logger,
"Received %zu viapoints, but this planner ignores them",
376 std::lock_guard<std::mutex> lock_reinit(_mutex);
377 steady_clock::time_point a = steady_clock::now();
379 std::unique_lock<nav2_costmap_2d::Costmap2D::mutex_t> lock(*(_costmap->getMutex()));
383 if (_downsample_costmap && _downsampling_factor > 1) {
384 costmap = _costmap_downsampler->downsample(_downsampling_factor);
392 _a_star = std::make_unique<AStarAlgorithm<NodeT>>(_motion_model, _search_info);
394 _allow_unknown, _max_iterations, _max_on_approach_iterations,
395 _terminal_checking_interval, _max_planning_time, _lookup_table_dim,
396 _angle_quantizations);
398 _collision_checker.setCostmap(costmap);
401 _collision_checker.setFootprint(
402 _costmap_ros->getRobotFootprint(),
403 _costmap_ros->getUseRadius(),
404 findCircumscribedCost(_costmap_ros));
405 _a_star->setCollisionChecker(&_collision_checker);
408 float mx_start, my_start, mx_goal, my_goal;
410 start.pose.position.x,
411 start.pose.position.y,
416 "Start Coordinates of(" + std::to_string(start.pose.position.x) +
", " +
417 std::to_string(start.pose.position.y) +
") was outside bounds");
420 double start_orientation_bin = std::round(tf2::getYaw(start.pose.orientation) / _angle_bin_size);
421 while (start_orientation_bin < 0.0) {
422 start_orientation_bin +=
static_cast<float>(_angle_quantizations);
425 if (start_orientation_bin >=
static_cast<float>(_angle_quantizations)) {
426 start_orientation_bin -=
static_cast<float>(_angle_quantizations);
428 unsigned int start_orientation_bin_int =
429 static_cast<unsigned int>(start_orientation_bin);
430 _a_star->setStart(mx_start, my_start, start_orientation_bin_int);
434 goal.pose.position.x,
435 goal.pose.position.y,
440 "Goal Coordinates of(" + std::to_string(goal.pose.position.x) +
", " +
441 std::to_string(goal.pose.position.y) +
") was outside bounds");
443 double goal_orientation_bin = std::round(tf2::getYaw(goal.pose.orientation) / _angle_bin_size);
444 while (goal_orientation_bin < 0.0) {
445 goal_orientation_bin +=
static_cast<float>(_angle_quantizations);
448 if (goal_orientation_bin >=
static_cast<float>(_angle_quantizations)) {
449 goal_orientation_bin -=
static_cast<float>(_angle_quantizations);
451 unsigned int goal_orientation_bin_int =
452 static_cast<unsigned int>(goal_orientation_bin);
454 mx_goal, my_goal,
static_cast<unsigned int>(goal_orientation_bin_int),
455 _goal_heading_mode, _coarse_search_resolution);
458 nav_msgs::msg::Path plan;
459 plan.header.stamp = _clock->now();
460 plan.header.frame_id = _global_frame;
461 geometry_msgs::msg::PoseStamped pose;
462 pose.header = plan.header;
463 pose.pose.position.z = 0.0;
464 pose.pose.orientation.x = 0.0;
465 pose.pose.orientation.y = 0.0;
466 pose.pose.orientation.z = 0.0;
467 pose.pose.orientation.w = 1.0;
470 if (std::floor(mx_start) == std::floor(mx_goal) &&
471 std::floor(my_start) == std::floor(my_goal) &&
472 start_orientation_bin_int == goal_orientation_bin_int)
474 pose.pose = start.pose;
475 pose.pose.orientation = goal.pose.orientation;
476 plan.poses.push_back(pose);
479 if (_raw_plan_publisher->get_subscription_count() > 0) {
480 auto msg = std::make_unique<nav_msgs::msg::Path>(plan);
481 _raw_plan_publisher->publish(std::move(msg));
488 typename NodeT::CoordinateVector path;
489 int num_iterations = 0;
491 std::unique_ptr<std::vector<std::tuple<float, float, float>>> expansions =
nullptr;
492 if (_debug_visualizations) {
493 expansions = std::make_unique<std::vector<std::tuple<float, float, float>>>();
496 if (!_a_star->createPath(
497 path, num_iterations,
498 _tolerance /
static_cast<float>(costmap->
getResolution()), cancel_checker, expansions.get()))
500 if (_debug_visualizations) {
501 auto msg = std::make_unique<geometry_msgs::msg::PoseArray>();
502 geometry_msgs::msg::Pose msg_pose;
503 msg->header.stamp = _clock->now();
504 msg->header.frame_id = _global_frame;
505 for (
auto & e : *expansions) {
506 msg_pose.position.x = std::get<0>(e);
507 msg_pose.position.y = std::get<1>(e);
508 msg_pose.orientation = getWorldOrientation(std::get<2>(e));
509 msg->poses.push_back(msg_pose);
511 _expansions_publisher->publish(std::move(msg));
515 if (num_iterations == 1) {
519 if (num_iterations < _a_star->getMaxIterations()) {
527 plan.poses.reserve(path.size());
528 for (
int i = path.size() - 1; i >= 0; --i) {
529 pose.pose = getWorldCoords(path[i].x, path[i].y, costmap);
530 pose.pose.orientation = getWorldOrientation(path[i].theta);
531 plan.poses.push_back(pose);
535 if (_raw_plan_publisher->get_subscription_count() > 0) {
536 auto msg = std::make_unique<nav_msgs::msg::Path>(plan);
537 _raw_plan_publisher->publish(std::move(msg));
540 if (_debug_visualizations) {
542 auto now = _clock->now();
543 auto msg = std::make_unique<geometry_msgs::msg::PoseArray>();
544 geometry_msgs::msg::Pose msg_pose;
545 msg->header.stamp = now;
546 msg->header.frame_id = _global_frame;
547 for (
auto & e : *expansions) {
548 msg_pose.position.x = std::get<0>(e);
549 msg_pose.position.y = std::get<1>(e);
550 msg_pose.orientation = getWorldOrientation(std::get<2>(e));
551 msg->poses.push_back(msg_pose);
553 _expansions_publisher->publish(std::move(msg));
555 if (_planned_footprints_publisher->get_subscription_count() > 0) {
557 auto marker_array = std::make_unique<visualization_msgs::msg::MarkerArray>();
558 visualization_msgs::msg::Marker clear_all_marker;
559 clear_all_marker.action = visualization_msgs::msg::Marker::DELETEALL;
560 marker_array->markers.push_back(clear_all_marker);
561 _planned_footprints_publisher->publish(std::move(marker_array));
564 marker_array = std::make_unique<visualization_msgs::msg::MarkerArray>();
565 for (
size_t i = 0; i < plan.poses.size(); i++) {
566 const std::vector<geometry_msgs::msg::Point> edge =
567 transformFootprintToEdges(plan.poses[i].pose, _costmap_ros->getRobotFootprint());
568 marker_array->markers.push_back(createMarker(edge, i, _global_frame, now));
570 _planned_footprints_publisher->publish(std::move(marker_array));
575 steady_clock::time_point b = steady_clock::now();
576 duration<double> time_span = duration_cast<duration<double>>(b - a);
577 double time_remaining = _max_planning_time -
static_cast<double>(time_span.count());
579 #ifdef BENCHMARK_TESTING
580 std::cout <<
"It took " << time_span.count() * 1000 <<
581 " milliseconds with " << num_iterations <<
" iterations." << std::endl;
585 if (_smoother && num_iterations > 1) {
590 _costmap_ros->getUseRadius() ? std::vector<geometry_msgs::msg::Point>() :
591 _costmap_ros->getRobotFootprint());
594 #ifdef BENCHMARK_TESTING
595 steady_clock::time_point c = steady_clock::now();
596 duration<double> time_span2 = duration_cast<duration<double>>(c - b);
597 std::cout <<
"It took " << time_span2.count() * 1000 <<
598 " milliseconds to smooth path." << std::endl;
601 if (_debug_visualizations) {
602 if (_smoothed_footprints_publisher->get_subscription_count() > 0) {
604 auto marker_array = std::make_unique<visualization_msgs::msg::MarkerArray>();
605 visualization_msgs::msg::Marker clear_all_marker;
606 clear_all_marker.action = visualization_msgs::msg::Marker::DELETEALL;
607 marker_array->markers.push_back(clear_all_marker);
608 _smoothed_footprints_publisher->publish(std::move(marker_array));
611 marker_array = std::make_unique<visualization_msgs::msg::MarkerArray>();
612 auto now = _clock->now();
613 for (
size_t i = 0; i < plan.poses.size(); i++) {
614 const std::vector<geometry_msgs::msg::Point> edge =
615 transformFootprintToEdges(plan.poses[i].pose, _costmap_ros->getRobotFootprint());
616 marker_array->markers.push_back(createMarker(edge, i, _global_frame, now));
618 _smoothed_footprints_publisher->publish(std::move(marker_array));
625 template<
typename NodeT>
626 rcl_interfaces::msg::SetParametersResult
628 const std::vector<rclcpp::Parameter> & parameters)
630 rcl_interfaces::msg::SetParametersResult result;
631 result.successful =
true;
632 for (
const auto & parameter : parameters) {
633 const auto & param_type = parameter.get_type();
634 const auto & param_name = parameter.get_name();
635 if (param_name.find(_name +
".") != 0) {
638 if (param_type == ParameterType::PARAMETER_DOUBLE) {
639 if (parameter.as_double() < 0.0) {
641 _logger,
"The value of parameter '%s' is incorrectly set to %f, "
642 "it should be >=0. Ignoring parameter update.",
643 param_name.c_str(), parameter.as_double());
644 result.successful =
false;
645 }
else if (param_name == _name +
".lookup_table_size" &&
646 parameter.as_double() > 20.0)
649 _logger,
"The value of parameter lookup_table_size is incorrectly set to %f, "
650 "it should be in [0.0, 20.0]. Ignoring parameter update.",
651 parameter.as_double());
652 result.successful =
false;
653 }
else if (param_name == _name +
".analytic_expansion_max_length" &&
654 parameter.as_double() > 1000.0)
657 _logger,
"The value of parameter analytic_expansion_max_length is incorrectly set "
658 "to %f, it should be <= 1000.0. Ignoring parameter update.",
659 parameter.as_double());
660 result.successful =
false;
661 }
else if (param_name == _name +
".minimum_turning_radius" &&
662 parameter.as_double() < _costmap->getResolution() * _downsampling_factor)
665 _logger,
"The value of parameter minimum_turning_radius is incorrectly set to %f, "
666 "it should be >= costmap resolution * downsampling factor (%f). "
667 "Ignoring parameter update.",
668 parameter.as_double(),
669 _costmap->getResolution() * _downsampling_factor);
670 result.successful =
false;
672 }
else if (param_type == ParameterType::PARAMETER_INTEGER) {
673 if (parameter.as_int() <= 0 && (param_name != _name +
".max_on_approach_iterations" &&
674 param_name != _name +
".max_iterations"))
677 _logger,
"The value of parameter '%s' is incorrectly set to %ld, "
678 "it should be >0. Ignoring parameter update.",
679 param_name.c_str(), parameter.as_int());
680 result.successful =
false;
681 }
else if (param_name == _name +
".angle_quantization_bins") {
682 unsigned int angle_quantizations =
static_cast<unsigned int>(parameter.as_int());
683 if (angle_quantizations > 1024) {
686 "The value of parameter angle_quantization_bins is incorrectly set to %u, "
687 "it should be <= 1024. Ignoring parameter update.",
688 angle_quantizations);
689 result.successful =
false;
690 }
else if (angle_quantizations % _coarse_search_resolution != 0) {
693 "The value of parameter angle_quantization_bins is incorrectly set to %u, "
694 "it should be an increment of the coarse_search_resolution (%u). "
695 "Ignoring parameter update.",
697 _coarse_search_resolution);
698 result.successful =
false;
700 }
else if (param_name == _name +
".coarse_search_resolution") {
701 if (_angle_quantizations %
static_cast<unsigned int>(parameter.as_int()) != 0) {
704 "The value of parameter coarse_search_resolution is incorrectly set to %ld, "
705 "it should be an increment of the angle_quantization_bins (%u). "
706 "Ignoring parameter update.",
708 _angle_quantizations);
709 result.successful =
false;
712 }
else if (param_type == ParameterType::PARAMETER_STRING) {
713 if (param_name == _name +
".motion_model_for_search") {
714 MotionModel motion_model = fromString(parameter.as_string());
715 if (motion_model == MotionModel::UNKNOWN) {
718 "Unable to get MotionModel search type. Given '%s', "
719 "valid options are MOORE, VON_NEUMANN, DUBIN, REEDS_SHEPP, STATE_LATTICE. "
720 "Ignoring parameter update.",
721 parameter.as_string().c_str());
722 result.successful =
false;
724 }
else if (param_name == _name +
".goal_heading_mode") {
725 GoalHeadingMode goal_heading_mode = fromStringToGH(parameter.as_string());
726 if (goal_heading_mode == GoalHeadingMode::UNKNOWN) {
729 "Unable to get GoalHeader type. Given '%s' Valid options are DEFAULT, "
730 "BIDIRECTIONAL, ALL_DIRECTION. Ignoring parameter update.",
731 parameter.as_string().c_str());
732 result.successful =
false;
740 template<
typename NodeT>
743 const std::vector<rclcpp::Parameter> & parameters)
745 std::lock_guard<std::mutex> lock_reinit(_mutex);
747 bool reinit_collision_checker =
false;
748 bool reinit_a_star =
false;
749 bool reinit_lookup_table =
false;
750 bool reinit_downsampler =
false;
751 bool reinit_smoother =
false;
753 for (
auto parameter : parameters) {
754 const auto & param_type = parameter.get_type();
755 const auto & param_name = parameter.get_name();
756 if (param_name.find(_name +
".") != 0) {
759 if (param_type == ParameterType::PARAMETER_DOUBLE) {
760 if (param_name == _name +
".max_planning_time") {
761 reinit_a_star =
true;
762 _max_planning_time = parameter.as_double();
763 }
else if (param_name == _name +
".tolerance") {
764 _tolerance =
static_cast<float>(parameter.as_double());
765 }
else if (param_name == _name +
".lookup_table_size") {
766 reinit_a_star =
true;
767 reinit_lookup_table =
true;
768 _lookup_table_size = parameter.as_double();
769 }
else if (param_name == _name +
".minimum_turning_radius") {
770 reinit_a_star =
true;
771 reinit_lookup_table =
true;
773 reinit_smoother =
true;
775 _minimum_turning_radius_global_coords =
static_cast<float>(parameter.as_double());
776 }
else if (param_name == _name +
".reverse_penalty") {
777 reinit_a_star =
true;
778 _search_info.reverse_penalty =
static_cast<float>(parameter.as_double());
779 }
else if (param_name == _name +
".change_penalty") {
780 reinit_a_star =
true;
781 _search_info.change_penalty =
static_cast<float>(parameter.as_double());
782 }
else if (param_name == _name +
".non_straight_penalty") {
783 reinit_a_star =
true;
784 _search_info.non_straight_penalty =
static_cast<float>(parameter.as_double());
785 }
else if (param_name == _name +
".cost_penalty") {
786 reinit_a_star =
true;
787 _search_info.cost_penalty =
static_cast<float>(parameter.as_double());
788 }
else if (param_name == _name +
".analytic_expansion_ratio") {
789 reinit_a_star =
true;
790 _search_info.analytic_expansion_ratio =
static_cast<float>(parameter.as_double());
791 }
else if (param_name == _name +
".analytic_expansion_max_length") {
792 reinit_a_star =
true;
793 _analytic_expansion_max_length_m = parameter.as_double();
794 }
else if (param_name == _name +
".analytic_expansion_max_cost") {
795 reinit_a_star =
true;
796 _search_info.analytic_expansion_max_cost =
static_cast<float>(parameter.as_double());
798 }
else if (param_type == ParameterType::PARAMETER_BOOL) {
799 if (param_name == _name +
".downsample_costmap") {
800 reinit_downsampler =
true;
801 _downsample_costmap = parameter.as_bool();
802 }
else if (param_name == _name +
".allow_unknown") {
803 reinit_a_star =
true;
804 _allow_unknown = parameter.as_bool();
805 }
else if (param_name == _name +
".cache_obstacle_heuristic") {
806 reinit_a_star =
true;
807 _search_info.cache_obstacle_heuristic = parameter.as_bool();
808 }
else if (param_name == _name +
".allow_primitive_interpolation") {
809 _search_info.allow_primitive_interpolation = parameter.as_bool();
810 reinit_a_star =
true;
811 }
else if (param_name == _name +
".smooth_path") {
812 if (parameter.as_bool()) {
813 reinit_smoother =
true;
817 }
else if (param_name == _name +
".analytic_expansion_max_cost_override") {
818 _search_info.analytic_expansion_max_cost_override = parameter.as_bool();
819 reinit_a_star =
true;
821 }
else if (param_type == ParameterType::PARAMETER_INTEGER) {
822 if (param_name == _name +
".downsampling_factor") {
823 reinit_a_star =
true;
824 reinit_lookup_table =
true;
825 reinit_downsampler =
true;
826 _downsampling_factor = parameter.as_int();
827 }
else if (param_name == _name +
".max_iterations") {
828 reinit_a_star =
true;
829 _max_iterations = parameter.as_int();
830 if (_max_iterations <= 0) {
832 _logger,
"maximum iteration selected as <= 0, "
833 "disabling maximum iterations.");
834 _max_iterations = std::numeric_limits<int>::max();
836 }
else if (param_name == _name +
".max_on_approach_iterations") {
837 reinit_a_star =
true;
838 _max_on_approach_iterations = parameter.as_int();
839 if (_max_on_approach_iterations <= 0) {
841 _logger,
"On approach iteration selected as <= 0, "
842 "disabling tolerance and on approach iterations.");
843 _max_on_approach_iterations = std::numeric_limits<int>::max();
845 }
else if (param_name == _name +
".terminal_checking_interval") {
846 reinit_a_star =
true;
847 _terminal_checking_interval = parameter.as_int();
848 }
else if (param_name == _name +
".angle_quantization_bins") {
849 reinit_collision_checker =
true;
850 reinit_a_star =
true;
851 reinit_lookup_table =
true;
852 int angle_quantizations = parameter.as_int();
853 _angle_bin_size = 2.0 * M_PI / angle_quantizations;
854 _angle_quantizations =
static_cast<unsigned int>(angle_quantizations);
855 }
else if (param_name == _name +
".coarse_search_resolution") {
856 _coarse_search_resolution = parameter.as_int();
858 }
else if (param_type == ParameterType::PARAMETER_STRING) {
859 if (param_name == _name +
".motion_model_for_search") {
860 reinit_a_star =
true;
861 reinit_lookup_table =
true;
862 _motion_model = fromString(parameter.as_string());
863 }
else if (param_name == _name +
".goal_heading_mode") {
864 std::string goal_heading_type = parameter.as_string();
865 GoalHeadingMode goal_heading_mode = fromStringToGH(goal_heading_type);
868 "GoalHeadingMode type set to '%s'.",
869 goal_heading_type.c_str());
870 _goal_heading_mode = goal_heading_mode;
875 if (reinit_a_star || reinit_downsampler || reinit_collision_checker || reinit_smoother) {
876 std::unique_lock<nav2_costmap_2d::Costmap2D::mutex_t> lock(*(_costmap->getMutex()));
877 if (_search_resolution != _costmap->getResolution() *
878 (_downsample_costmap ? _downsampling_factor : 1))
880 reinit_a_star =
true;
881 reinit_lookup_table =
true;
884 if (!_downsample_costmap) {
885 _downsampling_factor = 1;
887 updateSearchResolution(_costmap->getResolution() * _downsampling_factor);
888 auto node = _node.lock();
892 if (reinit_lookup_table) {
893 _a_star = std::make_unique<AStarAlgorithm<NodeT>>(_motion_model, _search_info);
895 _a_star->setSearchInfo(_search_info);
900 _max_on_approach_iterations,
901 _terminal_checking_interval,
904 _angle_quantizations);
908 if (reinit_downsampler) {
909 if (_downsample_costmap && _downsampling_factor > 1) {
910 std::string topic_name =
"downsampled_costmap";
911 _costmap_downsampler = std::make_unique<CostmapDownsampler>();
912 _costmap_downsampler->on_configure(
913 node, _global_frame, topic_name, _costmap, _downsampling_factor);
914 _costmap_downsampler->on_activate();
919 if (reinit_collision_checker) {
921 _collision_checker.setFootprint(
922 _costmap_ros->getRobotFootprint(),
923 _costmap_ros->getUseRadius(),
924 findCircumscribedCost(_costmap_ros));
928 if (reinit_smoother) {
930 params.
get(node, _name);
931 _smoother = std::make_unique<Smoother>(params);
932 _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 updateSearchResolution(double resolution)
Update resolution-dependent search settings from their world-unit values. Converts the turning radius...
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.