point_cloud_fusion v1.4.0
Loading...
Searching...
No Matches
point_cloud_fusion.hpp
Go to the documentation of this file.
1// Copyright Institute for Automotive Engineering (ika), RWTH Aachen University
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include <chrono>
7#include <limits>
8#include <memory>
9#include <mutex>
10#include <optional>
11#include <shared_mutex>
12#include <string>
13#include <vector>
14
15#include <message_filters/subscriber.h>
16#include <message_filters/sync_policies/approximate_time.h>
17#include <message_filters/synchronizer.h>
18#include <pcl/point_cloud.h>
19#include <pcl/point_types.h>
20#include <pcl_conversions/pcl_conversions.h>
21#include <tf2_ros/buffer.h>
22#include <tf2_ros/transform_listener.h>
23#include <geometry_msgs/msg/transform_stamped.hpp>
24#include <point_cloud_transport/point_cloud_transport.hpp>
25#include <point_cloud_transport/subscriber_filter.hpp>
26#include <rclcpp/rclcpp.hpp>
27#include <tf2_sensor_msgs/tf2_sensor_msgs.hpp>
28
29#ifdef ENABLE_CUDA
31#endif
32
34
35template <typename C>
36struct is_vector : std::false_type {};
37template <typename T, typename A>
38struct is_vector<std::vector<T, A>> : std::true_type {};
39template <typename C>
40inline constexpr bool is_vector_v = is_vector<C>::value;
41
45class PointCloudFusion : public rclcpp::Node {
46 public:
52 explicit PointCloudFusion(const rclcpp::NodeOptions& options);
53
54 private:
70 template <typename T>
71 void declareAndLoadParameter(const std::string& name,
72 T& param,
73 const std::string& description,
74 const bool add_to_auto_reconfigurable_params = true,
75 const bool is_required = false,
76 const bool read_only = false,
77 const std::optional<double>& from_value = std::nullopt,
78 const std::optional<double>& to_value = std::nullopt,
79 const std::optional<double>& step_value = std::nullopt,
80 const std::string& additional_constraints = "");
81
88 rcl_interfaces::msg::SetParametersResult parametersCallback(const std::vector<rclcpp::Parameter>& parameters);
89
93 void setup();
94
100 void handleSynchronizedPointClouds(const std::vector<sensor_msgs::msg::PointCloud2::ConstSharedPtr>& msgs);
101
108 template <std::size_t N>
109 void setupSynchronizer();
110
111 using PointCloudMsg = sensor_msgs::msg::PointCloud2;
112
120 FusionTiming() = default;
121 rclcpp::Time earliest_stamp;
122 rclcpp::Time latest_stamp;
123 rclcpp::Time input0_stamp;
125 };
126
134 bool collectTimingInfo(const std::vector<PointCloudMsg::ConstSharedPtr>& msgs, FusionTiming& timing) const;
135
145 PointCloudMsg::UniquePtr fusePointCloudBatch(const std::vector<PointCloudMsg::ConstSharedPtr>& msgs,
146 const FusionTiming& timing,
147 std::size_t& valid_point_count) const;
148
149#ifdef ENABLE_CUDA
150 PointCloudMsg::UniquePtr fusePointCloudBatchCUDA(const std::vector<PointCloudMsg::ConstSharedPtr>& msgs,
151 const FusionTiming& timing,
152 std::size_t& valid_point_count) const;
153#endif
154
167 void publishFusedCloud(PointCloudMsg::UniquePtr cloud,
168 const FusionTiming& timing,
169 std::size_t input_count,
170 std::size_t total_points,
171 std::chrono::steady_clock::time_point callback_start,
172 std::chrono::steady_clock::time_point processing_start,
173 std::chrono::steady_clock::time_point processing_end,
174 const char* event_name);
175
177
183 void configureOutputStampMode(const std::string& mode);
187 void validateInputTopicsParameter() const;
188
193 void validateRangeLimits();
194
195 static constexpr int32_t kMinSyncQueueSize = 1;
196 static constexpr int32_t kMaxSyncQueueSize = 1000;
197 static constexpr int32_t kStepSizeSyncQueueSize = 1;
198 static constexpr int32_t kMinOutputQueueSize = 1;
199 static constexpr int32_t kMaxOutputQueueSize = 1000;
200 static constexpr int32_t kStepSizeOutputQueueSize = 1;
201 static constexpr int64_t kMinFixedPointsPerInputCloud = 0;
202 static constexpr int64_t kMaxFixedPointsPerInputCloud = 10000000;
203 static constexpr int64_t kStepSizeFixedPointsPerInputCloud = 100;
204 static constexpr std::size_t kMaxInputTopics = 9;
205 static constexpr const char* kDefaultTransportHint = "raw";
206 static constexpr const char* kAllowedOutputStampModes = "latest, earliest, mean, input0";
207 static constexpr double kMinRangeXY = -1000.0;
208 static constexpr double kMaxRangeXY = 1000.0;
209 static constexpr double kMinRangeZ = -20.0;
210 static constexpr double kMaxRangeZ = 20.0;
211
215 double max_time_diff_sec_ = 0.05; // 50 ms default window
216 double age_penalty_ = 0.1; // Matches message_filters::ApproximateTime default
217 int64_t sync_queue_size_ = 3; // queue size for synchronizer
218 int64_t output_queue_size_ = 10; // queue size for output publisher
219 // Optional: limit each input cloud to this many points before processing.
220 // 0 = disabled (use actual point count per cloud)
223 double range_limits_x_min_ = -1000.0;
224 double range_limits_x_max_ = 1000.0;
225 double range_limits_y_min_ = -1000.0;
226 double range_limits_y_max_ = 1000.0;
227 double range_limits_z_min_ = -20.0;
228 double range_limits_z_max_ = 20.0;
229 bool use_cuda_ = true;
231 std::string output_stamp_mode_param_ = "earliest";
232 std::string target_frame_ = "base_link";
233 std::vector<std::string> output_fields_;
234 std::vector<std::string> input_topics_;
235 std::vector<std::string> input_transport_hints_;
236
240 std::vector<std::tuple<std::string, std::function<void(const rclcpp::Parameter&)>>> auto_reconfigurable_params_;
241 mutable std::shared_mutex config_mutex_;
242
243 std::vector<std::shared_ptr<point_cloud_transport::SubscriberFilter>> cloud_subscribers_;
244 std::vector<rclcpp::CallbackGroup::SharedPtr> cloud_subscriber_callback_groups_;
245 std::shared_ptr<void> synchronizer_;
246
250 OnSetParametersCallbackHandle::SharedPtr parameters_callback_;
251
255 std::shared_ptr<point_cloud_transport::Publisher> cloud_publisher_;
256
260 std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
261 std::shared_ptr<tf2_ros::TransformListener> tf_listener_;
262
266 rclcpp::TimerBase::SharedPtr setup_timer_;
267
268#ifdef ENABLE_CUDA
272 std::unique_ptr<cuda::CudaTransformContext> cuda_context_;
273 std::mutex cuda_context_mutex_;
274#endif
275};
276
277} // namespace point_cloud_fusion
void validateInputTopicsParameter() const
Validate that the configured input topic list is usable.
static constexpr int32_t kStepSizeOutputQueueSize
static constexpr std::size_t kMaxInputTopics
static constexpr const char * kAllowedOutputStampModes
PointCloudMsg::UniquePtr fusePointCloudBatch(const std::vector< PointCloudMsg::ConstSharedPtr > &msgs, const FusionTiming &timing, std::size_t &valid_point_count) const
Fuse a synchronized point-cloud batch using the CPU path.
void validateRangeLimits()
Validate configured XYZ range limits and disable filtering when invalid.
std::vector< std::string > output_fields_
void handleSynchronizedPointClouds(const std::vector< sensor_msgs::msg::PointCloud2::ConstSharedPtr > &msgs)
Process synchronized point clouds.
void configureOutputStampMode(const std::string &mode)
Parse and store the configured output timestamp mode.
void declareAndLoadParameter(const std::string &name, T &param, const std::string &description, const bool add_to_auto_reconfigurable_params=true, const bool is_required=false, const bool read_only=false, const std::optional< double > &from_value=std::nullopt, const std::optional< double > &to_value=std::nullopt, const std::optional< double > &step_value=std::nullopt, const std::string &additional_constraints="")
Declares and loads a ROS parameter.
void setup()
Sets up subscribers, publishers, etc. to configure the node.
rclcpp::TimerBase::SharedPtr setup_timer_
Timer to delay setup.
OnSetParametersCallbackHandle::SharedPtr parameters_callback_
Callback handle for dynamic parameter reconfiguration.
static constexpr const char * kDefaultTransportHint
rcl_interfaces::msg::SetParametersResult parametersCallback(const std::vector< rclcpp::Parameter > &parameters)
Validate and apply dynamic parameter updates.
std::vector< std::string > input_transport_hints_
static constexpr int64_t kMaxFixedPointsPerInputCloud
static constexpr int32_t kStepSizeSyncQueueSize
std::shared_ptr< tf2_ros::Buffer > tf_buffer_
TF2 buffer and transform listener.
std::shared_ptr< tf2_ros::TransformListener > tf_listener_
static constexpr int64_t kMinFixedPointsPerInputCloud
bool collectTimingInfo(const std::vector< PointCloudMsg::ConstSharedPtr > &msgs, FusionTiming &timing) const
Collect timestamp statistics for synchronized input clouds.
void publishFusedCloud(PointCloudMsg::UniquePtr cloud, const FusionTiming &timing, std::size_t input_count, std::size_t total_points, std::chrono::steady_clock::time_point callback_start, std::chrono::steady_clock::time_point processing_start, std::chrono::steady_clock::time_point processing_end, const char *event_name)
Publish a fused point cloud and emit tracing/timing diagnostics.
static constexpr int64_t kStepSizeFixedPointsPerInputCloud
void setupSynchronizer()
Create the approximate-time synchronizer for a fixed number of input topics.
std::vector< std::tuple< std::string, std::function< void(const rclcpp::Parameter &)> > > auto_reconfigurable_params_
Auto-reconfigurable parameters for dynamic reconfiguration.
std::vector< rclcpp::CallbackGroup::SharedPtr > cloud_subscriber_callback_groups_
sensor_msgs::msg::PointCloud2 PointCloudMsg
std::shared_ptr< point_cloud_transport::Publisher > cloud_publisher_
Publisher.
std::vector< std::shared_ptr< point_cloud_transport::SubscriberFilter > > cloud_subscribers_
PointCloudFusion(const rclcpp::NodeOptions &options)
Constructor.
Timing metadata for one synchronized fusion batch.
FusionTiming()=default
Construct timing metadata with zero-initialized stamps and deltas.