Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
simple_goal_checker.cpp
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2017, Locus Robotics
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <memory>
36 #include <string>
37 #include <limits>
38 #include <vector>
39 #include "nav2_controller/plugins/simple_goal_checker.hpp"
40 #include "pluginlib/class_list_macros.hpp"
41 #include "angles/angles.h"
42 #include "nav2_ros_common/node_utils.hpp"
43 #include "nav2_util/geometry_utils.hpp"
44 #include "tf2/utils.hpp"
45 
46 using rcl_interfaces::msg::ParameterType;
47 using std::placeholders::_1;
48 
49 namespace nav2_controller
50 {
51 
53 : xy_goal_tolerance_(0.25),
54  xy_goal_tolerance_buffer_(0.0),
55  yaw_goal_tolerance_(0.25),
56  path_length_tolerance_(1.0),
57  stateful_(true),
58  check_xy_(true),
59  symmetric_yaw_tolerance_(false),
60  xy_goal_tolerance_sq_(0.0625),
61  xy_goal_tolerance_reset_sq_(0.0625)
62 {
63 }
64 
66 {
67  auto node = node_.lock();
68  if (post_set_params_handler_ && node) {
69  node->remove_post_set_parameters_callback(post_set_params_handler_.get());
70  }
71  post_set_params_handler_.reset();
72  if (on_set_params_handler_ && node) {
73  node->remove_on_set_parameters_callback(on_set_params_handler_.get());
74  }
75  on_set_params_handler_.reset();
76 }
77 
79  const nav2::LifecycleNode::WeakPtr & parent,
80  const std::string & plugin_name,
81  const std::shared_ptr<nav2_costmap_2d::Costmap2DROS>/*costmap_ros*/)
82 {
83  plugin_name_ = plugin_name;
84  node_ = parent;
85  auto node = node_.lock();
86  logger_ = node->get_logger();
87 
88  xy_goal_tolerance_ = node->declare_or_get_parameter(plugin_name + ".xy_goal_tolerance", 0.25);
89  xy_goal_tolerance_buffer_ = node->declare_or_get_parameter(
90  plugin_name + ".xy_goal_tolerance_buffer", 0.0);
91  yaw_goal_tolerance_ = node->declare_or_get_parameter(plugin_name + ".yaw_goal_tolerance", 0.25);
92  path_length_tolerance_ = node->declare_or_get_parameter(
93  plugin_name + ".path_length_tolerance", 1.0);
94  stateful_ = node->declare_or_get_parameter(plugin_name + ".stateful", true);
95  symmetric_yaw_tolerance_ = node->declare_or_get_parameter(
96  plugin_name + ".symmetric_yaw_tolerance", false);
97 
98  xy_goal_tolerance_sq_ = xy_goal_tolerance_ * xy_goal_tolerance_;
99  xy_goal_tolerance_reset_sq_ = (xy_goal_tolerance_ + xy_goal_tolerance_buffer_) *
100  (xy_goal_tolerance_ + xy_goal_tolerance_buffer_);
101 
102  // Add callback for dynamic parameters
103  post_set_params_handler_ = node->add_post_set_parameters_callback(
104  std::bind(
106  this, std::placeholders::_1));
107  on_set_params_handler_ = node->add_on_set_parameters_callback(
108  std::bind(
110  this, std::placeholders::_1));
111 }
112 
114 {
115  check_xy_ = true;
116 }
117 
119  const geometry_msgs::msg::Pose & query_pose, const geometry_msgs::msg::Pose & goal_pose,
120  const geometry_msgs::msg::Twist & velocity, const nav_msgs::msg::Path & transformed_global_plan)
121 {
122  if (!isGoalXYReached(query_pose, goal_pose, velocity, transformed_global_plan)) {
123  return false;
124  }
125 
126  std::lock_guard<std::mutex> lock_reinit(mutex_);
127 
128  double query_yaw = tf2::getYaw(query_pose.orientation);
129  double goal_yaw = tf2::getYaw(goal_pose.orientation);
130  if (symmetric_yaw_tolerance_) {
131  // For symmetric robots: accept either goal orientation or goal + 180°
132  double dyaw_forward = angles::shortest_angular_distance(query_yaw, goal_yaw);
133  double dyaw_backward = angles::shortest_angular_distance(
134  query_yaw, angles::normalize_angle(goal_yaw + M_PI));
135 
136  bool forward_match = fabs(dyaw_forward) <= yaw_goal_tolerance_;
137  bool backward_match = fabs(dyaw_backward) <= yaw_goal_tolerance_;
138 
139  return forward_match || backward_match;
140  } else {
141  double dyaw = angles::shortest_angular_distance(query_yaw, goal_yaw);
142  return fabs(dyaw) <= yaw_goal_tolerance_;
143  }
144 }
145 
147  const geometry_msgs::msg::Pose & query_pose, const geometry_msgs::msg::Pose & goal_pose,
148  const geometry_msgs::msg::Twist &, const nav_msgs::msg::Path & transformed_global_plan)
149 {
150  std::lock_guard<std::mutex> lock_reinit(mutex_);
151  // If the local plan length is longer than the tolerance, we skip the check
152  if (nav2_util::geometry_utils::calculate_path_length(transformed_global_plan) >
153  path_length_tolerance_)
154  {
155  return false;
156  }
157  if (check_xy_) {
158  double dx = query_pose.position.x - goal_pose.position.x,
159  dy = query_pose.position.y - goal_pose.position.y;
160  if (dx * dx + dy * dy > xy_goal_tolerance_sq_) {
161  return false;
162  }
163  // We are within the window
164  // If we are stateful, change the state.
165  if (stateful_) {
166  check_xy_ = false;
167  }
168  } else if (stateful_ && xy_goal_tolerance_buffer_ > 0.0) {
169  // If we are stateful and have a buffer,
170  // check if we have left the buffer region to reset the state
171  double dx = query_pose.position.x - goal_pose.position.x,
172  dy = query_pose.position.y - goal_pose.position.y;
173  if (dx * dx + dy * dy > xy_goal_tolerance_reset_sq_) {
174  check_xy_ = true;
175  return false;
176  }
177  }
178 
179  return true;
180 }
181 
183  geometry_msgs::msg::Pose & pose_tolerance,
184  geometry_msgs::msg::Twist & vel_tolerance,
185  double & path_length_tolerance)
186 {
187  std::lock_guard<std::mutex> lock_reinit(mutex_);
188  double invalid_field = std::numeric_limits<double>::lowest();
189 
190  pose_tolerance.position.x = xy_goal_tolerance_;
191  pose_tolerance.position.y = xy_goal_tolerance_;
192  pose_tolerance.position.z = invalid_field;
193  pose_tolerance.orientation =
194  nav2_util::geometry_utils::orientationAroundZAxis(yaw_goal_tolerance_);
195 
196  vel_tolerance.linear.x = invalid_field;
197  vel_tolerance.linear.y = invalid_field;
198  vel_tolerance.linear.z = invalid_field;
199 
200  vel_tolerance.angular.x = invalid_field;
201  vel_tolerance.angular.y = invalid_field;
202  vel_tolerance.angular.z = invalid_field;
203 
204  path_length_tolerance = path_length_tolerance_;
205 
206  return true;
207 }
208 
209 rcl_interfaces::msg::SetParametersResult
211  const std::vector<rclcpp::Parameter> & parameters)
212 {
213  rcl_interfaces::msg::SetParametersResult result;
214  result.successful = true;
215  for (const auto & parameter : parameters) {
216  const auto & param_type = parameter.get_type();
217  const auto & param_name = parameter.get_name();
218  if (param_name.find(plugin_name_ + ".") != 0) {
219  continue;
220  }
221  if (param_type == ParameterType::PARAMETER_DOUBLE) {
222  if (parameter.as_double() < 0.0) {
223  RCLCPP_WARN(
224  logger_, "The value of parameter '%s' is incorrectly set to %f, "
225  "it should be >=0. Ignoring parameter update.",
226  param_name.c_str(), parameter.as_double());
227  result.successful = false;
228  }
229  }
230  }
231  return result;
232 }
233 
234 void
236  const std::vector<rclcpp::Parameter> & parameters)
237 {
238  std::lock_guard<std::mutex> lock_reinit(mutex_);
239  rcl_interfaces::msg::SetParametersResult result;
240  for (const auto & parameter : parameters) {
241  const auto & param_type = parameter.get_type();
242  const auto & param_name = parameter.get_name();
243  if (param_name.find(plugin_name_ + ".") != 0) {
244  continue;
245  }
246  if (param_type == ParameterType::PARAMETER_DOUBLE) {
247  if (param_name == plugin_name_ + ".xy_goal_tolerance") {
248  xy_goal_tolerance_ = parameter.as_double();
249  xy_goal_tolerance_sq_ = xy_goal_tolerance_ * xy_goal_tolerance_;
250  xy_goal_tolerance_reset_sq_ = (xy_goal_tolerance_ + xy_goal_tolerance_buffer_) *
251  (xy_goal_tolerance_ + xy_goal_tolerance_buffer_);
252  } else if (param_name == plugin_name_ + ".xy_goal_tolerance_buffer") {
253  xy_goal_tolerance_buffer_ = parameter.as_double();
254  xy_goal_tolerance_reset_sq_ = (xy_goal_tolerance_ + xy_goal_tolerance_buffer_) *
255  (xy_goal_tolerance_ + xy_goal_tolerance_buffer_);
256  } else if (param_name == plugin_name_ + ".yaw_goal_tolerance") {
257  yaw_goal_tolerance_ = parameter.as_double();
258  } else if (param_name == plugin_name_ + ".path_length_tolerance") {
259  path_length_tolerance_ = parameter.as_double();
260  }
261  } else if (param_type == ParameterType::PARAMETER_BOOL) {
262  if (param_name == plugin_name_ + ".stateful") {
263  stateful_ = parameter.as_bool();
264  } else if (param_name == plugin_name_ + ".symmetric_yaw_tolerance") {
265  symmetric_yaw_tolerance_ = parameter.as_bool();
266  }
267  }
268  }
269 }
270 
271 } // namespace nav2_controller
272 
Goal Checker plugin that only checks the position difference.
bool getTolerances(geometry_msgs::msg::Pose &pose_tolerance, geometry_msgs::msg::Twist &vel_tolerance, double &path_length_tolerance) override
Get the position and velocity tolerances.
void reset() override
Reset the goal checker state.
bool isGoalReached(const geometry_msgs::msg::Pose &query_pose, const geometry_msgs::msg::Pose &goal_pose, const geometry_msgs::msg::Twist &velocity, const nav_msgs::msg::Path &transformed_global_plan) override
Check if the goal is reached.
~SimpleGoalChecker()
Destroy the Simple Goal Checker object.
void updateParametersCallback(const std::vector< rclcpp::Parameter > &parameters)
Apply parameter updates after validation This callback is executed when parameters have been successf...
SimpleGoalChecker()
Construct a new Simple Goal Checker object.
bool isGoalXYReached(const geometry_msgs::msg::Pose &query_pose, const geometry_msgs::msg::Pose &goal_pose, const geometry_msgs::msg::Twist &velocity, const nav_msgs::msg::Path &transformed_global_plan) override
Check if XY goal position has been reached (without considering yaw)
rcl_interfaces::msg::SetParametersResult validateParameterUpdatesCallback(const std::vector< rclcpp::Parameter > &parameters)
Validate incoming parameter updates before applying them. This callback is triggered when one or more...
void initialize(const nav2::LifecycleNode::WeakPtr &parent, const std::string &plugin_name, const std::shared_ptr< nav2_costmap_2d::Costmap2DROS > costmap_ros) override
Initialize the goal checker.
Function-object for checking whether a goal has been reached.