Skip to content

Commit 022961e

Browse files
authored
Merge pull request #1289 from tier4/feat/v0.19.1_performance_test_0510
feat(X2 performance tuning): merge pr about concatenate_data, downsample_filter, occupancy_grid_map
2 parents e6164ac + 71a1f1b commit 022961e

21 files changed

+3410
-52
lines changed

launch/tier4_perception_launch/launch/perception.launch.xml

+22-3
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,25 @@
107107
description="if use_radar_tracking_fusion:=true, radar information is merged in tracking launch. Otherwise, radar information is merged in detection launch."
108108
/>
109109

110+
<!-- Downsample pointcloud for perception usage -->
111+
<arg name="downsample_input_pointcloud" default="false"/>
112+
<arg name="downsample_voxel_size" default="0.05"/>
113+
<let name="downsampled_pointcloud" value="/perception/common/pointcloud"/>
114+
<let name="perception_pointcloud" value="$(var input/pointcloud)" unless="$(var downsample_input_pointcloud)"/>
115+
<let name="perception_pointcloud" value="$(var downsampled_pointcloud)" if="$(var downsample_input_pointcloud)"/>
116+
<group if="$(var downsample_input_pointcloud)">
117+
<load_composable_node target="$(var pointcloud_container_name)">
118+
<composable_node pkg="pointcloud_preprocessor" plugin="pointcloud_preprocessor::PickupBasedVoxelGridDownsampleFilterComponent" name="perception_input_pc_downsample_node" namespace="">
119+
<remap from="input" to="$(var input/pointcloud)"/>
120+
<remap from="output" to="$(var downsampled_pointcloud)"/>
121+
<param name="voxel_size_x" value="$(var downsample_voxel_size)"/>
122+
<param name="voxel_size_y" value="$(var downsample_voxel_size)"/>
123+
<param name="voxel_size_z" value="$(var downsample_voxel_size)"/>
124+
<extra_arg name="use_intra_process_comms" value="true"/>
125+
</composable_node>
126+
</load_composable_node>
127+
</group>
128+
110129
<!-- Perception module -->
111130
<group>
112131
<push-ros-namespace namespace="perception"/>
@@ -120,7 +139,7 @@
120139
<arg name="use_multithread" value="true"/>
121140
<arg name="use_pointcloud_container" value="$(var use_pointcloud_container)"/>
122141
<arg name="container_name" value="$(var pointcloud_container_name)"/>
123-
<arg name="input/pointcloud" value="$(var input/pointcloud)"/>
142+
<arg name="input/pointcloud" value="$(var perception_pointcloud)"/>
124143
</include>
125144
</group>
126145

@@ -129,7 +148,7 @@
129148
<push-ros-namespace namespace="occupancy_grid_map"/>
130149
<include file="$(find-pkg-share tier4_perception_launch)/launch/occupancy_grid_map/probabilistic_occupancy_grid_map.launch.xml">
131150
<arg name="input/obstacle_pointcloud" value="/perception/obstacle_segmentation/single_frame/pointcloud_raw"/>
132-
<arg name="input/raw_pointcloud" value="$(var input/pointcloud)"/>
151+
<arg name="input/raw_pointcloud" value="$(var perception_pointcloud)"/>
133152
<arg name="output" value="/perception/occupancy_grid_map/map"/>
134153
<arg name="use_intra_process" value="true"/>
135154
<arg name="use_multithread" value="true"/>
@@ -150,7 +169,7 @@
150169
<push-ros-namespace namespace="detection"/>
151170
<include file="$(find-pkg-share tier4_perception_launch)/launch/object_recognition/detection/detection.launch.xml">
152171
<arg name="mode" value="$(var mode)"/>
153-
<arg name="input/pointcloud" value="$(var input/pointcloud)"/>
172+
<arg name="input/pointcloud" value="$(var perception_pointcloud)"/>
154173
<arg name="lidar_detection_model" value="$(var lidar_detection_model)"/>
155174
<arg name="image_raw0" value="$(var image_raw0)"/>
156175
<arg name="camera_info0" value="$(var camera_info0)"/>

perception/probabilistic_occupancy_grid_map/README.md

+36
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,39 @@ Additional argument is shown below:
7070
| `container_name` | `occupancy_grid_map_container` | |
7171
| `input_obstacle_pointcloud` | `false` | only for laserscan based method. If true, the node subscribe obstacle pointcloud |
7272
| `input_obstacle_and_raw_pointcloud` | `true` | only for laserscan based method. If true, the node subscribe both obstacle and raw pointcloud |
73+
74+
### Downsample input pointcloud(Optional)
75+
76+
If you set `downsample_input_pointcloud` to `true`, the input pointcloud will be downsampled and following topics are also used. This feature is currently only for the pointcloud based occupancy grid map.
77+
78+
- pointcloud_based_occupancy_grid_map method
79+
80+
```yaml
81+
# downsampled raw and obstacle pointcloud
82+
/perception/occupancy_grid_map/obstacle/downsample/pointcloud
83+
/perception/occupancy_grid_map/raw/downsample/pointcloud
84+
```
85+
86+
- multi_lidar_pointcloud_based_point_cloud
87+
88+
```yaml
89+
# downsampled raw and obstacle pointcloud
90+
/perception/occupancy_grid_map/obstacle/downsample/pointcloud
91+
/perception/occupancy_grid_map/<sensor_name>/raw/downsample/pointcloud
92+
```
93+
94+
### Test
95+
96+
This package provides unit tests using `gtest`.
97+
You can run the test by the following command.
98+
99+
```bash
100+
colcon test --packages-select probabilistic_occupancy_grid_map --event-handlers console_direct+
101+
```
102+
103+
Test contains the following.
104+
105+
- Unit test for cost value conversion function
106+
- Unit test for utility functions
107+
- Unit test for occupancy grid map fusion functions
108+
- Input/Output test for pointcloud based occupancy grid map

perception/probabilistic_occupancy_grid_map/config/pointcloud_based_occupancy_grid_map.param.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
min_height: -1.0
99
max_height: 2.0
1010

11+
# downsample input pointcloud
12+
downsample_input_pointcloud: true
13+
downsample_voxel_size: 0.25 # [m]
14+
1115
enable_single_frame_mode: false
1216
# use sensor pointcloud to filter obstacle pointcloud
1317
filter_obstacle_pointcloud_by_raw_pointcloud: false

perception/probabilistic_occupancy_grid_map/launch/pointcloud_based_occupancy_grid_map.launch.py

+64-5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,47 @@
2626
import yaml
2727

2828

29+
def get_downsample_filter_node(setting: dict) -> ComposableNode:
30+
plugin_str = setting["plugin"]
31+
voxel_size = setting["voxel_size"]
32+
node_name = setting["node_name"]
33+
return ComposableNode(
34+
package="pointcloud_preprocessor",
35+
plugin=plugin_str,
36+
name=node_name,
37+
remappings=[
38+
("input", setting["input_topic"]),
39+
("output", setting["output_topic"]),
40+
],
41+
parameters=[
42+
{
43+
"voxel_size_x": voxel_size,
44+
"voxel_size_y": voxel_size,
45+
"voxel_size_z": voxel_size,
46+
}
47+
],
48+
extra_arguments=[{"use_intra_process_comms": LaunchConfiguration("use_intra_process")}],
49+
)
50+
51+
52+
def get_downsample_preprocess_nodes(voxel_size: float) -> list:
53+
raw_settings = {
54+
"plugin": "pointcloud_preprocessor::PickupBasedVoxelGridDownsampleFilterComponent",
55+
"node_name": "raw_pc_downsample_filter",
56+
"input_topic": LaunchConfiguration("input/raw_pointcloud"),
57+
"output_topic": "raw/downsample/pointcloud",
58+
"voxel_size": voxel_size,
59+
}
60+
obstacle_settings = {
61+
"plugin": "pointcloud_preprocessor::PickupBasedVoxelGridDownsampleFilterComponent",
62+
"node_name": "obstacle_pc_downsample_filter",
63+
"input_topic": LaunchConfiguration("input/obstacle_pointcloud"),
64+
"output_topic": "obstacle/downsample/pointcloud",
65+
"voxel_size": voxel_size,
66+
}
67+
return [get_downsample_filter_node(raw_settings), get_downsample_filter_node(obstacle_settings)]
68+
69+
2970
def launch_setup(context, *args, **kwargs):
3071
# load parameter files
3172
param_file = LaunchConfiguration("param_file").perform(context)
@@ -38,19 +79,37 @@ def launch_setup(context, *args, **kwargs):
3879
with open(updater_param_file, "r") as f:
3980
occupancy_grid_map_updater_params = yaml.safe_load(f)["/**"]["ros__parameters"]
4081

41-
composable_nodes = [
82+
# composable nodes
83+
composable_nodes = []
84+
85+
# add downsample process
86+
downsample_input_pointcloud: bool = pointcloud_based_occupancy_grid_map_node_params[
87+
"downsample_input_pointcloud"
88+
]
89+
if downsample_input_pointcloud:
90+
voxel_grid_size: float = pointcloud_based_occupancy_grid_map_node_params[
91+
"downsample_voxel_size"
92+
]
93+
downsample_preprocess_nodes = get_downsample_preprocess_nodes(voxel_grid_size)
94+
composable_nodes.extend(downsample_preprocess_nodes)
95+
96+
composable_nodes.append(
4297
ComposableNode(
4398
package="probabilistic_occupancy_grid_map",
4499
plugin="occupancy_grid_map::PointcloudBasedOccupancyGridMapNode",
45100
name="occupancy_grid_map_node",
46101
remappings=[
47102
(
48103
"~/input/obstacle_pointcloud",
49-
LaunchConfiguration("input/obstacle_pointcloud"),
104+
LaunchConfiguration("input/obstacle_pointcloud")
105+
if not downsample_input_pointcloud
106+
else "obstacle/downsample/pointcloud",
50107
),
51108
(
52109
"~/input/raw_pointcloud",
53-
LaunchConfiguration("input/raw_pointcloud"),
110+
LaunchConfiguration("input/raw_pointcloud")
111+
if not downsample_input_pointcloud
112+
else "raw/downsample/pointcloud",
54113
),
55114
("~/output/occupancy_grid_map", LaunchConfiguration("output")),
56115
],
@@ -60,8 +119,8 @@ def launch_setup(context, *args, **kwargs):
60119
{"updater_type": LaunchConfiguration("updater_type")},
61120
],
62121
extra_arguments=[{"use_intra_process_comms": LaunchConfiguration("use_intra_process")}],
63-
),
64-
]
122+
)
123+
)
65124

66125
occupancy_grid_map_container = ComposableNodeContainer(
67126
name=LaunchConfiguration("container_name"),

perception/probabilistic_occupancy_grid_map/package.xml

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
<depend>tier4_autoware_utils</depend>
3535
<depend>visualization_msgs</depend>
3636

37+
<exec_depend>pointcloud_preprocessor</exec_depend>
3738
<exec_depend>pointcloud_to_laserscan</exec_depend>
3839

3940
<test_depend>ament_cmake_gtest</test_depend>
@@ -44,6 +45,7 @@
4445
<test_depend>launch_testing</test_depend>
4546
<test_depend>launch_testing_ament_cmake</test_depend>
4647
<test_depend>launch_testing_ros</test_depend>
48+
<test_depend>pointcloud_preprocessor</test_depend>
4749
<export>
4850
<build_type>ament_cmake</build_type>
4951
</export>

perception/probabilistic_occupancy_grid_map/pointcloud-based-occupancy-grid-map.md

+24-8
Original file line numberDiff line numberDiff line change
@@ -77,18 +77,34 @@ $$
7777
| ----------------------------- | ------------------------- | ------------------ |
7878
| `~/output/occupancy_grid_map` | `nav_msgs::OccupancyGrid` | occupancy grid map |
7979

80+
### Related topics
81+
82+
If you set `downsample_input_pointcloud` to `true`, the input pointcloud will be downsampled and following topics are also used.
83+
84+
- pointcloud_based_occupancy_grid_map method
85+
86+
```yaml
87+
# downsampled raw and obstacle pointcloud
88+
/perception/occupancy_grid_map/obstacle/downsample/pointcloud
89+
/perception/occupancy_grid_map/raw/downsample/pointcloud
90+
```
91+
8092
## Parameters
8193

8294
### Node Parameters
8395

84-
| Name | Type | Description |
85-
| ------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------- |
86-
| `map_frame` | string | map frame |
87-
| `base_link_frame` | string | base_link frame |
88-
| `use_height_filter` | bool | whether to height filter for `~/input/obstacle_pointcloud` and `~/input/raw_pointcloud`? By default, the height is set to -1~2m. |
89-
| `map_length` | double | The length of the map. -100 if it is 50~50[m] |
90-
| `map_resolution` | double | The map cell resolution [m] |
91-
| `grid_map_type` | string | The type of grid map for estimating `UNKNOWN` region behind obstacle point clouds |
96+
| Name | Type | Description |
97+
| ----------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------- |
98+
| `map_frame` | string | map frame |
99+
| `base_link_frame` | string | base_link frame |
100+
| `use_height_filter` | bool | whether to height filter for `~/input/obstacle_pointcloud` and `~/input/raw_pointcloud`? By default, the height is set to -1~2m. |
101+
| `map_length` | double | The length of the map. -100 if it is 50~50[m] |
102+
| `map_resolution` | double | The map cell resolution [m] |
103+
| `grid_map_type` | string | The type of grid map for estimating `UNKNOWN` region behind obstacle point clouds |
104+
| `scan_origin` | string | The origin of the scan. It should be a sensor frame. |
105+
| `pub_debug_grid` | bool | Whether to publish debug grid maps |
106+
| `downsample_input_pointcloud` | bool | Whether to downsample the input pointclouds. The downsampled pointclouds are used for the ray tracing. |
107+
| `downsample_voxel_size` | double | The voxel size for the downsampled pointclouds. |
92108

93109
## Assumptions / Known limits
94110

sensing/pointcloud_preprocessor/CMakeLists.txt

+6-1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ ament_auto_add_library(pointcloud_preprocessor_filter SHARED
6565
src/downsample_filter/voxel_grid_downsample_filter_nodelet.cpp
6666
src/downsample_filter/random_downsample_filter_nodelet.cpp
6767
src/downsample_filter/approximate_downsample_filter_nodelet.cpp
68+
src/downsample_filter/pickup_based_voxel_grid_downsample_filter.cpp
6869
src/outlier_filter/ring_outlier_filter_nodelet.cpp
6970
src/outlier_filter/voxel_grid_outlier_filter_nodelet.cpp
7071
src/outlier_filter/radius_search_2d_outlier_filter_nodelet.cpp
@@ -114,6 +115,11 @@ rclcpp_components_register_node(pointcloud_preprocessor_filter
114115
PLUGIN "pointcloud_preprocessor::VoxelGridDownsampleFilterComponent"
115116
EXECUTABLE voxel_grid_downsample_filter_node)
116117

118+
# -- Pickup Based Voxel Grid Downsample Filter --
119+
rclcpp_components_register_node(pointcloud_preprocessor_filter
120+
PLUGIN "pointcloud_preprocessor::PickupBasedVoxelGridDownsampleFilterComponent"
121+
EXECUTABLE pickup_based_voxel_grid_downsample_filter_node)
122+
117123
# -- Random Downsample Filter --
118124
rclcpp_components_register_node(pointcloud_preprocessor_filter
119125
PLUGIN "pointcloud_preprocessor::RandomDownsampleFilterComponent"
@@ -214,7 +220,6 @@ ament_auto_package(INSTALL_TO_SHARE
214220
config
215221
)
216222

217-
218223
if(BUILD_TESTING)
219224
add_ros_test(
220225
test/test_distortion_corrector.py

sensing/pointcloud_preprocessor/README.md

+39-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,45 @@ Detail description of each filter's algorithm is in the following links.
5656

5757
## Assumptions / Known limits
5858

59-
`pointcloud_preprocessor::Filter` is implemented based on pcl_perception [1] because of [this issue](https://github.com/ros-perception/perception_pcl/issues/9).
59+
`pointcloud_preprocessor::Filter` is implemented based on pcl_perception [1] because
60+
of [this issue](https://github.com/ros-perception/perception_pcl/issues/9).
61+
62+
## Measuring the performance
63+
64+
In Autoware, point cloud data from each LiDAR sensor undergoes preprocessing in the sensing pipeline before being input
65+
into the perception pipeline. The preprocessing stages are illustrated in the diagram below:
66+
67+
![pointcloud_preprocess_pipeline.drawio.png](docs%2Fimage%2Fpointcloud_preprocess_pipeline.drawio.png)
68+
69+
Each stage in the pipeline incurs a processing delay. Mostly, we've used `ros2 topic delay /topic_name` to measure
70+
the time between the message header and the current time. This approach works well for small-sized messages. However,
71+
when dealing with large point cloud messages, this method introduces an additional delay. This is primarily because
72+
accessing these large point cloud messages externally impacts the pipeline's performance.
73+
74+
Our sensing/perception nodes are designed to run within composable node containers, leveraging intra-process
75+
communication. External subscriptions to these messages (like using ros2 topic delay or rviz2) impose extra delays and
76+
can even slow down the pipeline by subscribing externally. Therefore, these measurements will not be accurate.
77+
78+
To mitigate this issue, we've adopted a method where each node in the pipeline reports its pipeline latency time.
79+
This approach ensures the integrity of intra-process communication and provides a more accurate measure of delays in the
80+
pipeline.
81+
82+
### Benchmarking The Pipeline
83+
84+
The nodes within the pipeline report the pipeline latency time, indicating the duration from the sensor driver's pointcloud
85+
output to the node's output. This data is crucial for assessing the pipeline's health and efficiency.
86+
87+
When running Autoware, you can monitor the pipeline latency times for each node in the pipeline by subscribing to the
88+
following ROS 2 topics:
89+
90+
- `/sensing/lidar/LidarX/crop_box_filter_self/debug/pipeline_latency_ms`
91+
- `/sensing/lidar/LidarX/crop_box_filter_mirror/debug/pipeline_latency_ms`
92+
- `/sensing/lidar/LidarX/distortion_corrector/debug/pipeline_latency_ms`
93+
- `/sensing/lidar/LidarX/ring_outlier_filter/debug/pipeline_latency_ms`
94+
- `/sensing/lidar/concatenate_data_synchronizer/debug/sensing/lidar/LidarX/pointcloud/pipeline_latency_ms`
95+
96+
These topics provide the pipeline latency times, giving insights into the delays at various stages of the pipeline
97+
from the sensor output of LidarX to each subsequent node.
6098

6199
## (Optional) Error detection and handling
62100

sensing/pointcloud_preprocessor/docs/downsample-filter.md

+16
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ The `downsample_filter` is a node that reduces the number of points.
1818

1919
`pcl::VoxelGrid` is used, which points in each voxel are approximated with their centroid.
2020

21+
### Pickup Based Voxel Grid Downsample Filter
22+
23+
This algorithm samples a single actual point existing within the voxel, not the centroid. The computation cost is low compared to Centroid Based Voxel Grid Filter.
24+
2125
## Inputs / Outputs
2226

2327
These implementations inherit `pointcloud_preprocessor::Filter` class, please refer [README](../README.md).
@@ -52,8 +56,20 @@ These implementations inherit `pointcloud_preprocessor::Filter` class, please re
5256
| `voxel_size_y` | double | 0.3 | voxel size y [m] |
5357
| `voxel_size_z` | double | 0.1 | voxel size z [m] |
5458

59+
### Pickup Based Voxel Grid Downsample Filter
60+
61+
| Name | Type | Default Value | Description |
62+
| -------------- | ------ | ------------- | ---------------- |
63+
| `voxel_size_x` | double | 1.0 | voxel size x [m] |
64+
| `voxel_size_y` | double | 1.0 | voxel size y [m] |
65+
| `voxel_size_z` | double | 1.0 | voxel size z [m] |
66+
5567
## Assumptions / Known limits
5668

69+
<!-- cspell: ignore martinus -->
70+
71+
This implementation uses the `robin_hood.h` hashing library by martinus, available under the MIT License at [martinus/robin-hood-hashing](https://github.com/martinus/robin-hood-hashing) on GitHub. Special thanks to martinus for this contribution.
72+
5773
## (Optional) Error detection and handling
5874

5975
## (Optional) Performance characterization
Loading

sensing/pointcloud_preprocessor/include/pointcloud_preprocessor/concatenate_data/concatenate_and_time_sync_nodelet.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ class PointCloudConcatenateDataSynchronizerComponent : public rclcpp::Node
126126
double timeout_sec_ = 0.1;
127127

128128
bool publish_synchronized_pointcloud_;
129+
bool keep_input_frame_in_synchronized_pointcloud_;
130+
std::string synchronized_pointcloud_postfix_;
129131

130132
std::set<std::string> not_subscribed_topic_names_;
131133

@@ -179,6 +181,8 @@ class PointCloudConcatenateDataSynchronizerComponent : public rclcpp::Node
179181
void timer_callback();
180182

181183
void checkConcatStatus(diagnostic_updater::DiagnosticStatusWrapper & stat);
184+
std::string replaceSyncTopicNamePostfix(
185+
const std::string & original_topic_name, const std::string & postfix);
182186

183187
/** \brief processing time publisher. **/
184188
std::unique_ptr<tier4_autoware_utils::StopWatch<std::chrono::milliseconds>> stop_watch_ptr_;

0 commit comments

Comments
 (0)