|
1 |
| -// Copyright 2024 TIER IV, Inc. |
| 1 | +// Copyright 2025 The Autoware Contributors |
2 | 2 | //
|
3 | 3 | // Licensed under the Apache License, Version 2.0 (the "License");
|
4 | 4 | // you may not use this file except in compliance with the License.
|
|
15 | 15 | #ifndef AUTOWARE_UTILS__ROS__MANAGED_TRANSFORM_BUFFER_HPP_
|
16 | 16 | #define AUTOWARE_UTILS__ROS__MANAGED_TRANSFORM_BUFFER_HPP_
|
17 | 17 |
|
18 |
| -#include "autoware_utils/ros/transform_listener.hpp" |
19 |
| - |
20 |
| -#include <eigen3/Eigen/Core> |
21 |
| -#include <pcl_ros/transforms.hpp> |
22 |
| -#include <rclcpp/rclcpp.hpp> |
23 |
| - |
24 |
| -#include <sensor_msgs/point_cloud2_iterator.hpp> |
25 |
| - |
26 |
| -#include <pcl_conversions/pcl_conversions.h> |
27 |
| - |
28 |
| -#include <chrono> |
29 |
| -#include <functional> |
30 |
| -#include <memory> |
31 |
| -#include <string> |
32 |
| -#include <string_view> |
33 |
| -#include <unordered_map> |
34 |
| -#include <utility> |
35 |
| - |
36 |
| -namespace std |
37 |
| -{ |
38 |
| -template <> |
39 |
| -struct hash<std::pair<std::string, std::string>> |
40 |
| -{ |
41 |
| - size_t operator()(const std::pair<std::string, std::string> & p) const |
42 |
| - { |
43 |
| - size_t h1 = std::hash<std::string>{}(p.first); |
44 |
| - size_t h2 = std::hash<std::string>{}(p.second); |
45 |
| - return h1 ^ (h2 << 1u); |
46 |
| - } |
47 |
| -}; |
48 |
| -} // namespace std |
| 18 | +#include <autoware_utils_pcl/managed_transform_buffer.hpp> |
49 | 19 |
|
50 | 20 | namespace autoware_utils
|
51 | 21 | {
|
52 |
| -using std::chrono_literals::operator""ms; |
53 |
| -using Key = std::pair<std::string, std::string>; |
54 |
| -struct PairEqual |
55 |
| -{ |
56 |
| - bool operator()(const Key & p1, const Key & p2) const |
57 |
| - { |
58 |
| - return p1.first == p2.first && p1.second == p2.second; |
59 |
| - } |
60 |
| -}; |
61 |
| -using TFMap = std::unordered_map<Key, Eigen::Matrix4f, std::hash<Key>, PairEqual>; |
62 |
| -constexpr std::array<std::string_view, 3> warn_frames = {"map", "odom", "world"}; |
63 |
| - |
64 |
| -class ManagedTransformBuffer |
65 |
| -{ |
66 |
| -public: |
67 |
| - explicit ManagedTransformBuffer(rclcpp::Node * node, const bool & has_static_tf_only) |
68 |
| - : node_(node) |
69 |
| - { |
70 |
| - if (has_static_tf_only) { |
71 |
| - get_transform_ = [this]( |
72 |
| - const std::string & target_frame, const std::string & source_frame, |
73 |
| - Eigen::Matrix4f & eigen_transform) { |
74 |
| - return get_static_transform(target_frame, source_frame, eigen_transform); |
75 |
| - }; |
76 |
| - } else { |
77 |
| - tf_listener_ = std::make_unique<autoware_utils::TransformListener>(node); |
78 |
| - get_transform_ = [this]( |
79 |
| - const std::string & target_frame, const std::string & source_frame, |
80 |
| - Eigen::Matrix4f & eigen_transform) { |
81 |
| - return get_dynamic_transform(target_frame, source_frame, eigen_transform); |
82 |
| - }; |
83 |
| - } |
84 |
| - } |
85 |
| - |
86 |
| - bool get_transform( |
87 |
| - const std::string & target_frame, const std::string & source_frame, |
88 |
| - Eigen::Matrix4f & eigen_transform) |
89 |
| - { |
90 |
| - return get_transform_(target_frame, source_frame, eigen_transform); |
91 |
| - } |
92 |
| - |
93 |
| - /** |
94 |
| - * Transforms a point cloud from one frame to another. |
95 |
| - * |
96 |
| - * @param target_frame The target frame to transform the point cloud to. |
97 |
| - * @param cloud_in The input point cloud to be transformed. |
98 |
| - * @param cloud_out The transformed point cloud. |
99 |
| - * @return True if the transformation is successful, false otherwise. |
100 |
| - */ |
101 |
| - bool transform_pointcloud( |
102 |
| - const std::string & target_frame, const sensor_msgs::msg::PointCloud2 & cloud_in, |
103 |
| - sensor_msgs::msg::PointCloud2 & cloud_out) |
104 |
| - { |
105 |
| - if ( |
106 |
| - pcl::getFieldIndex(cloud_in, "x") == -1 || pcl::getFieldIndex(cloud_in, "y") == -1 || |
107 |
| - pcl::getFieldIndex(cloud_in, "z") == -1) { |
108 |
| - RCLCPP_ERROR(node_->get_logger(), "Input pointcloud does not have xyz fields"); |
109 |
| - return false; |
110 |
| - } |
111 |
| - if (target_frame == cloud_in.header.frame_id) { |
112 |
| - cloud_out = cloud_in; |
113 |
| - return true; |
114 |
| - } |
115 |
| - Eigen::Matrix4f eigen_transform; |
116 |
| - if (!get_transform(target_frame, cloud_in.header.frame_id, eigen_transform)) { |
117 |
| - return false; |
118 |
| - } |
119 |
| - pcl_ros::transformPointCloud(eigen_transform, cloud_in, cloud_out); |
120 |
| - cloud_out.header.frame_id = target_frame; |
121 |
| - return true; |
122 |
| - } |
123 |
| - |
124 |
| -private: |
125 |
| - /** |
126 |
| - * @brief Retrieves a transform between two static frames. |
127 |
| - * |
128 |
| - * This function attempts to retrieve a transform between the target frame and the source frame. |
129 |
| - * If success, the transform matrix is set to the output parameter and the function returns true. |
130 |
| - * Otherwise, transform matrix is set to identity and the function returns false. Transform |
131 |
| - * Listener is destroyed after function call. |
132 |
| - * |
133 |
| - * @param target_frame The target frame. |
134 |
| - * @param source_frame The source frame. |
135 |
| - * @param eigen_transform The output Eigen transform matrix. It is set to the identity if the |
136 |
| - * transform is not found. |
137 |
| - * @return True if the transform was successfully retrieved, false otherwise. |
138 |
| - */ |
139 |
| - bool get_static_transform( |
140 |
| - const std::string & target_frame, const std::string & source_frame, |
141 |
| - Eigen::Matrix4f & eigen_transform) |
142 |
| - { |
143 |
| - if ( |
144 |
| - std::find(warn_frames.begin(), warn_frames.end(), target_frame) != warn_frames.end() || |
145 |
| - std::find(warn_frames.begin(), warn_frames.end(), source_frame) != warn_frames.end()) { |
146 |
| - RCLCPP_WARN( |
147 |
| - node_->get_logger(), "Using %s -> %s transform. This may not be a static transform.", |
148 |
| - target_frame.c_str(), source_frame.c_str()); |
149 |
| - } |
150 |
| - |
151 |
| - auto key = std::make_pair(target_frame, source_frame); |
152 |
| - auto key_inv = std::make_pair(source_frame, target_frame); |
153 |
| - |
154 |
| - // Check if the transform is already in the buffer |
155 |
| - auto it = buffer_.find(key); |
156 |
| - if (it != buffer_.end()) { |
157 |
| - eigen_transform = it->second; |
158 |
| - return true; |
159 |
| - } |
160 |
| - |
161 |
| - // Check if the inverse transform is already in the buffer |
162 |
| - auto it_inv = buffer_.find(key_inv); |
163 |
| - if (it_inv != buffer_.end()) { |
164 |
| - eigen_transform = it_inv->second.inverse(); |
165 |
| - buffer_[key] = eigen_transform; |
166 |
| - return true; |
167 |
| - } |
168 |
| - |
169 |
| - // Check if transform is needed |
170 |
| - if (target_frame == source_frame) { |
171 |
| - eigen_transform = Eigen::Matrix4f::Identity(); |
172 |
| - buffer_[key] = eigen_transform; |
173 |
| - return true; |
174 |
| - } |
175 |
| - |
176 |
| - // Get the transform from the TF tree |
177 |
| - tf_listener_ = std::make_unique<autoware_utils::TransformListener>(node_); |
178 |
| - auto tf = tf_listener_->get_transform( |
179 |
| - target_frame, source_frame, rclcpp::Time(0), rclcpp::Duration(1000ms)); |
180 |
| - tf_listener_.reset(); |
181 |
| - RCLCPP_DEBUG( |
182 |
| - node_->get_logger(), "Trying to enqueue %s -> %s transform to static TFs buffer...", |
183 |
| - target_frame.c_str(), source_frame.c_str()); |
184 |
| - if (tf == nullptr) { |
185 |
| - eigen_transform = Eigen::Matrix4f::Identity(); |
186 |
| - return false; |
187 |
| - } |
188 |
| - pcl_ros::transformAsMatrix(*tf, eigen_transform); |
189 |
| - buffer_[key] = eigen_transform; |
190 |
| - return true; |
191 |
| - } |
192 |
| - |
193 |
| - /** @brief Retrieves a transform between two dynamic frames. |
194 |
| - * |
195 |
| - * This function attempts to retrieve a transform between the target frame and the source frame. |
196 |
| - * If successful, the transformation matrix is assigned to the output parameter, and the function |
197 |
| - * returns true. Otherwise, the transformation matrix is set to the identity and the function |
198 |
| - * returns false. |
199 |
| - * |
200 |
| - * @param target_frame The target frame. |
201 |
| - * @param source_frame The source frame. |
202 |
| - * @param eigen_transform The output Eigen transformation matrix. It is set to the identity if the |
203 |
| - * transform is not found. |
204 |
| - * @return True if the transform was successfully retrieved, false otherwise. |
205 |
| - */ |
206 |
| - bool get_dynamic_transform( |
207 |
| - const std::string & target_frame, const std::string & source_frame, |
208 |
| - Eigen::Matrix4f & eigen_transform) |
209 |
| - { |
210 |
| - auto tf = tf_listener_->get_transform( |
211 |
| - target_frame, source_frame, rclcpp::Time(0), rclcpp::Duration(1000ms)); |
212 |
| - if (tf == nullptr) { |
213 |
| - eigen_transform = Eigen::Matrix4f::Identity(); |
214 |
| - return false; |
215 |
| - } |
216 |
| - pcl_ros::transformAsMatrix(*tf, eigen_transform); |
217 |
| - return true; |
218 |
| - } |
219 | 22 |
|
220 |
| - TFMap buffer_; |
221 |
| - rclcpp::Node * const node_; |
222 |
| - std::unique_ptr<autoware_utils::TransformListener> tf_listener_; |
223 |
| - std::function<bool(const std::string &, const std::string &, Eigen::Matrix4f &)> get_transform_; |
224 |
| -}; |
| 23 | +using namespace autoware_utils_pcl; // NOLINT(build/namespaces) |
225 | 24 |
|
226 | 25 | } // namespace autoware_utils
|
227 | 26 |
|
|
0 commit comments