Nav2 Navigation Stack - rolling  main
ROS 2 Navigation Stack
robot_utils.cpp
1 // Copyright (c) 2018 Intel Corporation
2 // Copyright (c) 2019 Steven Macenski
3 // Copyright (c) 2019 Samsung Research America
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #include <string>
18 #include <cmath>
19 #include <memory>
20 
21 #include "tf2/convert.hpp"
22 #include "tf2/utils.hpp"
23 #include "tf2_geometry_msgs/tf2_geometry_msgs.hpp"
24 
25 #include "nav2_util/robot_utils.hpp"
26 #include "rclcpp/logger.hpp"
27 
28 namespace nav2_util
29 {
30 
31 bool getCurrentPose(
32  geometry_msgs::msg::PoseStamped & global_pose,
33  tf2_ros::Buffer & tf_buffer, const std::string global_frame,
34  const std::string robot_frame, const double transform_timeout,
35  const rclcpp::Time stamp)
36 {
37  tf2::toMsg(tf2::Transform::getIdentity(), global_pose.pose);
38  global_pose.header.frame_id = robot_frame;
39  global_pose.header.stamp = stamp;
40 
41  return transformPoseInTargetFrame(
42  global_pose, global_pose, tf_buffer, global_frame, transform_timeout);
43 }
44 
45 bool transformPoseInTargetFrame(
46  const geometry_msgs::msg::PoseStamped & input_pose,
47  geometry_msgs::msg::PoseStamped & transformed_pose,
48  tf2_ros::Buffer & tf_buffer, const std::string target_frame,
49  const double transform_timeout)
50 {
51  static rclcpp::Logger logger = rclcpp::get_logger("transformPoseInTargetFrame");
52 
53  if(input_pose.header.frame_id == target_frame) {
54  transformed_pose = input_pose;
55  return true;
56  }
57 
58  try {
59  transformed_pose = tf_buffer.transform(
60  input_pose, target_frame,
61  tf2::durationFromSec(transform_timeout));
62  return true;
63  } catch (tf2::LookupException & ex) {
64  RCLCPP_ERROR(
65  logger,
66  "No Transform available Error looking up target frame: %s\n", ex.what());
67  } catch (tf2::ConnectivityException & ex) {
68  RCLCPP_ERROR(
69  logger,
70  "Connectivity Error looking up target frame: %s\n", ex.what());
71  } catch (tf2::ExtrapolationException & ex) {
72  RCLCPP_ERROR(
73  logger,
74  "Extrapolation Error looking up target frame: %s\n", ex.what());
75  } catch (tf2::TimeoutException & ex) {
76  RCLCPP_ERROR(
77  logger,
78  "Transform timeout with tolerance: %.4f", transform_timeout);
79  } catch (tf2::TransformException & ex) {
80  RCLCPP_ERROR(
81  logger, "Failed to transform from %s to %s",
82  input_pose.header.frame_id.c_str(), target_frame.c_str());
83  }
84 
85  return false;
86 }
87 
88 bool getTransform(
89  const std::string & source_frame_id,
90  const std::string & target_frame_id,
91  const tf2::Duration & transform_tolerance,
92  const std::shared_ptr<tf2_ros::Buffer> tf_buffer,
93  geometry_msgs::msg::TransformStamped & transform_msg)
94 {
95  if (source_frame_id == target_frame_id) {
96  // We are already in required frame
97  return true;
98  }
99 
100  try {
101  // Obtaining the transform to get data from source to target frame
102  transform_msg = tf_buffer->lookupTransform(
103  target_frame_id, source_frame_id,
104  tf2::TimePointZero, transform_tolerance);
105  } catch (tf2::TransformException & e) {
106  RCLCPP_ERROR(
107  rclcpp::get_logger("getTransform"),
108  "Failed to get \"%s\"->\"%s\" frame transform: %s",
109  source_frame_id.c_str(), target_frame_id.c_str(), e.what());
110  return false;
111  }
112  return true;
113 }
114 
115 bool getTransform(
116  const std::string & source_frame_id,
117  const std::string & target_frame_id,
118  const tf2::Duration & transform_tolerance,
119  const std::shared_ptr<tf2_ros::Buffer> tf_buffer,
120  tf2::Transform & tf2_transform)
121 {
122  tf2_transform.setIdentity(); // initialize by identical transform
123  geometry_msgs::msg::TransformStamped transform;
124  if (getTransform(source_frame_id, target_frame_id, transform_tolerance, tf_buffer, transform)) {
125  // Convert TransformStamped to TF2 transform
126  tf2::fromMsg(transform.transform, tf2_transform);
127  return true;
128  }
129  return false;
130 }
131 
132 bool getTransform(
133  const std::string & source_frame_id,
134  const rclcpp::Time & source_time,
135  const std::string & target_frame_id,
136  const rclcpp::Time & target_time,
137  const std::string & fixed_frame_id,
138  const tf2::Duration & transform_tolerance,
139  const std::shared_ptr<tf2_ros::Buffer> tf_buffer,
140  geometry_msgs::msg::TransformStamped & transform_msg)
141 {
142  try {
143  // Obtaining the transform to get data from source to target frame.
144  // This also considers the time shift between source and target.
145  transform_msg = tf_buffer->lookupTransform(
146  target_frame_id, target_time,
147  source_frame_id, source_time,
148  fixed_frame_id, transform_tolerance);
149  } catch (tf2::TransformException & ex) {
150  RCLCPP_ERROR(
151  rclcpp::get_logger("getTransform"),
152  "Failed to get \"%s\"->\"%s\" frame transform: %s",
153  source_frame_id.c_str(), target_frame_id.c_str(), ex.what());
154  return false;
155  }
156 
157  return true;
158 }
159 
160 bool getTransform(
161  const std::string & source_frame_id,
162  const rclcpp::Time & source_time,
163  const std::string & target_frame_id,
164  const rclcpp::Time & target_time,
165  const std::string & fixed_frame_id,
166  const tf2::Duration & transform_tolerance,
167  const std::shared_ptr<tf2_ros::Buffer> tf_buffer,
168  tf2::Transform & tf2_transform)
169 {
170  geometry_msgs::msg::TransformStamped transform;
171  tf2_transform.setIdentity(); // initialize by identical transform
172  if (getTransform(
173  source_frame_id, source_time, target_frame_id, target_time, fixed_frame_id,
174  transform_tolerance, tf_buffer, transform))
175  {
176  // Convert TransformStamped to TF2 transform
177  tf2::fromMsg(transform.transform, tf2_transform);
178  return true;
179  }
180 
181  return false;
182 }
183 
184 bool validateTwist(const geometry_msgs::msg::Twist & msg)
185 {
186  if (std::isinf(msg.linear.x) || std::isnan(msg.linear.x)) {
187  return false;
188  }
189 
190  if (std::isinf(msg.linear.y) || std::isnan(msg.linear.y)) {
191  return false;
192  }
193 
194  if (std::isinf(msg.linear.z) || std::isnan(msg.linear.z)) {
195  return false;
196  }
197 
198  if (std::isinf(msg.angular.x) || std::isnan(msg.angular.x)) {
199  return false;
200  }
201 
202  if (std::isinf(msg.angular.y) || std::isnan(msg.angular.y)) {
203  return false;
204  }
205 
206  if (std::isinf(msg.angular.z) || std::isnan(msg.angular.z)) {
207  return false;
208  }
209 
210  return true;
211 }
212 
213 } // end namespace nav2_util