Nav2 Navigation Stack - lyrical  lyrical
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 "nav2_ros_common/tf2_factories.hpp"
24 #include "tf2_geometry_msgs/tf2_geometry_msgs.hpp"
25 
26 #include "nav2_util/robot_utils.hpp"
27 #include "rclcpp/logger.hpp"
28 
29 namespace nav2_util
30 {
31 
32 bool getCurrentPose(
33  geometry_msgs::msg::PoseStamped & global_pose,
34  nav2::TransformBuffer & tf_buffer, const std::string global_frame,
35  const std::string robot_frame, const double transform_timeout,
36  const rclcpp::Time stamp)
37 {
38  tf2::toMsg(tf2::Transform::getIdentity(), global_pose.pose);
39  global_pose.header.frame_id = robot_frame;
40  global_pose.header.stamp = stamp;
41 
42  return transformPoseInTargetFrame(
43  global_pose, global_pose, tf_buffer, global_frame, transform_timeout);
44 }
45 
46 bool transformPoseInTargetFrame(
47  const geometry_msgs::msg::PoseStamped & input_pose,
48  geometry_msgs::msg::PoseStamped & transformed_pose,
49  nav2::TransformBuffer & tf_buffer, const std::string target_frame,
50  const double transform_timeout)
51 {
52  static rclcpp::Logger logger = rclcpp::get_logger("transformPoseInTargetFrame");
53 
54  if (input_pose.header.frame_id == target_frame) {
55  transformed_pose = input_pose;
56  return true;
57  }
58 
59  try {
60  transformed_pose = tf_buffer.transform(
61  input_pose, target_frame,
62  tf2::durationFromSec(transform_timeout));
63  return true;
64  } catch (tf2::LookupException & ex) {
65  RCLCPP_ERROR(
66  logger,
67  "No Transform available Error looking up target frame: %s\n", ex.what());
68  } catch (tf2::ConnectivityException & ex) {
69  RCLCPP_ERROR(
70  logger,
71  "Connectivity Error looking up target frame: %s\n", ex.what());
72  } catch (tf2::ExtrapolationException & ex) {
73  RCLCPP_ERROR(
74  logger,
75  "Extrapolation Error looking up target frame: %s\n", ex.what());
76  } catch (tf2::TimeoutException & ex) {
77  RCLCPP_ERROR(
78  logger,
79  "Transform timeout with tolerance: %.4f", transform_timeout);
80  } catch (tf2::TransformException & ex) {
81  RCLCPP_ERROR(
82  logger, "Failed to transform from %s to %s",
83  input_pose.header.frame_id.c_str(), target_frame.c_str());
84  }
85 
86  return false;
87 }
88 
89 bool getTransform(
90  const std::string & source_frame_id,
91  const std::string & target_frame_id,
92  const tf2::Duration & transform_tolerance,
93  const nav2::TransformBuffer::SharedPtr tf_buffer,
94  geometry_msgs::msg::TransformStamped & transform_msg)
95 {
96  if (source_frame_id == target_frame_id) {
97  // We are already in required frame
98  return true;
99  }
100 
101  try {
102  // Obtaining the transform to get data from source to target frame
103  transform_msg = tf_buffer->lookupTransform(
104  target_frame_id, source_frame_id,
105  tf2::TimePointZero, transform_tolerance);
106  } catch (tf2::TransformException & e) {
107  RCLCPP_ERROR(
108  rclcpp::get_logger("getTransform"),
109  "Failed to get \"%s\"->\"%s\" frame transform: %s",
110  source_frame_id.c_str(), target_frame_id.c_str(), e.what());
111  return false;
112  }
113  return true;
114 }
115 
116 bool getTransform(
117  const std::string & source_frame_id,
118  const std::string & target_frame_id,
119  const tf2::Duration & transform_tolerance,
120  const nav2::TransformBuffer::SharedPtr tf_buffer,
121  tf2::Transform & tf2_transform)
122 {
123  tf2_transform.setIdentity(); // initialize by identical transform
124  geometry_msgs::msg::TransformStamped transform;
125  if (getTransform(source_frame_id, target_frame_id, transform_tolerance, tf_buffer, transform)) {
126  // Convert TransformStamped to TF2 transform
127  tf2::fromMsg(transform.transform, tf2_transform);
128  return true;
129  }
130  return false;
131 }
132 
133 bool getTransform(
134  const std::string & source_frame_id,
135  const rclcpp::Time & source_time,
136  const std::string & target_frame_id,
137  const rclcpp::Time & target_time,
138  const std::string & fixed_frame_id,
139  const tf2::Duration & transform_tolerance,
140  const nav2::TransformBuffer::SharedPtr tf_buffer,
141  geometry_msgs::msg::TransformStamped & transform_msg)
142 {
143  try {
144  // Obtaining the transform to get data from source to target frame.
145  // This also considers the time shift between source and target.
146  transform_msg = tf_buffer->lookupTransform(
147  target_frame_id, target_time,
148  source_frame_id, source_time,
149  fixed_frame_id, transform_tolerance);
150  } catch (tf2::TransformException & ex) {
151  RCLCPP_ERROR(
152  rclcpp::get_logger("getTransform"),
153  "Failed to get \"%s\"->\"%s\" frame transform: %s",
154  source_frame_id.c_str(), target_frame_id.c_str(), ex.what());
155  return false;
156  }
157 
158  return true;
159 }
160 
161 bool getTransform(
162  const std::string & source_frame_id,
163  const rclcpp::Time & source_time,
164  const std::string & target_frame_id,
165  const rclcpp::Time & target_time,
166  const std::string & fixed_frame_id,
167  const tf2::Duration & transform_tolerance,
168  const nav2::TransformBuffer::SharedPtr tf_buffer,
169  tf2::Transform & tf2_transform)
170 {
171  geometry_msgs::msg::TransformStamped transform;
172  tf2_transform.setIdentity(); // initialize by identical transform
173  if (getTransform(
174  source_frame_id, source_time, target_frame_id, target_time, fixed_frame_id,
175  transform_tolerance, tf_buffer, transform))
176  {
177  // Convert TransformStamped to TF2 transform
178  tf2::fromMsg(transform.transform, tf2_transform);
179  return true;
180  }
181 
182  return false;
183 }
184 
185 bool validateTwist(const geometry_msgs::msg::Twist & msg)
186 {
187  if (std::isinf(msg.linear.x) || std::isnan(msg.linear.x)) {
188  return false;
189  }
190 
191  if (std::isinf(msg.linear.y) || std::isnan(msg.linear.y)) {
192  return false;
193  }
194 
195  if (std::isinf(msg.linear.z) || std::isnan(msg.linear.z)) {
196  return false;
197  }
198 
199  if (std::isinf(msg.angular.x) || std::isnan(msg.angular.x)) {
200  return false;
201  }
202 
203  if (std::isinf(msg.angular.y) || std::isnan(msg.angular.y)) {
204  return false;
205  }
206 
207  if (std::isinf(msg.angular.z) || std::isnan(msg.angular.z)) {
208  return false;
209  }
210 
211  return true;
212 }
213 
214 } // end namespace nav2_util