// Copyright (c) 2025 Prabhav Saxena // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include "nav2_controller/plugins/position_goal_checker.hpp" #include "pluginlib/class_list_macros.hpp" #include "nav2_util/node_utils.hpp" using rcl_interfaces::msg::ParameterType; using std::placeholders::_1; namespace nav2_controller { PositionGoalChecker::PositionGoalChecker() : xy_goal_tolerance_(0.25), xy_goal_tolerance_sq_(0.0625), stateful_(true), position_reached_(false) { } void PositionGoalChecker::initialize( const rclcpp_lifecycle::LifecycleNode::WeakPtr & parent, const std::string & plugin_name, const std::shared_ptr/*costmap_ros*/) { plugin_name_ = plugin_name; auto node = parent.lock(); nav2_util::declare_parameter_if_not_declared( node, plugin_name + ".xy_goal_tolerance", rclcpp::ParameterValue(0.25)); nav2_util::declare_parameter_if_not_declared( node, plugin_name + ".stateful", rclcpp::ParameterValue(true)); node->get_parameter(plugin_name + ".xy_goal_tolerance", xy_goal_tolerance_); node->get_parameter(plugin_name + ".stateful", stateful_); xy_goal_tolerance_sq_ = xy_goal_tolerance_ * xy_goal_tolerance_; // Add callback for dynamic parameters dyn_params_handler_ = node->add_on_set_parameters_callback( std::bind(&PositionGoalChecker::dynamicParametersCallback, this, _1)); } void PositionGoalChecker::reset() { position_reached_ = false; } bool PositionGoalChecker::isGoalReached( const geometry_msgs::msg::Pose & query_pose, const geometry_msgs::msg::Pose & goal_pose, const geometry_msgs::msg::Twist &) { // If stateful and position was already reached, maintain state if (stateful_ && position_reached_) { return true; } // Check if position is within tolerance double dx = query_pose.position.x - goal_pose.position.x; double dy = query_pose.position.y - goal_pose.position.y; bool position_reached = (dx * dx + dy * dy <= xy_goal_tolerance_sq_); // If stateful, remember that we reached the position if (stateful_ && position_reached) { position_reached_ = true; } return position_reached; } bool PositionGoalChecker::getTolerances( geometry_msgs::msg::Pose & pose_tolerance, geometry_msgs::msg::Twist & vel_tolerance) { double invalid_field = std::numeric_limits::lowest(); pose_tolerance.position.x = xy_goal_tolerance_; pose_tolerance.position.y = xy_goal_tolerance_; pose_tolerance.position.z = invalid_field; // Return zero orientation tolerance as we don't check it pose_tolerance.orientation.x = 0.0; pose_tolerance.orientation.y = 0.0; pose_tolerance.orientation.z = 0.0; pose_tolerance.orientation.w = 1.0; vel_tolerance.linear.x = invalid_field; vel_tolerance.linear.y = invalid_field; vel_tolerance.linear.z = invalid_field; vel_tolerance.angular.x = invalid_field; vel_tolerance.angular.y = invalid_field; vel_tolerance.angular.z = invalid_field; return true; } void nav2_controller::PositionGoalChecker::setXYGoalTolerance(double tolerance) { xy_goal_tolerance_ = tolerance; xy_goal_tolerance_sq_ = tolerance * tolerance; } rcl_interfaces::msg::SetParametersResult PositionGoalChecker::dynamicParametersCallback(std::vector parameters) { rcl_interfaces::msg::SetParametersResult result; for (auto & parameter : parameters) { const auto & type = parameter.get_type(); const auto & name = parameter.get_name(); if (type == ParameterType::PARAMETER_DOUBLE) { if (name == plugin_name_ + ".xy_goal_tolerance") { xy_goal_tolerance_ = parameter.as_double(); xy_goal_tolerance_sq_ = xy_goal_tolerance_ * xy_goal_tolerance_; } } else if (type == ParameterType::PARAMETER_BOOL) { if (name == plugin_name_ + ".stateful") { stateful_ = parameter.as_bool(); } } } result.successful = true; return result; } } // namespace nav2_controller PLUGINLIB_EXPORT_CLASS(nav2_controller::PositionGoalChecker, nav2_core::GoalChecker)