Skip to content

Commit 62b5953

Browse files
authored
feat(autoware_utils_pcl): split package (#29)
* feat(autoware_utils_pcl): split package Signed-off-by: Takagi, Isamu <isamu.takagi@tier4.jp> * add maintainer Signed-off-by: Takagi, Isamu <isamu.takagi@tier4.jp> * fix build error Signed-off-by: Takagi, Isamu <isamu.takagi@tier4.jp> * add compatibility Signed-off-by: Takagi, Isamu <isamu.takagi@tier4.jp> * rename package Signed-off-by: Takagi, Isamu <isamu.takagi@tier4.jp> * update readme Signed-off-by: Takagi, Isamu <isamu.takagi@tier4.jp> --------- Signed-off-by: Takagi, Isamu <isamu.takagi@tier4.jp>
1 parent 2a2ffa0 commit 62b5953

File tree

16 files changed

+615
-412
lines changed

16 files changed

+615
-412
lines changed

autoware_utils/README.md

-67
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ The ROS module provides utilities for working with ROS messages and nodes:
4747
- **`debug_publisher.hpp`**: A helper class for publishing debug messages with timestamps.
4848
- **`diagnostics_interface.hpp`**: An interface for publishing diagnostic messages.
4949
- **`logger_level_configure.hpp`**: Utility for configuring logger levels dynamically.
50-
- **`managed_transform_buffer.hpp`**: A managed buffer for handling static and dynamic transforms.
5150
- **`marker_helper.hpp`**: Helper functions for creating and manipulating visualization markers.
5251
- **`msg_covariance.hpp`**: Indices for accessing covariance matrices in ROS messages.
5352
- **`msg_operation.hpp`**: Overloaded operators for quaternion messages.
@@ -56,12 +55,10 @@ The ROS module provides utilities for working with ROS messages and nodes:
5655
- **`processing_time_publisher.hpp`**: Publishes processing times as diagnostic messages.
5756
- **`published_time_publisher.hpp`**: Tracks and publishes the time when messages are published.
5857
- **`self_pose_listener.hpp`**: Listens to the self-pose of the vehicle.
59-
- **`transform_listener.hpp`**: Manages transformation listeners.
6058
- **`update_param.hpp`**: Updates parameters from remote nodes.
6159
- **`uuid_helper.hpp`**: Utilities for generating and managing UUIDs.
6260
- **`wait_for_param.hpp`**: Waits for parameters from remote nodes.
6361
- **`debug_traits.hpp`**: Traits for identifying debug message types.
64-
- **`pcl_conversion.hpp`**: Efficient conversion and transformation of PointCloud2 messages to PCL point clouds.
6562

6663
#### System Module
6764

@@ -72,10 +69,6 @@ The system module provides low-level utilities for performance monitoring and er
7269
- **`stop_watch.hpp`**: Measures elapsed time for profiling.
7370
- **`time_keeper.hpp`**: Tracks and reports the processing time of various functions.
7471

75-
#### Transform Module
76-
77-
Efficient methods for transforming and manipulating point clouds.
78-
7972
## Usage
8073

8174
### Including Headers
@@ -140,36 +133,6 @@ int main() {
140133

141134
### Detailed Usage Examples
142135

143-
#### Transform Point Clouds with ManagedTransformBuffer
144-
145-
```cpp
146-
#include "autoware_utils/ros/managed_transform_buffer.hpp"
147-
#include "sensor_msgs/msg/point_cloud2.hpp"
148-
#include <rclcpp/rclcpp.hpp>
149-
150-
int main(int argc, char * argv[]) {
151-
rclcpp::init(argc, argv);
152-
auto node = rclcpp::Node::make_shared("transform_node");
153-
154-
// Initialize ManagedTransformBuffer
155-
autoware_utils::ManagedTransformBuffer transform_buffer(node, false);
156-
157-
// Load point cloud data
158-
sensor_msgs::msg::PointCloud2 cloud_in; // Assume this is populated with data
159-
sensor_msgs::msg::PointCloud2 cloud_out;
160-
161-
// Transform point cloud from "base_link" to "map" frame
162-
if (transform_buffer.transform_pointcloud("map", cloud_in, cloud_out)) {
163-
RCLCPP_INFO(node->get_logger(), "Point cloud transformed successfully.");
164-
} else {
165-
RCLCPP_ERROR(node->get_logger(), "Failed to transform point cloud.");
166-
}
167-
168-
rclcpp::shutdown();
169-
return 0;
170-
}
171-
```
172-
173136
#### Update Parameters Dynamically with update_param.hpp
174137

175138
```cpp
@@ -250,36 +213,6 @@ int main(int argc, char * argv[]) {
250213
}
251214
```
252215
253-
#### Efficient Point Cloud Conversion with pcl_conversion.hpp
254-
255-
```cpp
256-
#include "autoware_utils/ros/pcl_conversion.hpp"
257-
#include "sensor_msgs/msg/point_cloud2.hpp"
258-
#include <pcl/point_types.h>
259-
#include <pcl/PCLPointCloud2.h>
260-
#include <Eigen/Core>
261-
#include <rclcpp/rclcpp.hpp>
262-
263-
int main(int argc, char * argv[]) {
264-
rclcpp::init(argc, argv);
265-
auto node = rclcpp::Node::make_shared("pcl_conversion_node");
266-
267-
// Load point cloud data
268-
sensor_msgs::msg::PointCloud2 cloud_in; // Assume this is populated with data
269-
pcl::PointCloud<pcl::PointXYZ> pcl_cloud;
270-
271-
// Define transformation matrix
272-
Eigen::Matrix4f transform = Eigen::Matrix4f::Identity();
273-
// Populate transform matrix with actual values
274-
275-
// Convert and transform point cloud
276-
autoware_utils::transform_point_cloud_from_ros_msg(cloud_in, pcl_cloud, transform);
277-
278-
rclcpp::shutdown();
279-
return 0;
280-
}
281-
```
282-
283216
#### Handling Debug Message Types with debug_traits.hpp
284217
285218
```cpp

autoware_utils/include/autoware_utils/ros/managed_transform_buffer.hpp

+3-204
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2024 TIER IV, Inc.
1+
// Copyright 2025 The Autoware Contributors
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -15,213 +15,12 @@
1515
#ifndef AUTOWARE_UTILS__ROS__MANAGED_TRANSFORM_BUFFER_HPP_
1616
#define AUTOWARE_UTILS__ROS__MANAGED_TRANSFORM_BUFFER_HPP_
1717

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>
4919

5020
namespace autoware_utils
5121
{
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-
}
21922

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)
22524

22625
} // namespace autoware_utils
22726

autoware_utils/include/autoware_utils/ros/pcl_conversion.hpp

+3-48
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2023 Tier IV, Inc.
1+
// Copyright 2025 The Autoware Contributors
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -15,57 +15,12 @@
1515
#ifndef AUTOWARE_UTILS__ROS__PCL_CONVERSION_HPP_
1616
#define AUTOWARE_UTILS__ROS__PCL_CONVERSION_HPP_
1717

18-
#include <pcl/common/transforms.h>
19-
#include <pcl_conversions/pcl_conversions.h>
20-
21-
#include <vector>
18+
#include <autoware_utils_pcl/pcl_conversion.hpp>
2219

2320
namespace autoware_utils
2421
{
25-
/**
26-
* @brief a faster implementation of converting sensor_msgs::msg::PointCloud2 to
27-
* pcl::PointCloud<pcl::PointXYZ> and transform the cloud
28-
*
29-
* @tparam Scalar
30-
* @param cloud input PointCloud2 message
31-
* @param pcl_cloud output transformed pcl cloud
32-
* @param transform eigen transformation matrix
33-
*/
34-
template <typename Scalar>
35-
void transform_point_cloud_from_ros_msg(
36-
const sensor_msgs::msg::PointCloud2 & cloud, pcl::PointCloud<pcl::PointXYZ> & pcl_cloud,
37-
const Eigen::Matrix<Scalar, 4, 4> & transform)
38-
{
39-
// Copy info fields
40-
pcl_conversions::toPCL(cloud.header, pcl_cloud.header);
41-
pcl_cloud.width = cloud.width;
42-
pcl_cloud.height = cloud.height;
43-
pcl_cloud.is_dense = cloud.is_dense == 1;
44-
45-
pcl::MsgFieldMap field_map;
46-
std::vector<pcl::PCLPointField> msg_fields;
47-
pcl_conversions::toPCL(cloud.fields, msg_fields);
48-
pcl::createMapping<pcl::PointXYZ>(msg_fields, field_map);
49-
50-
// transform point data
51-
std::uint32_t num_points = cloud.width * cloud.height;
52-
pcl_cloud.points.resize(num_points);
53-
std::uint8_t * cloud_data = reinterpret_cast<std::uint8_t *>(&pcl_cloud.points[0]);
54-
pcl::detail::Transformer<Scalar> tf(transform);
5522

56-
for (std::uint32_t row = 0; row < cloud.height; ++row) {
57-
const std::uint8_t * row_data = &cloud.data[row * cloud.row_step];
58-
for (std::uint32_t col = 0; col < cloud.width; ++col) {
59-
const std::uint8_t * msg_data = row_data + col * cloud.point_step;
60-
for (const pcl::detail::FieldMapping & mapping : field_map) {
61-
const float * msg_ptr = reinterpret_cast<const float *>(msg_data);
62-
float * pcl_ptr = reinterpret_cast<float *>(cloud_data + mapping.struct_offset);
63-
tf.se3(msg_ptr, pcl_ptr);
64-
}
65-
cloud_data += sizeof(pcl::PointXYZ);
66-
}
67-
}
68-
}
23+
using namespace autoware_utils_pcl; // NOLINT(build/namespaces)
6924

7025
} // namespace autoware_utils
7126

0 commit comments

Comments
 (0)