Nav2 Navigation Stack - rolling  main
ROS 2 Navigation Stack
truncate_path_local_action.cpp
1 // Copyright (c) 2021 RoboTech Vision
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 <cmath>
16 #include <limits>
17 #include <memory>
18 #include <string>
19 #include <vector>
20 
21 #include "behaviortree_cpp/decorator_node.h"
22 #include "geometry_msgs/msg/pose_stamped.hpp"
23 #include "nav2_util/geometry_utils.hpp"
24 #include "nav2_util/robot_utils.hpp"
25 #include "nav_msgs/msg/path.hpp"
26 #include "rclcpp/rclcpp.hpp"
27 #include "tf2/LinearMath/Quaternion.hpp"
28 #include "nav2_ros_common/tf2_factories.hpp"
29 
30 #include "nav2_behavior_tree/plugins/action/truncate_path_local_action.hpp"
31 
32 namespace nav2_behavior_tree
33 {
34 
36  const std::string & name,
37  const BT::NodeConfiguration & conf)
38 : BT::ActionNodeBase(name, conf)
39 {
40  tf_buffer_ =
41  config().blackboard->template get<nav2::TransformBuffer::SharedPtr>(
42  "tf_buffer");
43  auto node = config().blackboard->get<nav2::LifecycleNode::SharedPtr>("node");
44  clock_ = node->get_clock();
45  transform_staleness_threshold_ = node->declare_or_get_parameter(
46  "transform_staleness_threshold", 0.0);
47 }
48 
49 inline BT::NodeStatus TruncatePathLocal::tick()
50 {
51  setStatus(BT::NodeStatus::RUNNING);
52 
53  double distance_forward, distance_backward;
54  geometry_msgs::msg::PoseStamped pose;
55  double angular_distance_weight;
56  double max_robot_pose_search_dist;
57 
58  getInput("distance_forward", distance_forward);
59  getInput("distance_backward", distance_backward);
60  getInput("angular_distance_weight", angular_distance_weight);
61  getInput("max_robot_pose_search_dist", max_robot_pose_search_dist);
62 
63  bool path_pruning = std::isfinite(max_robot_pose_search_dist);
64  if (distance_forward < 0.0) {
65  distance_forward = std::numeric_limits<double>::max();
66  }
67  nav_msgs::msg::Path new_path;
68  getInput("input_path", new_path);
69  if (!path_pruning || new_path != path_) {
70  path_ = new_path;
71  closest_pose_detection_begin_ = path_.poses.begin();
72  }
73 
74  if (!getRobotPose(path_.header.frame_id, pose)) {
75  return BT::NodeStatus::FAILURE;
76  }
77 
78  if (path_.poses.empty()) {
79  setOutput("output_path", path_);
80  return BT::NodeStatus::SUCCESS;
81  }
82 
83  auto closest_pose_detection_end = path_.poses.end();
84  if (path_pruning) {
85  closest_pose_detection_end = nav2_util::geometry_utils::first_after_integrated_distance(
86  closest_pose_detection_begin_, path_.poses.end(), max_robot_pose_search_dist);
87  }
88 
89  // find the closest pose on the path
90  auto current_pose = nav2_util::geometry_utils::min_by(
91  closest_pose_detection_begin_, closest_pose_detection_end,
92  [&pose, angular_distance_weight](const geometry_msgs::msg::PoseStamped & ps) {
93  return poseDistance(pose, ps, angular_distance_weight);
94  });
95 
96  if (path_pruning) {
97  closest_pose_detection_begin_ = current_pose;
98  }
99 
100  // expand forwards to extract desired length
101  auto forward_pose_it = nav2_util::geometry_utils::first_after_integrated_distance(
102  current_pose, path_.poses.end(), distance_forward);
103 
104  // expand backwards to extract desired length
105  // Note: current_pose + 1 is used because reverse iterator points to a cell before it
106  auto backward_pose_it = nav2_util::geometry_utils::first_after_integrated_distance(
107  std::reverse_iterator(current_pose + 1), path_.poses.rend(), distance_backward);
108 
109  nav_msgs::msg::Path output_path;
110  output_path.header = path_.header;
111  output_path.poses = std::vector<geometry_msgs::msg::PoseStamped>(
112  backward_pose_it.base(), forward_pose_it);
113  setOutput("output_path", output_path);
114 
115  return BT::NodeStatus::SUCCESS;
116 }
117 
118 inline bool TruncatePathLocal::getRobotPose(
119  std::string path_frame_id, geometry_msgs::msg::PoseStamped & pose)
120 {
121  if (!getInput("pose", pose)) {
122  auto node = config().blackboard->get<nav2::LifecycleNode::SharedPtr>("node");
123  std::string robot_frame = BT::deconflictPortAndParamFrame<std::string>(
124  node, "robot_base_frame", this);
125  if (robot_frame.empty()) {
126  RCLCPP_ERROR(
127  node->get_logger(),
128  "Neither pose nor robot_base_frame specified for %s", name().c_str());
129  return false;
130  }
131  if (!nav2_util::getFreshPose(
132  *tf_buffer_, path_frame_id, robot_frame, clock_->now(), transform_staleness_threshold_,
133  pose))
134  {
135  RCLCPP_WARN(
136  node->get_logger(),
137  "Failed to lookup current robot pose for %s", name().c_str());
138  return false;
139  }
140  }
141  return true;
142 }
143 
144 double
145 TruncatePathLocal::poseDistance(
146  const geometry_msgs::msg::PoseStamped & pose1,
147  const geometry_msgs::msg::PoseStamped & pose2,
148  const double angular_distance_weight)
149 {
150  double dx = pose1.pose.position.x - pose2.pose.position.x;
151  double dy = pose1.pose.position.y - pose2.pose.position.y;
152  // taking angular distance into account in addition to spatial distance
153  // (to improve picking a correct pose near cusps and loops)
154  tf2::Quaternion q1;
155  tf2::convert(pose1.pose.orientation, q1);
156  tf2::Quaternion q2;
157  tf2::convert(pose2.pose.orientation, q2);
158  double da = angular_distance_weight * std::abs(q1.angleShortestPath(q2));
159  return std::sqrt(dx * dx + dy * dy + da * da);
160 }
161 
162 } // namespace nav2_behavior_tree
163 
164 #include "behaviortree_cpp/bt_factory.h"
165 BT_REGISTER_NODES(factory) {
166  factory.registerNodeType<nav2_behavior_tree::TruncatePathLocal>(
167  "TruncatePathLocal");
168 }
A BT::ActionNodeBase to shorten path to some distance around robot.
TruncatePathLocal(const std::string &xml_tag_name, const BT::NodeConfiguration &conf)
A nav2_behavior_tree::TruncatePathLocal constructor.