Skip to content

Commit 3580420

Browse files
committed
fix: make it works (see below)
* Add missing parts: - Some codes are copied from following `autoware_pointcloud_preprocessor` package - https://github.com/autowarefoundation/autoware_universe/tree/main/sensing/autoware_pointcloud_preprocessor * But the code has not been tidy up yet at this time: - We'll provide the refactoring plan for this Signed-off-by: Junya Sasaki <junya.sasaki@tier4.jp>
1 parent 9e6bd5d commit 3580420

File tree

6 files changed

+600
-16
lines changed

6 files changed

+600
-16
lines changed

pointcloud_filter/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ include_directories(
2424
ament_auto_add_library(${PROJECT_NAME} SHARED
2525
src/scan_ground_filter/node.cpp
2626
src/scan_ground_filter/grid_ground_filter.cpp
27+
src/scan_ground_filter/sanity_check.cpp
2728
)
2829

2930
target_link_libraries(${PROJECT_NAME}

pointcloud_filter/package.xml

+2
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@
2222
<depend>ament_index_cpp</depend>
2323
<depend>autoware_utils</depend>
2424
<depend>autoware_vehicle_info_utils</depend>
25+
<depend>autoware_point_types</depend>
2526
<depend>pcl_conversions</depend>
2627
<depend>pcl_ros</depend>
2728
<depend>rclcpp</depend>
2829
<depend>rclcpp_components</depend>
2930
<depend>sensor_msgs</depend>
3031
<depend>std_msgs</depend>
32+
<depend>message_filters</depend>
3133
<depend>tf2</depend>
3234
<depend>tf2_eigen</depend>
3335
<depend>tf2_ros</depend>

pointcloud_filter/src/scan_ground_filter/node.cpp

+250-16
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "rclcpp/rclcpp.hpp"
1717

1818
#include "grid_ground_filter.hpp"
19+
#include "sanity_check.hpp"
1920

2021
#include <autoware_utils/geometry/geometry.hpp>
2122
#include <autoware_utils/math/normalization.hpp>
@@ -26,19 +27,6 @@
2627
#include <string>
2728
#include <vector>
2829

29-
namespace autoware::pointcloud_filter
30-
{
31-
// For PointCloud2
32-
using PointCloud2 = sensor_msgs::msg::PointCloud2;
33-
using PointCloud2ConstPtr = sensor_msgs::msg::PointCloud2::ConstSharedPtr;
34-
35-
using autoware::vehicle_info_utils::VehicleInfoUtils;
36-
using autoware_utils::calc_distance3d;
37-
using autoware_utils::deg2rad;
38-
using autoware_utils::normalize_degree;
39-
using autoware_utils::normalize_radian;
40-
using autoware_utils::ScopedTimeTrack;
41-
4230
namespace {
4331
/** \brief For parameter service callback */
4432
template <typename T>
@@ -55,6 +43,19 @@ bool get_param(const std::vector<rclcpp::Parameter> & p, const std::string & nam
5543
}
5644
}
5745

46+
namespace autoware::pointcloud_filter
47+
{
48+
// For PointCloud2
49+
using PointCloud2 = sensor_msgs::msg::PointCloud2;
50+
using PointCloud2ConstPtr = sensor_msgs::msg::PointCloud2::ConstSharedPtr;
51+
52+
using autoware::vehicle_info_utils::VehicleInfoUtils;
53+
using autoware_utils::calc_distance3d;
54+
using autoware_utils::deg2rad;
55+
using autoware_utils::normalize_degree;
56+
using autoware_utils::normalize_radian;
57+
using autoware_utils::ScopedTimeTrack;
58+
5859
ScanGroundFilterComponent::ScanGroundFilterComponent(const rclcpp::NodeOptions & options)
5960
: rclcpp::Node("ScanGroundFilter", options)
6061
{
@@ -147,6 +148,229 @@ ScanGroundFilterComponent::ScanGroundFilterComponent(const rclcpp::NodeOptions &
147148
grid_ground_filter_ptr_->setTimeKeeper(time_keeper_);
148149
}
149150
}
151+
152+
// pointcloud parameters
153+
tf_input_frame_ = static_cast<std::string>(declare_parameter("input_frame", ""));
154+
tf_output_frame_ = static_cast<std::string>(declare_parameter("output_frame", ""));
155+
has_static_tf_only_ = static_cast<bool>(declare_parameter("has_static_tf_only", false));
156+
max_queue_size_ = static_cast<std::size_t>(declare_parameter("max_queue_size", 5));
157+
use_indices_ = static_cast<bool>(declare_parameter("use_indices", false));
158+
latched_indices_ = static_cast<bool>(declare_parameter("latched_indices", false));
159+
approximate_sync_ = static_cast<bool>(declare_parameter("approximate_sync", false));
160+
161+
RCLCPP_DEBUG_STREAM(
162+
this->get_logger(),
163+
"Filter (as Component) successfully created with the following parameters:"
164+
<< std::endl
165+
<< " - approximate_sync : " << (approximate_sync_ ? "true" : "false") << std::endl
166+
<< " - use_indices : " << (use_indices_ ? "true" : "false") << std::endl
167+
<< " - latched_indices : " << (latched_indices_ ? "true" : "false") << std::endl
168+
<< " - max_queue_size : " << max_queue_size_);
169+
170+
// Set publisher
171+
{
172+
rclcpp::PublisherOptions pub_options;
173+
pub_options.qos_overriding_options = rclcpp::QosOverridingOptions::with_default_policies();
174+
pub_output_ = this->create_publisher<sensor_msgs::msg::PointCloud2>(
175+
"output", rclcpp::SensorDataQoS().keep_last(max_queue_size_), pub_options);
176+
}
177+
178+
subscribe();
179+
180+
// Set tf_listener, tf_buffer.
181+
setupTF();
182+
183+
published_time_publisher_ = std::make_unique<autoware_utils::PublishedTimePublisher>(this);
184+
RCLCPP_DEBUG(this->get_logger(), "[Filter Constructor] successfully created.");
185+
186+
}
187+
188+
void ScanGroundFilterComponent::setupTF()
189+
{
190+
// Always consider static TF if in & out frames are same
191+
if (tf_input_frame_ == tf_output_frame_) {
192+
if (!has_static_tf_only_) {
193+
RCLCPP_INFO(
194+
this->get_logger(),
195+
"Input and output frames are the same. Overriding has_static_tf_only to true.");
196+
}
197+
has_static_tf_only_ = true;
198+
}
199+
managed_tf_buffer_ =
200+
std::make_unique<autoware_utils::ManagedTransformBuffer>(this, has_static_tf_only_);
201+
}
202+
203+
void ScanGroundFilterComponent::subscribe()
204+
{
205+
if (use_indices_) {
206+
// Subscribe to the input using a filter
207+
sub_input_filter_.subscribe(
208+
this, "input", rclcpp::SensorDataQoS().keep_last(max_queue_size_).get_rmw_qos_profile());
209+
sub_indices_filter_.subscribe(
210+
this, "indices", rclcpp::SensorDataQoS().keep_last(max_queue_size_).get_rmw_qos_profile());
211+
212+
if (approximate_sync_) {
213+
sync_input_indices_a_ = std::make_shared<message_filters::Synchronizer<message_filters::sync_policies::ApproximateTime<sensor_msgs::msg::PointCloud2, pcl_msgs::msg::PointIndices>>>(max_queue_size_);
214+
sync_input_indices_a_->connectInput(sub_input_filter_, sub_indices_filter_);
215+
sync_input_indices_a_->registerCallback(
216+
std::bind(&ScanGroundFilterComponent::faster_input_indices_callback, this, std::placeholders::_1, std::placeholders::_2));
217+
} else {
218+
sync_input_indices_e_ = std::make_shared<message_filters::Synchronizer<message_filters::sync_policies::ExactTime<sensor_msgs::msg::PointCloud2, pcl_msgs::msg::PointIndices>>>(max_queue_size_);
219+
sync_input_indices_e_->connectInput(sub_input_filter_, sub_indices_filter_);
220+
sync_input_indices_e_->registerCallback(
221+
std::bind(&ScanGroundFilterComponent::faster_input_indices_callback, this, std::placeholders::_1, std::placeholders::_2));
222+
}
223+
} else {
224+
std::function<void(const sensor_msgs::msg::PointCloud2::ConstSharedPtr msg)> cb =
225+
std::bind(&ScanGroundFilterComponent::faster_input_indices_callback, this, std::placeholders::_1, pcl_msgs::msg::PointIndices::ConstSharedPtr());
226+
sub_input_ = this->create_subscription<sensor_msgs::msg::PointCloud2>(
227+
"input", rclcpp::SensorDataQoS().keep_last(max_queue_size_), cb);
228+
}
229+
}
230+
231+
bool ScanGroundFilterComponent::calculate_transform_matrix(
232+
const std::string & target_frame, const sensor_msgs::msg::PointCloud2 & from,
233+
TransformInfo & transform_info /*output*/)
234+
{
235+
transform_info.need_transform = false;
236+
237+
if (target_frame.empty() || from.header.frame_id == target_frame) return true;
238+
239+
RCLCPP_DEBUG(
240+
this->get_logger(), "[get_transform_matrix] Transforming input dataset from %s to %s.",
241+
from.header.frame_id.c_str(), target_frame.c_str());
242+
243+
if (!managed_tf_buffer_->get_transform(
244+
target_frame, from.header.frame_id, transform_info.eigen_transform)) {
245+
return false;
246+
}
247+
248+
transform_info.need_transform = true;
249+
return true;
250+
}
251+
252+
bool ScanGroundFilterComponent::convert_output_costly(
253+
std::unique_ptr<sensor_msgs::msg::PointCloud2> & output)
254+
{
255+
// In terms of performance, we should avoid using pcl_ros library function,
256+
// but this code path isn't reached in the main use case of Autoware, so it's left as is for now.
257+
if (!tf_output_frame_.empty() && output->header.frame_id != tf_output_frame_) {
258+
RCLCPP_DEBUG(
259+
this->get_logger(), "[convert_output_costly] Transforming output dataset from %s to %s.",
260+
output->header.frame_id.c_str(), tf_output_frame_.c_str());
261+
262+
// Convert the cloud into the different frame
263+
auto cloud_transformed = std::make_unique<sensor_msgs::msg::PointCloud2>();
264+
265+
if (!managed_tf_buffer_->transform_pointcloud(tf_output_frame_, *output, *cloud_transformed)) {
266+
RCLCPP_ERROR(
267+
this->get_logger(),
268+
"[convert_output_costly] Error converting output dataset from %s to %s.",
269+
output->header.frame_id.c_str(), tf_output_frame_.c_str());
270+
return false;
271+
}
272+
273+
output = std::move(cloud_transformed);
274+
}
275+
276+
// Same as the comment above
277+
if (tf_output_frame_.empty() && output->header.frame_id != tf_input_orig_frame_) {
278+
// No tf_output_frame given, transform the dataset to its original frame
279+
RCLCPP_DEBUG(
280+
this->get_logger(), "[convert_output_costly] Transforming output dataset from %s back to %s.",
281+
output->header.frame_id.c_str(), tf_input_orig_frame_.c_str());
282+
283+
auto cloud_transformed = std::make_unique<sensor_msgs::msg::PointCloud2>();
284+
285+
if (!managed_tf_buffer_->transform_pointcloud(
286+
tf_input_orig_frame_, *output, *cloud_transformed)) {
287+
return false;
288+
}
289+
290+
output = std::move(cloud_transformed);
291+
}
292+
293+
return true;
294+
}
295+
296+
void ScanGroundFilterComponent::faster_input_indices_callback(
297+
const sensor_msgs::msg::PointCloud2::ConstSharedPtr cloud, const pcl_msgs::msg::PointIndices::ConstSharedPtr indices)
298+
{
299+
if (
300+
!is_data_layout_compatible_with_point_xyzircaedt(*cloud) &&
301+
!is_data_layout_compatible_with_point_xyzirc(*cloud)) {
302+
RCLCPP_ERROR(
303+
get_logger(),
304+
"The pointcloud layout is not compatible with PointXYZIRCAEDT or PointXYZIRC. Aborting");
305+
306+
if (is_data_layout_compatible_with_point_xyziradrt(*cloud)) {
307+
RCLCPP_ERROR(
308+
get_logger(),
309+
"The pointcloud layout is compatible with PointXYZIRADRT. You may be using legacy "
310+
"code/data");
311+
}
312+
313+
if (is_data_layout_compatible_with_point_xyzi(*cloud)) {
314+
RCLCPP_ERROR(
315+
get_logger(),
316+
"The pointcloud layout is compatible with PointXYZI. You may be using legacy "
317+
"code/data");
318+
}
319+
320+
return;
321+
}
322+
323+
if (!isValid(cloud)) {
324+
RCLCPP_ERROR(this->get_logger(), "[input_indices_callback] Invalid input!");
325+
return;
326+
}
327+
328+
if (!isValid(indices)) {
329+
RCLCPP_ERROR(this->get_logger(), "[input_indices_callback] Invalid indices!");
330+
return;
331+
}
332+
333+
if (indices) {
334+
RCLCPP_DEBUG(
335+
this->get_logger(),
336+
"[input_indices_callback]\n"
337+
" - PointCloud with %d data points (%s), stamp %f, and frame %s on input topic received.\n"
338+
" - PointIndices with %zu values, stamp %f, and frame %s on indices topic received.",
339+
cloud->width * cloud->height, pcl::getFieldsList(*cloud).c_str(),
340+
rclcpp::Time(cloud->header.stamp).seconds(), cloud->header.frame_id.c_str(),
341+
indices->indices.size(), rclcpp::Time(indices->header.stamp).seconds(),
342+
indices->header.frame_id.c_str());
343+
} else {
344+
RCLCPP_DEBUG(
345+
this->get_logger(),
346+
"[input_indices_callback] PointCloud with %d data points and frame %s on input topic "
347+
"received.",
348+
cloud->width * cloud->height, cloud->header.frame_id.c_str());
349+
}
350+
351+
tf_input_orig_frame_ = cloud->header.frame_id;
352+
353+
// For performance reason, defer the transform computation.
354+
// Do not use pcl_ros::transformPointCloud(). It's too slow due to the unnecessary copy.
355+
TransformInfo transform_info;
356+
if (!calculate_transform_matrix(tf_input_frame_, *cloud, transform_info)) return;
357+
358+
// Need setInputCloud() here because we have to extract x/y/z
359+
pcl::IndicesPtr vindices;
360+
if (indices) {
361+
vindices.reset(new std::vector<int>(indices->indices));
362+
}
363+
364+
auto output = std::make_unique<PointCloud2>();
365+
366+
// TODO(sykwer): Change to `filter()` call after when the filter nodes conform to new API.
367+
faster_filter(cloud, vindices, *output, transform_info);
368+
369+
if (!convert_output_costly(output)) return;
370+
371+
output->header.stamp = cloud->header.stamp;
372+
pub_output_->publish(std::move(output));
373+
published_time_publisher_->publish_if_subscribed(pub_output_, cloud->header.stamp);
150374
}
151375

152376
void ScanGroundFilterComponent::convertPointcloud(
@@ -356,8 +580,7 @@ void ScanGroundFilterComponent::faster_filter(
356580
std::unique_ptr<autoware_utils::ScopedTimeTrack> st_ptr;
357581
if (time_keeper_) st_ptr = std::make_unique<autoware_utils::ScopedTimeTrack>(__func__, *time_keeper_);
358582

359-
// TODO(sasakisasaki): Understand why this mutex is defined before the porting. I guess this comes from pointcloud_preprocessor.
360-
//std::scoped_lock lock(mutex_);
583+
std::scoped_lock lock(mutex_);
361584

362585
if (stop_watch_ptr_) stop_watch_ptr_->toc("processing_time", true);
363586

@@ -463,13 +686,24 @@ rcl_interfaces::msg::SetParametersResult ScanGroundFilterComponent::onParameter(
463686
this->get_logger(),
464687
"Setting use_recheck_ground_cluster to: " << std::boolalpha << use_recheck_ground_cluster_);
465688
}
689+
690+
// For pointcloud
691+
std::scoped_lock lock(mutex_);
692+
693+
if (get_param(param, "input_frame", tf_input_frame_)) {
694+
RCLCPP_DEBUG(this->get_logger(), "Setting the input TF frame to: %s.", tf_input_frame_.c_str());
695+
}
696+
if (get_param(param, "output_frame", tf_output_frame_)) {
697+
RCLCPP_DEBUG(this->get_logger(), "Setting the output TF frame to: %s.", tf_output_frame_.c_str());
698+
}
699+
700+
// Finally return the result
466701
rcl_interfaces::msg::SetParametersResult result;
467702
result.successful = true;
468703
result.reason = "success";
469704

470705
return result;
471706
}
472-
473707
} // namespace autoware::pointcloud_filter
474708

475709
#include <rclcpp_components/register_node_macro.hpp>

0 commit comments

Comments
 (0)