22 #include "nav2_smac_planner/smac_planner_lattice.hpp"
26 namespace nav2_smac_planner
29 using namespace std::chrono;
30 using rcl_interfaces::msg::ParameterType;
34 _collision_checker(nullptr, 1, nullptr),
43 _logger,
"Destroying plugin %s of type SmacPlannerLattice",
48 const rclcpp_lifecycle::LifecycleNode::WeakPtr & parent,
49 std::string name, std::shared_ptr<tf2_ros::Buffer>,
50 std::shared_ptr<nav2_costmap_2d::Costmap2DROS> costmap_ros)
53 auto node = parent.lock();
54 _logger = node->get_logger();
55 _clock = node->get_clock();
56 _costmap = costmap_ros->getCostmap();
57 _costmap_ros = costmap_ros;
59 _global_frame = costmap_ros->getGlobalFrameID();
61 RCLCPP_INFO(_logger,
"Configuring %s of type SmacPlannerLattice", name.c_str());
64 double analytic_expansion_max_length_m;
67 nav2_util::declare_parameter_if_not_declared(
68 node, name +
".tolerance", rclcpp::ParameterValue(0.25));
69 _tolerance =
static_cast<float>(node->get_parameter(name +
".tolerance").as_double());
70 nav2_util::declare_parameter_if_not_declared(
71 node, name +
".allow_unknown", rclcpp::ParameterValue(
true));
72 node->get_parameter(name +
".allow_unknown", _allow_unknown);
73 nav2_util::declare_parameter_if_not_declared(
74 node, name +
".max_iterations", rclcpp::ParameterValue(1000000));
75 node->get_parameter(name +
".max_iterations", _max_iterations);
76 nav2_util::declare_parameter_if_not_declared(
77 node, name +
".max_on_approach_iterations", rclcpp::ParameterValue(1000));
78 node->get_parameter(name +
".max_on_approach_iterations", _max_on_approach_iterations);
79 nav2_util::declare_parameter_if_not_declared(
80 node, name +
".terminal_checking_interval", rclcpp::ParameterValue(5000));
81 node->get_parameter(name +
".terminal_checking_interval", _terminal_checking_interval);
82 nav2_util::declare_parameter_if_not_declared(
83 node, name +
".smooth_path", rclcpp::ParameterValue(
true));
84 node->get_parameter(name +
".smooth_path", smooth_path);
87 nav2_util::declare_parameter_if_not_declared(
88 node, name +
".lattice_filepath", rclcpp::ParameterValue(
89 ament_index_cpp::get_package_share_directory(
"nav2_smac_planner") +
90 "/sample_primitives/5cm_resolution/0.5m_turning_radius/ackermann/output.json"));
91 node->get_parameter(name +
".lattice_filepath", _search_info.lattice_filepath);
92 nav2_util::declare_parameter_if_not_declared(
93 node, name +
".cache_obstacle_heuristic", rclcpp::ParameterValue(
false));
94 node->get_parameter(name +
".cache_obstacle_heuristic", _search_info.cache_obstacle_heuristic);
95 nav2_util::declare_parameter_if_not_declared(
96 node, name +
".reverse_penalty", rclcpp::ParameterValue(2.0));
97 node->get_parameter(name +
".reverse_penalty", _search_info.reverse_penalty);
98 nav2_util::declare_parameter_if_not_declared(
99 node, name +
".change_penalty", rclcpp::ParameterValue(0.05));
100 node->get_parameter(name +
".change_penalty", _search_info.change_penalty);
101 nav2_util::declare_parameter_if_not_declared(
102 node, name +
".non_straight_penalty", rclcpp::ParameterValue(1.05));
103 node->get_parameter(name +
".non_straight_penalty", _search_info.non_straight_penalty);
104 nav2_util::declare_parameter_if_not_declared(
105 node, name +
".cost_penalty", rclcpp::ParameterValue(2.0));
106 node->get_parameter(name +
".cost_penalty", _search_info.cost_penalty);
107 nav2_util::declare_parameter_if_not_declared(
108 node, name +
".retrospective_penalty", rclcpp::ParameterValue(0.015));
109 node->get_parameter(name +
".retrospective_penalty", _search_info.retrospective_penalty);
110 nav2_util::declare_parameter_if_not_declared(
111 node, name +
".rotation_penalty", rclcpp::ParameterValue(5.0));
112 node->get_parameter(name +
".rotation_penalty", _search_info.rotation_penalty);
113 nav2_util::declare_parameter_if_not_declared(
114 node, name +
".analytic_expansion_ratio", rclcpp::ParameterValue(3.5));
115 node->get_parameter(name +
".analytic_expansion_ratio", _search_info.analytic_expansion_ratio);
116 nav2_util::declare_parameter_if_not_declared(
117 node, name +
".analytic_expansion_max_cost", rclcpp::ParameterValue(200.0));
119 name +
".analytic_expansion_max_cost", _search_info.analytic_expansion_max_cost);
120 nav2_util::declare_parameter_if_not_declared(
121 node, name +
".analytic_expansion_max_cost_override", rclcpp::ParameterValue(
false));
123 name +
".analytic_expansion_max_cost_override",
124 _search_info.analytic_expansion_max_cost_override);
125 nav2_util::declare_parameter_if_not_declared(
126 node, name +
".analytic_expansion_max_length", rclcpp::ParameterValue(3.0));
127 node->get_parameter(name +
".analytic_expansion_max_length", analytic_expansion_max_length_m);
128 _search_info.analytic_expansion_max_length =
131 nav2_util::declare_parameter_if_not_declared(
132 node, name +
".max_planning_time", rclcpp::ParameterValue(5.0));
133 node->get_parameter(name +
".max_planning_time", _max_planning_time);
134 nav2_util::declare_parameter_if_not_declared(
135 node, name +
".lookup_table_size", rclcpp::ParameterValue(20.0));
136 node->get_parameter(name +
".lookup_table_size", _lookup_table_size);
137 nav2_util::declare_parameter_if_not_declared(
138 node, name +
".allow_reverse_expansion", rclcpp::ParameterValue(
false));
139 node->get_parameter(name +
".allow_reverse_expansion", _search_info.allow_reverse_expansion);
140 nav2_util::declare_parameter_if_not_declared(
141 node, name +
".debug_visualizations", rclcpp::ParameterValue(
false));
142 node->get_parameter(name +
".debug_visualizations", _debug_visualizations);
145 _search_info.minimum_turning_radius =
147 _motion_model = MotionModel::STATE_LATTICE;
149 if (_metadata.motion_model ==
"omni" && _search_info.allow_reverse_expansion) {
152 "allow_reverse_expansion is not applicable for omnidirectional robots. Disabling.");
153 _search_info.allow_reverse_expansion =
false;
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 float lookup_table_dim =
171 static_cast<float>(_lookup_table_size) /
175 lookup_table_dim =
static_cast<float>(
static_cast<int>(lookup_table_dim));
178 if (
static_cast<int>(lookup_table_dim) % 2 == 0) {
181 "Even sized heuristic lookup table size set %f, increasing size by 1 to make odd",
183 lookup_table_dim += 1.0;
195 costmap_ros->getRobotFootprint(),
196 costmap_ros->getUseRadius(),
197 findCircumscribedCost(costmap_ros));
200 _a_star = std::make_unique<AStarAlgorithm<NodeLattice>>(_motion_model, _search_info);
204 _max_on_approach_iterations,
205 _terminal_checking_interval,
208 _metadata.number_of_headings);
212 params.
get(node, name);
213 if (_metadata.motion_model ==
"omni") {
214 params.holonomic_ =
true;
217 _smoother = std::make_unique<Smoother>(params);
218 _smoother->initialize(_metadata.min_turning_radius);
221 _raw_plan_publisher = node->create_publisher<nav_msgs::msg::Path>(
"unsmoothed_plan", 1);
223 if (_debug_visualizations) {
224 _expansions_publisher = node->create_publisher<geometry_msgs::msg::PoseArray>(
"expansions", 1);
225 _planned_footprints_publisher = node->create_publisher<visualization_msgs::msg::MarkerArray>(
226 "planned_footprints", 1);
227 _smoothed_footprints_publisher =
228 node->create_publisher<visualization_msgs::msg::MarkerArray>(
229 "smoothed_footprints", 1);
233 _logger,
"Configured plugin %s of type SmacPlannerLattice with "
234 "maximum iterations %i, max on approach iterations %i, "
235 "and %s. Tolerance %.2f. Using motion model: %s. State lattice file: %s.",
236 _name.c_str(), _max_iterations, _max_on_approach_iterations,
237 _allow_unknown ?
"allowing unknown traversal" :
"not allowing unknown traversal",
238 _tolerance, toString(_motion_model).c_str(), _search_info.lattice_filepath.c_str());
244 _logger,
"Activating plugin %s of type SmacPlannerLattice",
246 _raw_plan_publisher->on_activate();
247 if (_debug_visualizations) {
248 _expansions_publisher->on_activate();
249 _planned_footprints_publisher->on_activate();
250 _smoothed_footprints_publisher->on_activate();
252 auto node = _node.lock();
254 _dyn_params_handler = node->add_on_set_parameters_callback(
261 _logger,
"Deactivating plugin %s of type SmacPlannerLattice",
263 _raw_plan_publisher->on_deactivate();
264 if (_debug_visualizations) {
265 _expansions_publisher->on_deactivate();
266 _planned_footprints_publisher->on_deactivate();
267 _smoothed_footprints_publisher->on_deactivate();
270 auto node = _node.lock();
271 if (_dyn_params_handler && node) {
272 node->remove_on_set_parameters_callback(_dyn_params_handler.get());
274 _dyn_params_handler.reset();
280 _logger,
"Cleaning up plugin %s of type SmacPlannerLattice",
285 _raw_plan_publisher.reset();
286 if (_debug_visualizations) {
287 _expansions_publisher.reset();
288 _planned_footprints_publisher.reset();
289 _smoothed_footprints_publisher.reset();
294 const geometry_msgs::msg::PoseStamped & start,
295 const geometry_msgs::msg::PoseStamped & goal,
296 std::function<
bool()> cancel_checker)
298 std::lock_guard<std::mutex> lock_reinit(_mutex);
299 steady_clock::time_point a = steady_clock::now();
301 std::unique_lock<nav2_costmap_2d::Costmap2D::mutex_t> lock(*(_costmap->getMutex()));
305 _costmap_ros->getRobotFootprint(),
306 _costmap_ros->getUseRadius(),
307 findCircumscribedCost(_costmap_ros));
308 _a_star->setCollisionChecker(&_collision_checker);
311 float mx_start, my_start, mx_goal, my_goal;
313 start.pose.position.x,
314 start.pose.position.y,
319 "Start Coordinates of(" + std::to_string(start.pose.position.x) +
", " +
320 std::to_string(start.pose.position.y) +
") was outside bounds");
324 NodeLattice::motion_table.getClosestAngularBin(tf2::getYaw(start.pose.orientation)));
328 goal.pose.position.x,
329 goal.pose.position.y,
334 "Goal Coordinates of(" + std::to_string(goal.pose.position.x) +
", " +
335 std::to_string(goal.pose.position.y) +
") was outside bounds");
339 NodeLattice::motion_table.getClosestAngularBin(tf2::getYaw(goal.pose.orientation)));
342 nav_msgs::msg::Path plan;
343 plan.header.stamp = _clock->now();
344 plan.header.frame_id = _global_frame;
345 geometry_msgs::msg::PoseStamped pose;
346 pose.header = plan.header;
347 pose.pose.position.z = 0.0;
348 pose.pose.orientation.x = 0.0;
349 pose.pose.orientation.y = 0.0;
350 pose.pose.orientation.z = 0.0;
351 pose.pose.orientation.w = 1.0;
354 if (std::floor(mx_start) == std::floor(mx_goal) &&
355 std::floor(my_start) == std::floor(my_goal))
357 pose.pose = start.pose;
358 pose.pose.orientation = goal.pose.orientation;
359 plan.poses.push_back(pose);
362 if (_raw_plan_publisher->get_subscription_count() > 0) {
363 _raw_plan_publisher->publish(plan);
370 NodeLattice::CoordinateVector path;
371 int num_iterations = 0;
373 std::unique_ptr<std::vector<std::tuple<float, float, float>>> expansions =
nullptr;
374 if (_debug_visualizations) {
375 expansions = std::make_unique<std::vector<std::tuple<float, float, float>>>();
379 if (!_a_star->createPath(
380 path, num_iterations,
381 _tolerance /
static_cast<float>(_costmap->
getResolution()), cancel_checker, expansions.get()))
383 if (_debug_visualizations) {
384 auto now = _clock->now();
385 geometry_msgs::msg::PoseArray msg;
386 geometry_msgs::msg::Pose msg_pose;
387 msg.header.stamp = now;
388 msg.header.frame_id = _global_frame;
389 for (
auto & e : *expansions) {
390 msg_pose.position.x = std::get<0>(e);
391 msg_pose.position.y = std::get<1>(e);
392 msg_pose.orientation = getWorldOrientation(std::get<2>(e));
393 msg.poses.push_back(msg_pose);
395 _expansions_publisher->publish(msg);
399 if (num_iterations == 1) {
403 if (num_iterations < _a_star->getMaxIterations()) {
411 plan.poses.reserve(path.size());
412 geometry_msgs::msg::PoseStamped last_pose = pose;
413 for (
int i = path.size() - 1; i >= 0; --i) {
414 pose.pose = getWorldCoords(path[i].x, path[i].y, _costmap);
415 pose.pose.orientation = getWorldOrientation(path[i].theta);
416 if (fabs(pose.pose.position.x - last_pose.pose.position.x) < 1e-4 &&
417 fabs(pose.pose.position.y - last_pose.pose.position.y) < 1e-4 &&
418 fabs(tf2::getYaw(pose.pose.orientation) - tf2::getYaw(last_pose.pose.orientation)) < 1e-4)
422 "Removed a path from the path due to replication. "
423 "Make sure your minimum control set does not contain duplicate values!");
427 plan.poses.push_back(pose);
431 if (_raw_plan_publisher->get_subscription_count() > 0) {
432 _raw_plan_publisher->publish(plan);
435 if (_debug_visualizations) {
436 auto now = _clock->now();
438 geometry_msgs::msg::PoseArray msg;
439 geometry_msgs::msg::Pose msg_pose;
440 msg.header.stamp = now;
441 msg.header.frame_id = _global_frame;
442 for (
auto & e : *expansions) {
443 msg_pose.position.x = std::get<0>(e);
444 msg_pose.position.y = std::get<1>(e);
445 msg_pose.orientation = getWorldOrientation(std::get<2>(e));
446 msg.poses.push_back(msg_pose);
448 _expansions_publisher->publish(msg);
450 if (_planned_footprints_publisher->get_subscription_count() > 0) {
452 auto marker_array = std::make_unique<visualization_msgs::msg::MarkerArray>();
453 visualization_msgs::msg::Marker clear_all_marker;
454 clear_all_marker.action = visualization_msgs::msg::Marker::DELETEALL;
455 marker_array->markers.push_back(clear_all_marker);
456 _planned_footprints_publisher->publish(std::move(marker_array));
459 marker_array = std::make_unique<visualization_msgs::msg::MarkerArray>();
460 for (
size_t i = 0; i < plan.poses.size(); i++) {
461 const std::vector<geometry_msgs::msg::Point> edge =
462 transformFootprintToEdges(plan.poses[i].pose, _costmap_ros->getRobotFootprint());
463 marker_array->markers.push_back(createMarker(edge, i, _global_frame, now));
465 _planned_footprints_publisher->publish(std::move(marker_array));
470 steady_clock::time_point b = steady_clock::now();
471 duration<double> time_span = duration_cast<duration<double>>(b - a);
472 double time_remaining = _max_planning_time -
static_cast<double>(time_span.count());
474 #ifdef BENCHMARK_TESTING
475 std::cout <<
"It took " << time_span.count() * 1000 <<
476 " milliseconds with " << num_iterations <<
" iterations." << std::endl;
480 if (_smoother && num_iterations > 1) {
481 _smoother->smooth(plan, _costmap, time_remaining);
484 #ifdef BENCHMARK_TESTING
485 steady_clock::time_point c = steady_clock::now();
486 duration<double> time_span2 = duration_cast<duration<double>>(c - b);
487 std::cout <<
"It took " << time_span2.count() * 1000 <<
488 " milliseconds to smooth path." << std::endl;
491 if (_debug_visualizations) {
492 if (_smoothed_footprints_publisher->get_subscription_count() > 0) {
494 auto marker_array = std::make_unique<visualization_msgs::msg::MarkerArray>();
495 visualization_msgs::msg::Marker clear_all_marker;
496 clear_all_marker.action = visualization_msgs::msg::Marker::DELETEALL;
497 marker_array->markers.push_back(clear_all_marker);
498 _smoothed_footprints_publisher->publish(std::move(marker_array));
501 marker_array = std::make_unique<visualization_msgs::msg::MarkerArray>();
502 auto now = _clock->now();
503 for (
size_t i = 0; i < plan.poses.size(); i++) {
504 const std::vector<geometry_msgs::msg::Point> edge =
505 transformFootprintToEdges(plan.poses[i].pose, _costmap_ros->getRobotFootprint());
506 marker_array->markers.push_back(createMarker(edge, i, _global_frame, now));
508 _smoothed_footprints_publisher->publish(std::move(marker_array));
515 rcl_interfaces::msg::SetParametersResult
518 rcl_interfaces::msg::SetParametersResult result;
519 std::lock_guard<std::mutex> lock_reinit(_mutex);
521 bool reinit_a_star =
false;
522 bool reinit_smoother =
false;
524 for (
auto parameter : parameters) {
525 const auto & type = parameter.get_type();
526 const auto & name = parameter.get_name();
528 if (type == ParameterType::PARAMETER_DOUBLE) {
529 if (name == _name +
".max_planning_time") {
530 reinit_a_star =
true;
531 _max_planning_time = parameter.as_double();
532 }
else if (name == _name +
".tolerance") {
533 _tolerance =
static_cast<float>(parameter.as_double());
534 }
else if (name == _name +
".lookup_table_size") {
535 reinit_a_star =
true;
536 _lookup_table_size = parameter.as_double();
537 }
else if (name == _name +
".reverse_penalty") {
538 reinit_a_star =
true;
539 _search_info.reverse_penalty =
static_cast<float>(parameter.as_double());
540 }
else if (name == _name +
".change_penalty") {
541 reinit_a_star =
true;
542 _search_info.change_penalty =
static_cast<float>(parameter.as_double());
543 }
else if (name == _name +
".non_straight_penalty") {
544 reinit_a_star =
true;
545 _search_info.non_straight_penalty =
static_cast<float>(parameter.as_double());
546 }
else if (name == _name +
".cost_penalty") {
547 reinit_a_star =
true;
548 _search_info.cost_penalty =
static_cast<float>(parameter.as_double());
549 }
else if (name == _name +
".rotation_penalty") {
550 reinit_a_star =
true;
551 _search_info.rotation_penalty =
static_cast<float>(parameter.as_double());
552 }
else if (name == _name +
".analytic_expansion_ratio") {
553 reinit_a_star =
true;
554 _search_info.analytic_expansion_ratio =
static_cast<float>(parameter.as_double());
555 }
else if (name == _name +
".analytic_expansion_max_length") {
556 reinit_a_star =
true;
557 _search_info.analytic_expansion_max_length =
558 static_cast<float>(parameter.as_double()) / _costmap->
getResolution();
559 }
else if (name == _name +
".analytic_expansion_max_cost") {
560 reinit_a_star =
true;
561 _search_info.analytic_expansion_max_cost =
static_cast<float>(parameter.as_double());
563 }
else if (type == ParameterType::PARAMETER_BOOL) {
564 if (name == _name +
".allow_unknown") {
565 reinit_a_star =
true;
566 _allow_unknown = parameter.as_bool();
567 }
else if (name == _name +
".cache_obstacle_heuristic") {
568 reinit_a_star =
true;
569 _search_info.cache_obstacle_heuristic = parameter.as_bool();
570 }
else if (name == _name +
".allow_reverse_expansion") {
571 reinit_a_star =
true;
572 _search_info.allow_reverse_expansion = parameter.as_bool();
573 }
else if (name == _name +
".smooth_path") {
574 if (parameter.as_bool()) {
575 reinit_smoother =
true;
579 }
else if (name == _name +
".analytic_expansion_max_cost_override") {
580 _search_info.analytic_expansion_max_cost_override = parameter.as_bool();
581 reinit_a_star =
true;
583 }
else if (type == ParameterType::PARAMETER_INTEGER) {
584 if (name == _name +
".max_iterations") {
585 reinit_a_star =
true;
586 _max_iterations = parameter.as_int();
587 if (_max_iterations <= 0) {
589 _logger,
"maximum iteration selected as <= 0, "
590 "disabling maximum iterations.");
591 _max_iterations = std::numeric_limits<int>::max();
593 }
else if (name == _name +
".max_on_approach_iterations") {
594 reinit_a_star =
true;
595 _max_on_approach_iterations = parameter.as_int();
596 if (_max_on_approach_iterations <= 0) {
598 _logger,
"On approach iteration selected as <= 0, "
599 "disabling tolerance and on approach iterations.");
600 _max_on_approach_iterations = std::numeric_limits<int>::max();
602 }
else if (name == _name +
".terminal_checking_interval") {
603 reinit_a_star =
true;
604 _terminal_checking_interval = parameter.as_int();
606 }
else if (type == ParameterType::PARAMETER_STRING) {
607 if (name == _name +
".lattice_filepath") {
608 reinit_a_star =
true;
610 reinit_smoother =
true;
612 _search_info.lattice_filepath = parameter.as_string();
614 _search_info.minimum_turning_radius =
621 if (reinit_a_star || reinit_smoother) {
623 _search_info.minimum_turning_radius =
625 float lookup_table_dim =
626 static_cast<float>(_lookup_table_size) /
630 lookup_table_dim =
static_cast<float>(
static_cast<int>(lookup_table_dim));
633 if (
static_cast<int>(lookup_table_dim) % 2 == 0) {
636 "Even sized heuristic lookup table size set %f, increasing size by 1 to make odd",
638 lookup_table_dim += 1.0;
642 if (reinit_smoother) {
643 auto node = _node.lock();
645 params.
get(node, _name);
646 if (_metadata.motion_model ==
"omni") {
647 params.holonomic_ =
true;
649 _smoother = std::make_unique<Smoother>(params);
650 _smoother->initialize(_metadata.min_turning_radius);
655 if (_metadata.motion_model ==
"omni" && _search_info.allow_reverse_expansion) {
658 "allow_reverse_expansion is not applicable for omnidirectional robots. Disabling.");
659 _search_info.allow_reverse_expansion =
false;
661 _a_star = std::make_unique<AStarAlgorithm<NodeLattice>>(_motion_model, _search_info);
665 _max_on_approach_iterations,
666 _terminal_checking_interval,
669 _metadata.number_of_headings);
673 result.successful =
true;
679 #include "pluginlib/class_list_macros.hpp"
Abstract interface for global planners to adhere to with pluginlib.
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.
void setFootprint(const nav2_costmap_2d::Footprint &footprint, const bool &radius, const double &possible_collision_cost)
A constructor for nav2_smac_planner::GridCollisionChecker for use when irregular bin intervals are ap...
static void destroyStaticAssets()
Destroy shared pointer assets at the end of the process that don't require normal destruction handlin...
void deactivate() override
Deactivate lifecycle node.
void configure(const rclcpp_lifecycle::LifecycleNode::WeakPtr &parent, std::string name, std::shared_ptr< tf2_ros::Buffer > 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, std::function< bool()> cancel_checker) override
Creating a plan from start and goal poses.
~SmacPlannerLattice()
destructor
rcl_interfaces::msg::SetParametersResult dynamicParametersCallback(std::vector< rclcpp::Parameter > parameters)
Callback executed when a paramter change is detected.
void cleanup() override
Cleanup lifecycle node.
SmacPlannerLattice()
constructor
void activate() override
Activate lifecycle node.
static LatticeMetadata getLatticeMetadata(const std::string &lattice_filepath)
Get file metadata needed.
Parameters for the smoother cost function.
void get(std::shared_ptr< rclcpp_lifecycle::LifecycleNode > node, const std::string &name)
Get params from ROS parameter.