Skip to content

Commit 48ba396

Browse files
authored
Merge pull request #12 from Cardinal-Space-Mining/v0.5.0
V0.5.0
2 parents 97c1ee1 + 455c05c commit 48ba396

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+5033
-5172
lines changed

.clang-tidy

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
Checks: "*,
3+
-abseil-*,
4+
-altera-*,
5+
-android-*,
6+
-fuchsia-*,
7+
-google-*,
8+
-llvm*,
9+
-modernize-use-trailing-return-type,
10+
-zircon-*,
11+
-readability-else-after-return,
12+
-readability-static-accessed-through-instance,
13+
-readability-avoid-const-params-in-decls,
14+
-cppcoreguidelines-non-private-member-variables-in-classes,
15+
-misc-non-private-member-variables-in-classes,
16+
-misc-include-cleaner,
17+
-readability-isolate-declaration,
18+
-cppcoreguidelines-avoid-magic-numbers,
19+
-readability-magic-numbers,
20+
-hicpp-braces-around-statements,
21+
-readability-braces-around-statements,
22+
-misc-const-correctness,
23+
-bugprone-narrowing-conversions,
24+
-cppcoreguidelines-narrowing-conversions,
25+
-readability-function-cognitive-complexity,
26+
-cppcoreguidelines-pro-type-union-access,
27+
-readability-identifier-length,
28+
-cppcoreguidelines-avoid-do-while,
29+
-cppcoreguidelines-pro-bounds-constant-array-index,
30+
-hicpp-use-auto,
31+
-modernize-use-auto,
32+
-hicpp-uppercase-literal-suffix,
33+
-readability-uppercase-literal-suffix,
34+
35+
"
36+
WarningsAsErrors: ''
37+
HeaderFilterRegex: ''
38+
FormatStyle: none
39+
40+
41+
42+
43+

CMakeLists.txt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,17 +74,13 @@ add_library(nano_gicp STATIC "src/nano_gicp/lsq_registration.cpp" "src/nano_gicp
7474
target_link_libraries(nano_gicp ${PCL_LIBRARIES} ${OpenMP_LIBS} nanoflann)
7575
ament_target_dependencies(nano_gicp)
7676

77-
# add_library(ikd_tree STATIC "src/ikd_tree/ikd_tree.cpp")
78-
# target_link_libraries(ikd_tree ${PCL_LIBRARIES})
79-
# ament_target_dependencies(ikd_tree)
80-
8177
add_library(stats STATIC "src/stats/stats.cpp")
8278
ament_target_dependencies(stats)
8379

8480

8581
add_executable(perception_node
8682
"src/perception_node.cpp"
87-
"src/core/localization.cpp"
83+
"src/core/perception.cpp"
8884
"src/core/odometry.cpp")
8985
target_link_libraries(perception_node
9086
${PCL_LIBRARIES}

README.md

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
# Cardinal Perception
1+
<!-- # Cardinal Perception -->
2+
![Cardinal Perception](doc/cardinal-perception.png)
23

3-
This package currently comprises localization (lidar odometry + apriltag rebias) and mapping components as used in CSM's autonomy solution (2024 and onward). The system has been designed around our hardware setup, but theoretically is compatible with varying configurations. See the architecture section for more info on sensor inputs and their role in the pipeline.
4+
This package currently comprises localization (lidar odometry + fiducial rebiasing), terrain mapping, traversability evaluation (in progress), and path generation (also in progress) components as used in CSM's autonomy solution (2024 and onward). The system has been designed around our hardware setup, but theoretically is compatible with varying configurations. See the architecture section for more info on sensor inputs and their role in the pipeline.
45

5-
## Architecture
6-
TODO
6+
## Overview
7+
![architecture overview](doc/cardinal-perception-v050-overview.svg)
8+
9+
Cardinal Perception is currently split into two [ROS] nodes - a core node which accomplishes the vast majority of functionality, as well as a helper node used for detecting AprilTags and calculating pose information. The primary node is architected to act as a pipeline - comprising stages which accomlish localization; terrain mapping; traversibility generation; and trajectory generation tasks, respectively. This architecture supports a failry simple multithreading paradigm as well as minimizes latency for crucial stages (localization) while decoupling later stages such that they don't bottleneck the system as a whole. For more information on each stage as well as I/O and performance considerations, see the [architecture documentation](doc/architecture.md).
710

811
## Build
912
1. Install [ROS2](https://docs.ros.org/en/jazzy/Installation.html) if necessary
@@ -31,8 +34,35 @@ TODO
3134
source install/setup.bash
3235
```
3336

34-
## VSCode
37+
*This package has been verified on and developed for ROS2 Humble (with Ubuntu 22.04) as well as ROS2 Jazzy (with Ubuntu 24.04). WSL has not been tested but theoretically should work.*
38+
39+
## Usage
40+
### Prerequisites
41+
**To run Cardinal Perception, you will need (REQUIRED):**
42+
- A `sensor_msgs::msg::PointCloud2` topic providing a 3D LiDAR scan.
43+
- A correctly configured `config/perception.yaml` file (or equivalent) - see the [related documentation](doc/config.md) for information on parameters.
44+
45+
**Optionally, you may also need:**
46+
- A `sensor_msgs::msg::Imu` topic providing IMU samples. This can help stabilize the odometry system, especially when an orientation estimate is directly usable as apart of each sample.
47+
- A set of `/tf` of `/tf_static` transforms provided by `robot_state_publisher`. This is necessary when the coordinate frame of the LiDAR scan is different from the coordinate frame of the IMU, or if you want to compute odometry for a frame different than that of the LiDAR scan.
48+
- A customized launchfile
49+
50+
**Finally, to use the AprilTag detector for global estimates, you will need:**
51+
- A set of `sensor_msgs::msg::Image` and accompanying `sensor_msgs::msg::CameraInfo` topic for each camera to be used.
52+
- A correctly configured `config/tag_detection.yaml` file (or equivalent) - see the [related documentation](doc/config.md#tag-detection-node) for information on parameters.
3553

54+
### Running
55+
If using the included launchfile:
56+
```bash
57+
ros2 launch cardinal_perception cardinal_perception.launch.py
58+
```
59+
To run the perception node by itself (not recommended):
60+
```bash
61+
ros2 run cardinal_perception perception_node --ros-args --params-file <PATH TO CARDINAL PERCEPTION INSTALL>/config/perception.yaml
62+
```
63+
**_For an advanced usage example, see [this repo](https://github.com/Cardinal-Space-Mining/lance-2025)._**
64+
65+
## VSCode
3666
If intellisense is not working properly, ensure the CMake and C++ extensions are installed, and the C/C++ configuration is correct. This configuration can be edited by clicking the current configuration name in the bottom-right corner of the window, and editing the JSON file. Under the configuration you plan to use, make sure the following line is present:
3767
```json
3868
"configurationProvider": "ms-vscode.cmake-tools"
@@ -57,5 +87,5 @@ This tells the C/C++ extension to use CMake as a configuration source for includ
5787
"version": 4
5888
}
5989
```
60-
__*Last updated: 11/28/24*__
90+
__*Last updated: 2/19/25*__
6191

config/perception.yaml

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@
88
scan_topic: "/lance/lidar_scan"
99
imu_topic: "/lance/imu"
1010

11-
use_tag_detections: -1 # 1: enable, 0: disable, -1: filtered only
12-
require_rebias_before_tf_pub: true # wait until successful trajectory filter rebias before publishing map --> odom tf
13-
require_rebias_before_scan_pub: true # wait until successful trajectory filter rebias before republishing scans
11+
use_tag_detections: 1 # 1: enable, 0: disable, -1: filtered only
12+
require_rebias_before_tf_pub: false # wait until successful trajectory filter rebias before publishing map --> odom tf
13+
require_rebias_before_scan_pub: false # wait until successful trajectory filter rebias before republishing scans
1414

1515
metrics_pub_freq: 10. # frequency for printing stats
16+
publish_odometry_debug: true
1617

17-
max_localization_threads: 3
18-
max_mapping_threads: 2
18+
cropbox_filter: # points within this bounding box are exluded from processing (in base_frame coords)
19+
min: [ -0.405, -0.6, 0.0 ] # min corner ^
20+
max: [ 0.735, 0.6, 0.959 ] # max corner ^
1921

2022
trajectory_filter:
2123
sampling_window_s: 0.6
@@ -27,12 +29,11 @@
2729
max_angular_deviation: 0.04
2830

2931
dlo:
30-
debug:
31-
publish_scans: true
32+
use_timestamps_as_init: true
33+
gravity_align: false # enable/disable gravity alignment on startup
3234
adaptive_params:
3335
use: true # whether or not keyframe params scale with "spaciousness"
3436
lpf_coeff: 0.8
35-
gravity_align: true # enable/disable gravity alignment on startup
3637
keyframe:
3738
thresh_D: 1. # distance threshold in meters for creating a new keyframe
3839
thresh_R: 30. # rotation threshold in degrees for creating a new keyframe
@@ -44,10 +45,6 @@
4445
use: true # start with the provided pose?
4546
position: [ 0., 0., 0. ] # x, y, z
4647
orientation: [ 1., 0., 0., 0. ] # w, x, y, z
47-
crop_filter:
48-
use: true # exclude points within the provided bounding box (in the base frame) from processing
49-
min: [ -0.405, -0.6, 0.0 ] # min corner ^
50-
max: [ 0.735, 0.6, 0.959 ] # max corner ^
5148
voxel_filter:
5249
scan:
5350
use: true # voxelize each input scan?
@@ -62,36 +59,53 @@
6259
floor: 0.04
6360
ceil: 0.5
6461
precision: 0.01
62+
immediate_filter:
63+
use: false
64+
range: 1.0
65+
thresh_proportion: 0.3
6566
imu:
6667
use: true # integrate imu data to hint GICP?
6768
use_orientation: true
6869
calib_time: 3 # calibration time
69-
buffer_size: 2000 # measurement buffer length
7070
gicp:
71-
min_num_points: 1000 # minimum points required
71+
num_threads: 4
72+
min_num_points: 500 # minimum points required
7273
s2s:
73-
k_correspondences: 10
74-
max_correspondence_distance: 0.1
74+
k_correspondences: 15
75+
max_correspondence_distance: 0.25
7576
max_iterations: 32
7677
transformation_epsilon: 0.01
7778
euclidean_fitness_epsilon: 0.01
7879
ransac:
7980
iterations: 5
80-
outlier_rejection_thresh: 0.5
81+
outlier_rejection_thresh: 0.1
8182
s2m:
82-
k_correspondences: 20
83-
max_correspondence_distance: 0.05
83+
k_correspondences: 30
84+
max_correspondence_distance: 0.1
8485
max_iterations: 32
85-
transformation_epsilon: 0.01
86-
euclidean_fitness_epsilon: 0.01
86+
transformation_epsilon: 0.0009
87+
euclidean_fitness_epsilon: 0.005
8788
ransac:
88-
iterations: 5
89-
outlier_rejection_thresh: 1.
89+
iterations: 6
90+
outlier_rejection_thresh: 0.05
9091

9192
mapping:
9293
frustum_search_radius: 0.009
9394
radial_distance_thresh: 0.01
9495
delete_delta_coeff: 0.03
95-
delete_max_range: 3.
96-
add_max_range: 5.
97-
voxel_size: 0.04
96+
delete_max_range: 4.
97+
add_max_range: 4.
98+
voxel_size: 0.08
99+
100+
fiducial_detection:
101+
max_range: 2.
102+
plane_distance_threshold: 0.005
103+
plane_eps_thresh: 0.1
104+
vox_resolution: 0.03
105+
remaining_points_thresh: 0.05
106+
minimum_input_points: 100
107+
minimum_segmented_points: 15
108+
109+
traversibility:
110+
chunk_horizontal_range: 3.5
111+
chunk_vertical_range: 1.

doc/architecture.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
## Cardinal Perception System Architecture
2+
### Localization
3+
The localization solution consists of two components: LiDAR odometry and fiducial detection for global alignment. The LiDAR odometry is based off of [direct_lidar_odometry](https://github.com/vectr-ucla/direct_lidar_odometry) (DLO) and utilizes a scan-to-scan and scan-to-map based odometry solution, with optional IMU input to seed registration. Fiducial detection is not required but can come in one of two forms - AprilTag detections or LiDAR-reflector detection (this is custom). Fusion between local and global measurements is currently only done on a simple transform-offset basis, utilizing the `map` and `odom` transform-tree frames (meaning that without fiducial detection, odometry is implicitly treated as the full localization solution).
4+
5+
![localization overview](localization-v050.svg)
6+
7+
**Localization subsribes to the following ROS2 topics:**
8+
1. A `sensor_msgs/msg/PointCloud2` topic as configured by the parameter `scan_topic` (default is `scan`). This can be any pointcloud and is not restricted to being organized or needing have timestamp data, etc..
9+
2. A `sensor_msgs/msg/Imu` topic as configured by the parameter `imu_topic` (default is `imu`). *This is optional and IMU usage can be disabled by setting the `dlo.imu.use` parameter to `false`.* IMU data must be in the same time-base as LiDAR scans, since these are timestamp matched internally.
10+
3. A `cardinal_perception/msg/TagsTransform` topic which defaults to `"/tags_detections"` in both nodes. This is only relevant when using the AprilTag detector node to provide global measurements, which can be parameter-disabled by setting `use_tag_detections` to `false` or compile-time disabled by using setting the `USE_TAG_DETECTION_PIPELINE` macro to `0`.
11+
12+
### Terrain Mapping
13+
Terrain mapping attempts to model the real world utilizing a set of cartesian points. The map itself is stored as a pointcloud, and indexed using a specialized octree which automatically voxelizes all points in the same leaf and allows for direct deletion of points/leaves. Point-deletion is calculating using the custom-developed "KDTree Frustum Collision" (KFC) mapping model, which provides (more or less) realtime mapping using just LiDAR scans. This stage does not have any additonal ROS subscriptions but works directly off of buffers which are reused from the localization stage, as well as the most recent localization results.
14+
15+
![mapping overview](mapping-v050.svg)
16+
17+
#### KFC Map Iteration Steps
18+
1. Assemble submap from global map using distance from current LiDAR scanner position.
19+
2. Calculate the direction to each submap point from the LiDAR position, and normalize to be of unit length.
20+
3. Build a KDTree from the global submap direction vectors.
21+
4. Calculate the direction to each scan point from the LiDAR position, and normalize to be of unit length. For each point, complete a range search in the submap KDTree to find points within the "frustum cone" for the current LiDAR ray.
22+
5. Apply the collision model to determine which points should be deleted (points that are closer than the scan point get deleted).
23+
6. Perform delete operation on global map.
24+
7. Add scan points to global map.
25+
8. Optimize the underlying octree structure.
26+
27+
### Traversability Generation
28+
(Not implemented yet!)
29+
30+
### Trajectory Generation
31+
(Not implemented yet!)
32+
33+
__*Last updated: 2/19/25*__

doc/cardinal-perception-v050-overview.svg

Lines changed: 4 additions & 0 deletions
Loading

doc/cardinal-perception.png

85.7 KB
Loading

0 commit comments

Comments
 (0)