Nav2 Navigation Stack - rolling  main
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  clock_ = node_->get_clock();
30  tf_buffer_ = config().blackboard->get<nav2::TransformBuffer::SharedPtr>("tf_buffer");
31  node_->get_parameter("transform_tolerance", transform_tolerance_);
32  transform_staleness_threshold_ = node_->declare_or_get_parameter(
33  "transform_staleness_threshold", 0.0);
34 
35  global_frame_ = BT::deconflictPortAndParamFrame<std::string>(node_, "global_frame", this);
36  robot_base_frame_ = BT::deconflictPortAndParamFrame<std::string>(node_, "robot_base_frame", this);
37 }
38 
40 {
41  nav_msgs::msg::Path new_path;
42  double prox_thr = 0.0;
43  double max_robot_pose_search_dist = -1.0;
44  getInput("path", new_path);
45  getInput("proximity_threshold", prox_thr);
46  getInput("max_robot_pose_search_dist", max_robot_pose_search_dist);
47 
48  if (new_path.poses.empty()) {
49  RCLCPP_WARN(node_->get_logger(), "Path is empty");
50  return BT::NodeStatus::FAILURE;
51  }
52 
53  bool path_pruning = true;
54  if (max_robot_pose_search_dist < 0.0) {
55  path_pruning = false;
56  }
57 
58  if (!path_pruning || new_path != path_) {
59  path_ = new_path;
60  closest_pose_detection_begin_ = path_.poses.begin();
61  }
62 
63  geometry_msgs::msg::PoseStamped pose;
64  if (!nav2_util::getFreshPose(
65  *tf_buffer_, global_frame_, robot_base_frame_, clock_->now(), transform_staleness_threshold_,
66  pose))
67  {
68  RCLCPP_ERROR(node_->get_logger(), "Failed to get current robot pose");
69  return BT::NodeStatus::FAILURE;
70  }
71 
72  // let's get the pose of the robot in the frame of the plan
73  geometry_msgs::msg::PoseStamped robot_pose;
74  if (!nav2_util::transformPoseInTargetFrame(
75  pose, robot_pose, *tf_buffer_, path_.header.frame_id))
76  {
77  RCLCPP_ERROR(
78  node_->get_logger(), "Failed to transform robot pose to path frame '%s'",
79  path_.header.frame_id.c_str());
80  return BT::NodeStatus::FAILURE;
81  }
82 
83  auto closest_pose_upper_bound = path_.poses.end();
84  if (path_pruning) {
85  closest_pose_upper_bound = nav2_util::geometry_utils::first_after_integrated_distance(
86  closest_pose_detection_begin_, path_.poses.end(), max_robot_pose_search_dist);
87  }
88 
89  // First find the closest pose on the path to the robot
90  // bounded by when the path turns around (if it does) so we don't get a pose from a later
91  // portion of the path
92  auto closest_pose_it = nav2_util::geometry_utils::min_by(
93  closest_pose_detection_begin_, closest_pose_upper_bound,
94  [&robot_pose](const geometry_msgs::msg::PoseStamped & ps) {
95  return nav2_util::geometry_utils::euclidean_distance(robot_pose, ps);
96  });
97 
98  closest_pose_detection_begin_ = closest_pose_it;
99 
100  const std::size_t closest_index = static_cast<std::size_t>(closest_pose_it - path_.poses.begin());
101  const double remaining_length =
102  nav2_util::geometry_utils::calculate_path_length(path_, closest_index);
103 
104  return (remaining_length < prox_thr) ? BT::NodeStatus::SUCCESS : BT::NodeStatus::FAILURE;
105 }
106 
107 } // namespace nav2_behavior_tree
108 
109 #include "behaviortree_cpp/bt_factory.h"
110 BT_REGISTER_NODES(factory)
111 {
112  factory.registerNodeType<nav2_behavior_tree::IsGoalNearbyCondition>("IsGoalNearby");
113 }
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.