Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
is_goal_nearby_condition.cpp
1 // Copyright (c) 2026 Jakub ChudziƄski
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "nav2_behavior_tree/plugins/condition/is_goal_nearby_condition.hpp"
16 
17 #include "nav2_util/geometry_utils.hpp"
18 #include "nav2_ros_common/tf2_factories.hpp"
19 #include "nav2_util/robot_utils.hpp"
20 
21 namespace nav2_behavior_tree
22 {
23 
24 IsGoalNearbyCondition::IsGoalNearbyCondition(
25  const std::string & condition_name, const BT::NodeConfiguration & conf)
26 : BT::ConditionNode(condition_name, conf), transform_tolerance_(0.1)
27 {
28  node_ = config().blackboard->get<nav2::LifecycleNode::SharedPtr>("node");
29  tf_buffer_ = config().blackboard->get<nav2::TransformBuffer::SharedPtr>("tf_buffer");
30  node_->get_parameter("transform_tolerance", transform_tolerance_);
31 
32  global_frame_ = BT::deconflictPortAndParamFrame<std::string>(node_, "global_frame", this);
33  robot_base_frame_ = BT::deconflictPortAndParamFrame<std::string>(node_, "robot_base_frame", this);
34 }
35 
37 {
38  nav_msgs::msg::Path new_path;
39  double prox_thr = 0.0;
40  double max_robot_pose_search_dist = -1.0;
41  getInput("path", new_path);
42  getInput("proximity_threshold", prox_thr);
43  getInput("max_robot_pose_search_dist", max_robot_pose_search_dist);
44 
45  if (new_path.poses.empty()) {
46  RCLCPP_WARN(node_->get_logger(), "Path is empty");
47  return BT::NodeStatus::FAILURE;
48  }
49 
50  bool path_pruning = true;
51  if (max_robot_pose_search_dist < 0.0) {
52  path_pruning = false;
53  }
54 
55  if (!path_pruning || new_path != path_) {
56  path_ = new_path;
57  closest_pose_detection_begin_ = path_.poses.begin();
58  }
59 
60  geometry_msgs::msg::PoseStamped pose;
61  if (!nav2_util::getCurrentPose(
62  pose, *tf_buffer_, global_frame_, robot_base_frame_, transform_tolerance_))
63  {
64  RCLCPP_ERROR(node_->get_logger(), "Failed to get current robot pose");
65  return BT::NodeStatus::FAILURE;
66  }
67 
68  // let's get the pose of the robot in the frame of the plan
69  geometry_msgs::msg::PoseStamped robot_pose;
70  if (!nav2_util::transformPoseInTargetFrame(
71  pose, robot_pose, *tf_buffer_, path_.header.frame_id))
72  {
73  RCLCPP_ERROR(
74  node_->get_logger(), "Failed to transform robot pose to path frame '%s'",
75  path_.header.frame_id.c_str());
76  return BT::NodeStatus::FAILURE;
77  }
78 
79  auto closest_pose_upper_bound = path_.poses.end();
80  if (path_pruning) {
81  closest_pose_upper_bound = nav2_util::geometry_utils::first_after_integrated_distance(
82  closest_pose_detection_begin_, path_.poses.end(), max_robot_pose_search_dist);
83  }
84 
85  // First find the closest pose on the path to the robot
86  // bounded by when the path turns around (if it does) so we don't get a pose from a later
87  // portion of the path
88  auto closest_pose_it = nav2_util::geometry_utils::min_by(
89  closest_pose_detection_begin_, closest_pose_upper_bound,
90  [&robot_pose](const geometry_msgs::msg::PoseStamped & ps) {
91  return nav2_util::geometry_utils::euclidean_distance(robot_pose, ps);
92  });
93 
94  closest_pose_detection_begin_ = closest_pose_it;
95 
96  const std::size_t closest_index = static_cast<std::size_t>(closest_pose_it - path_.poses.begin());
97  const double remaining_length =
98  nav2_util::geometry_utils::calculate_path_length(path_, closest_index);
99 
100  return (remaining_length < prox_thr) ? BT::NodeStatus::SUCCESS : BT::NodeStatus::FAILURE;
101 }
102 
103 } // namespace nav2_behavior_tree
104 
105 #include "behaviortree_cpp/bt_factory.h"
106 BT_REGISTER_NODES(factory)
107 {
108  factory.registerNodeType<nav2_behavior_tree::IsGoalNearbyCondition>("IsGoalNearby");
109 }
A BT::ConditionNode that returns SUCCESS when remaining length of the current planned path is less th...
BT::NodeStatus tick() override
The main override required by a BT action.