18 #include "angles/angles.h"
19 #include "pluginlib/class_list_macros.hpp"
20 #include "nav2_controller/plugins/feasible_path_handler.hpp"
21 #include "nav2_util/path_utils.hpp"
22 #include "nav2_util/geometry_utils.hpp"
23 #include "nav2_core/controller_exceptions.hpp"
24 #include "nav2_ros_common/tf2_factories.hpp"
27 using rcl_interfaces::msg::ParameterType;
28 using std::placeholders::_1;
30 namespace nav2_controller
32 using nav2_util::geometry_utils::euclidean_distance;
36 auto node = node_.lock();
37 if (post_set_params_handler_ && node) {
38 node->remove_post_set_parameters_callback(post_set_params_handler_.get());
40 post_set_params_handler_.reset();
41 if (on_set_params_handler_ && node) {
42 node->remove_on_set_parameters_callback(on_set_params_handler_.get());
44 on_set_params_handler_.reset();
48 const nav2::LifecycleNode::WeakPtr & parent,
49 const rclcpp::Logger & logger,
50 const std::string & plugin_name,
51 const std::shared_ptr<nav2_costmap_2d::Costmap2DROS> costmap_ros,
52 nav2::TransformBuffer::SharedPtr tf)
55 plugin_name_ = plugin_name;
57 auto node = node_.lock();
58 costmap_ros_ = costmap_ros;
60 transform_tolerance_ = costmap_ros_->getTransformTolerance();
61 reject_unit_path_ = node->declare_or_get_parameter(
62 plugin_name +
".reject_unit_path",
false);
63 max_robot_pose_search_dist_ = node->declare_or_get_parameter(
65 prune_distance_ = node->declare_or_get_parameter(
66 plugin_name +
".prune_distance", 2.0);
67 enforce_path_inversion_ = node->declare_or_get_parameter(
68 plugin_name +
".enforce_path_inversion",
false);
69 enforce_path_rotation_ = node->declare_or_get_parameter(
70 plugin_name +
".enforce_path_rotation",
false);
71 inversion_xy_tolerance_ = node->declare_or_get_parameter(
72 plugin_name +
".inversion_xy_tolerance", 0.2);
73 inversion_yaw_tolerance_ = node->declare_or_get_parameter(
74 plugin_name +
".inversion_yaw_tolerance", 0.4);
75 minimum_rotation_angle_ = node->declare_or_get_parameter(
76 plugin_name +
".minimum_rotation_angle", 0.785);
77 if (max_robot_pose_search_dist_ < 0.0) {
79 logger_,
"Max robot search distance is negative, setting to max to search"
80 " every point on path for the closest value.");
81 max_robot_pose_search_dist_ = std::numeric_limits<double>::max();
83 constraint_locale_ = 0u;
84 if (!enforce_path_rotation_) {
85 minimum_rotation_angle_ = 0.0f;
89 post_set_params_handler_ = node->add_post_set_parameters_callback(
92 this, std::placeholders::_1));
93 on_set_params_handler_ = node->add_on_set_parameters_callback(
96 this, std::placeholders::_1));
101 const double max_costmap_dim_meters = std::max(
102 costmap_ros_->getCostmap()->getSizeInMetersX(),
103 costmap_ros_->getCostmap()->getSizeInMetersY());
104 return max_costmap_dim_meters / 2.0;
109 plan.poses.erase(plan.poses.begin(), end);
113 const geometry_msgs::msg::PoseStamped & robot_pose)
116 const auto last_pose = global_plan_up_to_constraint_.poses.back();
117 float distance = hypotf(
118 robot_pose.pose.position.x - last_pose.pose.position.x,
119 robot_pose.pose.position.y - last_pose.pose.position.y);
121 float angle_distance = angles::shortest_angular_distance(
122 tf2::getYaw(robot_pose.pose.orientation),
123 tf2::getYaw(last_pose.pose.orientation));
125 return distance <= inversion_xy_tolerance_ &&
126 fabs(angle_distance) <= inversion_yaw_tolerance_;
131 std::lock_guard<std::mutex> lock_reinit(mutex_);
133 global_plan_up_to_constraint_ = global_plan_;
134 if (enforce_path_inversion_ || enforce_path_rotation_) {
135 constraint_locale_ = nav2_util::removePosesAfterFirstConstraint(global_plan_up_to_constraint_,
136 enforce_path_inversion_, minimum_rotation_angle_);
141 const geometry_msgs::msg::PoseStamped & pose)
143 if (global_plan_up_to_constraint_.poses.empty()) {
147 if (reject_unit_path_ && global_plan_up_to_constraint_.poses.size() == 1) {
152 geometry_msgs::msg::PoseStamped robot_pose;
153 if (!nav2_util::transformPoseInTargetFrame(pose, robot_pose, *tf_,
154 global_plan_up_to_constraint_.header.frame_id,
155 transform_tolerance_))
164 const geometry_msgs::msg::PoseStamped & pose)
166 std::lock_guard<std::mutex> lock_reinit(mutex_);
170 auto closest_pose_upper_bound =
171 nav2_util::geometry_utils::first_after_integrated_distance(
172 global_plan_up_to_constraint_.poses.begin(), global_plan_up_to_constraint_.poses.end(),
173 max_robot_pose_search_dist_);
179 nav2_util::geometry_utils::min_by(
180 global_plan_up_to_constraint_.poses.begin(), closest_pose_upper_bound,
181 [
this](
const geometry_msgs::msg::PoseStamped & ps) {
182 return euclidean_distance(global_pose_, ps);
188 if (global_plan_up_to_constraint_.poses.begin() != closest_pose_upper_bound &&
189 global_plan_up_to_constraint_.poses.size() > 1 &&
190 closest_point == std::prev(closest_pose_upper_bound))
192 closest_point = std::prev(std::prev(closest_pose_upper_bound));
195 auto pruned_plan_end =
196 nav2_util::geometry_utils::first_after_integrated_distance(
197 closest_point, global_plan_up_to_constraint_.poses.end(), prune_distance_);
199 return {closest_point, pruned_plan_end};
204 const nav2_core::PathIterator & closest_point,
205 const nav2_core::PathIterator & pruned_plan_end)
207 std::lock_guard<std::mutex> lock_reinit(mutex_);
208 nav_msgs::msg::Path transformed_plan;
209 transformed_plan.header.frame_id = costmap_ros_->getGlobalFrameID();
210 transformed_plan.header.stamp = global_pose_.header.stamp;
215 for (
auto global_plan_pose = closest_point; global_plan_pose != pruned_plan_end;
219 geometry_msgs::msg::PoseStamped costmap_plan_pose;
220 global_plan_pose->header.stamp = global_pose_.header.stamp;
221 global_plan_pose->header.frame_id = global_plan_.header.frame_id;
222 nav2_util::transformPoseInTargetFrame(*global_plan_pose, costmap_plan_pose, *tf_,
223 costmap_ros_->getGlobalFrameID(), transform_tolerance_);
226 if (!costmap_ros_->getCostmap()->worldToMap(
227 costmap_plan_pose.pose.position.x, costmap_plan_pose.pose.position.y, mx, my))
233 transformed_plan.poses.push_back(costmap_plan_pose);
238 prunePlan(global_plan_up_to_constraint_, closest_point);
240 if ((enforce_path_inversion_ || enforce_path_rotation_) && constraint_locale_ != 0u) {
242 prunePlan(global_plan_, global_plan_.poses.begin() + constraint_locale_);
243 global_plan_up_to_constraint_ = global_plan_;
244 constraint_locale_ = nav2_util::removePosesAfterFirstConstraint(global_plan_up_to_constraint_,
245 enforce_path_inversion_, minimum_rotation_angle_);
249 if (transformed_plan.poses.empty()) {
253 return transformed_plan;
257 const builtin_interfaces::msg::Time & stamp)
259 auto goal = global_plan_.poses.back();
260 goal.header.frame_id = global_plan_.header.frame_id;
261 goal.header.stamp = stamp;
262 if (goal.header.frame_id.empty()) {
265 geometry_msgs::msg::PoseStamped transformed_goal;
266 if (!nav2_util::transformPoseInTargetFrame(goal, transformed_goal, *costmap_ros_->getTfBuffer(),
267 costmap_ros_->getGlobalFrameID(), transform_tolerance_))
271 return transformed_goal;
274 rcl_interfaces::msg::SetParametersResult
276 const std::vector<rclcpp::Parameter> & parameters)
278 rcl_interfaces::msg::SetParametersResult result;
279 result.successful =
true;
280 for (
const auto & parameter : parameters) {
281 const auto & param_type = parameter.get_type();
282 const auto & param_name = parameter.get_name();
283 if (param_name.find(plugin_name_ +
".") != 0) {
286 if (param_type == ParameterType::PARAMETER_DOUBLE) {
287 if (parameter.as_double() < 0.0) {
289 logger_,
"The value of parameter '%s' is incorrectly set to %f, "
290 "it should be >=0. Ignoring parameter update.",
291 param_name.c_str(), parameter.as_double());
292 result.successful =
false;
301 const std::vector<rclcpp::Parameter> & parameters)
303 std::lock_guard<std::mutex> lock_reinit(mutex_);
304 rcl_interfaces::msg::SetParametersResult result;
305 for (
const auto & parameter : parameters) {
306 const auto & param_type = parameter.get_type();
307 const auto & param_name = parameter.get_name();
308 if (param_name.find(plugin_name_ +
".") != 0) {
311 if (param_type == ParameterType::PARAMETER_DOUBLE) {
312 if (param_name == plugin_name_ +
".max_robot_pose_search_dist") {
313 max_robot_pose_search_dist_ = parameter.as_double();
314 }
else if (param_name == plugin_name_ +
".inversion_xy_tolerance") {
315 inversion_xy_tolerance_ = parameter.as_double();
316 }
else if (param_name == plugin_name_ +
".inversion_yaw_tolerance") {
317 inversion_yaw_tolerance_ = parameter.as_double();
318 }
else if (param_name == plugin_name_ +
".prune_distance") {
319 prune_distance_ = parameter.as_double();
320 }
else if (param_name == plugin_name_ +
".minimum_rotation_angle") {
321 minimum_rotation_angle_ = parameter.as_double();
323 }
else if (param_type == ParameterType::PARAMETER_BOOL) {
324 if (param_name == plugin_name_ +
".enforce_path_inversion") {
325 enforce_path_inversion_ = parameter.as_bool();
326 }
else if (param_name == plugin_name_ +
".enforce_path_rotation") {
327 enforce_path_rotation_ = parameter.as_bool();
328 if (!enforce_path_rotation_) {
329 minimum_rotation_angle_ = 0.0f;
This plugin manages the global plan by clipping it to the local segment, typically bounded by the loc...
~FeasiblePathHandler()
Destroy the Feasible Path Handler object.
double getCostmapMaxExtent() const
void prunePlan(nav_msgs::msg::Path &plan, const nav2_core::PathIterator end)
Prune a path to only interesting portions.
nav_msgs::msg::Path transformLocalPlan(const nav2_core::PathIterator &closest_point, const nav2_core::PathIterator &pruned_plan_end) override
Transforms a predefined segment of the global plan into the costmap global frame.
bool isWithinInversionTolerances(const geometry_msgs::msg::PoseStamped &robot_pose)
Check if the robot pose is within the set inversion tolerances.
geometry_msgs::msg::PoseStamped transformToGlobalPlanFrame(const geometry_msgs::msg::PoseStamped &pose)
Transform a pose to the global reference frame.
void setPlan(const nav_msgs::msg::Path &path) override
Set new reference plan.
void updateParametersCallback(const std::vector< rclcpp::Parameter > ¶meters)
Apply parameter updates after validation This callback is executed when parameters have been successf...
geometry_msgs::msg::PoseStamped getTransformedGoal(const builtin_interfaces::msg::Time &stamp) override
Get the global goal pose transformed to the costmap global frame.
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...
nav2_core::PathSegment findPlanSegment(const geometry_msgs::msg::PoseStamped &pose) override
Determines the portion of the global plan to be used for local control. This function locates the sta...
void initialize(const nav2::LifecycleNode::WeakPtr &parent, const rclcpp::Logger &logger, const std::string &plugin_name, const std::shared_ptr< nav2_costmap_2d::Costmap2DROS > costmap_ros, nav2::TransformBuffer::SharedPtr tf) override
Initialize parameters.
Function-object for handling the path from Planner Server.