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 path_length_tolerance_(1.0), direction_estimation_distance_(0.15), is_overshoot_valid_(false)
40 auto node = node_.lock();
41 if (post_set_params_handler_ && node) {
42 node->remove_post_set_parameters_callback(post_set_params_handler_.get());
44 post_set_params_handler_.reset();
45 if (on_set_params_handler_ && node) {
46 node->remove_on_set_parameters_callback(on_set_params_handler_.get());
48 on_set_params_handler_.reset();
52 const nav2::LifecycleNode::WeakPtr & parent,
53 const std::string & plugin_name,
54 const std::shared_ptr<nav2_costmap_2d::Costmap2DROS>)
56 plugin_name_ = plugin_name;
58 auto node = node_.lock();
59 logger_ = node->get_logger();
61 along_path_tolerance_ = node->declare_or_get_parameter(
62 plugin_name +
".along_path_tolerance", 0.25);
63 cross_track_tolerance_ = node->declare_or_get_parameter(
64 plugin_name +
".cross_track_tolerance", 0.25);
65 path_length_tolerance_ = node->declare_or_get_parameter(
66 plugin_name +
".path_length_tolerance", 1.0);
67 direction_estimation_distance_ = node->declare_or_get_parameter(
68 plugin_name +
".direction_estimation_distance", 0.15);
69 is_overshoot_valid_ = node->declare_or_get_parameter(
70 plugin_name +
".is_overshoot_valid",
false);
73 post_set_params_handler_ = node->add_post_set_parameters_callback(
76 this, std::placeholders::_1));
77 on_set_params_handler_ = node->add_on_set_parameters_callback(
80 this, std::placeholders::_1));
85 std::lock_guard<std::mutex> lock_reinit(mutex_);
86 cached_end_of_path_yaw_.reset();
90 const geometry_msgs::msg::Pose & query_pose,
const geometry_msgs::msg::Pose & goal_pose,
91 const geometry_msgs::msg::Twist & velocity,
92 const nav_msgs::msg::Path & transformed_global_plan)
96 return isGoalXYReached(query_pose, goal_pose, velocity, transformed_global_plan);
100 const geometry_msgs::msg::Pose & query_pose,
const geometry_msgs::msg::Pose & goal_pose,
101 const geometry_msgs::msg::Twist &,
102 const nav_msgs::msg::Path & transformed_global_plan)
104 std::lock_guard<std::mutex> lock_reinit(mutex_);
106 double robot_to_goal_dx = goal_pose.position.x - query_pose.position.x;
107 double robot_to_goal_dy = goal_pose.position.y - query_pose.position.y;
108 double distance_to_goal = std::hypot(robot_to_goal_dx, robot_to_goal_dy);
111 if (distance_to_goal < 1e-6) {
116 for (
int i =
static_cast<int>(transformed_global_plan.poses.size()) - 2; i >= 0; --i) {
117 const auto & candidate_pose = transformed_global_plan.poses[i].pose;
118 double dx = goal_pose.position.x - candidate_pose.position.x;
119 double dy = goal_pose.position.y - candidate_pose.position.y;
121 if (std::hypot(dx, dy) >= direction_estimation_distance_) {
122 cached_end_of_path_yaw_ = atan2(dy, dx);
128 if (nav2_util::geometry_utils::calculate_path_length(transformed_global_plan) >
129 path_length_tolerance_)
135 if (!cached_end_of_path_yaw_.has_value()) {
138 "No path direction available, falling back to simple distance check");
139 return distance_to_goal < std::min(along_path_tolerance_, cross_track_tolerance_);
142 double robot_to_goal_yaw = atan2(robot_to_goal_dy, robot_to_goal_dx);
143 double projection_angle = angles::shortest_angular_distance(
144 robot_to_goal_yaw, cached_end_of_path_yaw_.value());
145 double along_path_distance = distance_to_goal * cos(projection_angle);
146 double cross_track_distance = distance_to_goal * sin(projection_angle);
148 if (is_overshoot_valid_) {
149 return along_path_distance < along_path_tolerance_ &&
150 fabs(cross_track_distance) < cross_track_tolerance_;
152 return fabs(along_path_distance) < along_path_tolerance_ &&
153 fabs(cross_track_distance) < cross_track_tolerance_;
158 geometry_msgs::msg::Pose & pose_tolerance,
159 geometry_msgs::msg::Twist & vel_tolerance,
160 double & path_length_tolerance)
162 std::lock_guard<std::mutex> lock_reinit(mutex_);
163 double invalid_field = std::numeric_limits<double>::lowest();
165 pose_tolerance.position.x = std::min(along_path_tolerance_, cross_track_tolerance_);
166 pose_tolerance.position.y = std::min(along_path_tolerance_, cross_track_tolerance_);
167 pose_tolerance.position.z = invalid_field;
168 pose_tolerance.orientation =
169 nav2_util::geometry_utils::orientationAroundZAxis(M_PI_2);
171 vel_tolerance.linear.x = invalid_field;
172 vel_tolerance.linear.y = invalid_field;
173 vel_tolerance.linear.z = invalid_field;
175 vel_tolerance.angular.x = invalid_field;
176 vel_tolerance.angular.y = invalid_field;
177 vel_tolerance.angular.z = invalid_field;
179 path_length_tolerance = path_length_tolerance_;
184 rcl_interfaces::msg::SetParametersResult
186 const std::vector<rclcpp::Parameter> & parameters)
188 rcl_interfaces::msg::SetParametersResult result;
189 result.successful =
true;
190 for (
auto parameter : parameters) {
191 const auto & param_type = parameter.get_type();
192 const auto & param_name = parameter.get_name();
193 if (param_name.find(plugin_name_ +
".") != 0) {
196 if (param_type == ParameterType::PARAMETER_DOUBLE) {
197 if (parameter.as_double() < 0.0) {
199 logger_,
"The value of parameter '%s' is incorrectly set to %f, "
200 "it should be >=0. Ignoring parameter update.",
201 param_name.c_str(), parameter.as_double());
202 result.successful =
false;
204 if (param_name == plugin_name_ +
".direction_estimation_distance") {
205 const double value = parameter.as_double();
206 if (value <= 0.0 || value >= path_length_tolerance_) {
208 logger_,
"The value of parameter '%s' is set to %f, it should be >0 and "
209 "<path_length_tolerance (%f). Ignoring parameter update.",
210 param_name.c_str(), value, path_length_tolerance_);
211 result.successful =
false;
221 const std::vector<rclcpp::Parameter> & parameters)
223 std::lock_guard<std::mutex> lock_reinit(mutex_);
224 for (
const auto & parameter : parameters) {
225 const auto & type = parameter.get_type();
226 const auto & name = parameter.get_name();
227 if (name.find(plugin_name_ +
".") != 0) {
230 if (type == ParameterType::PARAMETER_DOUBLE) {
231 if (name == plugin_name_ +
".along_path_tolerance") {
232 along_path_tolerance_ = parameter.as_double();
233 }
else if (name == plugin_name_ +
".cross_track_tolerance") {
234 cross_track_tolerance_ = parameter.as_double();
235 }
else if (name == plugin_name_ +
".path_length_tolerance") {
236 path_length_tolerance_ = parameter.as_double();
237 }
else if (name == plugin_name_ +
".direction_estimation_distance") {
238 direction_estimation_distance_ = parameter.as_double();
240 }
else if (type == ParameterType::PARAMETER_BOOL) {
241 if (name == plugin_name_ +
".is_overshoot_valid") {
242 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.