20 #include "angles/angles.h"
21 #include "nav2_controller/plugins/axis_goal_checker.hpp"
22 #include "pluginlib/class_list_macros.hpp"
23 #include "nav2_ros_common/node_utils.hpp"
24 #include "nav2_util/geometry_utils.hpp"
26 using rcl_interfaces::msg::ParameterType;
27 using std::placeholders::_1;
29 namespace nav2_controller
33 : along_path_tolerance_(0.25), cross_track_tolerance_(0.25),
34 fallback_radial_goal_tolerance_(0.25), path_length_tolerance_(1.0),
35 direction_estimation_distance_(0.15), is_overshoot_valid_(false)
41 auto node = node_.lock();
42 if (post_set_params_handler_ && node) {
43 node->remove_post_set_parameters_callback(post_set_params_handler_.get());
45 post_set_params_handler_.reset();
46 if (on_set_params_handler_ && node) {
47 node->remove_on_set_parameters_callback(on_set_params_handler_.get());
49 on_set_params_handler_.reset();
53 const nav2::LifecycleNode::WeakPtr & parent,
54 const std::string & plugin_name,
55 const std::shared_ptr<nav2_costmap_2d::Costmap2DROS>)
57 plugin_name_ = plugin_name;
59 auto node = node_.lock();
60 logger_ = node->get_logger();
62 along_path_tolerance_ = node->declare_or_get_parameter(
63 plugin_name +
".along_path_tolerance", 0.25);
64 cross_track_tolerance_ = node->declare_or_get_parameter(
65 plugin_name +
".cross_track_tolerance", 0.25);
66 fallback_radial_goal_tolerance_ = node->declare_or_get_parameter(
67 plugin_name +
".fallback_radial_goal_tolerance",
68 std::min(along_path_tolerance_, cross_track_tolerance_));
69 path_length_tolerance_ = node->declare_or_get_parameter(
70 plugin_name +
".path_length_tolerance", 1.0);
71 direction_estimation_distance_ = node->declare_or_get_parameter(
72 plugin_name +
".direction_estimation_distance", 0.15);
73 is_overshoot_valid_ = node->declare_or_get_parameter(
74 plugin_name +
".is_overshoot_valid",
false);
77 post_set_params_handler_ = node->add_post_set_parameters_callback(
80 this, std::placeholders::_1));
81 on_set_params_handler_ = node->add_on_set_parameters_callback(
84 this, std::placeholders::_1));
89 std::lock_guard<std::mutex> lock_reinit(mutex_);
90 cached_end_of_path_yaw_.reset();
94 const geometry_msgs::msg::Pose & query_pose,
const geometry_msgs::msg::Pose & goal_pose,
95 const geometry_msgs::msg::Twist & velocity,
96 const nav_msgs::msg::Path & transformed_global_plan)
100 return isGoalXYReached(query_pose, goal_pose, velocity, transformed_global_plan);
104 const geometry_msgs::msg::Pose & query_pose,
const geometry_msgs::msg::Pose & goal_pose,
105 const geometry_msgs::msg::Twist &,
106 const nav_msgs::msg::Path & transformed_global_plan)
108 std::lock_guard<std::mutex> lock_reinit(mutex_);
110 double robot_to_goal_dx = goal_pose.position.x - query_pose.position.x;
111 double robot_to_goal_dy = goal_pose.position.y - query_pose.position.y;
112 double distance_to_goal = std::hypot(robot_to_goal_dx, robot_to_goal_dy);
115 if (distance_to_goal < 1e-6) {
120 for (
int i =
static_cast<int>(transformed_global_plan.poses.size()) - 2; i >= 0; --i) {
121 const auto & candidate_pose = transformed_global_plan.poses[i].pose;
122 double dx = goal_pose.position.x - candidate_pose.position.x;
123 double dy = goal_pose.position.y - candidate_pose.position.y;
125 if (std::hypot(dx, dy) >= direction_estimation_distance_) {
126 cached_end_of_path_yaw_ = atan2(dy, dx);
132 if (nav2_util::geometry_utils::calculate_path_length(transformed_global_plan) >
133 path_length_tolerance_)
139 if (!cached_end_of_path_yaw_.has_value()) {
142 "No path direction available, falling back to simple distance check");
143 return distance_to_goal < fallback_radial_goal_tolerance_;
146 double robot_to_goal_yaw = atan2(robot_to_goal_dy, robot_to_goal_dx);
147 double projection_angle = angles::shortest_angular_distance(
148 robot_to_goal_yaw, cached_end_of_path_yaw_.value());
149 double along_path_distance = distance_to_goal * cos(projection_angle);
150 double cross_track_distance = distance_to_goal * sin(projection_angle);
152 if (is_overshoot_valid_) {
153 return along_path_distance < along_path_tolerance_ &&
154 fabs(cross_track_distance) < cross_track_tolerance_;
156 return fabs(along_path_distance) < along_path_tolerance_ &&
157 fabs(cross_track_distance) < cross_track_tolerance_;
162 geometry_msgs::msg::Pose & pose_tolerance,
163 geometry_msgs::msg::Twist & vel_tolerance,
164 double & path_length_tolerance)
166 std::lock_guard<std::mutex> lock_reinit(mutex_);
167 double invalid_field = std::numeric_limits<double>::lowest();
169 pose_tolerance.position.x = std::min(along_path_tolerance_, cross_track_tolerance_);
170 pose_tolerance.position.y = std::min(along_path_tolerance_, cross_track_tolerance_);
171 pose_tolerance.position.z = invalid_field;
172 pose_tolerance.orientation =
173 nav2_util::geometry_utils::orientationAroundZAxis(M_PI_2);
175 vel_tolerance.linear.x = invalid_field;
176 vel_tolerance.linear.y = invalid_field;
177 vel_tolerance.linear.z = invalid_field;
179 vel_tolerance.angular.x = invalid_field;
180 vel_tolerance.angular.y = invalid_field;
181 vel_tolerance.angular.z = invalid_field;
183 path_length_tolerance = path_length_tolerance_;
188 rcl_interfaces::msg::SetParametersResult
190 const std::vector<rclcpp::Parameter> & parameters)
192 rcl_interfaces::msg::SetParametersResult result;
193 result.successful =
true;
194 for (
auto parameter : parameters) {
195 const auto & param_type = parameter.get_type();
196 const auto & param_name = parameter.get_name();
197 if (param_name.find(plugin_name_ +
".") != 0) {
200 if (param_type == ParameterType::PARAMETER_DOUBLE) {
201 if (parameter.as_double() < 0.0) {
203 logger_,
"The value of parameter '%s' is incorrectly set to %f, "
204 "it should be >=0. Ignoring parameter update.",
205 param_name.c_str(), parameter.as_double());
206 result.successful =
false;
208 if (param_name == plugin_name_ +
".direction_estimation_distance") {
209 const double value = parameter.as_double();
210 if (value <= 0.0 || value >= path_length_tolerance_) {
212 logger_,
"The value of parameter '%s' is set to %f, it should be >0 and "
213 "<path_length_tolerance (%f). Ignoring parameter update.",
214 param_name.c_str(), value, path_length_tolerance_);
215 result.successful =
false;
225 const std::vector<rclcpp::Parameter> & parameters)
227 std::lock_guard<std::mutex> lock_reinit(mutex_);
228 for (
const auto & parameter : parameters) {
229 const auto & type = parameter.get_type();
230 const auto & name = parameter.get_name();
231 if (name.find(plugin_name_ +
".") != 0) {
234 if (type == ParameterType::PARAMETER_DOUBLE) {
235 if (name == plugin_name_ +
".along_path_tolerance") {
236 along_path_tolerance_ = parameter.as_double();
237 }
else if (name == plugin_name_ +
".cross_track_tolerance") {
238 cross_track_tolerance_ = parameter.as_double();
239 }
else if (name == plugin_name_ +
".fallback_radial_goal_tolerance") {
240 fallback_radial_goal_tolerance_ = parameter.as_double();
241 }
else if (name == plugin_name_ +
".path_length_tolerance") {
242 path_length_tolerance_ = parameter.as_double();
243 }
else if (name == plugin_name_ +
".direction_estimation_distance") {
244 direction_estimation_distance_ = parameter.as_double();
246 }
else if (type == ParameterType::PARAMETER_BOOL) {
247 if (name == plugin_name_ +
".is_overshoot_valid") {
248 is_overshoot_valid_ = parameter.as_bool();
Goal Checker plugin that checks progress along the axis defined by the last segment of the path to th...
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.
~AxisGoalChecker()
Destroy the Axis 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 > ¶meters)
Validate incoming parameter updates before applying them. This callback is triggered when one or more...
void reset() override
Reset the goal checker state.
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.
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.
void updateParametersCallback(const std::vector< rclcpp::Parameter > ¶meters)
Apply parameter updates after validation This callback is executed when parameters have been successf...
AxisGoalChecker()
Construct a new Axis Goal Checker object.
Function-object for checking whether a goal has been reached.