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