├── CMakeLists.txt
├── README.md
├── config
├── l515.yaml
└── velodyne.yaml
├── docs
└── C3P_VoxelMap_Appendix.pdf
├── include
├── common_lib.h
├── so3_math.h
└── voxel_map_util.hpp
├── launch
├── mapping_l515.launch
└── mapping_velodyne.launch
├── msg
├── Pose6D.msg
└── States.msg
├── package.xml
├── rviz_cfg
└── c3p_voxelmap.rviz
└── src
├── IMU_Processing.hpp
├── preprocess.cpp
├── preprocess.h
└── voxelMapping.cpp
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(c3p_voxelmap)
3 |
4 | SET(CMAKE_BUILD_TYPE "RelWithDebInfo")
5 |
6 | ADD_COMPILE_OPTIONS(-std=c++14 )
7 | ADD_COMPILE_OPTIONS(-std=c++14 )
8 | set( CMAKE_CXX_FLAGS "-std=c++14 -O3" )
9 |
10 | add_definitions(-DROOT_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/\")
11 |
12 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexceptions" )
13 | set(CMAKE_CXX_STANDARD 14)
14 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
15 | set(CMAKE_CXX_EXTENSIONS OFF)
16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -pthread -std=c++0x -std=c++14 -fexceptions")
17 |
18 | message("Current CPU archtecture: ${CMAKE_SYSTEM_PROCESSOR}")
19 | if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)" )
20 | include(ProcessorCount)
21 | ProcessorCount(N)
22 | message("Processer number: ${N}")
23 | if(N GREATER 5)
24 | add_definitions(-DMP_EN)
25 | add_definitions(-DMP_PROC_NUM=4)
26 | message("core for MP: 4")
27 | elseif(N GREATER 3)
28 | math(EXPR PROC_NUM "${N} - 2")
29 | add_definitions(-DMP_EN)
30 | add_definitions(-DMP_PROC_NUM="${PROC_NUM}")
31 | message("core for MP: ${PROC_NUM}")
32 | else()
33 | add_definitions(-DMP_PROC_NUM=1)
34 | endif()
35 | else()
36 | add_definitions(-DMP_PROC_NUM=1)
37 | endif()
38 |
39 |
40 | find_package(catkin REQUIRED COMPONENTS
41 | geometry_msgs
42 | nav_msgs
43 | sensor_msgs
44 | roscpp
45 | rospy
46 | std_msgs
47 | pcl_ros
48 | tf
49 | livox_ros_driver
50 | message_generation
51 | eigen_conversions
52 | )
53 | find_package(OpenMP QUIET)
54 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
55 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
56 | find_package(Eigen3 REQUIRED)
57 | find_package(PCL 1.7 REQUIRED)
58 |
59 | message(Eigen: ${EIGEN3_INCLUDE_DIR})
60 |
61 | include_directories(
62 | ${catkin_INCLUDE_DIRS}
63 | ${EIGEN3_INCLUDE_DIR}
64 | ${PCL_INCLUDE_DIRS}
65 | ${PYTHON_INCLUDE_DIRS}
66 | include)
67 |
68 | add_message_files(
69 | FILES
70 | Pose6D.msg
71 | States.msg
72 | )
73 |
74 | generate_messages(
75 | DEPENDENCIES
76 | geometry_msgs
77 | )
78 |
79 | catkin_package(
80 | CATKIN_DEPENDS geometry_msgs nav_msgs roscpp rospy std_msgs message_runtime
81 | DEPENDS EIGEN3 PCL
82 | INCLUDE_DIRS
83 | )
84 |
85 | add_executable(c3p_voxelmap src/voxelMapping.cpp src/preprocess.cpp)
86 | target_link_libraries(c3p_voxelmap ${catkin_LIBRARIES} ${PCL_LIBRARIES})
87 | target_include_directories(c3p_voxelmap PRIVATE ${PYTHON_INCLUDE_DIRS})
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # C3P-VoxelMap
2 |
3 | This repository implements **C3P-VoxelMap**, a compact, cumulative, and coalescible probabilistic voxel mapping method to enhance performance, accuracy, and memory efficiency in LiDAR odometry. Based on [VoxelMap](https://github.com/hku-mars/VoxelMap), our work reduces memory consumption by two strategies:
4 | 1. Compact point-free representation for probabilistic voxels and cumulative update of the planar uncertainty without caching original point clouds.
5 | 2. On-demand voxel merging by taking advantage of the geometric features in the real world, accumulating voxels in a locality-sensitive hash and triggers merging lazily.
6 |
7 | The paper is available on **arxiv**:
8 | [C3P-VoxelMap: Compact, Cumulative and Coalescible Probabilistic Voxel Mapping](https://arxiv.org/abs/2406.01195)
9 |
10 | ## Dependency
11 |
12 | ROS (tested on Noetic)
13 |
14 | PCL (>= 1.8)
15 |
16 | Eigen (>= 3.3.4)
17 |
18 | livox_ros_driver, follow [livox_ros_driver Installation](https://github.com/Livox-SDK/livox_ros_driver).
19 |
20 | ## Compilation
21 |
22 | Clone the repository and compile it by catkin_make:
23 | ```
24 | mkdir -P ~/catkin_ws/src & cd ~/catkin_ws/src
25 | git clone https://github.com/deptrum/c3p-voxelmap.git
26 | cd ..
27 | catkin_make
28 | source devel/setup.bash
29 | ```
30 |
31 | ## Running on Dataset
32 |
33 | To run on dataset (KITTI dataset for example), firstly edit configuration file ``` config/velodyne.yaml ```.
34 |
35 | Besides general parameters such as point cloud topic name, there are some extra configutations concerning on-demand voxel merging. To enable voxel merging, set ```voxel_merging/enable_voxel_merging``` to ```true```. The other parameters in ```voxel_merging``` can also be configured to adjust the effectiveness of on-demand voxel merging.
36 |
37 | Optionally, set ```visualization/pub_merged_voxel``` to ```true``` to visualize voxel merging results. Merged voxel planes are shown with the same color in visualization.
38 |
39 | After setting parameters, run the ROS package:
40 | ```
41 | cd ~/catkin_ws
42 | source devel/setup.bash
43 | roslaunch c3p_voxelmap mapping_velodyne.launch
44 | ```
45 |
46 | In the meanwhile, play rosbag and the visualization results will be shown in RViz window.
47 |
48 | ## Acknowledgments
49 | Thanks for [VoxelMap](https://github.com/hku-mars/VoxelMap).
--------------------------------------------------------------------------------
/config/l515.yaml:
--------------------------------------------------------------------------------
1 | common:
2 | lid_topic: "/camera/depth/color/points"
3 | imu_topic: "/no_imu"
4 |
5 | preprocess:
6 | lidar_type: 3 # L515 LiDAR
7 | scan_line: 64
8 | blind: 0.1
9 | point_filter_num: 1
10 | calib_laser: false
11 |
12 | mapping:
13 | down_sample_size: 0.1
14 | max_iteration: 3
15 | voxel_size: 0.25
16 | max_layer: 2
17 | layer_point_size: [20, 10, 10, 5, 5]
18 | plannar_threshold: 0.01
19 |
20 | voxel_merging:
21 | enable_voxel_merging: true
22 | merge_theta_thresh: 0.2
23 | merge_dist_thresh: 0.1
24 | merge_cov_min_eigen_val_thresh: 0.002
25 | merge_x_coord_diff_thresh: 5.0
26 | merge_y_coord_diff_thresh: 5.0
27 |
28 | noise_model:
29 | ranging_cov: 0.05
30 | angle_cov: 0.25
31 | acc_cov_scale: 0.1
32 | gyr_cov_scale: 0.2
33 |
34 | imu:
35 | imu_en: false
36 | extrinsic_T: [ 0, 0, 0]
37 | extrinsic_R: [ 1, 0, 0,
38 | 0, 1, 0,
39 | 0, 0, 1]
40 |
41 | visualization:
42 | pub_voxel_map: false
43 | publish_max_voxel_layer: 1 # only publish 0,1 layer's plane
44 | pub_point_cloud: true
45 | dense_map_enable: false
46 | pub_point_cloud_skip: 1 # publish one points per five points
47 | pub_merged_voxel: true
48 |
49 | Result:
50 | write_kitti_log: false
51 | result_path: ""
--------------------------------------------------------------------------------
/config/velodyne.yaml:
--------------------------------------------------------------------------------
1 | common:
2 | lid_topic: "/velodyne_points"
3 | imu_topic: "/imu_data"
4 |
5 | preprocess:
6 | lidar_type: 2 #1 for Livox serials LiDAR, 2 for Velodyne LiDAR, 3 for L515 LiDAR
7 | scan_line: 64
8 | blind: 1
9 | point_filter_num: 1
10 | calib_laser: true # true for KITTI Odometry dataset
11 |
12 | mapping:
13 | down_sample_size: 0.5
14 | max_iteration: 3
15 | voxel_size: 3.0
16 | max_layer: 3 # 4 layer, 0, 1, 2, 3
17 | layer_point_size: [5, 5, 5, 5, 5]
18 | plannar_threshold: 0.01
19 |
20 | voxel_merging:
21 | enable_voxel_merging: true
22 | merge_theta_thresh: 0.2
23 | merge_dist_thresh: 0.1
24 | merge_cov_min_eigen_val_thresh: 0.001
25 | merge_x_coord_diff_thresh: 10.0
26 | merge_y_coord_diff_thresh: 10.0
27 |
28 | noise_model:
29 | ranging_cov: 0.04
30 | angle_cov: 0.1
31 | acc_cov_scale: 1.0
32 | gyr_cov_scale: 0.5
33 |
34 | imu:
35 | imu_en: false
36 | extrinsic_T: [ 0, 0, 0]
37 | extrinsic_R: [ 1, 0, 0,
38 | 0, 1, 0,
39 | 0, 0, 1]
40 |
41 | visualization:
42 | pub_voxel_map: false
43 | publish_max_voxel_layer: 1 # only publish 0,1,2 layer's plane
44 | pub_point_cloud: true
45 | dense_map_enable: false
46 | pub_point_cloud_skip: 5 # publish one points per five points
47 | pub_merged_voxel: false
48 |
49 | Result:
50 | write_kitti_log: false
51 | result_path: ""
--------------------------------------------------------------------------------
/docs/C3P_VoxelMap_Appendix.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deptrum/c3p-voxelmap/69f9ac63938f7a55d048c48f6a2ec19c00730a69/docs/C3P_VoxelMap_Appendix.pdf
--------------------------------------------------------------------------------
/include/common_lib.h:
--------------------------------------------------------------------------------
1 | #ifndef COMMON_LIB_H
2 | #define COMMON_LIB_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | using namespace std;
16 | using namespace Eigen;
17 |
18 | #define PI_M (3.14159265358)
19 | #define G_m_s2 (9.81) // Gravaty const in GuangDong/China
20 | #define DIM_STATE (18) // Dimension of states (Let Dim(SO(3)) = 3)
21 | #define DIM_PROC_N (12) // Dimension of process noise (Let Dim(SO(3)) = 3)
22 | #define CUBE_LEN (6.0)
23 | #define LIDAR_SP_LEN (2)
24 | // old init
25 | #define INIT_COV (0.0000001)
26 | #define NUM_MATCH_POINTS (5)
27 | #define MAX_MEAS_DIM (10000)
28 |
29 | #define VEC_FROM_ARRAY(v) v[0], v[1], v[2]
30 | #define MAT_FROM_ARRAY(v) v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]
31 | #define CONSTRAIN(v, min, max) ((v > min) ? ((v < max) ? v : max) : min)
32 | #define ARRAY_FROM_EIGEN(mat) mat.data(), mat.data() + mat.rows() * mat.cols()
33 | #define STD_VEC_FROM_EIGEN(mat) \
34 | vector(mat.data(), mat.data() + mat.rows() * mat.cols())
35 | #define DEBUG_FILE_DIR(name) (string(string(ROOT_DIR) + "Log/" + name))
36 |
37 | typedef voxel_map::Pose6D Pose6D;
38 | typedef pcl::PointXYZINormal PointType;
39 | typedef pcl::PointCloud PointCloudXYZI;
40 | typedef vector> PointVector;
41 | typedef Vector3d V3D;
42 | typedef Matrix3d M3D;
43 | typedef Vector3f V3F;
44 | typedef Matrix3f M3F;
45 |
46 | #define MD(a, b) Matrix
47 | #define VD(a) Matrix
48 | #define MF(a, b) Matrix
49 | #define VF(a) Matrix
50 |
51 | M3D Eye3d(M3D::Identity());
52 | M3F Eye3f(M3F::Identity());
53 | V3D Zero3d(0, 0, 0);
54 | V3F Zero3f(0, 0, 0);
55 | Vector3d Lidar_offset_to_IMU(0, 0, 0);
56 |
57 | struct MeasureGroup // Lidar data and imu dates for the curent process
58 | {
59 | MeasureGroup() { this->lidar.reset(new PointCloudXYZI()); };
60 | double lidar_beg_time;
61 | PointCloudXYZI::Ptr lidar;
62 | deque imu;
63 | };
64 |
65 | struct StatesGroup {
66 | StatesGroup() {
67 | this->rot_end = M3D::Identity();
68 | this->pos_end = Zero3d;
69 | this->vel_end = Zero3d;
70 | this->bias_g = Zero3d;
71 | this->bias_a = Zero3d;
72 | this->gravity = Zero3d;
73 | this->cov = Matrix::Identity() * INIT_COV;
74 | };
75 |
76 | StatesGroup(const StatesGroup& b) {
77 | this->rot_end = b.rot_end;
78 | this->pos_end = b.pos_end;
79 | this->vel_end = b.vel_end;
80 | this->bias_g = b.bias_g;
81 | this->bias_a = b.bias_a;
82 | this->gravity = b.gravity;
83 | this->cov = b.cov;
84 | };
85 |
86 | StatesGroup& operator=(const StatesGroup& b) {
87 | this->rot_end = b.rot_end;
88 | this->pos_end = b.pos_end;
89 | this->vel_end = b.vel_end;
90 | this->bias_g = b.bias_g;
91 | this->bias_a = b.bias_a;
92 | this->gravity = b.gravity;
93 | this->cov = b.cov;
94 | return *this;
95 | };
96 |
97 | StatesGroup operator+(const Matrix& state_add) {
98 | StatesGroup a;
99 | a.rot_end = this->rot_end * Exp(state_add(0, 0), state_add(1, 0), state_add(2, 0));
100 | a.pos_end = this->pos_end + state_add.block<3, 1>(3, 0);
101 | a.vel_end = this->vel_end + state_add.block<3, 1>(6, 0);
102 | a.bias_g = this->bias_g + state_add.block<3, 1>(9, 0);
103 | a.bias_a = this->bias_a + state_add.block<3, 1>(12, 0);
104 | a.gravity = this->gravity + state_add.block<3, 1>(15, 0);
105 | a.cov = this->cov;
106 | return a;
107 | };
108 |
109 | StatesGroup& operator+=(const Matrix& state_add) {
110 | this->rot_end = this->rot_end * Exp(state_add(0, 0), state_add(1, 0), state_add(2, 0));
111 | this->pos_end += state_add.block<3, 1>(3, 0);
112 | this->vel_end += state_add.block<3, 1>(6, 0);
113 | this->bias_g += state_add.block<3, 1>(9, 0);
114 | this->bias_a += state_add.block<3, 1>(12, 0);
115 | this->gravity += state_add.block<3, 1>(15, 0);
116 | return *this;
117 | };
118 |
119 | Matrix operator-(const StatesGroup& b) {
120 | Matrix a;
121 | M3D rotd(b.rot_end.transpose() * this->rot_end);
122 | a.block<3, 1>(0, 0) = Log(rotd);
123 | a.block<3, 1>(3, 0) = this->pos_end - b.pos_end;
124 | a.block<3, 1>(6, 0) = this->vel_end - b.vel_end;
125 | a.block<3, 1>(9, 0) = this->bias_g - b.bias_g;
126 | a.block<3, 1>(12, 0) = this->bias_a - b.bias_a;
127 | a.block<3, 1>(15, 0) = this->gravity - b.gravity;
128 | return a;
129 | };
130 |
131 | void resetpose() {
132 | this->rot_end = M3D::Identity();
133 | this->pos_end = Zero3d;
134 | this->vel_end = Zero3d;
135 | }
136 |
137 | M3D rot_end; // the estimated attitude (rotation matrix) at the end lidar
138 | // point
139 | V3D pos_end; // the estimated position at the end lidar point (world frame)
140 | V3D vel_end; // the estimated velocity at the end lidar point (world frame)
141 | V3D bias_g; // gyroscope bias
142 | V3D bias_a; // accelerator bias
143 | V3D gravity; // the estimated gravity acceleration
144 | Matrix cov; // states covariance
145 | };
146 |
147 | template
148 | T rad2deg(T radians) {
149 | return radians * 180.0 / PI_M;
150 | }
151 |
152 | template
153 | T deg2rad(T degrees) {
154 | return degrees * PI_M / 180.0;
155 | }
156 |
157 | template
158 | auto set_pose6d(const double t,
159 | const Matrix& a,
160 | const Matrix& g,
161 | const Matrix& v,
162 | const Matrix& p,
163 | const Matrix& R) {
164 | Pose6D rot_kp;
165 | rot_kp.offset_time = t;
166 | for (int i = 0; i < 3; i++) {
167 | rot_kp.acc[i] = a(i);
168 | rot_kp.gyr[i] = g(i);
169 | rot_kp.vel[i] = v(i);
170 | rot_kp.pos[i] = p(i);
171 | for (int j = 0; j < 3; j++)
172 | rot_kp.rot[i * 3 + j] = R(i, j);
173 | }
174 | // Map(rot_kp.rot, 3,3) = R;
175 | return move(rot_kp);
176 | }
177 |
178 | /* comment
179 | plane equation: Ax + By + Cz + D = 0
180 | convert to: A/D*x + B/D*y + C/D*z = -1
181 | solve: A0*x0 = b0
182 | where A0_i = [x_i, y_i, z_i], x0 = [A/D, B/D, C/D]^T, b0 = [-1, ..., -1]^T
183 | normvec: normalized x0
184 | */
185 | template
186 | bool esti_normvector(Matrix& normvec,
187 | const PointVector& point,
188 | const T& threshold,
189 | const int& point_num) {
190 | MatrixXf A(point_num, 3);
191 | MatrixXf b(point_num, 1);
192 | b.setOnes();
193 | b *= -1.0f;
194 |
195 | for (int j = 0; j < point_num; j++) {
196 | A(j, 0) = point[j].x;
197 | A(j, 1) = point[j].y;
198 | A(j, 2) = point[j].z;
199 | }
200 | normvec = A.colPivHouseholderQr().solve(b);
201 |
202 | for (int j = 0; j < point_num; j++) {
203 | if (fabs(normvec(0) * point[j].x + normvec(1) * point[j].y + normvec(2) * point[j].z + 1.0f) >
204 | threshold) {
205 | return false;
206 | }
207 | }
208 |
209 | normvec.normalize();
210 | return true;
211 | }
212 |
213 | template
214 | bool esti_plane(Matrix& pca_result, const PointVector& point, const T& threshold) {
215 | Matrix A;
216 | Matrix b;
217 | b.setOnes();
218 | b *= -1.0f;
219 |
220 | for (int j = 0; j < NUM_MATCH_POINTS; j++) {
221 | A(j, 0) = point[j].x;
222 | A(j, 1) = point[j].y;
223 | A(j, 2) = point[j].z;
224 | }
225 |
226 | Matrix normvec = A.colPivHouseholderQr().solve(b);
227 |
228 | for (int j = 0; j < NUM_MATCH_POINTS; j++) {
229 | if (fabs(normvec(0) * point[j].x + normvec(1) * point[j].y + normvec(2) * point[j].z + 1.0f) >
230 | threshold) {
231 | return false;
232 | }
233 | }
234 |
235 | T n = normvec.norm();
236 | pca_result(0) = normvec(0) / n;
237 | pca_result(1) = normvec(1) / n;
238 | pca_result(2) = normvec(2) / n;
239 | pca_result(3) = 1.0 / n;
240 | return true;
241 | }
242 |
243 | #endif
--------------------------------------------------------------------------------
/include/so3_math.h:
--------------------------------------------------------------------------------
1 | #ifndef SO3_MATH_H
2 | #define SO3_MATH_H
3 |
4 | #include
5 | #include
6 |
7 | // #include
8 |
9 | #define SKEW_SYM_MATRX(v) 0.0, -v[2], v[1], v[2], 0.0, -v[0], -v[1], v[0], 0.0
10 |
11 | template
12 | Eigen::Matrix Exp(const Eigen::Matrix&& ang) {
13 | T ang_norm = ang.norm();
14 | Eigen::Matrix Eye3 = Eigen::Matrix::Identity();
15 | if (ang_norm > 0.0000001) {
16 | Eigen::Matrix r_axis = ang / ang_norm;
17 | Eigen::Matrix K;
18 | K << SKEW_SYM_MATRX(r_axis);
19 | /// Roderigous Tranformation
20 | return Eye3 + std::sin(ang_norm) * K + (1.0 - std::cos(ang_norm)) * K * K;
21 | } else {
22 | return Eye3;
23 | }
24 | }
25 |
26 | template
27 | Eigen::Matrix Exp(const Eigen::Matrix& ang_vel, const Ts& dt) {
28 | T ang_vel_norm = ang_vel.norm();
29 | Eigen::Matrix Eye3 = Eigen::Matrix::Identity();
30 |
31 | if (ang_vel_norm > 0.0000001) {
32 | Eigen::Matrix r_axis = ang_vel / ang_vel_norm;
33 | Eigen::Matrix K;
34 |
35 | K << SKEW_SYM_MATRX(r_axis);
36 |
37 | T r_ang = ang_vel_norm * dt;
38 |
39 | /// Roderigous Tranformation
40 | return Eye3 + std::sin(r_ang) * K + (1.0 - std::cos(r_ang)) * K * K;
41 | } else {
42 | return Eye3;
43 | }
44 | }
45 |
46 | template
47 | Eigen::Matrix Exp(const T& v1, const T& v2, const T& v3) {
48 | T&& norm = sqrt(v1 * v1 + v2 * v2 + v3 * v3);
49 | Eigen::Matrix Eye3 = Eigen::Matrix::Identity();
50 | if (norm > 0.00001) {
51 | T r_ang[3] = {v1 / norm, v2 / norm, v3 / norm};
52 | Eigen::Matrix K;
53 | K << SKEW_SYM_MATRX(r_ang);
54 |
55 | /// Roderigous Tranformation
56 | return Eye3 + std::sin(norm) * K + (1.0 - std::cos(norm)) * K * K;
57 | } else {
58 | return Eye3;
59 | }
60 | }
61 |
62 | /* Logrithm of a Rotation Matrix */
63 | template
64 | Eigen::Matrix Log(const Eigen::Matrix& R) {
65 | T theta = (R.trace() > 3.0 - 1e-6) ? 0.0 : std::acos(0.5 * (R.trace() - 1));
66 | Eigen::Matrix K(R(2, 1) - R(1, 2), R(0, 2) - R(2, 0), R(1, 0) - R(0, 1));
67 | return (std::abs(theta) < 0.001) ? (0.5 * K) : (0.5 * theta / std::sin(theta) * K);
68 | }
69 |
70 | template
71 | Eigen::Matrix RotMtoEuler(const Eigen::Matrix& rot) {
72 | T sy = sqrt(rot(0, 0) * rot(0, 0) + rot(1, 0) * rot(1, 0));
73 | bool singular = sy < 1e-6;
74 | T x, y, z;
75 | if (!singular) {
76 | x = atan2(rot(2, 1), rot(2, 2));
77 | y = atan2(-rot(2, 0), sy);
78 | z = atan2(rot(1, 0), rot(0, 0));
79 | } else {
80 | x = atan2(-rot(1, 2), rot(1, 1));
81 | y = atan2(-rot(2, 0), sy);
82 | z = 0;
83 | }
84 | Eigen::Matrix ang(x, y, z);
85 | return ang;
86 | }
87 |
88 | inline Eigen::Matrix3d SkewSymmetricMatrix(const Eigen::Vector3d& v) {
89 | Eigen::Matrix3d skew_v;
90 | skew_v << 0.0, -v[2], v[1], v[2], 0.0, -v[0], -v[1], v[0], 0.0;
91 |
92 | return skew_v;
93 | }
94 |
95 | Eigen::Matrix3d Exp(const Eigen::Vector3d& ang) {
96 | double ang_norm = ang.norm();
97 |
98 | Eigen::Matrix3d I33(Eigen::Matrix3d::Identity());
99 | if (ang_norm >= std::numeric_limits::epsilon()) {
100 | Eigen::Matrix r_axis = ang / ang_norm;
101 | Eigen::Matrix K;
102 | K << SkewSymmetricMatrix(r_axis);
103 | /// Roderigous Tranformation
104 | return I33 + std::sin(ang_norm) * K + (1.0 - std::cos(ang_norm)) * K * K;
105 | }
106 |
107 | return I33;
108 | }
109 |
110 | #endif
111 |
--------------------------------------------------------------------------------
/include/voxel_map_util.hpp:
--------------------------------------------------------------------------------
1 | #ifndef VOXEL_MAP_UTIL_HPP
2 | #define VOXEL_MAP_UTIL_HPP
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include "common_lib.h"
18 | #include "omp.h"
19 |
20 | #define HASH_P 116101
21 | #define MAX_N 10000000000
22 |
23 | static int plane_id = 0;
24 | static int merged_plane_idx = 0;
25 | int voxel_nums = 0;
26 | int merged_voxel_nums = 0;
27 |
28 | // a point to plane matching structure
29 | typedef struct ptpl {
30 | Eigen::Vector3d point;
31 | Eigen::Vector3d normal;
32 | Eigen::Vector3d center;
33 | Eigen::Matrix plane_cov;
34 | double d;
35 | int layer;
36 | } ptpl;
37 |
38 | // 3D point with covariance
39 | typedef struct pointWithCov {
40 | Eigen::Vector3d point;
41 | Eigen::Vector3d point_world;
42 | Eigen::Matrix3d cov;
43 | } pointWithCov;
44 |
45 | struct Plane {
46 | Eigen::Vector3d center;
47 | Eigen::Vector3d normal;
48 | Eigen::Vector3d y_normal;
49 | Eigen::Vector3d x_normal;
50 | Eigen::Matrix3d covariance;
51 | Eigen::Matrix plane_cov;
52 | float radius = 0;
53 | float min_eigen_value = 1;
54 | float mid_eigen_value = 1;
55 | float max_eigen_value = 1;
56 | float d = 0;
57 | int points_size = 0;
58 |
59 | bool is_plane = false;
60 | bool is_init = false;
61 | int id = -1;
62 | int merge_plane_id = -1;
63 | // is_update and last_update_points_size are only for publish plane
64 | bool is_update = false;
65 | int last_update_points_size = 0;
66 |
67 | Plane() = default;
68 | };
69 |
70 | typedef struct PointFreeParams {
71 | Eigen::Matrix sigma_p_pt;
72 | Eigen::Vector3d sigma_p;
73 | size_t point_nums;
74 | Eigen::Matrix sigma_cov11_ppt;
75 | Eigen::Matrix sigma_cov12_ppt;
76 | Eigen::Matrix sigma_cov13_ppt;
77 | Eigen::Matrix sigma_cov22_ppt;
78 | Eigen::Matrix sigma_cov23_ppt;
79 | Eigen::Matrix sigma_cov33_ppt;
80 | Eigen::Matrix3d sigma_cov_e1_pt;
81 | Eigen::Matrix3d sigma_cov_e2_pt;
82 | Eigen::Matrix3d sigma_cov_e3_pt;
83 | Eigen::Matrix sigma_cov;
84 |
85 | void Initialize() {
86 | sigma_p_pt.setZero();
87 | sigma_p.setZero();
88 | point_nums = 0;
89 | sigma_cov11_ppt.setZero();
90 | sigma_cov12_ppt.setZero();
91 | sigma_cov13_ppt.setZero();
92 | sigma_cov22_ppt.setZero();
93 | sigma_cov23_ppt.setZero();
94 | sigma_cov33_ppt.setZero();
95 | sigma_cov_e1_pt.setZero();
96 | sigma_cov_e2_pt.setZero();
97 | sigma_cov_e3_pt.setZero();
98 | sigma_cov.setZero();
99 | }
100 | } PointFreeParams;
101 |
102 | class PointCluster {
103 | public:
104 | Eigen::Matrix3d P;
105 | Eigen::Vector3d v;
106 | int N;
107 |
108 | PointCluster() {
109 | P.setZero();
110 | v.setZero();
111 | N = 0;
112 | }
113 |
114 | void Clear() {
115 | P.setZero();
116 | v.setZero();
117 | N = 0;
118 | }
119 | void Push(const Eigen::Vector3d& vec) {
120 | N++;
121 | P += vec * vec.transpose();
122 | v += vec;
123 | }
124 |
125 | Eigen::Matrix3d Cov() {
126 | Eigen::Vector3d center = v / N;
127 | return P / N - center * center.transpose();
128 | }
129 |
130 | PointCluster operator+(const PointCluster& b) const {
131 | PointCluster res;
132 |
133 | res.P = this->P + b.P;
134 | res.v = this->v + b.v;
135 | res.N = this->N + b.N;
136 |
137 | return res;
138 | }
139 |
140 | PointCluster& operator+=(const PointCluster& sigv) {
141 | this->P += sigv.P;
142 | this->v += sigv.v;
143 | this->N += sigv.N;
144 |
145 | return *this;
146 | }
147 | };
148 |
149 | class VOXEL_LOC {
150 | public:
151 | int64_t x, y, z;
152 |
153 | VOXEL_LOC(int64_t vx = 0, int64_t vy = 0, int64_t vz = 0) : x(vx), y(vy), z(vz) {}
154 |
155 | bool operator==(const VOXEL_LOC& other) const {
156 | return (x == other.x && y == other.y && z == other.z);
157 | }
158 | };
159 |
160 | struct PlaneDesc {
161 | public:
162 | int64_t theta_bin;
163 | int64_t phi_bin;
164 | int64_t d_bin;
165 | int64_t x_bin;
166 | int64_t y_bin;
167 |
168 | PlaneDesc(const Plane* const plane,
169 | double merge_x_coord_diff_thresh,
170 | double merge_y_coord_diff_thresh) {
171 | double phi = std::asin(plane->normal[2]);
172 | double theta = std::atan2(plane->normal[1], plane->normal[0]);
173 |
174 | Eigen::Matrix3d R = (Eigen::AngleAxisd(theta, Vector3d::UnitZ()) *
175 | Eigen::AngleAxisd(-phi, Vector3d::UnitY()))
176 | .toRotationMatrix();
177 |
178 | if (phi < std::numeric_limits::epsilon()) {
179 | phi += M_PI;
180 | }
181 |
182 | if (theta < std::numeric_limits::epsilon()) {
183 | theta += 2 * M_PI;
184 | }
185 | phi *= 57.29578;
186 | theta *= 57.29578;
187 |
188 | float d = 10.f * plane->d;
189 |
190 | theta_bin = static_cast(phi / 10.f);
191 | phi_bin = static_cast(theta / 5.f);
192 | d_bin = static_cast(d / 10.f);
193 |
194 | Eigen::Vector3d coord_in_xy_plane = R * plane->center;
195 |
196 | x_bin = static_cast(coord_in_xy_plane(1) / merge_x_coord_diff_thresh);
197 | y_bin = static_cast(coord_in_xy_plane(2) / merge_y_coord_diff_thresh);
198 | }
199 | bool operator==(const PlaneDesc& other) const {
200 | return (theta_bin == other.theta_bin && phi_bin == other.phi_bin && d_bin == other.d_bin &&
201 | x_bin == other.x_bin && y_bin == other.y_bin);
202 | }
203 | };
204 |
205 | struct NodeLoc {
206 | public:
207 | int64_t x;
208 | int64_t y;
209 | int64_t z;
210 | int64_t leaf_num;
211 | NodeLoc() : x(0), y(0), z(0), leaf_num(0) {}
212 | NodeLoc(int64_t x_, int64_t y_, int64_t z_, int64_t leaf_num_) :
213 | x(x_),
214 | y(y_),
215 | z(z_),
216 | leaf_num(leaf_num_){};
217 |
218 | NodeLoc(const VOXEL_LOC& v, const std::vector& leaf_path) : x(v.x), y(v.y), z(v.z) {
219 | leaf_num = 0;
220 |
221 | if (!leaf_path.empty()) {
222 | for (int i = leaf_path.size() - 1; i >= 0; i--) {
223 | leaf_num = 10 * leaf_num + leaf_path[i] + 1;
224 | }
225 | }
226 | }
227 |
228 | bool operator==(const NodeLoc& other) const {
229 | return (x == other.x) && (y == other.y) && (z == other.z) && (leaf_num == other.leaf_num);
230 | }
231 | };
232 |
233 | // Hash value
234 | namespace std {
235 | template<>
236 | struct hash {
237 | int64_t operator()(const VOXEL_LOC& s) const {
238 | using std::hash;
239 | using std::size_t;
240 | return ((((s.z) * HASH_P) % MAX_N + (s.y)) * HASH_P) % MAX_N + (s.x);
241 | }
242 | };
243 |
244 | template<>
245 | struct hash {
246 | int64_t operator()(const PlaneDesc& plane) const {
247 | using std::hash;
248 | using std::size_t;
249 | return ((((((((plane.theta_bin) * HASH_P) % MAX_N + (plane.phi_bin)) * HASH_P) % MAX_N +
250 | (plane.d_bin)) *
251 | HASH_P) %
252 | MAX_N +
253 | (plane.x_bin)) *
254 | HASH_P) %
255 | MAX_N +
256 | (plane.y_bin);
257 | }
258 | };
259 |
260 | template<>
261 | struct hash {
262 | std::size_t operator()(const NodeLoc& c) const {
263 | return ((((((c.z) * HASH_P) % MAX_N + (c.y)) * HASH_P) % MAX_N + (c.x)) * HASH_P) % MAX_N +
264 | c.leaf_num;
265 | }
266 | };
267 | } // namespace std
268 |
269 | struct UnionPlane {
270 | NodeLoc root_node_loc;
271 | std::unordered_set plane_bucket;
272 | };
273 |
274 | class OctoTree {
275 | public:
276 | std::vector temp_points_; // all points in an octo tree
277 | std::vector new_points_; // new points in an octo tree
278 | Plane* plane_ptr_;
279 | PointFreeParams* point_free_params_;
280 | int max_layer_;
281 | bool indoor_mode_;
282 | int layer_;
283 | int octo_state_; // 0 is end of tree, 1 is not
284 | OctoTree* leaves_[8];
285 | double voxel_center_[3]; // x, y, z
286 | std::vector layer_point_size_;
287 | float quater_length_;
288 | float planer_threshold_;
289 | int max_plane_update_threshold_;
290 | bool init_octo_;
291 | PointCluster point_cluster_;
292 | uint32_t last_update_frame_;
293 | OctoTree(int max_layer, int layer, std::vector layer_point_size, float planer_threshold) :
294 | max_layer_(max_layer),
295 | layer_(layer),
296 | layer_point_size_(layer_point_size),
297 | planer_threshold_(planer_threshold) {
298 | temp_points_.clear();
299 | octo_state_ = 0;
300 | init_octo_ = false;
301 | max_plane_update_threshold_ = layer_point_size_[layer_];
302 | for (int i = 0; i < 8; i++) {
303 | leaves_[i] = nullptr;
304 | }
305 | point_free_params_ = nullptr;
306 | plane_ptr_ = new Plane;
307 | last_update_frame_ = 0;
308 | }
309 |
310 | ~OctoTree() {
311 | delete plane_ptr_;
312 | delete point_free_params_;
313 | for (size_t i = 0; i < 8; i++) {
314 | delete leaves_[i];
315 | }
316 | }
317 |
318 | int GetLeafNums() {
319 | int res = 0;
320 | for (size_t i = 0; i < 8; i++) {
321 | if (leaves_[i] != nullptr) {
322 | res += leaves_[i]->GetLeafNums();
323 | }
324 | }
325 | return res;
326 | }
327 |
328 | void MergeVoxelPlane(const OctoTree* const node) {
329 | point_cluster_ += node->point_cluster_;
330 |
331 | point_free_params_->sigma_p_pt += node->point_free_params_->sigma_p_pt;
332 | point_free_params_->sigma_p += node->point_free_params_->sigma_p;
333 | point_free_params_->point_nums += node->point_free_params_->point_nums;
334 | point_free_params_->sigma_cov11_ppt += node->point_free_params_->sigma_cov11_ppt;
335 | point_free_params_->sigma_cov12_ppt += node->point_free_params_->sigma_cov12_ppt;
336 | point_free_params_->sigma_cov13_ppt += node->point_free_params_->sigma_cov13_ppt;
337 | point_free_params_->sigma_cov22_ppt += node->point_free_params_->sigma_cov22_ppt;
338 | point_free_params_->sigma_cov23_ppt += node->point_free_params_->sigma_cov23_ppt;
339 | point_free_params_->sigma_cov33_ppt += node->point_free_params_->sigma_cov33_ppt;
340 | point_free_params_->sigma_cov_e1_pt += node->point_free_params_->sigma_cov_e1_pt;
341 | point_free_params_->sigma_cov_e2_pt += node->point_free_params_->sigma_cov_e2_pt;
342 | point_free_params_->sigma_cov_e3_pt += node->point_free_params_->sigma_cov_e3_pt;
343 | point_free_params_->sigma_cov += node->point_free_params_->sigma_cov;
344 |
345 | plane_ptr_->center = point_cluster_.v / point_cluster_.N;
346 | plane_ptr_->covariance = point_cluster_.Cov();
347 | Eigen::SelfAdjointEigenSolver solver(plane_ptr_->covariance);
348 |
349 | Eigen::Vector3d eigen_value = solver.eigenvalues();
350 | Eigen::Matrix3d eigen_vector = solver.eigenvectors();
351 |
352 | plane_ptr_->normal = eigen_vector.col(0);
353 |
354 | plane_ptr_->min_eigen_value = eigen_value(0);
355 | plane_ptr_->mid_eigen_value = eigen_value(1);
356 | plane_ptr_->max_eigen_value = eigen_value(2);
357 | plane_ptr_->radius = std::sqrt(eigen_value(2));
358 | plane_ptr_->d = -(plane_ptr_->normal.dot(plane_ptr_->center));
359 | plane_ptr_->points_size = point_cluster_.N;
360 |
361 | std::vector B(3);
362 | // Jacobian of the normal of plane w.r.t the world point
363 | for (int m = 0; m < 3; m++) {
364 | if (m != 0) {
365 | B[m] = (eigen_vector.col(m) * eigen_vector.col(0).transpose() +
366 | eigen_vector.col(0) * eigen_vector.col(m).transpose()) /
367 | (plane_ptr_->points_size * (eigen_value[0] - eigen_value[m]));
368 | } else {
369 | B[m].setZero();
370 | }
371 | }
372 | CalculatePointFreeVoxelPlaneCovariance(plane_ptr_->plane_cov,
373 | plane_ptr_->center,
374 | B,
375 | eigen_vector,
376 | 0);
377 | }
378 |
379 | void UpdatePointFreeParams(const pointWithCov& pv) {
380 | const auto& pi = pv.point;
381 | const auto& cov = pv.cov;
382 |
383 | Eigen::Vector3d e1(1.0, 0.0, 0.0);
384 | Eigen::Vector3d e2(0.0, 1.0, 0.0);
385 | Eigen::Vector3d e3(0.0, 0.0, 1.0);
386 |
387 | point_free_params_->point_nums++;
388 | point_free_params_->sigma_p += pi;
389 |
390 | auto p_pt = pi * pi.transpose();
391 | point_free_params_->sigma_p_pt(0) += p_pt(0, 0);
392 | point_free_params_->sigma_p_pt(1) += p_pt(0, 1);
393 | point_free_params_->sigma_p_pt(2) += p_pt(0, 2);
394 | point_free_params_->sigma_p_pt(3) += p_pt(1, 1);
395 | point_free_params_->sigma_p_pt(4) += p_pt(1, 2);
396 | point_free_params_->sigma_p_pt(5) += p_pt(2, 2);
397 |
398 | Eigen::Matrix3d cov11_ppt = cov(0, 0) * pi * pi.transpose();
399 | point_free_params_->sigma_cov11_ppt(0) += cov11_ppt(0, 0);
400 | point_free_params_->sigma_cov11_ppt(1) += cov11_ppt(0, 1);
401 | point_free_params_->sigma_cov11_ppt(2) += cov11_ppt(0, 2);
402 | point_free_params_->sigma_cov11_ppt(3) += cov11_ppt(1, 1);
403 | point_free_params_->sigma_cov11_ppt(4) += cov11_ppt(1, 2);
404 | point_free_params_->sigma_cov11_ppt(5) += cov11_ppt(2, 2);
405 |
406 | Eigen::Matrix3d cov12_ppt = cov(0, 1) * pi * pi.transpose();
407 | point_free_params_->sigma_cov12_ppt(0) += cov12_ppt(0, 0);
408 | point_free_params_->sigma_cov12_ppt(1) += cov12_ppt(0, 1);
409 | point_free_params_->sigma_cov12_ppt(2) += cov12_ppt(0, 2);
410 | point_free_params_->sigma_cov12_ppt(3) += cov12_ppt(1, 1);
411 | point_free_params_->sigma_cov12_ppt(4) += cov12_ppt(1, 2);
412 | point_free_params_->sigma_cov12_ppt(5) += cov12_ppt(2, 2);
413 |
414 | Eigen::Matrix3d cov13_ppt = cov(0, 2) * pi * pi.transpose();
415 | point_free_params_->sigma_cov13_ppt(0) += cov13_ppt(0, 0);
416 | point_free_params_->sigma_cov13_ppt(1) += cov13_ppt(0, 1);
417 | point_free_params_->sigma_cov13_ppt(2) += cov13_ppt(0, 2);
418 | point_free_params_->sigma_cov13_ppt(3) += cov13_ppt(1, 1);
419 | point_free_params_->sigma_cov13_ppt(4) += cov13_ppt(1, 2);
420 | point_free_params_->sigma_cov13_ppt(5) += cov13_ppt(2, 2);
421 |
422 | Eigen::Matrix3d cov22_ppt = cov(1, 1) * pi * pi.transpose();
423 | point_free_params_->sigma_cov22_ppt(0) += cov22_ppt(0, 0);
424 | point_free_params_->sigma_cov22_ppt(1) += cov22_ppt(0, 1);
425 | point_free_params_->sigma_cov22_ppt(2) += cov22_ppt(0, 2);
426 | point_free_params_->sigma_cov22_ppt(3) += cov22_ppt(1, 1);
427 | point_free_params_->sigma_cov22_ppt(4) += cov22_ppt(1, 2);
428 | point_free_params_->sigma_cov22_ppt(5) += cov22_ppt(2, 2);
429 |
430 | Eigen::Matrix3d cov23_ppt = cov(1, 2) * pi * pi.transpose();
431 | point_free_params_->sigma_cov23_ppt(0) += cov23_ppt(0, 0);
432 | point_free_params_->sigma_cov23_ppt(1) += cov23_ppt(0, 1);
433 | point_free_params_->sigma_cov23_ppt(2) += cov23_ppt(0, 2);
434 | point_free_params_->sigma_cov23_ppt(3) += cov23_ppt(1, 1);
435 | point_free_params_->sigma_cov23_ppt(4) += cov23_ppt(1, 2);
436 | point_free_params_->sigma_cov23_ppt(5) += cov23_ppt(2, 2);
437 |
438 | Eigen::Matrix3d cov33_ppt = cov(2, 2) * pi * pi.transpose();
439 | point_free_params_->sigma_cov33_ppt(0) += cov33_ppt(0, 0);
440 | point_free_params_->sigma_cov33_ppt(1) += cov33_ppt(0, 1);
441 | point_free_params_->sigma_cov33_ppt(2) += cov33_ppt(0, 2);
442 | point_free_params_->sigma_cov33_ppt(3) += cov33_ppt(1, 1);
443 | point_free_params_->sigma_cov33_ppt(4) += cov33_ppt(1, 2);
444 | point_free_params_->sigma_cov33_ppt(5) += cov33_ppt(2, 2);
445 |
446 | point_free_params_->sigma_cov_e1_pt += cov * e1 * pi.transpose();
447 | point_free_params_->sigma_cov_e2_pt += cov * e2 * pi.transpose();
448 | point_free_params_->sigma_cov_e3_pt += cov * e3 * pi.transpose();
449 |
450 | point_free_params_->sigma_cov(0) += cov(0, 0);
451 | point_free_params_->sigma_cov(1) += cov(0, 1);
452 | point_free_params_->sigma_cov(2) += cov(0, 2);
453 | point_free_params_->sigma_cov(3) += cov(1, 1);
454 | point_free_params_->sigma_cov(4) += cov(1, 2);
455 | point_free_params_->sigma_cov(5) += cov(2, 2);
456 | }
457 |
458 | bool UpdateMergedPlanePointFreeParams(const pointWithCov& pv) {
459 | const auto& pi = pv.point;
460 | const auto& cov = pv.cov;
461 |
462 | auto p_pt = pi * pi.transpose();
463 | Eigen::Matrix sigma_p_pt;
464 | sigma_p_pt(0) = point_free_params_->sigma_p_pt(0) + p_pt(0, 0);
465 | sigma_p_pt(1) = point_free_params_->sigma_p_pt(1) + p_pt(0, 1);
466 | sigma_p_pt(2) = point_free_params_->sigma_p_pt(2) + p_pt(0, 2);
467 | sigma_p_pt(3) = point_free_params_->sigma_p_pt(3) + p_pt(1, 1);
468 | sigma_p_pt(4) = point_free_params_->sigma_p_pt(4) + p_pt(1, 2);
469 | sigma_p_pt(5) = point_free_params_->sigma_p_pt(5) + p_pt(2, 2);
470 |
471 | Eigen::Vector3d sigma_p = point_free_params_->sigma_p + pi;
472 |
473 | Eigen::Matrix3d sigma_p_pt_mat;
474 | sigma_p_pt_mat(0, 0) = sigma_p_pt(0);
475 | sigma_p_pt_mat(0, 1) = sigma_p_pt(1);
476 | sigma_p_pt_mat(0, 2) = sigma_p_pt(2);
477 | sigma_p_pt_mat(1, 0) = sigma_p_pt(1);
478 | sigma_p_pt_mat(1, 1) = sigma_p_pt(3);
479 | sigma_p_pt_mat(1, 2) = sigma_p_pt(4);
480 | sigma_p_pt_mat(2, 0) = sigma_p_pt(2);
481 | sigma_p_pt_mat(2, 1) = sigma_p_pt(4);
482 | sigma_p_pt_mat(2, 2) = sigma_p_pt(5);
483 |
484 | int cur_point_size = point_free_params_->point_nums + 1;
485 | Eigen::Vector3d cur_center = sigma_p / cur_point_size;
486 | Eigen::Matrix3d cur_covariance = sigma_p_pt_mat / cur_point_size -
487 | cur_center * cur_center.transpose();
488 |
489 | Eigen::EigenSolver es(cur_covariance);
490 | Eigen::Matrix3cd evecs = es.eigenvectors();
491 | Eigen::Vector3cd evals = es.eigenvalues();
492 | Eigen::Vector3d evalsReal;
493 | evalsReal = evals.real();
494 | Eigen::Matrix3d::Index evalsMin, evalsMax;
495 | evalsReal.rowwise().sum().minCoeff(&evalsMin);
496 | evalsReal.rowwise().sum().maxCoeff(&evalsMax);
497 | int evalsMid = 3 - evalsMin - evalsMax;
498 | Eigen::Vector3d evecMin = evecs.real().col(evalsMin);
499 | Eigen::Vector3d evecMid = evecs.real().col(evalsMid);
500 | Eigen::Vector3d evecMax = evecs.real().col(evalsMax);
501 |
502 | if (evalsReal(evalsMin) < planer_threshold_) {
503 | UpdatePointFreeParams(pv);
504 |
505 | return false;
506 | }
507 |
508 | return true;
509 | }
510 |
511 | void CalculatePointFreeVoxelPlaneCovariance(Eigen::Matrix& plane_cov,
512 | const Eigen::Vector3d& center,
513 | const std::vector& B,
514 | const Eigen::Matrix3d& J_n_pw,
515 | const int& min_eval_idx) {
516 | plane_cov.setZero();
517 | Eigen::Vector3d e1(1.0, 0.0, 0.0);
518 | Eigen::Vector3d e2(0.0, 1.0, 0.0);
519 | Eigen::Vector3d e3(0.0, 0.0, 1.0);
520 |
521 | Eigen::Matrix3d sigma_cov11_ppt_mat;
522 | sigma_cov11_ppt_mat(0, 0) = point_free_params_->sigma_cov11_ppt(0);
523 | sigma_cov11_ppt_mat(0, 1) = point_free_params_->sigma_cov11_ppt(1);
524 | sigma_cov11_ppt_mat(0, 2) = point_free_params_->sigma_cov11_ppt(2);
525 | sigma_cov11_ppt_mat(1, 0) = point_free_params_->sigma_cov11_ppt(1);
526 | sigma_cov11_ppt_mat(1, 1) = point_free_params_->sigma_cov11_ppt(3);
527 | sigma_cov11_ppt_mat(1, 2) = point_free_params_->sigma_cov11_ppt(4);
528 | sigma_cov11_ppt_mat(2, 0) = point_free_params_->sigma_cov11_ppt(2);
529 | sigma_cov11_ppt_mat(2, 1) = point_free_params_->sigma_cov11_ppt(4);
530 | sigma_cov11_ppt_mat(2, 2) = point_free_params_->sigma_cov11_ppt(5);
531 |
532 | Eigen::Matrix3d sigma_cov12_ppt_mat;
533 | sigma_cov12_ppt_mat(0, 0) = point_free_params_->sigma_cov12_ppt(0);
534 | sigma_cov12_ppt_mat(0, 1) = point_free_params_->sigma_cov12_ppt(1);
535 | sigma_cov12_ppt_mat(0, 2) = point_free_params_->sigma_cov12_ppt(2);
536 | sigma_cov12_ppt_mat(1, 0) = point_free_params_->sigma_cov12_ppt(1);
537 | sigma_cov12_ppt_mat(1, 1) = point_free_params_->sigma_cov12_ppt(3);
538 | sigma_cov12_ppt_mat(1, 2) = point_free_params_->sigma_cov12_ppt(4);
539 | sigma_cov12_ppt_mat(2, 0) = point_free_params_->sigma_cov12_ppt(2);
540 | sigma_cov12_ppt_mat(2, 1) = point_free_params_->sigma_cov12_ppt(4);
541 | sigma_cov12_ppt_mat(2, 2) = point_free_params_->sigma_cov12_ppt(5);
542 |
543 | Eigen::Matrix3d sigma_cov13_ppt_mat;
544 | sigma_cov13_ppt_mat(0, 0) = point_free_params_->sigma_cov13_ppt(0);
545 | sigma_cov13_ppt_mat(0, 1) = point_free_params_->sigma_cov13_ppt(1);
546 | sigma_cov13_ppt_mat(0, 2) = point_free_params_->sigma_cov13_ppt(2);
547 | sigma_cov13_ppt_mat(1, 0) = point_free_params_->sigma_cov13_ppt(1);
548 | sigma_cov13_ppt_mat(1, 1) = point_free_params_->sigma_cov13_ppt(3);
549 | sigma_cov13_ppt_mat(1, 2) = point_free_params_->sigma_cov13_ppt(4);
550 | sigma_cov13_ppt_mat(2, 0) = point_free_params_->sigma_cov13_ppt(2);
551 | sigma_cov13_ppt_mat(2, 1) = point_free_params_->sigma_cov13_ppt(4);
552 | sigma_cov13_ppt_mat(2, 2) = point_free_params_->sigma_cov13_ppt(5);
553 |
554 | Eigen::Matrix3d sigma_cov22_ppt_mat;
555 | sigma_cov22_ppt_mat(0, 0) = point_free_params_->sigma_cov22_ppt(0);
556 | sigma_cov22_ppt_mat(0, 1) = point_free_params_->sigma_cov22_ppt(1);
557 | sigma_cov22_ppt_mat(0, 2) = point_free_params_->sigma_cov22_ppt(2);
558 | sigma_cov22_ppt_mat(1, 0) = point_free_params_->sigma_cov22_ppt(1);
559 | sigma_cov22_ppt_mat(1, 1) = point_free_params_->sigma_cov22_ppt(3);
560 | sigma_cov22_ppt_mat(1, 2) = point_free_params_->sigma_cov22_ppt(4);
561 | sigma_cov22_ppt_mat(2, 0) = point_free_params_->sigma_cov22_ppt(2);
562 | sigma_cov22_ppt_mat(2, 1) = point_free_params_->sigma_cov22_ppt(4);
563 | sigma_cov22_ppt_mat(2, 2) = point_free_params_->sigma_cov22_ppt(5);
564 |
565 | Eigen::Matrix3d sigma_cov23_ppt_mat;
566 | sigma_cov23_ppt_mat(0, 0) = point_free_params_->sigma_cov23_ppt(0);
567 | sigma_cov23_ppt_mat(0, 1) = point_free_params_->sigma_cov23_ppt(1);
568 | sigma_cov23_ppt_mat(0, 2) = point_free_params_->sigma_cov23_ppt(2);
569 | sigma_cov23_ppt_mat(1, 0) = point_free_params_->sigma_cov23_ppt(1);
570 | sigma_cov23_ppt_mat(1, 1) = point_free_params_->sigma_cov23_ppt(3);
571 | sigma_cov23_ppt_mat(1, 2) = point_free_params_->sigma_cov23_ppt(4);
572 | sigma_cov23_ppt_mat(2, 0) = point_free_params_->sigma_cov23_ppt(2);
573 | sigma_cov23_ppt_mat(2, 1) = point_free_params_->sigma_cov23_ppt(4);
574 | sigma_cov23_ppt_mat(2, 2) = point_free_params_->sigma_cov23_ppt(5);
575 |
576 | Eigen::Matrix3d sigma_cov33_ppt_mat;
577 | sigma_cov33_ppt_mat(0, 0) = point_free_params_->sigma_cov33_ppt(0);
578 | sigma_cov33_ppt_mat(0, 1) = point_free_params_->sigma_cov33_ppt(1);
579 | sigma_cov33_ppt_mat(0, 2) = point_free_params_->sigma_cov33_ppt(2);
580 | sigma_cov33_ppt_mat(1, 0) = point_free_params_->sigma_cov33_ppt(1);
581 | sigma_cov33_ppt_mat(1, 1) = point_free_params_->sigma_cov33_ppt(3);
582 | sigma_cov33_ppt_mat(1, 2) = point_free_params_->sigma_cov33_ppt(4);
583 | sigma_cov33_ppt_mat(2, 0) = point_free_params_->sigma_cov33_ppt(2);
584 | sigma_cov33_ppt_mat(2, 1) = point_free_params_->sigma_cov33_ppt(4);
585 | sigma_cov33_ppt_mat(2, 2) = point_free_params_->sigma_cov33_ppt(5);
586 |
587 | Eigen::Matrix3d sigma_cov_mat;
588 | sigma_cov_mat(0, 0) = point_free_params_->sigma_cov(0);
589 | sigma_cov_mat(0, 1) = point_free_params_->sigma_cov(1);
590 | sigma_cov_mat(0, 2) = point_free_params_->sigma_cov(2);
591 | sigma_cov_mat(1, 0) = point_free_params_->sigma_cov(1);
592 | sigma_cov_mat(1, 1) = point_free_params_->sigma_cov(3);
593 | sigma_cov_mat(1, 2) = point_free_params_->sigma_cov(4);
594 | sigma_cov_mat(2, 0) = point_free_params_->sigma_cov(2);
595 | sigma_cov_mat(2, 1) = point_free_params_->sigma_cov(4);
596 | sigma_cov_mat(2, 2) = point_free_params_->sigma_cov(5);
597 |
598 | // Calculate plane_cov.block<3, 3>(0, 0)
599 | for (int i = 0; i < 3; i++) {
600 | if (i != min_eval_idx) {
601 | for (int j = i; j < 3; j++) {
602 | if (j != min_eval_idx) {
603 | const auto& B1 = B[i];
604 | const auto& B2 = B[j].transpose();
605 |
606 | double sigma_pt_B1_cov_B2t_p = (sigma_cov11_ppt_mat * B1 * e1 * e1.transpose() * B2)
607 | .trace() +
608 | (sigma_cov12_ppt_mat * B1 * e1 * e2.transpose() * B2)
609 | .trace() +
610 | (sigma_cov13_ppt_mat * B1 * e1 * e3.transpose() * B2)
611 | .trace() +
612 | (sigma_cov12_ppt_mat * B1 * e2 * e1.transpose() * B2)
613 | .trace() +
614 | (sigma_cov22_ppt_mat * B1 * e2 * e2.transpose() * B2)
615 | .trace() +
616 | (sigma_cov23_ppt_mat * B1 * e2 * e3.transpose() * B2)
617 | .trace() +
618 | (sigma_cov13_ppt_mat * B1 * e3 * e1.transpose() * B2)
619 | .trace() +
620 | (sigma_cov23_ppt_mat * B1 * e3 * e2.transpose() * B2)
621 | .trace() +
622 | (sigma_cov33_ppt_mat * B1 * e3 * e3.transpose() * B2)
623 | .trace();
624 |
625 | double e1t_B2_q = e1.transpose() * B2 * center;
626 | double e2t_B2_q = e2.transpose() * B2 * center;
627 | double e3t_B2_q = e3.transpose() * B2 * center;
628 | double e1t_B1_q = e1.transpose() * B1 * center;
629 | double e2t_B1_q = e2.transpose() * B1 * center;
630 | double e3t_B1_q = e3.transpose() * B1 * center;
631 | double sigma_pt_B1_cov_B2t_q = e1t_B2_q *
632 | (point_free_params_->sigma_cov_e1_pt * B1).trace() +
633 | e2t_B2_q *
634 | (point_free_params_->sigma_cov_e2_pt * B1).trace() +
635 | e3t_B2_q *
636 | (point_free_params_->sigma_cov_e3_pt * B1).trace();
637 |
638 | double sigma_qt_B1_cov_B2t_p = e1t_B1_q *
639 | (point_free_params_->sigma_cov_e1_pt * B2).trace() +
640 | e2t_B1_q *
641 | (point_free_params_->sigma_cov_e2_pt * B2).trace() +
642 | e3t_B1_q *
643 | (point_free_params_->sigma_cov_e3_pt * B2).trace();
644 |
645 | double sigma_qt_B1_cov_B2t_q = center.transpose() * B1 * sigma_cov_mat * B2 * center;
646 |
647 | plane_cov(i, j) = sigma_pt_B1_cov_B2t_p - sigma_pt_B1_cov_B2t_q -
648 | sigma_qt_B1_cov_B2t_p + sigma_qt_B1_cov_B2t_q;
649 | }
650 | }
651 | }
652 | }
653 | for (size_t i = 0; i < 3; i++) {
654 | for (size_t j = i + 1; j < 3; j++) {
655 | plane_cov(j, i) = plane_cov(i, j);
656 | }
657 | }
658 | plane_cov.block<3, 3>(0, 0) = J_n_pw * plane_cov.block<3, 3>(0, 0).eval() * J_n_pw.transpose();
659 |
660 | // Calculate plane_cov.block<3, 3>(0, 3) and plane_cov.block<3, 3>(3, 0)
661 | for (int i = 0; i < 3; i++) {
662 | if (i != min_eval_idx) {
663 | const auto& Bk = B[i];
664 |
665 | Eigen::Vector3d pt_Bk_cov;
666 | Eigen::Vector3d qt_Bk_cov;
667 |
668 | pt_Bk_cov(0) = (point_free_params_->sigma_cov_e1_pt * Bk).trace();
669 | pt_Bk_cov(1) = (point_free_params_->sigma_cov_e2_pt * Bk).trace();
670 | pt_Bk_cov(2) = (point_free_params_->sigma_cov_e3_pt * Bk).trace();
671 |
672 | qt_Bk_cov = center.transpose() * Bk * sigma_cov_mat;
673 | plane_cov.block<1, 3>(i, 3) = pt_Bk_cov - qt_Bk_cov;
674 | }
675 | }
676 | plane_cov.block<3, 3>(0, 3) = J_n_pw * plane_cov.block<3, 3>(0, 3).eval() /
677 | point_free_params_->point_nums;
678 | plane_cov.block<3, 3>(3, 0) = plane_cov.block<3, 3>(0, 3).transpose();
679 |
680 | // Calculate plane_cov.block<3, 3>(3, 3)
681 | plane_cov.block<3, 3>(3, 3) = sigma_cov_mat /
682 | (point_free_params_->point_nums * point_free_params_->point_nums);
683 | }
684 |
685 | // check is plane , calc plane parameters including plane covariance
686 | void init_plane(const std::vector& points, Plane* plane) {
687 | plane->plane_cov = Eigen::Matrix::Zero();
688 | plane->covariance = Eigen::Matrix3d::Zero();
689 | plane->center = Eigen::Vector3d::Zero();
690 | plane->normal = Eigen::Vector3d::Zero();
691 | plane->radius = 0;
692 |
693 | if (!init_octo_) {
694 | plane->points_size = points.size();
695 | for (auto pv : points) {
696 | plane->covariance += pv.point * pv.point.transpose();
697 | plane->center += pv.point;
698 | }
699 | plane->center = plane->center / plane->points_size;
700 | plane->covariance = plane->covariance / plane->points_size -
701 | plane->center * plane->center.transpose();
702 | } else {
703 | Eigen::Matrix3d sigma_p_pt_mat;
704 | sigma_p_pt_mat(0, 0) = point_free_params_->sigma_p_pt(0);
705 | sigma_p_pt_mat(0, 1) = point_free_params_->sigma_p_pt(1);
706 | sigma_p_pt_mat(0, 2) = point_free_params_->sigma_p_pt(2);
707 | sigma_p_pt_mat(1, 0) = point_free_params_->sigma_p_pt(1);
708 | sigma_p_pt_mat(1, 1) = point_free_params_->sigma_p_pt(3);
709 | sigma_p_pt_mat(1, 2) = point_free_params_->sigma_p_pt(4);
710 | sigma_p_pt_mat(2, 0) = point_free_params_->sigma_p_pt(2);
711 | sigma_p_pt_mat(2, 1) = point_free_params_->sigma_p_pt(4);
712 | sigma_p_pt_mat(2, 2) = point_free_params_->sigma_p_pt(5);
713 | plane->points_size = point_free_params_->point_nums;
714 | plane->center = point_free_params_->sigma_p / plane->points_size;
715 | plane->covariance = sigma_p_pt_mat / plane->points_size -
716 | plane->center * plane->center.transpose();
717 | }
718 |
719 | Eigen::EigenSolver es(plane->covariance);
720 | Eigen::Matrix3cd evecs = es.eigenvectors();
721 | Eigen::Vector3cd evals = es.eigenvalues();
722 | Eigen::Vector3d evalsReal;
723 | evalsReal = evals.real();
724 | Eigen::Matrix3d::Index evalsMin, evalsMax;
725 | evalsReal.rowwise().sum().minCoeff(&evalsMin);
726 | evalsReal.rowwise().sum().maxCoeff(&evalsMax);
727 | int evalsMid = 3 - evalsMin - evalsMax;
728 | Eigen::Vector3d evecMin = evecs.real().col(evalsMin);
729 | Eigen::Vector3d evecMid = evecs.real().col(evalsMid);
730 | Eigen::Vector3d evecMax = evecs.real().col(evalsMax);
731 | // plane covariance calculation
732 | Eigen::Matrix3d J_Q;
733 | J_Q << 1.0 / plane->points_size, 0, 0, 0, 1.0 / plane->points_size, 0, 0, 0,
734 | 1.0 / plane->points_size;
735 |
736 | if (evalsReal(evalsMin) < planer_threshold_) {
737 | if (!init_octo_) {
738 | point_free_params_ = new PointFreeParams();
739 | point_free_params_->Initialize();
740 | for (const auto& pv : temp_points_) {
741 | UpdatePointFreeParams(pv);
742 | }
743 | }
744 | std::vector B(3);
745 | // Jacobian of the normal of plane w.r.t the world point
746 | auto J_n_pw = evecs.real();
747 | std::vector F_aux(3);
748 | for (int m = 0; m < 3; m++) {
749 | if (m != (int) evalsMin) {
750 | B[m] = (evecs.real().col(m) * evecs.real().col(evalsMin).transpose() +
751 | evecs.real().col(evalsMin) * evecs.real().col(m).transpose()) /
752 | (plane->points_size * (evalsReal[evalsMin] - evalsReal[m]));
753 | } else {
754 | B[m].setZero();
755 | }
756 | }
757 | CalculatePointFreeVoxelPlaneCovariance(plane->plane_cov,
758 | plane->center,
759 | B,
760 | J_n_pw,
761 | (int) evalsMin);
762 |
763 | plane->normal << evecs.real()(0, evalsMin), evecs.real()(1, evalsMin),
764 | evecs.real()(2, evalsMin);
765 | plane->y_normal << evecs.real()(0, evalsMid), evecs.real()(1, evalsMid),
766 | evecs.real()(2, evalsMid);
767 | plane->x_normal << evecs.real()(0, evalsMax), evecs.real()(1, evalsMax),
768 | evecs.real()(2, evalsMax);
769 | plane->min_eigen_value = evalsReal(evalsMin);
770 | plane->mid_eigen_value = evalsReal(evalsMid);
771 | plane->max_eigen_value = evalsReal(evalsMax);
772 | plane->radius = sqrt(evalsReal(evalsMax));
773 | plane->d = -(plane->normal(0) * plane->center(0) + plane->normal(1) * plane->center(1) +
774 | plane->normal(2) * plane->center(2));
775 |
776 | plane->is_plane = true;
777 | if (plane->last_update_points_size == 0) {
778 | plane->last_update_points_size = plane->points_size;
779 | plane->is_update = true;
780 | } else if (plane->points_size - plane->last_update_points_size > 100) {
781 | plane->last_update_points_size = plane->points_size;
782 | plane->is_update = true;
783 | }
784 |
785 | if (!plane->is_init) {
786 | plane->id = plane_id;
787 | plane_id++;
788 | plane->is_init = true;
789 | }
790 | } else {
791 | if (!plane->is_init) {
792 | plane->id = plane_id;
793 | plane_id++;
794 | plane->is_init = true;
795 | }
796 | if (plane->last_update_points_size == 0) {
797 | plane->last_update_points_size = plane->points_size;
798 | plane->is_update = true;
799 | } else if (plane->points_size - plane->last_update_points_size > 100) {
800 | plane->last_update_points_size = plane->points_size;
801 | plane->is_update = true;
802 | }
803 | plane->is_plane = false;
804 | plane->normal << evecs.real()(0, evalsMin), evecs.real()(1, evalsMin),
805 | evecs.real()(2, evalsMin);
806 | plane->y_normal << evecs.real()(0, evalsMid), evecs.real()(1, evalsMid),
807 | evecs.real()(2, evalsMid);
808 | plane->x_normal << evecs.real()(0, evalsMax), evecs.real()(1, evalsMax),
809 | evecs.real()(2, evalsMax);
810 | plane->min_eigen_value = evalsReal(evalsMin);
811 | plane->mid_eigen_value = evalsReal(evalsMid);
812 | plane->max_eigen_value = evalsReal(evalsMax);
813 | plane->radius = sqrt(evalsReal(evalsMax));
814 | plane->d = -(plane->normal(0) * plane->center(0) + plane->normal(1) * plane->center(1) +
815 | plane->normal(2) * plane->center(2));
816 | }
817 | }
818 |
819 | void UpdatePlaneCov() {
820 | plane_ptr_->plane_cov = Eigen::Matrix::Zero();
821 | plane_ptr_->covariance = Eigen::Matrix3d::Zero();
822 | plane_ptr_->center = Eigen::Vector3d::Zero();
823 | plane_ptr_->normal = Eigen::Vector3d::Zero();
824 | plane_ptr_->radius = 0;
825 |
826 | Eigen::Matrix3d sigma_p_pt_mat;
827 | sigma_p_pt_mat(0, 0) = point_free_params_->sigma_p_pt(0);
828 | sigma_p_pt_mat(0, 1) = point_free_params_->sigma_p_pt(1);
829 | sigma_p_pt_mat(0, 2) = point_free_params_->sigma_p_pt(2);
830 | sigma_p_pt_mat(1, 0) = point_free_params_->sigma_p_pt(1);
831 | sigma_p_pt_mat(1, 1) = point_free_params_->sigma_p_pt(3);
832 | sigma_p_pt_mat(1, 2) = point_free_params_->sigma_p_pt(4);
833 | sigma_p_pt_mat(2, 0) = point_free_params_->sigma_p_pt(2);
834 | sigma_p_pt_mat(2, 1) = point_free_params_->sigma_p_pt(4);
835 | sigma_p_pt_mat(2, 2) = point_free_params_->sigma_p_pt(5);
836 | plane_ptr_->points_size = point_free_params_->point_nums;
837 | plane_ptr_->center = point_free_params_->sigma_p / plane_ptr_->points_size;
838 | plane_ptr_->covariance = sigma_p_pt_mat / plane_ptr_->points_size -
839 | plane_ptr_->center * plane_ptr_->center.transpose();
840 |
841 | Eigen::EigenSolver es(plane_ptr_->covariance);
842 | Eigen::Matrix3cd evecs = es.eigenvectors();
843 | Eigen::Vector3cd evals = es.eigenvalues();
844 | Eigen::Vector3d evalsReal;
845 | evalsReal = evals.real();
846 | Eigen::Matrix3d::Index evalsMin, evalsMax;
847 | evalsReal.rowwise().sum().minCoeff(&evalsMin);
848 | evalsReal.rowwise().sum().maxCoeff(&evalsMax);
849 | int evalsMid = 3 - evalsMin - evalsMax;
850 | Eigen::Vector3d evecMin = evecs.real().col(evalsMin);
851 | Eigen::Vector3d evecMid = evecs.real().col(evalsMid);
852 | Eigen::Vector3d evecMax = evecs.real().col(evalsMax);
853 | // plane covariance calculation
854 | Eigen::Matrix3d J_Q;
855 | J_Q << 1.0 / plane_ptr_->points_size, 0, 0, 0, 1.0 / plane_ptr_->points_size, 0, 0, 0,
856 | 1.0 / plane_ptr_->points_size;
857 |
858 | std::vector B(3);
859 | // Jacobian of the normal of plane w.r.t the world point
860 | auto J_n_pw = evecs.real();
861 | std::vector F_aux(3);
862 | for (int m = 0; m < 3; m++) {
863 | if (m != (int) evalsMin) {
864 | B[m] = (evecs.real().col(m) * evecs.real().col(evalsMin).transpose() +
865 | evecs.real().col(evalsMin) * evecs.real().col(m).transpose()) /
866 | (plane_ptr_->points_size * (evalsReal[evalsMin] - evalsReal[m]));
867 | } else {
868 | B[m].setZero();
869 | }
870 | }
871 | CalculatePointFreeVoxelPlaneCovariance(plane_ptr_->plane_cov,
872 | plane_ptr_->center,
873 | B,
874 | J_n_pw,
875 | (int) evalsMin);
876 |
877 | plane_ptr_->normal << evecs.real()(0, evalsMin), evecs.real()(1, evalsMin),
878 | evecs.real()(2, evalsMin);
879 | plane_ptr_->y_normal << evecs.real()(0, evalsMid), evecs.real()(1, evalsMid),
880 | evecs.real()(2, evalsMid);
881 | plane_ptr_->x_normal << evecs.real()(0, evalsMax), evecs.real()(1, evalsMax),
882 | evecs.real()(2, evalsMax);
883 | plane_ptr_->min_eigen_value = evalsReal(evalsMin);
884 | plane_ptr_->mid_eigen_value = evalsReal(evalsMid);
885 | plane_ptr_->max_eigen_value = evalsReal(evalsMax);
886 | plane_ptr_->radius = sqrt(evalsReal(evalsMax));
887 | plane_ptr_->d = -(plane_ptr_->normal(0) * plane_ptr_->center(0) +
888 | plane_ptr_->normal(1) * plane_ptr_->center(1) +
889 | plane_ptr_->normal(2) * plane_ptr_->center(2));
890 |
891 | plane_ptr_->is_plane = true;
892 | if (plane_ptr_->last_update_points_size == 0) {
893 | plane_ptr_->last_update_points_size = plane_ptr_->points_size;
894 | plane_ptr_->is_update = true;
895 | } else if (plane_ptr_->points_size - plane_ptr_->last_update_points_size > 100) {
896 | plane_ptr_->last_update_points_size = plane_ptr_->points_size;
897 | plane_ptr_->is_update = true;
898 | }
899 | }
900 |
901 | void init_octo_tree(std::vector& leaf_path, const VOXEL_LOC& voxel_loc) {
902 | if (temp_points_.size() > max_plane_update_threshold_) {
903 | init_plane(temp_points_, plane_ptr_);
904 | if (plane_ptr_->is_plane == true) {
905 | octo_state_ = 0;
906 | } else {
907 | if (layer_ < max_layer_) {
908 | octo_state_ = 1;
909 | cut_octo_tree(leaf_path, voxel_loc);
910 | } else {
911 | point_free_params_ = new PointFreeParams();
912 | point_free_params_->Initialize();
913 | for (const auto& pv : temp_points_) {
914 | UpdatePointFreeParams(pv);
915 | }
916 | }
917 | }
918 | std::vector().swap(temp_points_);
919 | init_octo_ = true;
920 | }
921 | }
922 |
923 | void cut_octo_tree(std::vector& leaf_path, const VOXEL_LOC& voxel_loc) {
924 | if (layer_ == max_layer_) {
925 | octo_state_ = 0;
926 | return;
927 | }
928 | for (size_t i = 0; i < temp_points_.size(); i++) {
929 | int xyz[3] = {0, 0, 0};
930 | if (temp_points_[i].point[0] > voxel_center_[0]) {
931 | xyz[0] = 1;
932 | }
933 | if (temp_points_[i].point[1] > voxel_center_[1]) {
934 | xyz[1] = 1;
935 | }
936 | if (temp_points_[i].point[2] > voxel_center_[2]) {
937 | xyz[2] = 1;
938 | }
939 | int leafnum = 4 * xyz[0] + 2 * xyz[1] + xyz[2];
940 | if (leaves_[leafnum] == nullptr) {
941 | leaves_[leafnum] = new OctoTree(max_layer_,
942 | layer_ + 1,
943 | layer_point_size_,
944 | planer_threshold_);
945 | voxel_nums++;
946 | leaves_[leafnum]->voxel_center_[0] = voxel_center_[0] + (2 * xyz[0] - 1) * quater_length_;
947 | leaves_[leafnum]->voxel_center_[1] = voxel_center_[1] + (2 * xyz[1] - 1) * quater_length_;
948 | leaves_[leafnum]->voxel_center_[2] = voxel_center_[2] + (2 * xyz[2] - 1) * quater_length_;
949 | leaves_[leafnum]->quater_length_ = quater_length_ / 2;
950 | leaf_path.push_back(leafnum);
951 | std::bitset<32> leaf_id;
952 | leaf_id.reset();
953 | for (size_t i = 0; i < leaf_path.size(); i++) {
954 | size_t bit_idx = 4 * i + 1;
955 | if (i == leaf_path.size() - 1) {
956 | leaf_id[bit_idx] = 1;
957 | }
958 | size_t leaf_idx = leaf_path[i];
959 | leaf_id[bit_idx + 1] = leaf_idx & 1;
960 | leaf_id[bit_idx + 2] = (leaf_idx >> 1) & 1;
961 | leaf_id[bit_idx + 3] = (leaf_idx >> 2) & 1;
962 | }
963 | leaf_path.pop_back();
964 | }
965 | leaves_[leafnum]->temp_points_.push_back(temp_points_[i]);
966 | }
967 | for (size_t leafnum = 0; leafnum < 8; ++leafnum) {
968 | if (leaves_[leafnum]) {
969 | if (leaves_[leafnum]->temp_points_.size() > leaves_[leafnum]->max_plane_update_threshold_) {
970 | leaf_path.push_back(leafnum);
971 | leaves_[leafnum]->init_octo_tree(leaf_path, voxel_loc);
972 | leaf_path.pop_back();
973 | }
974 | }
975 | }
976 | }
977 |
978 | void UpdateOctoTree(bool& plane_is_update,
979 | std::vector& plane_leaf_path,
980 | bool& node_need_split,
981 | const pointWithCov& pv,
982 | std::vector& leaf_path,
983 | const VOXEL_LOC& voxel_loc,
984 | uint32_t frame_num) {
985 | last_update_frame_ = frame_num;
986 | if (!init_octo_) {
987 | point_cluster_.Push(pv.point);
988 | temp_points_.push_back(pv);
989 | if (temp_points_.size() > max_plane_update_threshold_) {
990 | init_octo_tree(leaf_path, voxel_loc);
991 | }
992 | } else {
993 | if (plane_ptr_->is_plane) {
994 | point_cluster_.Push(pv.point);
995 | if (plane_ptr_->merge_plane_id >= 0) {
996 | node_need_split = UpdateMergedPlanePointFreeParams(pv);
997 | UpdatePlaneCov();
998 | } else {
999 | UpdatePointFreeParams(pv);
1000 | init_plane(temp_points_, plane_ptr_);
1001 | if (plane_ptr_->is_plane) {
1002 | plane_is_update = true;
1003 | }
1004 | }
1005 | } else {
1006 | if (layer_ < max_layer_) {
1007 | if (temp_points_.size() != 0) {
1008 | std::vector().swap(temp_points_);
1009 | }
1010 | if (new_points_.size() != 0) {
1011 | std::vector().swap(new_points_);
1012 | }
1013 | int xyz[3] = {0, 0, 0};
1014 | if (pv.point[0] > voxel_center_[0]) {
1015 | xyz[0] = 1;
1016 | }
1017 | if (pv.point[1] > voxel_center_[1]) {
1018 | xyz[1] = 1;
1019 | }
1020 | if (pv.point[2] > voxel_center_[2]) {
1021 | xyz[2] = 1;
1022 | }
1023 | int leafnum = 4 * xyz[0] + 2 * xyz[1] + xyz[2];
1024 |
1025 | leaf_path.push_back(leafnum);
1026 | if (leaves_[leafnum] != nullptr) {
1027 | plane_leaf_path.push_back(leafnum);
1028 | leaves_[leafnum]->UpdateOctoTree(plane_is_update,
1029 | plane_leaf_path,
1030 | node_need_split,
1031 | pv,
1032 | leaf_path,
1033 | voxel_loc,
1034 | frame_num);
1035 | } else {
1036 | leaves_[leafnum] = new OctoTree(max_layer_,
1037 | layer_ + 1,
1038 | layer_point_size_,
1039 | planer_threshold_);
1040 | voxel_nums++;
1041 | leaves_[leafnum]->layer_point_size_ = layer_point_size_;
1042 | leaves_[leafnum]->voxel_center_[0] = voxel_center_[0] +
1043 | (2 * xyz[0] - 1) * quater_length_;
1044 | leaves_[leafnum]->voxel_center_[1] = voxel_center_[1] +
1045 | (2 * xyz[1] - 1) * quater_length_;
1046 | leaves_[leafnum]->voxel_center_[2] = voxel_center_[2] +
1047 | (2 * xyz[2] - 1) * quater_length_;
1048 | leaves_[leafnum]->quater_length_ = quater_length_ / 2;
1049 |
1050 | std::bitset<32> leaf_id;
1051 | leaf_id.reset();
1052 | for (size_t i = 0; i < leaf_path.size(); i++) {
1053 | size_t bit_idx = 4 * i + 1;
1054 | if (i == leaf_path.size() - 1) {
1055 | leaf_id[bit_idx] = 1;
1056 | }
1057 | size_t leaf_idx = leaf_path[i];
1058 | leaf_id[bit_idx + 1] = leaf_idx & 1;
1059 | leaf_id[bit_idx + 2] = (leaf_idx >> 1) & 1;
1060 | leaf_id[bit_idx + 3] = (leaf_idx >> 2) & 1;
1061 | }
1062 |
1063 | plane_leaf_path.push_back(leafnum);
1064 | leaves_[leafnum]->UpdateOctoTree(plane_is_update,
1065 | plane_leaf_path,
1066 | node_need_split,
1067 | pv,
1068 | leaf_path,
1069 | voxel_loc,
1070 | frame_num);
1071 | }
1072 | leaf_path.pop_back();
1073 | } else {
1074 | point_cluster_.Push(pv.point);
1075 | UpdatePointFreeParams(pv);
1076 | init_plane(temp_points_, plane_ptr_);
1077 | }
1078 | }
1079 | }
1080 | }
1081 |
1082 | void MergeNode(OctoTree* merged_node, int64_t leaf_num, bool need_delete) {
1083 | int64_t leaf_layer_num = leaf_num / 10;
1084 | int64_t leaf_idx = leaf_num % 10 - 1;
1085 |
1086 | if (leaf_layer_num == 0) {
1087 | if (need_delete) {
1088 | merged_voxel_nums++;
1089 | merged_voxel_nums += leaves_[leaf_idx]->GetLeafNums();
1090 | delete leaves_[leaf_idx];
1091 | }
1092 | leaves_[leaf_idx] = merged_node;
1093 | return;
1094 | } else {
1095 | leaves_[leaf_idx]->MergeNode(merged_node, leaf_layer_num, need_delete);
1096 | }
1097 | }
1098 |
1099 | void SplitMergedNode(std::vector& leaf_path,
1100 | const VOXEL_LOC& voxel_loc,
1101 | const pointWithCov& pv,
1102 | uint32_t frame_num,
1103 | int64_t leaf_num,
1104 | int layer) {
1105 | int64_t leaf_layer_num = leaf_num / 10;
1106 | int64_t leaf_idx = leaf_num % 10 - 1;
1107 |
1108 | int xyz[3] = {0, 0, 0};
1109 | if (pv.point[0] > voxel_center_[0]) {
1110 | xyz[0] = 1;
1111 | }
1112 | if (pv.point[1] > voxel_center_[1]) {
1113 | xyz[1] = 1;
1114 | }
1115 | if (pv.point[2] > voxel_center_[2]) {
1116 | xyz[2] = 1;
1117 | }
1118 | int leafnum = 4 * xyz[0] + 2 * xyz[1] + xyz[2];
1119 |
1120 | if (leaf_layer_num == 0) {
1121 | OctoTree* node = new OctoTree(leaves_[leaf_idx]->max_layer_,
1122 | layer,
1123 | leaves_[leaf_idx]->layer_point_size_,
1124 | leaves_[leaf_idx]->planer_threshold_);
1125 | voxel_nums++;
1126 | leaves_[leaf_idx] = node;
1127 |
1128 | leaves_[leaf_idx]->voxel_center_[0] = voxel_center_[0] + (2 * xyz[0] - 1) * quater_length_;
1129 | leaves_[leaf_idx]->voxel_center_[1] = voxel_center_[1] + (2 * xyz[1] - 1) * quater_length_;
1130 | leaves_[leaf_idx]->voxel_center_[2] = voxel_center_[2] + (2 * xyz[2] - 1) * quater_length_;
1131 | leaves_[leaf_idx]->quater_length_ = quater_length_ / 2;
1132 |
1133 | leaves_[leaf_idx]->last_update_frame_ = frame_num;
1134 | leaves_[leaf_idx]->temp_points_.push_back(pv);
1135 | leaves_[leaf_idx]->point_cluster_.Push(pv.point);
1136 |
1137 | leaf_path.push_back(leaf_idx);
1138 | std::bitset<32> leaf_id;
1139 | leaf_id.reset();
1140 | for (size_t i = 0; i < leaf_path.size(); i++) {
1141 | size_t bit_idx = 4 * i + 1;
1142 | if (i == leaf_path.size() - 1) {
1143 | leaf_id[bit_idx] = 1;
1144 | }
1145 | size_t leaf_idx = leaf_path[i];
1146 | leaf_id[bit_idx + 1] = leaf_idx & 1;
1147 | leaf_id[bit_idx + 2] = (leaf_idx >> 1) & 1;
1148 | leaf_id[bit_idx + 3] = (leaf_idx >> 2) & 1;
1149 | }
1150 | return;
1151 | } else {
1152 | leaf_path.push_back(leaf_idx);
1153 | leaves_[leaf_idx]
1154 | ->SplitMergedNode(leaf_path, voxel_loc, pv, frame_num, leaf_layer_num, layer + 1);
1155 | }
1156 | }
1157 | };
1158 |
1159 | void mapJet(double v, double vmin, double vmax, uint8_t& r, uint8_t& g, uint8_t& b) {
1160 | r = 255;
1161 | g = 255;
1162 | b = 255;
1163 |
1164 | if (v < vmin) {
1165 | v = vmin;
1166 | }
1167 |
1168 | if (v > vmax) {
1169 | v = vmax;
1170 | }
1171 |
1172 | double dr, dg, db;
1173 |
1174 | if (v < 0.1242) {
1175 | db = 0.504 + ((1. - 0.504) / 0.1242) * v;
1176 | dg = dr = 0.;
1177 | } else if (v < 0.3747) {
1178 | db = 1.;
1179 | dr = 0.;
1180 | dg = (v - 0.1242) * (1. / (0.3747 - 0.1242));
1181 | } else if (v < 0.6253) {
1182 | db = (0.6253 - v) * (1. / (0.6253 - 0.3747));
1183 | dg = 1.;
1184 | dr = (v - 0.3747) * (1. / (0.6253 - 0.3747));
1185 | } else if (v < 0.8758) {
1186 | db = 0.;
1187 | dr = 1.;
1188 | dg = (0.8758 - v) * (1. / (0.8758 - 0.6253));
1189 | } else {
1190 | db = 0.;
1191 | dg = 0.;
1192 | dr = 1. - (v - 0.8758) * ((1. - 0.504) / (1. - 0.8758));
1193 | }
1194 |
1195 | r = (uint8_t)(255 * dr);
1196 | g = (uint8_t)(255 * dg);
1197 | b = (uint8_t)(255 * db);
1198 | }
1199 |
1200 | bool CheckIfMerge(std::pair& target_plane_coeff,
1201 | PointCluster& target_cluster,
1202 | const Plane* const candidate,
1203 | const PointCluster& candidate_cluster,
1204 | double merge_theta_thresh,
1205 | double merge_dist_thresh,
1206 | double merge_cov_min_eigen_val_thresh,
1207 | double merge_x_coord_diff_thresh,
1208 | double merge_y_coord_diff_thresh) {
1209 | double length = (target_plane_coeff.second - candidate->center).norm();
1210 | double dist = length * (target_plane_coeff.second - candidate->center)
1211 | .normalized()
1212 | .dot(target_plane_coeff.first);
1213 |
1214 | const auto& candidate_normal = candidate->normal;
1215 | if (std::abs(target_plane_coeff.first.normalized().dot(candidate_normal.normalized())) <
1216 | std::cos(merge_theta_thresh)) {
1217 | return false;
1218 | }
1219 |
1220 | if (std::abs(dist) > merge_dist_thresh) {
1221 | return false;
1222 | }
1223 |
1224 | PointCluster plane_merged = target_cluster + candidate_cluster;
1225 |
1226 | Eigen::SelfAdjointEigenSolver solver(plane_merged.Cov());
1227 |
1228 | if (solver.eigenvalues()[0] < merge_cov_min_eigen_val_thresh && solver.eigenvalues()[0] > 0) {
1229 | target_cluster = plane_merged;
1230 |
1231 | target_plane_coeff.first = solver.eigenvectors().col(0);
1232 | target_plane_coeff.second = target_cluster.v / target_cluster.N;
1233 |
1234 | return true;
1235 | }
1236 |
1237 | return false;
1238 | }
1239 |
1240 | OctoTree* GetVoxelPlaneNodeRecursive(OctoTree* current_node, int64_t leaf_num) {
1241 | int64_t leaf_layer_num = leaf_num / 10;
1242 | int64_t leaf_idx = leaf_num % 10 - 1;
1243 |
1244 | if (leaf_layer_num == 0) {
1245 | return current_node->leaves_[leaf_idx];
1246 | }
1247 |
1248 | return GetVoxelPlaneNodeRecursive(current_node->leaves_[leaf_idx], leaf_layer_num);
1249 | }
1250 |
1251 | OctoTree* GetVoxelPlaneNode(std::unordered_map& feat_map,
1252 | const NodeLoc& node_loc) {
1253 | VOXEL_LOC voxel_loc(node_loc.x, node_loc.y, node_loc.z);
1254 |
1255 | if (node_loc.leaf_num == 0) {
1256 | return feat_map[voxel_loc];
1257 | } else {
1258 | return GetVoxelPlaneNodeRecursive(feat_map[voxel_loc], node_loc.leaf_num);
1259 | }
1260 | }
1261 |
1262 | void MergeVoxelPlaneNode(OctoTree* root_node,
1263 | std::unordered_map& feat_map,
1264 | const NodeLoc& node_loc,
1265 | bool need_delete) {
1266 | VOXEL_LOC voxel_loc(node_loc.x, node_loc.y, node_loc.z);
1267 |
1268 | if (node_loc.leaf_num == 0) {
1269 | if (need_delete) {
1270 | merged_voxel_nums++;
1271 | merged_voxel_nums += feat_map[voxel_loc]->GetLeafNums();
1272 | delete feat_map[voxel_loc];
1273 | }
1274 | feat_map[voxel_loc] = root_node;
1275 | } else {
1276 | feat_map[voxel_loc]->MergeNode(root_node, node_loc.leaf_num, need_delete);
1277 | }
1278 | }
1279 |
1280 | void UpdatePlaneHashMap(std::unordered_map& feat_map,
1281 | std::unordered_map& plane_map,
1282 | std::unordered_map>& merged_table,
1283 | const VOXEL_LOC& voxel_loc,
1284 | const std::vector& leaf_path,
1285 | double merge_theta_thresh,
1286 | double merge_dist_thresh,
1287 | double merge_cov_min_eigen_val_thresh,
1288 | double merge_x_coord_diff_thresh,
1289 | double merge_y_coord_diff_thresh) {
1290 | std::unordered_map unique_node_table;
1291 |
1292 | NodeLoc node_loc(voxel_loc, leaf_path);
1293 |
1294 | const OctoTree* const current_node = GetVoxelPlaneNode(feat_map, node_loc);
1295 |
1296 | if (!current_node->plane_ptr_->is_plane) {
1297 | return;
1298 | }
1299 |
1300 | PlaneDesc plane_loc(current_node->plane_ptr_,
1301 | merge_x_coord_diff_thresh,
1302 | merge_y_coord_diff_thresh);
1303 | auto plane_loc_it = plane_map.find(plane_loc);
1304 |
1305 | if (plane_loc_it != plane_map.end()) {
1306 | auto& union_plane_bucket = plane_loc_it->second.plane_bucket;
1307 |
1308 | if (union_plane_bucket.count(node_loc) == 0) {
1309 | union_plane_bucket.insert(node_loc);
1310 |
1311 | if (union_plane_bucket.size() > 4) {
1312 | bool has_initialized = false;
1313 | {
1314 | for (const auto& plane_i : union_plane_bucket) {
1315 | if (has_initialized && plane_i == plane_loc_it->second.root_node_loc) {
1316 | continue;
1317 | }
1318 |
1319 | const OctoTree* const p1 = GetVoxelPlaneNode(feat_map, plane_i);
1320 | if (!p1 || !p1->plane_ptr_->is_plane) {
1321 | continue;
1322 | }
1323 |
1324 | if (!has_initialized) {
1325 | plane_loc_it->second.root_node_loc = plane_i;
1326 | has_initialized = true;
1327 | continue;
1328 | }
1329 |
1330 | const OctoTree* const p2 = GetVoxelPlaneNode(feat_map,
1331 | plane_loc_it->second.root_node_loc);
1332 |
1333 | if (!p2 || p1->point_cluster_.N > p2->point_cluster_.N) {
1334 | plane_loc_it->second.root_node_loc = plane_i;
1335 | }
1336 | }
1337 | }
1338 |
1339 | if (!has_initialized) {
1340 | return;
1341 | }
1342 |
1343 | const auto& root_node_loc = plane_loc_it->second.root_node_loc;
1344 |
1345 | OctoTree* root_plane_content = GetVoxelPlaneNode(feat_map, root_node_loc);
1346 |
1347 | if (!root_plane_content) {
1348 | return;
1349 | }
1350 |
1351 | PointCluster merged_plane = root_plane_content->point_cluster_;
1352 | std::pair merged_plane_coeff = std::make_pair(
1353 | root_plane_content->plane_ptr_->normal,
1354 | root_plane_content->plane_ptr_->center);
1355 |
1356 | for (auto vit = union_plane_bucket.begin(); vit != union_plane_bucket.end(); ++vit) {
1357 | const auto& node_loc_cur = *vit;
1358 |
1359 | if (node_loc_cur == root_node_loc) {
1360 | continue;
1361 | }
1362 |
1363 | int node_cur_merged_id = -1;
1364 | {
1365 | OctoTree* voxel_plane_cur = GetVoxelPlaneNode(feat_map, node_loc_cur);
1366 | if (!voxel_plane_cur || !voxel_plane_cur->plane_ptr_->is_plane ||
1367 | voxel_plane_cur == root_plane_content) {
1368 | continue;
1369 | }
1370 |
1371 | if (!CheckIfMerge(merged_plane_coeff,
1372 | merged_plane,
1373 | voxel_plane_cur->plane_ptr_,
1374 | voxel_plane_cur->point_cluster_,
1375 | merge_theta_thresh,
1376 | merge_dist_thresh,
1377 | merge_cov_min_eigen_val_thresh,
1378 | merge_x_coord_diff_thresh,
1379 | merge_y_coord_diff_thresh)) {
1380 | continue;
1381 | }
1382 |
1383 | if (root_plane_content->plane_ptr_->merge_plane_id < 0) {
1384 | root_plane_content->plane_ptr_->merge_plane_id = merged_plane_idx;
1385 | merged_plane_idx++;
1386 | }
1387 |
1388 | node_cur_merged_id = voxel_plane_cur->plane_ptr_->merge_plane_id;
1389 |
1390 | root_plane_content->MergeVoxelPlane(voxel_plane_cur);
1391 | }
1392 |
1393 | merged_table[root_plane_content->plane_ptr_->merge_plane_id].insert(root_node_loc);
1394 | merged_table[root_plane_content->plane_ptr_->merge_plane_id].insert(node_loc_cur);
1395 |
1396 | if (node_cur_merged_id >= 0) {
1397 | auto& nodes_with_id = merged_table[node_cur_merged_id];
1398 | for (const auto& node_loc : nodes_with_id) {
1399 | MergeVoxelPlaneNode(root_plane_content, feat_map, node_loc, node_loc == node_loc_cur);
1400 |
1401 | merged_table[root_plane_content->plane_ptr_->merge_plane_id].insert(node_loc);
1402 | }
1403 | std::unordered_set().swap(nodes_with_id);
1404 | merged_table.erase(node_cur_merged_id);
1405 | } else {
1406 | MergeVoxelPlaneNode(root_plane_content, feat_map, node_loc_cur, true);
1407 | }
1408 | }
1409 |
1410 | std::unordered_set().swap(union_plane_bucket);
1411 | plane_map.erase(plane_loc_it);
1412 |
1413 | PlaneDesc root_plane_loc(root_plane_content->plane_ptr_,
1414 | merge_x_coord_diff_thresh,
1415 | merge_y_coord_diff_thresh);
1416 | auto root_plane_loc_it = plane_map.find(root_plane_loc);
1417 | if (root_plane_loc_it != plane_map.end()) {
1418 | root_plane_loc_it->second.plane_bucket.insert(root_node_loc);
1419 | } else {
1420 | UnionPlane union_plane;
1421 | union_plane.plane_bucket.insert(root_node_loc);
1422 | union_plane.root_node_loc = root_node_loc;
1423 | plane_map[root_plane_loc] = union_plane;
1424 | }
1425 | }
1426 | }
1427 | } else {
1428 | UnionPlane union_plane;
1429 | union_plane.plane_bucket.insert(node_loc);
1430 | union_plane.root_node_loc = node_loc;
1431 | plane_map[plane_loc] = union_plane;
1432 | }
1433 | }
1434 |
1435 | void buildVoxelMap(bool enable_voxel_merging,
1436 | const std::vector& input_points,
1437 | const float voxel_size,
1438 | const int max_layer,
1439 | const std::vector& layer_point_size,
1440 | const float planer_threshold,
1441 | std::unordered_map& feat_map,
1442 | std::unordered_map& plane_map,
1443 | std::unordered_map>& merged_table,
1444 | double merge_theta_thresh,
1445 | double merge_dist_thresh,
1446 | double merge_cov_min_eigen_val_thresh,
1447 | double merge_x_coord_diff_thresh,
1448 | double merge_y_coord_diff_thresh) {
1449 | uint plsize = input_points.size();
1450 | for (uint i = 0; i < plsize; i++) {
1451 | const pointWithCov& p_v = input_points[i];
1452 | float loc_xyz[3];
1453 | for (int j = 0; j < 3; j++) {
1454 | loc_xyz[j] = p_v.point[j] / voxel_size;
1455 | if (loc_xyz[j] < 0) {
1456 | loc_xyz[j] -= 1.0;
1457 | }
1458 | }
1459 | VOXEL_LOC position((int64_t) loc_xyz[0], (int64_t) loc_xyz[1], (int64_t) loc_xyz[2]);
1460 | auto iter = feat_map.find(position);
1461 | if (iter != feat_map.end()) {
1462 | feat_map[position]->temp_points_.push_back(p_v);
1463 |
1464 | feat_map[position]->point_cluster_.Push(p_v.point);
1465 | } else {
1466 | OctoTree* octo_tree = new OctoTree(max_layer, 0, layer_point_size, planer_threshold);
1467 | voxel_nums++;
1468 | feat_map[position] = octo_tree;
1469 | feat_map[position]->quater_length_ = voxel_size / 4;
1470 | feat_map[position]->voxel_center_[0] = (0.5 + position.x) * voxel_size;
1471 | feat_map[position]->voxel_center_[1] = (0.5 + position.y) * voxel_size;
1472 | feat_map[position]->voxel_center_[2] = (0.5 + position.z) * voxel_size;
1473 | feat_map[position]->temp_points_.push_back(p_v);
1474 | feat_map[position]->layer_point_size_ = layer_point_size;
1475 | std::bitset<32> leaf_id;
1476 | leaf_id.reset();
1477 | leaf_id[0] = 1;
1478 | feat_map[position]->point_cluster_.Push(p_v.point);
1479 | }
1480 | }
1481 | for (auto iter = feat_map.begin(); iter != feat_map.end(); ++iter) {
1482 | std::vector leaf_path;
1483 | iter->second->init_octo_tree(leaf_path, iter->first);
1484 |
1485 | if (enable_voxel_merging && iter->second->plane_ptr_->is_plane) {
1486 | UpdatePlaneHashMap(feat_map,
1487 | plane_map,
1488 | merged_table,
1489 | iter->first,
1490 | std::vector(),
1491 | merge_theta_thresh,
1492 | merge_dist_thresh,
1493 | merge_cov_min_eigen_val_thresh,
1494 | merge_x_coord_diff_thresh,
1495 | merge_y_coord_diff_thresh);
1496 | }
1497 | }
1498 | }
1499 |
1500 | void updateVoxelMap(bool enable_voxel_merging,
1501 | const std::vector& input_points,
1502 | const float voxel_size,
1503 | const int max_layer,
1504 | const std::vector& layer_point_size,
1505 | const float planer_threshold,
1506 | std::unordered_map& feat_map,
1507 | std::unordered_map& plane_map,
1508 | std::unordered_map>& merged_table,
1509 | uint32_t frame_num,
1510 | double merge_theta_thresh,
1511 | double merge_dist_thresh,
1512 | double merge_cov_min_eigen_val_thresh,
1513 | double merge_x_coord_diff_thresh,
1514 | double merge_y_coord_diff_thresh) {
1515 | uint plsize = input_points.size();
1516 |
1517 | for (uint i = 0; i < plsize; i++) {
1518 | // Check plane of voxel is update
1519 | bool plane_is_update = false;
1520 | // Node path in voxel
1521 | std::vector plane_node_loc;
1522 |
1523 | const pointWithCov p_v = input_points[i];
1524 | float loc_xyz[3];
1525 | for (int j = 0; j < 3; j++) {
1526 | loc_xyz[j] = p_v.point[j] / voxel_size;
1527 | if (loc_xyz[j] < 0) {
1528 | loc_xyz[j] -= 1.0;
1529 | }
1530 | }
1531 | VOXEL_LOC position((int64_t) loc_xyz[0], (int64_t) loc_xyz[1], (int64_t) loc_xyz[2]);
1532 |
1533 | bool node_need_split = false;
1534 | auto iter = feat_map.find(position);
1535 | if (iter != feat_map.end()) {
1536 | std::vector leaf_path;
1537 | feat_map[position]->UpdateOctoTree(plane_is_update,
1538 | plane_node_loc,
1539 | node_need_split,
1540 | p_v,
1541 | leaf_path,
1542 | position,
1543 | frame_num);
1544 | } else {
1545 | OctoTree* octo_tree = new OctoTree(max_layer, 0, layer_point_size, planer_threshold);
1546 | voxel_nums++;
1547 | feat_map[position] = octo_tree;
1548 | feat_map[position]->quater_length_ = voxel_size / 4;
1549 | feat_map[position]->voxel_center_[0] = (0.5 + position.x) * voxel_size;
1550 | feat_map[position]->voxel_center_[1] = (0.5 + position.y) * voxel_size;
1551 | feat_map[position]->voxel_center_[2] = (0.5 + position.z) * voxel_size;
1552 | std::bitset<32> leaf_id;
1553 | leaf_id.reset();
1554 | leaf_id[0] = 1;
1555 | std::vector leaf_path;
1556 | feat_map[position]->UpdateOctoTree(plane_is_update,
1557 | plane_node_loc,
1558 | node_need_split,
1559 | p_v,
1560 | leaf_path,
1561 | position,
1562 | frame_num);
1563 | }
1564 |
1565 | if (enable_voxel_merging) {
1566 | if (plane_is_update) {
1567 | UpdatePlaneHashMap(feat_map,
1568 | plane_map,
1569 | merged_table,
1570 | position,
1571 | plane_node_loc,
1572 | merge_theta_thresh,
1573 | merge_dist_thresh,
1574 | merge_cov_min_eigen_val_thresh,
1575 | merge_x_coord_diff_thresh,
1576 | merge_y_coord_diff_thresh);
1577 | }
1578 | }
1579 | }
1580 | }
1581 |
1582 | void transformLidar(const StatesGroup& state,
1583 | const shared_ptr& p_imu,
1584 | const PointCloudXYZI::Ptr& input_cloud,
1585 | pcl::PointCloud::Ptr& trans_cloud) {
1586 | trans_cloud->clear();
1587 | for (size_t i = 0; i < input_cloud->size(); i++) {
1588 | pcl::PointXYZINormal p_c = input_cloud->points[i];
1589 | Eigen::Vector3d p(p_c.x, p_c.y, p_c.z);
1590 | // p = p_imu->Lid_rot_to_IMU * p + p_imu->Lid_offset_to_IMU;
1591 | p = state.rot_end * p + state.pos_end;
1592 | pcl::PointXYZI pi;
1593 | pi.x = p(0);
1594 | pi.y = p(1);
1595 | pi.z = p(2);
1596 | pi.intensity = p_c.intensity;
1597 | trans_cloud->points.push_back(pi);
1598 | }
1599 | }
1600 |
1601 | void build_single_residual(const pointWithCov& pv,
1602 | const OctoTree* current_octo,
1603 | const int current_layer,
1604 | const int max_layer,
1605 | const double sigma_num,
1606 | bool& is_sucess,
1607 | double& prob,
1608 | ptpl& single_ptpl) {
1609 | double radius_k = 3;
1610 | Eigen::Vector3d p_w = pv.point_world;
1611 | if (current_octo->plane_ptr_->is_plane) {
1612 | Plane& plane = *current_octo->plane_ptr_;
1613 | Eigen::Vector3d p_world_to_center = p_w - plane.center;
1614 | double proj_x = p_world_to_center.dot(plane.x_normal);
1615 | double proj_y = p_world_to_center.dot(plane.y_normal);
1616 | float dis_to_plane = fabs(plane.normal(0) * p_w(0) + plane.normal(1) * p_w(1) +
1617 | plane.normal(2) * p_w(2) + plane.d);
1618 | float dis_to_center = (plane.center(0) - p_w(0)) * (plane.center(0) - p_w(0)) +
1619 | (plane.center(1) - p_w(1)) * (plane.center(1) - p_w(1)) +
1620 | (plane.center(2) - p_w(2)) * (plane.center(2) - p_w(2));
1621 | float range_dis = sqrt(dis_to_center - dis_to_plane * dis_to_plane);
1622 |
1623 | if (range_dis <= radius_k * plane.radius) {
1624 | Eigen::Matrix J_nq;
1625 | J_nq.block<1, 3>(0, 0) = p_w - plane.center;
1626 | J_nq.block<1, 3>(0, 3) = -plane.normal;
1627 | double sigma_l = J_nq * plane.plane_cov * J_nq.transpose();
1628 | sigma_l += plane.normal.transpose() * pv.cov * plane.normal;
1629 | if (dis_to_plane < sigma_num * sqrt(sigma_l)) {
1630 | is_sucess = true;
1631 | double this_prob = 1.0 / (sqrt(sigma_l)) *
1632 | exp(-0.5 * dis_to_plane * dis_to_plane / sigma_l);
1633 | if (this_prob > prob) {
1634 | prob = this_prob;
1635 | single_ptpl.point = pv.point;
1636 | single_ptpl.plane_cov = plane.plane_cov;
1637 | single_ptpl.normal = plane.normal;
1638 | single_ptpl.center = plane.center;
1639 | single_ptpl.d = plane.d;
1640 | single_ptpl.layer = current_layer;
1641 | }
1642 | return;
1643 | } else {
1644 | // is_sucess = false;
1645 | return;
1646 | }
1647 | } else {
1648 | // is_sucess = false;
1649 | return;
1650 | }
1651 | } else {
1652 | if (current_layer < max_layer) {
1653 | for (size_t leafnum = 0; leafnum < 8; leafnum++) {
1654 | if (current_octo->leaves_[leafnum] != nullptr) {
1655 | OctoTree* leaf_octo = current_octo->leaves_[leafnum];
1656 | build_single_residual(pv,
1657 | leaf_octo,
1658 | current_layer + 1,
1659 | max_layer,
1660 | sigma_num,
1661 | is_sucess,
1662 | prob,
1663 | single_ptpl);
1664 | }
1665 | }
1666 | return;
1667 | } else {
1668 | // is_sucess = false;
1669 | return;
1670 | }
1671 | }
1672 | }
1673 |
1674 | void GetUpdatePlane(const OctoTree* current_octo,
1675 | const int pub_max_voxel_layer,
1676 | std::vector& plane_list) {
1677 | if (current_octo->layer_ > pub_max_voxel_layer) {
1678 | return;
1679 | }
1680 | if (current_octo->plane_ptr_->is_update) {
1681 | plane_list.push_back(*current_octo->plane_ptr_);
1682 | }
1683 | if (current_octo->layer_ < current_octo->max_layer_) {
1684 | if (!current_octo->plane_ptr_->is_plane) {
1685 | for (size_t i = 0; i < 8; i++) {
1686 | if (current_octo->leaves_[i] != nullptr) {
1687 | GetUpdatePlane(current_octo->leaves_[i], pub_max_voxel_layer, plane_list);
1688 | }
1689 | }
1690 | }
1691 | }
1692 | return;
1693 | }
1694 |
1695 | // void BuildResidualListTBB(const unordered_map
1696 | // &voxel_map,
1697 | // const double voxel_size, const double sigma_num,
1698 | // const int max_layer,
1699 | // const std::vector &pv_list,
1700 | // std::vector &ptpl_list,
1701 | // std::vector &non_match) {
1702 | // std::mutex mylock;
1703 | // ptpl_list.clear();
1704 | // std::vector all_ptpl_list(pv_list.size());
1705 | // std::vector useful_ptpl(pv_list.size());
1706 | // std::vector index(pv_list.size());
1707 | // for (size_t i = 0; i < index.size(); ++i) {
1708 | // index[i] = i;
1709 | // useful_ptpl[i] = false;
1710 | // }
1711 | // std::for_each(
1712 | // std::execution::par_unseq, index.begin(), index.end(),
1713 | // [&](const size_t &i) {
1714 | // pointWithCov pv = pv_list[i];
1715 | // float loc_xyz[3];
1716 | // for (int j = 0; j < 3; j++) {
1717 | // loc_xyz[j] = pv.point_world[j] / voxel_size;
1718 | // if (loc_xyz[j] < 0) {
1719 | // loc_xyz[j] -= 1.0;
1720 | // }
1721 | // }
1722 | // VOXEL_LOC position((int64_t)loc_xyz[0], (int64_t)loc_xyz[1],
1723 | // (int64_t)loc_xyz[2]);
1724 | // auto iter = voxel_map.find(position);
1725 | // if (iter != voxel_map.end()) {
1726 | // OctoTree *current_octo = iter->second;
1727 | // ptpl single_ptpl;
1728 | // bool is_sucess = false;
1729 | // double prob = 0;
1730 | // build_single_residual(pv, current_octo, 0, max_layer, sigma_num,
1731 | // is_sucess, prob, single_ptpl);
1732 | // if (!is_sucess) {
1733 | // VOXEL_LOC near_position = position;
1734 | // if (loc_xyz[0] > (current_octo->voxel_center_[0] +
1735 | // current_octo->quater_length_)) {
1736 | // near_position.x = near_position.x + 1;
1737 | // } else if (loc_xyz[0] < (current_octo->voxel_center_[0] -
1738 | // current_octo->quater_length_)) {
1739 | // near_position.x = near_position.x - 1;
1740 | // }
1741 | // if (loc_xyz[1] > (current_octo->voxel_center_[1] +
1742 | // current_octo->quater_length_)) {
1743 | // near_position.y = near_position.y + 1;
1744 | // } else if (loc_xyz[1] < (current_octo->voxel_center_[1] -
1745 | // current_octo->quater_length_)) {
1746 | // near_position.y = near_position.y - 1;
1747 | // }
1748 | // if (loc_xyz[2] > (current_octo->voxel_center_[2] +
1749 | // current_octo->quater_length_)) {
1750 | // near_position.z = near_position.z + 1;
1751 | // } else if (loc_xyz[2] < (current_octo->voxel_center_[2] -
1752 | // current_octo->quater_length_)) {
1753 | // near_position.z = near_position.z - 1;
1754 | // }
1755 | // auto iter_near = voxel_map.find(near_position);
1756 | // if (iter_near != voxel_map.end()) {
1757 | // build_single_residual(pv, iter_near->second, 0, max_layer,
1758 | // sigma_num, is_sucess, prob, single_ptpl);
1759 | // }
1760 | // }
1761 | // if (is_sucess) {
1762 |
1763 | // mylock.lock();
1764 | // useful_ptpl[i] = true;
1765 | // all_ptpl_list[i] = single_ptpl;
1766 | // mylock.unlock();
1767 | // } else {
1768 | // mylock.lock();
1769 | // useful_ptpl[i] = false;
1770 | // mylock.unlock();
1771 | // }
1772 | // }
1773 | // });
1774 | // for (size_t i = 0; i < useful_ptpl.size(); i++) {
1775 | // if (useful_ptpl[i]) {
1776 | // ptpl_list.push_back(all_ptpl_list[i]);
1777 | // }
1778 | // }
1779 | // }
1780 |
1781 | void BuildResidualListOMP(const unordered_map& voxel_map,
1782 | const double voxel_size,
1783 | const double sigma_num,
1784 | const int max_layer,
1785 | const std::vector& pv_list,
1786 | std::vector& ptpl_list,
1787 | std::vector& non_match) {
1788 | std::mutex mylock;
1789 | ptpl_list.clear();
1790 | std::vector all_ptpl_list(pv_list.size());
1791 | std::vector useful_ptpl(pv_list.size());
1792 | std::vector index(pv_list.size());
1793 | for (size_t i = 0; i < index.size(); ++i) {
1794 | index[i] = i;
1795 | useful_ptpl[i] = false;
1796 | }
1797 | #ifdef MP_EN
1798 | omp_set_num_threads(MP_PROC_NUM);
1799 | #pragma omp parallel for
1800 | #endif
1801 | for (int i = 0; i < index.size(); i++) {
1802 | pointWithCov pv = pv_list[i];
1803 | float loc_xyz[3];
1804 | for (int j = 0; j < 3; j++) {
1805 | loc_xyz[j] = pv.point_world[j] / voxel_size;
1806 | if (loc_xyz[j] < 0) {
1807 | loc_xyz[j] -= 1.0;
1808 | }
1809 | }
1810 | VOXEL_LOC position((int64_t) loc_xyz[0], (int64_t) loc_xyz[1], (int64_t) loc_xyz[2]);
1811 | auto iter = voxel_map.find(position);
1812 | if (iter != voxel_map.end()) {
1813 | OctoTree* current_octo = iter->second;
1814 | ptpl single_ptpl;
1815 | bool is_sucess = false;
1816 | double prob = 0;
1817 | build_single_residual(pv,
1818 | current_octo,
1819 | 0,
1820 | max_layer,
1821 | sigma_num,
1822 | is_sucess,
1823 | prob,
1824 | single_ptpl);
1825 | if (!is_sucess) {
1826 | VOXEL_LOC near_position = position;
1827 | if (loc_xyz[0] > (current_octo->voxel_center_[0] + current_octo->quater_length_)) {
1828 | near_position.x = near_position.x + 1;
1829 | } else if (loc_xyz[0] < (current_octo->voxel_center_[0] - current_octo->quater_length_)) {
1830 | near_position.x = near_position.x - 1;
1831 | }
1832 | if (loc_xyz[1] > (current_octo->voxel_center_[1] + current_octo->quater_length_)) {
1833 | near_position.y = near_position.y + 1;
1834 | } else if (loc_xyz[1] < (current_octo->voxel_center_[1] - current_octo->quater_length_)) {
1835 | near_position.y = near_position.y - 1;
1836 | }
1837 | if (loc_xyz[2] > (current_octo->voxel_center_[2] + current_octo->quater_length_)) {
1838 | near_position.z = near_position.z + 1;
1839 | } else if (loc_xyz[2] < (current_octo->voxel_center_[2] - current_octo->quater_length_)) {
1840 | near_position.z = near_position.z - 1;
1841 | }
1842 | auto iter_near = voxel_map.find(near_position);
1843 | if (iter_near != voxel_map.end()) {
1844 | build_single_residual(pv,
1845 | iter_near->second,
1846 | 0,
1847 | max_layer,
1848 | sigma_num,
1849 | is_sucess,
1850 | prob,
1851 | single_ptpl);
1852 | }
1853 | }
1854 | if (is_sucess) {
1855 | mylock.lock();
1856 | useful_ptpl[i] = true;
1857 | all_ptpl_list[i] = single_ptpl;
1858 | mylock.unlock();
1859 | } else {
1860 | mylock.lock();
1861 | useful_ptpl[i] = false;
1862 | mylock.unlock();
1863 | }
1864 | }
1865 | }
1866 | for (size_t i = 0; i < useful_ptpl.size(); i++) {
1867 | if (useful_ptpl[i]) {
1868 | ptpl_list.push_back(all_ptpl_list[i]);
1869 | }
1870 | }
1871 | }
1872 |
1873 | void BuildResidualListNormal(const unordered_map& voxel_map,
1874 | const double voxel_size,
1875 | const double sigma_num,
1876 | const int max_layer,
1877 | const std::vector& pv_list,
1878 | std::vector& ptpl_list,
1879 | std::vector& non_match) {
1880 | ptpl_list.clear();
1881 | std::vector index(pv_list.size());
1882 | for (size_t i = 0; i < pv_list.size(); ++i) {
1883 | pointWithCov pv = pv_list[i];
1884 | float loc_xyz[3];
1885 | for (int j = 0; j < 3; j++) {
1886 | loc_xyz[j] = pv.point_world[j] / voxel_size;
1887 | if (loc_xyz[j] < 0) {
1888 | loc_xyz[j] -= 1.0;
1889 | }
1890 | }
1891 | VOXEL_LOC position((int64_t) loc_xyz[0], (int64_t) loc_xyz[1], (int64_t) loc_xyz[2]);
1892 | auto iter = voxel_map.find(position);
1893 | if (iter != voxel_map.end()) {
1894 | OctoTree* current_octo = iter->second;
1895 | ptpl single_ptpl;
1896 | bool is_sucess = false;
1897 | double prob = 0;
1898 | build_single_residual(pv,
1899 | current_octo,
1900 | 0,
1901 | max_layer,
1902 | sigma_num,
1903 | is_sucess,
1904 | prob,
1905 | single_ptpl);
1906 |
1907 | if (!is_sucess) {
1908 | VOXEL_LOC near_position = position;
1909 | if (loc_xyz[0] > (current_octo->voxel_center_[0] + current_octo->quater_length_)) {
1910 | near_position.x = near_position.x + 1;
1911 | } else if (loc_xyz[0] < (current_octo->voxel_center_[0] - current_octo->quater_length_)) {
1912 | near_position.x = near_position.x - 1;
1913 | }
1914 | if (loc_xyz[1] > (current_octo->voxel_center_[1] + current_octo->quater_length_)) {
1915 | near_position.y = near_position.y + 1;
1916 | } else if (loc_xyz[1] < (current_octo->voxel_center_[1] - current_octo->quater_length_)) {
1917 | near_position.y = near_position.y - 1;
1918 | }
1919 | if (loc_xyz[2] > (current_octo->voxel_center_[2] + current_octo->quater_length_)) {
1920 | near_position.z = near_position.z + 1;
1921 | } else if (loc_xyz[2] < (current_octo->voxel_center_[2] - current_octo->quater_length_)) {
1922 | near_position.z = near_position.z - 1;
1923 | }
1924 | auto iter_near = voxel_map.find(near_position);
1925 | if (iter_near != voxel_map.end()) {
1926 | build_single_residual(pv,
1927 | iter_near->second,
1928 | 0,
1929 | max_layer,
1930 | sigma_num,
1931 | is_sucess,
1932 | prob,
1933 | single_ptpl);
1934 | }
1935 | }
1936 | if (is_sucess) {
1937 | ptpl_list.push_back(single_ptpl);
1938 | } else {
1939 | non_match.push_back(pv.point_world);
1940 | }
1941 | }
1942 | }
1943 | }
1944 |
1945 | void CalcVectQuation(const Eigen::Vector3d& x_vec,
1946 | const Eigen::Vector3d& y_vec,
1947 | const Eigen::Vector3d& z_vec,
1948 | geometry_msgs::Quaternion& q) {
1949 | Eigen::Matrix3d rot;
1950 | rot << x_vec(0), x_vec(1), x_vec(2), y_vec(0), y_vec(1), y_vec(2), z_vec(0), z_vec(1), z_vec(2);
1951 | Eigen::Matrix3d rotation = rot.transpose();
1952 | Eigen::Quaterniond eq(rotation);
1953 | q.w = eq.w();
1954 | q.x = eq.x();
1955 | q.y = eq.y();
1956 | q.z = eq.z();
1957 | }
1958 |
1959 | void CalcQuation(const Eigen::Vector3d& vec, const int axis, geometry_msgs::Quaternion& q) {
1960 | Eigen::Vector3d x_body = vec;
1961 | Eigen::Vector3d y_body(1, 1, 0);
1962 | if (x_body(2) != 0) {
1963 | y_body(2) = -(y_body(0) * x_body(0) + y_body(1) * x_body(1)) / x_body(2);
1964 | } else {
1965 | if (x_body(1) != 0) {
1966 | y_body(1) = -(y_body(0) * x_body(0)) / x_body(1);
1967 | } else {
1968 | y_body(0) = 0;
1969 | }
1970 | }
1971 | y_body.normalize();
1972 | Eigen::Vector3d z_body = x_body.cross(y_body);
1973 | Eigen::Matrix3d rot;
1974 |
1975 | rot << x_body(0), x_body(1), x_body(2), y_body(0), y_body(1), y_body(2), z_body(0), z_body(1),
1976 | z_body(2);
1977 | Eigen::Matrix3d rotation = rot.transpose();
1978 | if (axis == 2) {
1979 | Eigen::Matrix3d rot_inc;
1980 | rot_inc << 0, 0, 1, 0, 1, 0, -1, 0, 0;
1981 | rotation = rotation * rot_inc;
1982 | }
1983 | Eigen::Quaterniond eq(rotation);
1984 | q.w = eq.w();
1985 | q.x = eq.x();
1986 | q.y = eq.y();
1987 | q.z = eq.z();
1988 | }
1989 |
1990 | void pubSinglePlane(visualization_msgs::MarkerArray& plane_pub,
1991 | const std::string plane_ns,
1992 | const Plane& single_plane,
1993 | const float alpha,
1994 | const Eigen::Vector3d rgb) {
1995 | visualization_msgs::Marker plane;
1996 | plane.header.frame_id = "camera_init";
1997 | plane.header.stamp = ros::Time();
1998 | plane.ns = plane_ns;
1999 | plane.id = single_plane.id;
2000 | plane.type = visualization_msgs::Marker::CYLINDER;
2001 | plane.action = visualization_msgs::Marker::ADD;
2002 | plane.pose.position.x = single_plane.center[0];
2003 | plane.pose.position.y = single_plane.center[1];
2004 | plane.pose.position.z = single_plane.center[2];
2005 | geometry_msgs::Quaternion q;
2006 | CalcVectQuation(single_plane.x_normal, single_plane.y_normal, single_plane.normal, q);
2007 | plane.pose.orientation = q;
2008 | plane.scale.x = 3 * sqrt(single_plane.max_eigen_value);
2009 | plane.scale.y = 3 * sqrt(single_plane.mid_eigen_value);
2010 | plane.scale.z = 2 * sqrt(single_plane.min_eigen_value);
2011 | plane.color.a = alpha;
2012 | plane.color.r = rgb(0);
2013 | plane.color.g = rgb(1);
2014 | plane.color.b = rgb(2);
2015 | plane.lifetime = ros::Duration();
2016 | plane_pub.markers.push_back(plane);
2017 | }
2018 |
2019 | void pubNoPlaneMap(const std::unordered_map& feat_map,
2020 | const ros::Publisher& plane_map_pub) {
2021 | int id = 0;
2022 | ros::Rate loop(500);
2023 | float use_alpha = 0.8;
2024 | visualization_msgs::MarkerArray voxel_plane;
2025 | voxel_plane.markers.reserve(1000000);
2026 | for (auto iter = feat_map.begin(); iter != feat_map.end(); iter++) {
2027 | if (!iter->second->plane_ptr_->is_plane) {
2028 | for (uint i = 0; i < 8; i++) {
2029 | if (iter->second->leaves_[i] != nullptr) {
2030 | OctoTree* temp_octo_tree = iter->second->leaves_[i];
2031 | if (!temp_octo_tree->plane_ptr_->is_plane) {
2032 | for (uint j = 0; j < 8; j++) {
2033 | if (temp_octo_tree->leaves_[j] != nullptr) {
2034 | if (!temp_octo_tree->leaves_[j]->plane_ptr_->is_plane) {
2035 | Eigen::Vector3d plane_rgb(1, 1, 1);
2036 | pubSinglePlane(voxel_plane,
2037 | "no_plane",
2038 | *(temp_octo_tree->leaves_[j]->plane_ptr_),
2039 | use_alpha,
2040 | plane_rgb);
2041 | }
2042 | }
2043 | }
2044 | }
2045 | }
2046 | }
2047 | }
2048 | }
2049 | plane_map_pub.publish(voxel_plane);
2050 | loop.sleep();
2051 | }
2052 |
2053 | void pubVoxelMap(const std::unordered_map& voxel_map,
2054 | const int pub_max_voxel_layer,
2055 | const ros::Publisher& plane_map_pub) {
2056 | double max_trace = 0.25;
2057 | double pow_num = 0.2;
2058 | ros::Rate loop(500);
2059 | float use_alpha = 0.8;
2060 | visualization_msgs::MarkerArray voxel_plane;
2061 | voxel_plane.markers.reserve(1000000);
2062 | std::vector pub_plane_list;
2063 | for (auto iter = voxel_map.begin(); iter != voxel_map.end(); iter++) {
2064 | GetUpdatePlane(iter->second, pub_max_voxel_layer, pub_plane_list);
2065 | }
2066 | for (size_t i = 0; i < pub_plane_list.size(); i++) {
2067 | V3D plane_cov = pub_plane_list[i].plane_cov.block<3, 3>(0, 0).diagonal();
2068 | double trace = plane_cov.sum();
2069 | if (trace >= max_trace) {
2070 | trace = max_trace;
2071 | }
2072 | trace = trace * (1.0 / max_trace);
2073 | trace = pow(trace, pow_num);
2074 | uint8_t r, g, b;
2075 | mapJet(trace, 0, 1, r, g, b);
2076 | Eigen::Vector3d plane_rgb(r / 256.0, g / 256.0, b / 256.0);
2077 | double alpha;
2078 | if (pub_plane_list[i].is_plane) {
2079 | alpha = use_alpha;
2080 | } else {
2081 | alpha = 0;
2082 | }
2083 | pubSinglePlane(voxel_plane, "plane", pub_plane_list[i], alpha, plane_rgb);
2084 | }
2085 | plane_map_pub.publish(voxel_plane);
2086 | loop.sleep();
2087 | }
2088 |
2089 | void pubPlaneMap(const std::unordered_map& feat_map,
2090 | const ros::Publisher& plane_map_pub) {
2091 | OctoTree* current_octo = nullptr;
2092 |
2093 | double max_trace = 0.25;
2094 | double pow_num = 0.2;
2095 | ros::Rate loop(500);
2096 | float use_alpha = 1.0;
2097 | visualization_msgs::MarkerArray voxel_plane;
2098 | voxel_plane.markers.reserve(1000000);
2099 |
2100 | for (auto iter = feat_map.begin(); iter != feat_map.end(); iter++) {
2101 | if (iter->second->plane_ptr_->is_update) {
2102 | Eigen::Vector3d normal_rgb(0.0, 1.0, 0.0);
2103 |
2104 | V3D plane_cov = iter->second->plane_ptr_->plane_cov.block<3, 3>(0, 0).diagonal();
2105 | double trace = plane_cov.sum();
2106 | if (trace >= max_trace) {
2107 | trace = max_trace;
2108 | }
2109 | trace = trace * (1.0 / max_trace);
2110 | trace = pow(trace, pow_num);
2111 | uint8_t r, g, b;
2112 | mapJet(trace, 0, 1, r, g, b);
2113 | Eigen::Vector3d plane_rgb(r / 256.0, g / 256.0, b / 256.0);
2114 | // Eigen::Vector3d plane_rgb(1, 0, 0);
2115 | float alpha = 0.0;
2116 | if (iter->second->plane_ptr_->is_plane) {
2117 | alpha = use_alpha;
2118 | } else {
2119 | // std::cout << "delete plane" << std::endl;
2120 | }
2121 | pubSinglePlane(voxel_plane, "plane", *(iter->second->plane_ptr_), alpha, plane_rgb);
2122 |
2123 | iter->second->plane_ptr_->is_update = false;
2124 | } else {
2125 | for (uint i = 0; i < 8; i++) {
2126 | if (iter->second->leaves_[i] != nullptr) {
2127 | if (iter->second->leaves_[i]->plane_ptr_->is_update) {
2128 | Eigen::Vector3d normal_rgb(0.0, 1.0, 0.0);
2129 |
2130 | V3D plane_cov = iter->second->leaves_[i]
2131 | ->plane_ptr_->plane_cov.block<3, 3>(0, 0)
2132 | .diagonal();
2133 | double trace = plane_cov.sum();
2134 | if (trace >= max_trace) {
2135 | trace = max_trace;
2136 | }
2137 | trace = trace * (1.0 / max_trace);
2138 | // trace = (max_trace - trace) / max_trace;
2139 | trace = pow(trace, pow_num);
2140 | uint8_t r, g, b;
2141 | mapJet(trace, 0, 1, r, g, b);
2142 | Eigen::Vector3d plane_rgb(r / 256.0, g / 256.0, b / 256.0);
2143 | plane_rgb << 0, 1, 0;
2144 | // fabs(iter->second->leaves_[i]->plane_ptr_->normal[0]),
2145 | // fabs(iter->second->leaves_[i]->plane_ptr_->normal[1]),
2146 | // fabs(iter->second->leaves_[i]->plane_ptr_->normal[2]);
2147 | float alpha = 0.0;
2148 | if (iter->second->leaves_[i]->plane_ptr_->is_plane) {
2149 | alpha = use_alpha;
2150 | } else {
2151 | // std::cout << "delete plane" << std::endl;
2152 | }
2153 | pubSinglePlane(voxel_plane,
2154 | "plane",
2155 | *(iter->second->leaves_[i]->plane_ptr_),
2156 | alpha,
2157 | plane_rgb);
2158 | // loop.sleep();
2159 | iter->second->leaves_[i]->plane_ptr_->is_update = false;
2160 | // loop.sleep();
2161 | } else {
2162 | OctoTree* temp_octo_tree = iter->second->leaves_[i];
2163 | for (uint j = 0; j < 8; j++) {
2164 | if (temp_octo_tree->leaves_[j] != nullptr) {
2165 | if (temp_octo_tree->leaves_[j]->octo_state_ == 0 &&
2166 | temp_octo_tree->leaves_[j]->plane_ptr_->is_update) {
2167 | if (temp_octo_tree->leaves_[j]->plane_ptr_->is_plane) {
2168 | // std::cout << "subsubplane" << std::endl;
2169 | Eigen::Vector3d normal_rgb(0.0, 1.0, 0.0);
2170 | V3D plane_cov = temp_octo_tree->leaves_[j]
2171 | ->plane_ptr_->plane_cov.block<3, 3>(0, 0)
2172 | .diagonal();
2173 | double trace = plane_cov.sum();
2174 | if (trace >= max_trace) {
2175 | trace = max_trace;
2176 | }
2177 | trace = trace * (1.0 / max_trace);
2178 | // trace = (max_trace - trace) / max_trace;
2179 | trace = pow(trace, pow_num);
2180 | uint8_t r, g, b;
2181 | mapJet(trace, 0, 1, r, g, b);
2182 | Eigen::Vector3d plane_rgb(r / 256.0, g / 256.0, b / 256.0);
2183 | plane_rgb << 0, 0, 1;
2184 | float alpha = 0.0;
2185 | if (temp_octo_tree->leaves_[j]->plane_ptr_->is_plane) {
2186 | alpha = use_alpha;
2187 | }
2188 |
2189 | pubSinglePlane(voxel_plane,
2190 | "plane",
2191 | *(temp_octo_tree->leaves_[j]->plane_ptr_),
2192 | alpha,
2193 | plane_rgb);
2194 | // loop.sleep();
2195 | temp_octo_tree->leaves_[j]->plane_ptr_->is_update = false;
2196 | }
2197 | }
2198 | }
2199 | }
2200 | }
2201 | }
2202 | }
2203 | }
2204 | }
2205 |
2206 | plane_map_pub.publish(voxel_plane);
2207 | // plane_map_pub.publish(voxel_norm);
2208 | loop.sleep();
2209 | // cout << "[Map Info] Plane counts:" << plane_count
2210 | // << " Sub Plane counts:" << sub_plane_count
2211 | // << " Sub Sub Plane counts:" << sub_sub_plane_count << endl;
2212 | // cout << "[Map Info] Update plane counts:" << update_count
2213 | // << "total size: " << feat_map.size() << endl;
2214 | }
2215 |
2216 | std::tuple GenerateBoundaryRGB(size_t idx) {
2217 | std::hash hasher;
2218 | std::mt19937 rng(hasher(idx));
2219 | std::uniform_int_distribution dist(0, 255);
2220 |
2221 | int r = dist(rng);
2222 | int g = dist(rng);
2223 | int b = dist(rng);
2224 |
2225 | return std::make_tuple(r, g, b);
2226 | }
2227 |
2228 | void SetVoxelPlaneVisualizationInfo(visualization_msgs::MarkerArray& plane_pub,
2229 | const Plane* const single_plane,
2230 | const Eigen::Vector3d& plane_position,
2231 | double plane_scale,
2232 | int viz_plane_id) {
2233 | visualization_msgs::Marker plane;
2234 | plane.header.frame_id = "camera_init";
2235 | plane.header.stamp = ros::Time();
2236 | plane.ns = "merged voxel";
2237 | plane.id = viz_plane_id;
2238 | plane.type = visualization_msgs::Marker::CYLINDER;
2239 | plane.action = visualization_msgs::Marker::ADD;
2240 |
2241 | auto color = GenerateBoundaryRGB(single_plane->merge_plane_id);
2242 | int r = std::get<0>(color);
2243 | int g = std::get<1>(color);
2244 | int b = std::get<2>(color);
2245 |
2246 | Eigen::Vector3f plane_rgb(r / 256.f, g / 256.f, b / 256.f);
2247 |
2248 | plane.color.r = plane_rgb(0);
2249 | plane.color.g = plane_rgb(1);
2250 | plane.color.b = plane_rgb(2);
2251 |
2252 | plane.pose.position.x = plane_position[0];
2253 | plane.pose.position.y = plane_position[1];
2254 | plane.pose.position.z = plane_position[2];
2255 |
2256 | const auto& plane_normal = single_plane->normal.normalized();
2257 | Eigen::Vector3d base(0, 0, 1);
2258 | size_t max_index = 0;
2259 | plane_normal.cwiseAbs().maxCoeff(&max_index);
2260 | if (max_index == 2) {
2261 | base << 1.f, 0.f, 0.f;
2262 | }
2263 | Eigen::Vector3d x_normal = (plane_normal.cross(base)).normalized();
2264 | Eigen::Vector3d y_normal = plane_normal.cross(x_normal);
2265 |
2266 | geometry_msgs::Quaternion q;
2267 | CalcVectQuation(x_normal, y_normal, plane_normal, q);
2268 |
2269 | plane.pose.orientation = q;
2270 | plane.scale.x = plane_scale;
2271 | plane.scale.y = plane_scale;
2272 | plane.scale.z = 0.01;
2273 | plane.color.a = 0.8;
2274 |
2275 | plane_pub.markers.push_back(plane);
2276 | }
2277 |
2278 | void PublishMergedVoxelPlane(
2279 | std::unordered_map& feat_map,
2280 | const std::unordered_map>& merged_voxels,
2281 | const ros::Publisher& plane_map_pub,
2282 | double voxel_size) {
2283 | if (merged_voxels.empty()) {
2284 | return;
2285 | }
2286 |
2287 | visualization_msgs::MarkerArray voxel_plane;
2288 | voxel_plane.markers.reserve(1000000);
2289 |
2290 | int viz_plane_id = 0;
2291 |
2292 | for (const auto& plane_i : merged_voxels) {
2293 | if (plane_i.second.empty()) {
2294 | continue;
2295 | }
2296 |
2297 | auto node_loc_it = *(plane_i.second.begin());
2298 |
2299 | const OctoTree* const current_node = GetVoxelPlaneNode(feat_map, node_loc_it);
2300 |
2301 | auto current_plane = current_node->plane_ptr_;
2302 |
2303 | for (const auto& content_loc : plane_i.second) {
2304 | VOXEL_LOC v(content_loc.x, content_loc.y, content_loc.z);
2305 |
2306 | double plane_scale = voxel_size;
2307 |
2308 | Eigen::Vector3d viz_center;
2309 | viz_center << (0.5f + v.x) * plane_scale, (0.5f + v.y) * plane_scale,
2310 | (0.5f + v.z) * plane_scale;
2311 |
2312 | Eigen::Vector3d n = current_plane->normal;
2313 |
2314 | double t = n.dot(current_plane->center) - n.dot(viz_center);
2315 |
2316 | Eigen::Vector3d plane_pose = viz_center + t * n;
2317 |
2318 | if (content_loc.leaf_num > 0) {
2319 | plane_scale *= 0.5f;
2320 | }
2321 |
2322 | SetVoxelPlaneVisualizationInfo(voxel_plane,
2323 | current_plane,
2324 | plane_pose,
2325 | plane_scale,
2326 | viz_plane_id);
2327 |
2328 | viz_plane_id++;
2329 | }
2330 | }
2331 | plane_map_pub.publish(voxel_plane);
2332 | }
2333 |
2334 | void calcBodyCov(Eigen::Vector3d& pb,
2335 | const float range_inc,
2336 | const float degree_inc,
2337 | Eigen::Matrix3d& cov) {
2338 | float range = sqrt(pb[0] * pb[0] + pb[1] * pb[1] + pb[2] * pb[2]);
2339 | float range_var = range_inc * range_inc;
2340 | Eigen::Matrix2d direction_var;
2341 | direction_var << pow(sin(DEG2RAD(degree_inc)), 2), 0, 0, pow(sin(DEG2RAD(degree_inc)), 2);
2342 | Eigen::Vector3d direction(pb);
2343 | direction.normalize();
2344 | Eigen::Matrix3d direction_hat;
2345 | direction_hat << 0, -direction(2), direction(1), direction(2), 0, -direction(0), -direction(1),
2346 | direction(0), 0;
2347 | Eigen::Vector3d base_vector1(1, 1, -(direction(0) + direction(1)) / direction(2));
2348 | base_vector1.normalize();
2349 | Eigen::Vector3d base_vector2 = base_vector1.cross(direction);
2350 | base_vector2.normalize();
2351 | Eigen::Matrix N;
2352 | N << base_vector1(0), base_vector2(0), base_vector1(1), base_vector2(1), base_vector1(2),
2353 | base_vector2(2);
2354 | Eigen::Matrix A = range * direction_hat * N;
2355 | cov = direction * range_var * direction.transpose() + A * direction_var * A.transpose();
2356 | };
2357 |
2358 | #endif
--------------------------------------------------------------------------------
/launch/mapping_l515.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/launch/mapping_velodyne.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/msg/Pose6D.msg:
--------------------------------------------------------------------------------
1 | # the preintegrated Lidar states at the time of IMU measurements in a frame
2 | float64 offset_time # the offset time of IMU measurement w.r.t the first lidar point
3 | float64[3] acc # the preintegrated total acceleration (global frame) at the Lidar origin
4 | float64[3] gyr # the unbiased angular velocity (body frame) at the Lidar origin
5 | float64[3] vel # the preintegrated velocity (global frame) at the Lidar origin
6 | float64[3] pos # the preintegrated position (global frame) at the Lidar origin
7 | float64[9] rot # the preintegrated rotation (global frame) at the Lidar origin
--------------------------------------------------------------------------------
/msg/States.msg:
--------------------------------------------------------------------------------
1 | Header header # timestamp of the first lidar in a frame
2 | float64[] rot_end # the estimated attitude (rotation matrix) at the end lidar point
3 | float64[] pos_end # the estimated position at the end lidar point (world frame)
4 | float64[] vel_end # the estimated velocity at the end lidar point (world frame)
5 | float64[] bias_gyr # gyroscope bias
6 | float64[] bias_acc # accelerator bias
7 | float64[] gravity # the estimated gravity acceleration
8 | float64[] cov # states covariance
9 | # Pose6D[] IMUpose # 6D pose at each imu measurements
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | c3p_voxelmap
4 | 1.0.0
5 |
6 |
7 | C3P-VoxelMap is a probabilistic voxel mapping method based on VoxelMap,
8 | enhancing performance, accuracy, and memory efficiency in LiDAR odometry.
9 |
10 |
11 | Xu Yang
12 |
13 | BSD
14 |
15 | Xu Yang
16 |
17 | catkin
18 | geometry_msgs
19 | nav_msgs
20 | roscpp
21 | rospy
22 | std_msgs
23 | sensor_msgs
24 | tf
25 | pcl_ros
26 | livox_ros_driver
27 | message_generation
28 |
29 | geometry_msgs
30 | nav_msgs
31 | sensor_msgs
32 | roscpp
33 | rospy
34 | std_msgs
35 | tf
36 | pcl_ros
37 | livox_ros_driver
38 | message_runtime
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/rviz_cfg/c3p_voxelmap.rviz:
--------------------------------------------------------------------------------
1 | Panels:
2 | - Class: rviz/Displays
3 | Help Height: 0
4 | Name: Displays
5 | Property Tree Widget:
6 | Expanded:
7 | - /Global Options1
8 | - /mapping1/surround1
9 | - /mapping1/currPoints1
10 | - /mapping1/currPoints1/Autocompute Value Bounds1
11 | - /Odometry1/Odometry1
12 | - /Odometry1/Odometry1/Shape1
13 | - /Odometry1/Odometry2
14 | - /Odometry1/Odometry2/Shape1
15 | - /Odometry2/Shape1
16 | Splitter Ratio: 0.520588219165802
17 | Tree Height: 653
18 | - Class: rviz/Selection
19 | Name: Selection
20 | - Class: rviz/Tool Properties
21 | Expanded:
22 | - /2D Pose Estimate1
23 | - /2D Nav Goal1
24 | - /Publish Point1
25 | Name: Tool Properties
26 | Splitter Ratio: 0.5886790156364441
27 | - Class: rviz/Views
28 | Expanded:
29 | - /Current View1
30 | Name: Views
31 | Splitter Ratio: 0.5
32 | - Class: rviz/Time
33 | Name: Time
34 | SyncMode: 0
35 | SyncSource: currPoints
36 | Preferences:
37 | PromptSaveOnExit: true
38 | Toolbars:
39 | toolButtonStyle: 2
40 | Visualization Manager:
41 | Class: ""
42 | Displays:
43 | - Alpha: 1
44 | Cell Size: 3
45 | Class: rviz/Grid
46 | Color: 160; 160; 164
47 | Enabled: false
48 | Line Style:
49 | Line Width: 0.029999999329447746
50 | Value: Lines
51 | Name: Grid
52 | Normal Cell Count: 0
53 | Offset:
54 | X: 0
55 | Y: 0
56 | Z: 0
57 | Plane: XY
58 | Plane Cell Count: 1000
59 | Reference Frame:
60 | Value: false
61 | - Alpha: 1
62 | Class: rviz/Axes
63 | Enabled: true
64 | Length: 0.699999988079071
65 | Name: Axes
66 | Radius: 0.05999999865889549
67 | Reference Frame:
68 | Show Trail: false
69 | Value: true
70 | - Class: rviz/Group
71 | Displays:
72 | - Alpha: 1
73 | Autocompute Intensity Bounds: false
74 | Autocompute Value Bounds:
75 | Max Value: 10
76 | Min Value: -10
77 | Value: true
78 | Axis: Z
79 | Channel Name: intensity
80 | Class: rviz/PointCloud2
81 | Color: 255; 255; 255
82 | Color Transformer: FlatColor
83 | Decay Time: 0
84 | Enabled: false
85 | Invert Rainbow: false
86 | Max Color: 255; 255; 255
87 | Max Intensity: 1
88 | Min Color: 0; 0; 0
89 | Min Intensity: 0
90 | Name: surround
91 | Position Transformer: XYZ
92 | Queue Size: 1
93 | Selectable: false
94 | Size (Pixels): 5
95 | Size (m): 0.05000000074505806
96 | Style: Points
97 | Topic: /cloud_registered
98 | Unreliable: false
99 | Use Fixed Frame: true
100 | Use rainbow: true
101 | Value: false
102 | - Alpha: 0.5
103 | Autocompute Intensity Bounds: true
104 | Autocompute Value Bounds:
105 | Max Value: 6.024350166320801
106 | Min Value: -1.9103225469589233
107 | Value: true
108 | Axis: Z
109 | Channel Name: intensity
110 | Class: rviz/PointCloud2
111 | Color: 255; 255; 255
112 | Color Transformer: AxisColor
113 | Decay Time: 99999
114 | Enabled: true
115 | Invert Rainbow: true
116 | Max Color: 255; 255; 255
117 | Min Color: 0; 0; 0
118 | Name: currPoints
119 | Position Transformer: XYZ
120 | Queue Size: 100000
121 | Selectable: true
122 | Size (Pixels): 1
123 | Size (m): 0.009999999776482582
124 | Style: Points
125 | Topic: /cloud_registered
126 | Unreliable: false
127 | Use Fixed Frame: true
128 | Use rainbow: true
129 | Value: true
130 | Enabled: true
131 | Name: mapping
132 | - Class: rviz/Group
133 | Displays:
134 | - Angle Tolerance: 0.009999999776482582
135 | Class: rviz/Odometry
136 | Covariance:
137 | Orientation:
138 | Alpha: 0.5
139 | Color: 255; 255; 127
140 | Color Style: Unique
141 | Frame: Local
142 | Offset: 1
143 | Scale: 1
144 | Value: true
145 | Position:
146 | Alpha: 0.30000001192092896
147 | Color: 204; 51; 204
148 | Scale: 1
149 | Value: true
150 | Value: true
151 | Enabled: false
152 | Keep: 1
153 | Name: Odometry
154 | Position Tolerance: 0.009999999776482582
155 | Queue Size: 10
156 | Shape:
157 | Alpha: 1
158 | Axes Length: 0.5
159 | Axes Radius: 0.009999999776482582
160 | Color: 0; 255; 0
161 | Head Length: 0
162 | Head Radius: 0
163 | Shaft Length: 0.05000000074505806
164 | Shaft Radius: 0.05000000074505806
165 | Value: Arrow
166 | Topic: /re_local_pose
167 | Unreliable: false
168 | Value: false
169 | - Angle Tolerance: 0.009999999776482582
170 | Class: rviz/Odometry
171 | Covariance:
172 | Orientation:
173 | Alpha: 0.5
174 | Color: 255; 255; 127
175 | Color Style: Unique
176 | Frame: Local
177 | Offset: 1
178 | Scale: 1
179 | Value: true
180 | Position:
181 | Alpha: 0.30000001192092896
182 | Color: 204; 51; 204
183 | Scale: 1
184 | Value: true
185 | Value: true
186 | Enabled: true
187 | Keep: 1
188 | Name: Odometry
189 | Position Tolerance: 0.0010000000474974513
190 | Queue Size: 10
191 | Shape:
192 | Alpha: 1
193 | Axes Length: 0.699999988079071
194 | Axes Radius: 0.10000000149011612
195 | Color: 255; 85; 0
196 | Head Length: 0
197 | Head Radius: 0
198 | Shaft Length: 0.05000000074505806
199 | Shaft Radius: 0.05000000074505806
200 | Value: Axes
201 | Topic: /aft_mapped_to_init
202 | Unreliable: false
203 | Value: true
204 | Enabled: true
205 | Name: Odometry
206 | - Alpha: 1
207 | Class: rviz/Axes
208 | Enabled: true
209 | Length: 0.699999988079071
210 | Name: Axes
211 | Radius: 0.10000000149011612
212 | Reference Frame: aft_mapped
213 | Show Trail: false
214 | Value: true
215 | - Alpha: 0
216 | Buffer Length: 2
217 | Class: rviz/Path
218 | Color: 25; 255; 255
219 | Enabled: true
220 | Head Diameter: 0
221 | Head Length: 0.10000000149011612
222 | Length: 0.5
223 | Line Style: Lines
224 | Line Width: 0.029999999329447746
225 | Name: Path
226 | Offset:
227 | X: 0
228 | Y: 0
229 | Z: 0
230 | Pose Color: 25; 255; 255
231 | Pose Style: None
232 | Queue Size: 10
233 | Radius: 0.20000000298023224
234 | Shaft Diameter: 0.10000000149011612
235 | Shaft Length: 0.5
236 | Topic: /path
237 | Unreliable: false
238 | Value: true
239 | - Class: rviz/Marker
240 | Enabled: true
241 | Marker Topic: /planner_normal
242 | Name: Marker
243 | Namespaces:
244 | {}
245 | Queue Size: 100
246 | Value: true
247 | - Alpha: 1
248 | Autocompute Intensity Bounds: true
249 | Autocompute Value Bounds:
250 | Max Value: 10
251 | Min Value: -10
252 | Value: true
253 | Axis: Z
254 | Channel Name: intensity
255 | Class: rviz/PointCloud2
256 | Color: 255; 0; 0
257 | Color Transformer: Intensity
258 | Decay Time: 0
259 | Enabled: true
260 | Invert Rainbow: false
261 | Max Color: 255; 255; 255
262 | Min Color: 0; 0; 0
263 | Name: PointCloud2
264 | Position Transformer: XYZ
265 | Queue Size: 10
266 | Selectable: true
267 | Size (Pixels): 3
268 | Size (m): 0.05000000074505806
269 | Style: Points
270 | Topic: /cloud_effected
271 | Unreliable: false
272 | Use Fixed Frame: true
273 | Use rainbow: true
274 | Value: true
275 | - Class: rviz/MarkerArray
276 | Enabled: true
277 | Marker Topic: /points_with_vars
278 | Name: MarkerArray
279 | Namespaces:
280 | {}
281 | Queue Size: 10000
282 | Value: true
283 | - Alpha: 1
284 | Autocompute Intensity Bounds: true
285 | Autocompute Value Bounds:
286 | Max Value: 10
287 | Min Value: -10
288 | Value: true
289 | Axis: Z
290 | Channel Name: intensity
291 | Class: rviz/PointCloud2
292 | Color: 170; 255; 0
293 | Color Transformer: FlatColor
294 | Decay Time: 0
295 | Enabled: true
296 | Invert Rainbow: false
297 | Max Color: 255; 255; 255
298 | Min Color: 0; 0; 0
299 | Name: PointCloud2
300 | Position Transformer: XYZ
301 | Queue Size: 10
302 | Selectable: true
303 | Size (Pixels): 3
304 | Size (m): 0.029999999329447746
305 | Style: Flat Squares
306 | Topic: /transform_cloud
307 | Unreliable: false
308 | Use Fixed Frame: true
309 | Use rainbow: true
310 | Value: true
311 | - Alpha: 1
312 | Autocompute Intensity Bounds: true
313 | Autocompute Value Bounds:
314 | Max Value: 10
315 | Min Value: -10
316 | Value: true
317 | Axis: Z
318 | Channel Name: intensity
319 | Class: rviz/PointCloud2
320 | Color: 255; 255; 255
321 | Color Transformer: FlatColor
322 | Decay Time: 0
323 | Enabled: true
324 | Invert Rainbow: false
325 | Max Color: 255; 255; 255
326 | Min Color: 0; 0; 0
327 | Name: PointCloud2
328 | Position Transformer: XYZ
329 | Queue Size: 10
330 | Selectable: true
331 | Size (Pixels): 3
332 | Size (m): 0.029999999329447746
333 | Style: Flat Squares
334 | Topic: /voxel_cloud
335 | Unreliable: false
336 | Use Fixed Frame: true
337 | Use rainbow: true
338 | Value: true
339 | - Alpha: 0.20000000298023224
340 | Autocompute Intensity Bounds: true
341 | Autocompute Value Bounds:
342 | Max Value: 10
343 | Min Value: -10
344 | Value: true
345 | Axis: Z
346 | Channel Name: intensity
347 | Class: rviz/PointCloud2
348 | Color: 255; 255; 255
349 | Color Transformer: FlatColor
350 | Decay Time: 0
351 | Enabled: false
352 | Invert Rainbow: false
353 | Max Color: 255; 255; 255
354 | Min Color: 0; 0; 0
355 | Name: PointCloud2
356 | Position Transformer: XYZ
357 | Queue Size: 10
358 | Selectable: true
359 | Size (Pixels): 3
360 | Size (m): 0.30000001192092896
361 | Style: Flat Squares
362 | Topic: /cloud_low_intens
363 | Unreliable: false
364 | Use Fixed Frame: true
365 | Use rainbow: true
366 | Value: false
367 | - Angle Tolerance: 0.10000000149011612
368 | Class: rviz/Odometry
369 | Covariance:
370 | Orientation:
371 | Alpha: 0.5
372 | Color: 255; 255; 127
373 | Color Style: Unique
374 | Frame: Local
375 | Offset: 1
376 | Scale: 1
377 | Value: true
378 | Position:
379 | Alpha: 0.30000001192092896
380 | Color: 204; 51; 204
381 | Scale: 1
382 | Value: true
383 | Value: true
384 | Enabled: false
385 | Keep: 10000
386 | Name: Odometry
387 | Position Tolerance: 0.10000000149011612
388 | Queue Size: 10
389 | Shape:
390 | Alpha: 1
391 | Axes Length: 10
392 | Axes Radius: 0.10000000149011612
393 | Color: 255; 25; 0
394 | Head Length: 0.30000001192092896
395 | Head Radius: 0.10000000149011612
396 | Shaft Length: 1
397 | Shaft Radius: 0.05000000074505806
398 | Value: Axes
399 | Topic: /odometry_gt
400 | Unreliable: false
401 | Value: false
402 | - Class: rviz/Image
403 | Enabled: true
404 | Image Topic: /camera/color/image_raw
405 | Max Value: 1
406 | Median window: 5
407 | Min Value: 0
408 | Name: Image
409 | Normalize Range: true
410 | Queue Size: 2
411 | Transport Hint: raw
412 | Unreliable: false
413 | Value: true
414 | - Class: rviz/MarkerArray
415 | Enabled: true
416 | Marker Topic: /planes
417 | Name: MarkerArray
418 | Namespaces:
419 | {}
420 | Queue Size: 100
421 | Value: true
422 | - Alpha: 1
423 | Autocompute Intensity Bounds: true
424 | Autocompute Value Bounds:
425 | Max Value: 10
426 | Min Value: -10
427 | Value: true
428 | Axis: Z
429 | Channel Name: intensity
430 | Class: rviz/PointCloud2
431 | Color: 255; 255; 255
432 | Color Transformer: FlatColor
433 | Decay Time: 0
434 | Enabled: true
435 | Invert Rainbow: false
436 | Max Color: 255; 255; 255
437 | Min Color: 0; 0; 0
438 | Name: PointCloud2
439 | Position Transformer: XYZ
440 | Queue Size: 10
441 | Selectable: true
442 | Size (Pixels): 5
443 | Size (m): 0.009999999776482582
444 | Style: Points
445 | Topic: /cloud_no_effected
446 | Unreliable: false
447 | Use Fixed Frame: true
448 | Use rainbow: true
449 | Value: true
450 | - Alpha: 1
451 | Autocompute Intensity Bounds: true
452 | Autocompute Value Bounds:
453 | Max Value: 10
454 | Min Value: -10
455 | Value: true
456 | Axis: Z
457 | Channel Name: intensity
458 | Class: rviz/PointCloud2
459 | Color: 239; 41; 41
460 | Color Transformer: FlatColor
461 | Decay Time: 0
462 | Enabled: false
463 | Invert Rainbow: false
464 | Max Color: 255; 255; 255
465 | Min Color: 0; 0; 0
466 | Name: PointCloud2
467 | Position Transformer: XYZ
468 | Queue Size: 10
469 | Selectable: true
470 | Size (Pixels): 3
471 | Size (m): 0.009999999776482582
472 | Style: Points
473 | Topic: /cloud_error
474 | Unreliable: false
475 | Use Fixed Frame: true
476 | Use rainbow: true
477 | Value: false
478 | - Class: rviz/Image
479 | Enabled: false
480 | Image Topic: /camera/color/image_raw
481 | Max Value: 1
482 | Median window: 5
483 | Min Value: 0
484 | Name: Image
485 | Normalize Range: true
486 | Queue Size: 2
487 | Transport Hint: raw
488 | Unreliable: false
489 | Value: false
490 | - Alpha: 1
491 | Autocompute Intensity Bounds: true
492 | Autocompute Value Bounds:
493 | Max Value: 10
494 | Min Value: -10
495 | Value: true
496 | Axis: Z
497 | Channel Name: intensity
498 | Class: rviz/PointCloud2
499 | Color: 255; 255; 255
500 | Color Transformer: Intensity
501 | Decay Time: 0
502 | Enabled: true
503 | Invert Rainbow: false
504 | Max Color: 255; 255; 255
505 | Min Color: 0; 0; 0
506 | Name: pgoMap
507 | Position Transformer: XYZ
508 | Queue Size: 10
509 | Selectable: true
510 | Size (Pixels): 3
511 | Size (m): 0.009999999776482582
512 | Style: Flat Squares
513 | Topic: /aft_pgo_map
514 | Unreliable: false
515 | Use Fixed Frame: true
516 | Use rainbow: true
517 | Value: true
518 | - Alpha: 1
519 | Buffer Length: 1
520 | Class: rviz/Path
521 | Color: 255; 0; 0
522 | Enabled: true
523 | Head Diameter: 0.30000001192092896
524 | Head Length: 0.20000000298023224
525 | Length: 0.30000001192092896
526 | Line Style: Lines
527 | Line Width: 0.029999999329447746
528 | Name: pgoPath
529 | Offset:
530 | X: 0
531 | Y: 0
532 | Z: 0
533 | Pose Color: 255; 85; 255
534 | Pose Style: None
535 | Queue Size: 10
536 | Radius: 0.029999999329447746
537 | Shaft Diameter: 0.10000000149011612
538 | Shaft Length: 0.10000000149011612
539 | Topic: /aft_pgo_path
540 | Unreliable: false
541 | Value: true
542 | - Class: rviz/MarkerArray
543 | Enabled: true
544 | Marker Topic: /plane_hash_map
545 | Name: PlaneHashMap
546 | Namespaces:
547 | {}
548 | Queue Size: 100
549 | Value: true
550 | - Class: rviz/MarkerArray
551 | Enabled: true
552 | Marker Topic: /merged_voxels
553 | Name: MarkerArray
554 | Namespaces:
555 | merged voxel: true
556 | Queue Size: 100
557 | Value: true
558 | Enabled: true
559 | Global Options:
560 | Background Color: 0; 0; 0
561 | Default Light: true
562 | Fixed Frame: camera_init
563 | Frame Rate: 30
564 | Name: root
565 | Tools:
566 | - Class: rviz/Interact
567 | Hide Inactive Objects: true
568 | - Class: rviz/MoveCamera
569 | - Class: rviz/Select
570 | - Class: rviz/FocusCamera
571 | - Class: rviz/Measure
572 | - Class: rviz/SetInitialPose
573 | Theta std deviation: 0.2617993950843811
574 | Topic: /initialpose
575 | X std deviation: 0.5
576 | Y std deviation: 0.5
577 | - Class: rviz/SetGoal
578 | Topic: /move_base_simple/goal
579 | - Class: rviz/PublishPoint
580 | Single click: true
581 | Topic: /clicked_point
582 | Value: true
583 | Views:
584 | Current:
585 | Class: rviz/Orbit
586 | Distance: 296.3080139160156
587 | Enable Stereo Rendering:
588 | Stereo Eye Separation: 0.05999999865889549
589 | Stereo Focal Distance: 1
590 | Swap Stereo Eyes: false
591 | Value: false
592 | Field of View: 0.7853981852531433
593 | Focal Point:
594 | X: 135.8769073486328
595 | Y: -10.643716812133789
596 | Z: 3.868349552154541
597 | Focal Shape Fixed Size: false
598 | Focal Shape Size: 0.05000000074505806
599 | Invert Z Axis: false
600 | Name: Current View
601 | Near Clip Distance: 0.009999999776482582
602 | Pitch: 1.5297963619232178
603 | Target Frame: camera_init
604 | Yaw: 1.458579182624817
605 | Saved:
606 | - Class: rviz/Orbit
607 | Distance: 310.7291564941406
608 | Enable Stereo Rendering:
609 | Stereo Eye Separation: 0.05999999865889549
610 | Stereo Focal Distance: 1
611 | Swap Stereo Eyes: false
612 | Value: false
613 | Field of View: 0.7853981852531433
614 | Focal Point:
615 | X: 73.46565246582031
616 | Y: -55.00351333618164
617 | Z: -20.647184371948242
618 | Focal Shape Fixed Size: false
619 | Focal Shape Size: 0.05000000074505806
620 | Invert Z Axis: false
621 | Name: garden
622 | Near Clip Distance: 0.009999999776482582
623 | Pitch: 1.5597963333129883
624 | Target Frame:
625 | Yaw: 4.355392932891846
626 | - Class: rviz/Orbit
627 | Distance: 440.30224609375
628 | Enable Stereo Rendering:
629 | Stereo Eye Separation: 0.05999999865889549
630 | Stereo Focal Distance: 1
631 | Swap Stereo Eyes: false
632 | Value: false
633 | Field of View: 0.7853981852531433
634 | Focal Point:
635 | X: -30.845176696777344
636 | Y: 166.62318420410156
637 | Z: 129.23764038085938
638 | Focal Shape Fixed Size: false
639 | Focal Shape Size: 0.05000000074505806
640 | Invert Z Axis: false
641 | Name: fly
642 | Near Clip Distance: 0.009999999776482582
643 | Pitch: -0.010202649049460888
644 | Target Frame:
645 | Yaw: 3.255385160446167
646 | - Class: rviz/Orbit
647 | Distance: 93.19469451904297
648 | Enable Stereo Rendering:
649 | Stereo Eye Separation: 0.05999999865889549
650 | Stereo Focal Distance: 1
651 | Swap Stereo Eyes: false
652 | Value: false
653 | Field of View: 0.7853981852531433
654 | Focal Point:
655 | X: 64.74459838867188
656 | Y: -83.73934936523438
657 | Z: 73.07307434082031
658 | Focal Shape Fixed Size: false
659 | Focal Shape Size: 0.05000000074505806
660 | Invert Z Axis: false
661 | Name: park
662 | Near Clip Distance: 0.009999999776482582
663 | Pitch: 1.5697963237762451
664 | Target Frame:
665 | Yaw: 4.00038480758667
666 | - Class: rviz/Orbit
667 | Distance: 806.5628051757812
668 | Enable Stereo Rendering:
669 | Stereo Eye Separation: 0.05999999865889549
670 | Stereo Focal Distance: 1
671 | Swap Stereo Eyes: false
672 | Value: false
673 | Field of View: 0.7853981852531433
674 | Focal Point:
675 | X: 0.03874540328979492
676 | Y: -172.88673400878906
677 | Z: 215.0831756591797
678 | Focal Shape Fixed Size: false
679 | Focal Shape Size: 0.05000000074505806
680 | Invert Z Axis: false
681 | Name: KITTI
682 | Near Clip Distance: 0.009999999776482582
683 | Pitch: 0.010398204438388348
684 | Target Frame: camera_init
685 | Yaw: 1.6403980255126953
686 | - Class: rviz/ThirdPersonFollower
687 | Distance: 19.453998565673828
688 | Enable Stereo Rendering:
689 | Stereo Eye Separation: 0.05999999865889549
690 | Stereo Focal Distance: 1
691 | Swap Stereo Eyes: false
692 | Value: false
693 | Field of View: 0.7853981852531433
694 | Focal Point:
695 | X: -5.738302230834961
696 | Y: 7.975442409515381
697 | Z: 0
698 | Focal Shape Fixed Size: false
699 | Focal Shape Size: 0.05000000074505806
700 | Invert Z Axis: false
701 | Name: Kitti_start
702 | Near Clip Distance: 0.009999999776482582
703 | Pitch: 0.25039851665496826
704 | Target Frame: aft_mapped
705 | Yaw: 3.2403976917266846
706 | Window Geometry:
707 | Displays:
708 | collapsed: false
709 | Height: 1536
710 | Hide Left Dock: false
711 | Hide Right Dock: false
712 | Image:
713 | collapsed: false
714 | QMainWindow State: 000000ff00000000fd0000000400000000000001560000054efc0200000015fb0000001200530065006c0065006300740069006f006e000000003b0000009e0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed0000023000000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d000002ca000000c900fffffffb0000000a0049006d006100670065010000030d0000027e0000001600fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d00610067006502000001bc0000023000000280000001e0fb0000000a0049006d00610067006500000001b1000001b70000000000000000fb0000000a0049006d0061006700650000000297000002480000000000000000fb0000000a0049006d00610067006500000003b2000000930000000000000000fb0000000a0049006d0061006700650000000436000000a90000000000000000fb0000000a0049006d006100670065020000066c000000df00000280000001e0fb0000000a0049006d006100670065020000079f000000660000064900000338fb0000000a0049006d0061006700650300000080000001030000034900000168fb0000000a0049006d0061006700650000000408000000d70000000000000000fb0000000a0049006d00610067006503000002780000016b000001db000000d7fb0000000a0049006d00610067006501000003620000019f0000000000000000fb0000000a0049006d006100670065010000017b000001ed000000000000000000000001000001520000054efc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d0000054e000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b2000000000000000000000002000009b8000000a9fc0100000002fb0000000a0049006d00610067006503000005b40000013b0000028f000001d5fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000009b800000052fc0100000002fb0000000800540069006d00650100000000000009b8000003bc00fffffffb0000000800540069006d00650100000000000004500000000000000000000007040000054e00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
715 | Selection:
716 | collapsed: false
717 | Time:
718 | collapsed: false
719 | Tool Properties:
720 | collapsed: false
721 | Views:
722 | collapsed: false
723 | Width: 2488
724 | X: 72
725 | Y: 587
726 |
--------------------------------------------------------------------------------
/src/IMU_Processing.hpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 |
27 | /// *************Preconfiguration
28 | #define INITIAL_MEA_NOISE (0.0001)
29 | #define NITIAL_BIAS_NOISE (0.00001)
30 | #define MAX_INI_COUNT (20)
31 |
32 | const bool time_list(PointType& x, PointType& y) {
33 | return (x.curvature < y.curvature);
34 | };
35 |
36 | /// *************IMU Process and undistortion
37 | class ImuProcess {
38 | public:
39 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW
40 |
41 | ImuProcess();
42 | ~ImuProcess();
43 |
44 | void Reset();
45 | void Reset(double start_timestamp, const sensor_msgs::ImuConstPtr& lastimu);
46 | void set_extrinsic(const V3D& transl, const M3D& rot);
47 | void set_extrinsic(const V3D& transl);
48 | void set_extrinsic(const MD(4, 4) & T);
49 | void set_gyr_cov_scale(const V3D& scaler);
50 | void set_acc_cov_scale(const V3D& scaler);
51 | void set_gyr_bias_cov(const V3D& b_g);
52 | void set_acc_bias_cov(const V3D& b_a);
53 | void Process(const MeasureGroup& meas, StatesGroup& state, PointCloudXYZI::Ptr& pcl_un_);
54 |
55 | ros::NodeHandle nh;
56 | V3D cov_acc;
57 | V3D cov_gyr;
58 | V3D cov_acc_scale;
59 | V3D cov_gyr_scale;
60 | V3D cov_bias_gyr;
61 | V3D cov_bias_acc;
62 | M3D Lid_rot_to_IMU;
63 | V3D Lid_offset_to_IMU;
64 |
65 | double first_lidar_time;
66 | bool imu_en;
67 |
68 | private:
69 | void IMU_init(const MeasureGroup& meas, StatesGroup& state, int& N);
70 | void UndistortPcl(const MeasureGroup& meas, StatesGroup& state_inout, PointCloudXYZI& pcl_in_out);
71 | void only_propag(const MeasureGroup& meas,
72 | StatesGroup& state_inout,
73 | PointCloudXYZI::Ptr& pcl_out);
74 |
75 | PointCloudXYZI::Ptr cur_pcl_un_;
76 | sensor_msgs::ImuConstPtr last_imu_;
77 | deque v_imu_;
78 | vector IMUpose;
79 | vector v_rot_pcl_;
80 |
81 | V3D mean_acc;
82 | V3D mean_gyr;
83 | V3D angvel_last;
84 | V3D acc_s_last;
85 | double start_timestamp_;
86 | double time_last_scan_;
87 | int init_iter_num = 1;
88 | bool b_first_frame_ = true;
89 | bool imu_need_init_ = true;
90 | };
91 |
92 | ImuProcess::ImuProcess() : b_first_frame_(true), imu_need_init_(true), start_timestamp_(-1) {
93 | imu_en = true;
94 | init_iter_num = 1;
95 | cov_acc = V3D(0.1, 0.1, 0.1);
96 | cov_gyr = V3D(0.1, 0.1, 0.1);
97 | // old
98 | cov_acc_scale = V3D(1, 1, 1);
99 | cov_gyr_scale = V3D(1, 1, 1);
100 |
101 | cov_bias_gyr = V3D(0.1, 0.1, 0.1);
102 | cov_bias_acc = V3D(0.1, 0.1, 0.1);
103 | mean_acc = V3D(0, 0, -1.0);
104 | mean_gyr = V3D(0, 0, 0);
105 | angvel_last = Zero3d;
106 | Lid_offset_to_IMU = Zero3d;
107 | Lid_rot_to_IMU = Eye3d;
108 | last_imu_.reset(new sensor_msgs::Imu());
109 | }
110 |
111 | ImuProcess::~ImuProcess() {}
112 |
113 | void ImuProcess::Reset() {
114 | ROS_WARN("Reset ImuProcess");
115 | mean_acc = V3D(0, 0, -1.0);
116 | mean_gyr = V3D(0, 0, 0);
117 | angvel_last = Zero3d;
118 | imu_need_init_ = true;
119 | start_timestamp_ = -1;
120 | init_iter_num = 1;
121 | v_imu_.clear();
122 | IMUpose.clear();
123 | last_imu_.reset(new sensor_msgs::Imu());
124 | cur_pcl_un_.reset(new PointCloudXYZI());
125 | }
126 |
127 | void ImuProcess::set_extrinsic(const MD(4, 4) & T) {
128 | Lid_offset_to_IMU = T.block<3, 1>(0, 3);
129 | Lid_rot_to_IMU = T.block<3, 3>(0, 0);
130 | }
131 |
132 | void ImuProcess::set_extrinsic(const V3D& transl) {
133 | Lid_offset_to_IMU = transl;
134 | Lid_rot_to_IMU.setIdentity();
135 | }
136 |
137 | void ImuProcess::set_extrinsic(const V3D& transl, const M3D& rot) {
138 | Lid_offset_to_IMU = transl;
139 | Lid_rot_to_IMU = rot;
140 | }
141 |
142 | void ImuProcess::set_gyr_cov_scale(const V3D& scaler) {
143 | cov_gyr_scale = scaler;
144 | }
145 |
146 | void ImuProcess::set_acc_cov_scale(const V3D& scaler) {
147 | cov_acc_scale = scaler;
148 | }
149 |
150 | void ImuProcess::set_gyr_bias_cov(const V3D& b_g) {
151 | cov_bias_gyr = b_g;
152 | }
153 |
154 | void ImuProcess::set_acc_bias_cov(const V3D& b_a) {
155 | cov_bias_acc = b_a;
156 | }
157 |
158 | void ImuProcess::IMU_init(const MeasureGroup& meas, StatesGroup& state_inout, int& N) {
159 | /** 1. initializing the gravity, gyro bias, acc and gyro covariance
160 | ** 2. normalize the acceleration measurenments to unit gravity **/
161 | V3D cur_acc, cur_gyr;
162 |
163 | if (b_first_frame_) {
164 | Reset();
165 | N = 1;
166 | b_first_frame_ = false;
167 | const auto& imu_acc = meas.imu.front()->linear_acceleration;
168 | const auto& gyr_acc = meas.imu.front()->angular_velocity;
169 | mean_acc << imu_acc.x, imu_acc.y, imu_acc.z;
170 | mean_gyr << gyr_acc.x, gyr_acc.y, gyr_acc.z;
171 | first_lidar_time = meas.lidar_beg_time;
172 | // cout<<"init acc norm: "<linear_acceleration;
177 | const auto& gyr_acc = imu->angular_velocity;
178 | cur_acc << imu_acc.x, imu_acc.y, imu_acc.z;
179 | cur_gyr << gyr_acc.x, gyr_acc.y, gyr_acc.z;
180 |
181 | mean_acc += (cur_acc - mean_acc) / N;
182 | mean_gyr += (cur_gyr - mean_gyr) / N;
183 |
184 | cov_acc = cov_acc * (N - 1.0) / N +
185 | (cur_acc - mean_acc).cwiseProduct(cur_acc - mean_acc) * (N - 1.0) / (N * N);
186 | cov_gyr = cov_gyr * (N - 1.0) / N +
187 | (cur_gyr - mean_gyr).cwiseProduct(cur_gyr - mean_gyr) * (N - 1.0) / (N * N);
188 |
189 | // cout<<"acc norm: "<header.stamp.toSec();
209 | const double& imu_end_time = v_imu.back()->header.stamp.toSec();
210 | const double& pcl_beg_time = meas.lidar_beg_time;
211 |
212 | /*** sort point clouds by offset time ***/
213 | pcl_out = *(meas.lidar);
214 | sort(pcl_out.points.begin(), pcl_out.points.end(), time_list);
215 | const double& pcl_end_time = pcl_beg_time + pcl_out.points.back().curvature / double(1000);
216 | // cout<<"[ IMU Process ]: Process lidar from "<header.stamp.toSec() < time_last_scan_)
240 | continue;
241 |
242 | angvel_avr << 0.5 * (head->angular_velocity.x + tail->angular_velocity.x),
243 | 0.5 * (head->angular_velocity.y + tail->angular_velocity.y),
244 | 0.5 * (head->angular_velocity.z + tail->angular_velocity.z);
245 |
246 | acc_avr << 0.5 * (head->linear_acceleration.x + tail->linear_acceleration.x),
247 | 0.5 * (head->linear_acceleration.y + tail->linear_acceleration.y),
248 | 0.5 * (head->linear_acceleration.z + tail->linear_acceleration.z);
249 |
250 | angvel_avr -= state_inout.bias_g;
251 | acc_avr = acc_avr * G_m_s2 / mean_acc.norm() - state_inout.bias_a;
252 |
253 | if (head->header.stamp.toSec() < time_last_scan_) {
254 | dt = tail->header.stamp.toSec() - time_last_scan_;
255 | } else {
256 | dt = tail->header.stamp.toSec() - head->header.stamp.toSec();
257 | }
258 |
259 | /* covariance propagation */
260 | M3D acc_avr_skew;
261 | M3D Exp_f = Exp(angvel_avr, dt);
262 | acc_avr_skew << SKEW_SYM_MATRX(acc_avr);
263 |
264 | F_x.setIdentity();
265 | cov_w.setZero();
266 |
267 | F_x.block<3, 3>(0, 0) = Exp(angvel_avr, -dt);
268 | F_x.block<3, 3>(0, 9) = -Eye3d * dt;
269 | // F_x.block<3,3>(3,0) = R_imu * off_vel_skew * dt;
270 | F_x.block<3, 3>(3, 6) = Eye3d * dt;
271 | F_x.block<3, 3>(6, 0) = -R_imu * acc_avr_skew * dt;
272 | F_x.block<3, 3>(6, 12) = -R_imu * dt;
273 | F_x.block<3, 3>(6, 15) = Eye3d * dt;
274 |
275 | cov_w.block<3, 3>(0, 0).diagonal() = cov_gyr * dt * dt;
276 | cov_w.block<3, 3>(6, 6) = R_imu * cov_acc.asDiagonal() * R_imu.transpose() * dt * dt;
277 | cov_w.block<3, 3>(9, 9).diagonal() = cov_bias_gyr * dt * dt; // bias gyro covariance
278 | cov_w.block<3, 3>(12, 12).diagonal() = cov_bias_acc * dt * dt; // bias acc covariance
279 |
280 | state_inout.cov = F_x * state_inout.cov * F_x.transpose() + cov_w;
281 |
282 | /* propogation of IMU attitude */
283 | R_imu = R_imu * Exp_f;
284 |
285 | /* Specific acceleration (global frame) of IMU */
286 | acc_imu = R_imu * acc_avr + state_inout.gravity;
287 |
288 | /* propogation of IMU */
289 | pos_imu = pos_imu + vel_imu * dt + 0.5 * acc_imu * dt * dt;
290 |
291 | /* velocity of IMU */
292 | vel_imu = vel_imu + acc_imu * dt;
293 |
294 | /* save the poses at each IMU measurements */
295 | angvel_last = angvel_avr;
296 | acc_s_last = acc_imu;
297 | double&& offs_t = tail->header.stamp.toSec() - pcl_beg_time;
298 |
299 | IMUpose.push_back(set_pose6d(offs_t, acc_imu, angvel_avr, vel_imu, pos_imu, R_imu));
300 | }
301 |
302 | /*** calculated the pos and attitude prediction at the frame-end ***/
303 | if (imu_end_time > pcl_beg_time) {
304 | double note = pcl_end_time > imu_end_time ? 1.0 : -1.0;
305 | dt = note * (pcl_end_time - imu_end_time);
306 | state_inout.vel_end = vel_imu + note * acc_imu * dt;
307 | state_inout.rot_end = R_imu * Exp(V3D(note * angvel_avr), dt);
308 | state_inout.pos_end = pos_imu + note * vel_imu * dt + note * 0.5 * acc_imu * dt * dt;
309 | } else {
310 | double note = pcl_end_time > pcl_beg_time ? 1.0 : -1.0;
311 | dt = note * (pcl_end_time - pcl_beg_time);
312 | state_inout.vel_end = vel_imu + note * acc_imu * dt;
313 | state_inout.rot_end = R_imu * Exp(V3D(note * angvel_avr), dt);
314 | state_inout.pos_end = pos_imu + note * vel_imu * dt + note * 0.5 * acc_imu * dt * dt;
315 | }
316 |
317 | last_imu_ = v_imu.back();
318 | time_last_scan_ = pcl_end_time;
319 |
320 | if (pcl_out.points.empty()) {
321 | return;
322 | }
323 |
324 | /*** undistort each lidar point (backward propagation) ***/
325 | auto it_pcl = pcl_out.points.end() - 1;
326 |
327 | for (auto it_kp = IMUpose.end() - 1; it_kp != IMUpose.begin(); it_kp--) {
328 | auto head = it_kp - 1;
329 | auto tail = it_kp;
330 | R_imu << MAT_FROM_ARRAY(head->rot);
331 | acc_imu << VEC_FROM_ARRAY(head->acc);
332 |
333 | vel_imu << VEC_FROM_ARRAY(head->vel);
334 | pos_imu << VEC_FROM_ARRAY(head->pos);
335 | angvel_avr << VEC_FROM_ARRAY(head->gyr);
336 |
337 | for (; it_pcl->curvature / double(1000) > head->offset_time; it_pcl--) {
338 | dt = it_pcl->curvature / double(1000) - head->offset_time;
339 |
340 | // /* Transform to the 'end' frame, using only the rotation
341 | // * Note: Compensation direction is INVERSE of Frame's moving direction
342 | // * So if we want to compensate a point at timestamp-i to the frame-e
343 | // * P_compensate = R_imu_e ^ T * (R_i * P_i + T_ei) where T_ei is
344 | // * represented in global frame */
345 | M3D R_i(R_imu * Exp(angvel_avr, dt));
346 | V3D T_ei(pos_imu + vel_imu * dt + 0.5 * acc_imu * dt * dt - state_inout.pos_end);
347 |
348 | V3D P_i(it_pcl->x, it_pcl->y, it_pcl->z);
349 | V3D P_compensate = Lid_rot_to_IMU.transpose() *
350 | (state_inout.rot_end.transpose() *
351 | (R_i * (Lid_rot_to_IMU * P_i + Lid_offset_to_IMU) + T_ei) -
352 | Lid_offset_to_IMU);
353 | // save Undistorted points and their rotation
354 | it_pcl->x = P_compensate(0);
355 | it_pcl->y = P_compensate(1);
356 | it_pcl->z = P_compensate(2);
357 |
358 | if (it_pcl == pcl_out.points.begin())
359 | break;
360 | }
361 | }
362 | }
363 |
364 | // constant velocity model
365 | void ImuProcess::only_propag(const MeasureGroup& meas,
366 | StatesGroup& state_inout,
367 | PointCloudXYZI::Ptr& pcl_out) {
368 | const double& pcl_beg_time = meas.lidar_beg_time;
369 |
370 | /*** sort point clouds by offset time ***/
371 | pcl_out = meas.lidar;
372 | const double& pcl_end_time = pcl_beg_time + pcl_out->points.back().curvature / double(1000);
373 |
374 | MD(DIM_STATE, DIM_STATE) F_x, cov_w;
375 | double dt = 0;
376 |
377 | if (b_first_frame_) {
378 | dt = 0.1;
379 | b_first_frame_ = false;
380 | time_last_scan_ = pcl_beg_time;
381 | } else {
382 | dt = pcl_beg_time - time_last_scan_;
383 | time_last_scan_ = pcl_beg_time;
384 | }
385 |
386 | /* covariance propagation */
387 | // M3D acc_avr_skew;
388 | M3D Exp_f = Exp(state_inout.bias_g, dt);
389 |
390 | F_x.setIdentity();
391 | cov_w.setZero();
392 |
393 | F_x.block<3, 3>(0, 0) = Exp(state_inout.bias_g, -dt);
394 | F_x.block<3, 3>(0, 9) = Eye3d * dt;
395 | F_x.block<3, 3>(3, 6) = Eye3d * dt;
396 | cov_w.block<3, 3>(9, 9).diagonal() = cov_gyr * dt * dt; // for omega in constant model
397 | cov_w.block<3, 3>(6, 6).diagonal() = cov_acc * dt * dt; // for velocity in constant model
398 |
399 | state_inout.cov = F_x * state_inout.cov * F_x.transpose() + cov_w;
400 | state_inout.rot_end = state_inout.rot_end * Exp_f;
401 | state_inout.pos_end = state_inout.pos_end + state_inout.vel_end * dt;
402 | }
403 |
404 | void ImuProcess::Process(const MeasureGroup& meas,
405 | StatesGroup& stat,
406 | PointCloudXYZI::Ptr& cur_pcl_un_) {
407 | double t1, t2, t3;
408 |
409 | if (meas.imu.empty() && imu_en) {
410 | return;
411 | }
412 | ROS_ASSERT(meas.lidar != nullptr);
413 |
414 | if (imu_need_init_ && imu_en) {
415 | /// The very first lidar frame
416 | IMU_init(meas, stat, init_iter_num);
417 |
418 | imu_need_init_ = true;
419 |
420 | last_imu_ = meas.imu.back();
421 |
422 | if (init_iter_num > MAX_INI_COUNT) {
423 | imu_need_init_ = false;
424 |
425 | cov_acc = cov_acc_scale;
426 | cov_gyr = cov_gyr_scale;
427 |
428 | ROS_INFO("IMU Initial Done!");
429 | ROS_INFO("Gravity: %.4f %.4f %.4f %.4f; state.bias_g: %.8f "
430 | "%.8f %.8f; acc covarience: %.8f %.8f %.8f; gry covarience: "
431 | "%.8f %.8f %.8f",
432 | stat.gravity[0],
433 | stat.gravity[1],
434 | stat.gravity[2],
435 | mean_acc.norm(),
436 | cov_bias_gyr[0],
437 | cov_bias_gyr[1],
438 | cov_bias_gyr[2],
439 | cov_acc[0],
440 | cov_acc[1],
441 | cov_acc[2],
442 | cov_gyr[0],
443 | cov_gyr[1],
444 | cov_gyr[2]);
445 | }
446 |
447 | return;
448 | }
449 |
450 | /// Undistort points: the first point is assummed as the base frame
451 | /// Compensate lidar points with IMU rotation (with only rotation now)
452 | if (imu_en) {
453 | // cout << "Use IMU" << endl;
454 | UndistortPcl(meas, stat, *cur_pcl_un_);
455 | last_imu_ = meas.imu.back();
456 | } else {
457 | // cout << "No IMU, use constant velocity model" << endl;
458 | cov_acc = Eye3d * cov_acc_scale;
459 | cov_gyr = Eye3d * cov_gyr_scale;
460 | only_propag(meas, stat, cur_pcl_un_);
461 | }
462 | }
--------------------------------------------------------------------------------
/src/preprocess.cpp:
--------------------------------------------------------------------------------
1 | #include "preprocess.h"
2 |
3 | #define RETURN0 0x00
4 | #define RETURN0AND1 0x10
5 |
6 | Preprocess::Preprocess() : feature_enabled(0), lidar_type(AVIA), blind(0.01), point_filter_num(1) {
7 | N_SCANS = 6;
8 | given_offset_time = false;
9 | }
10 |
11 | Preprocess::~Preprocess() {}
12 |
13 | void Preprocess::set(bool feat_en, int lid_type, double bld, int pfilt_num) {
14 | feature_enabled = feat_en;
15 | lidar_type = lid_type;
16 | blind = bld;
17 | point_filter_num = pfilt_num;
18 | }
19 |
20 | void Preprocess::process(const livox_ros_driver::CustomMsg::ConstPtr& msg,
21 | PointCloudXYZI::Ptr& pcl_out) {
22 | avia_handler(msg);
23 | *pcl_out = pl_surf;
24 | }
25 |
26 | void Preprocess::process(const sensor_msgs::PointCloud2::ConstPtr& msg,
27 | PointCloudXYZI::Ptr& pcl_out) {
28 | switch (lidar_type) {
29 | case L515:
30 | l515_handler(msg);
31 | break;
32 |
33 | case VELO16:
34 | velodyne_handler(msg);
35 | break;
36 |
37 | case VELO32:
38 | velodyne_handler32(msg);
39 | break;
40 |
41 | default:
42 | printf("Error LiDAR Type");
43 | break;
44 | }
45 | *pcl_out = pl_surf;
46 | }
47 |
48 | void Preprocess::avia_handler(const livox_ros_driver::CustomMsg::ConstPtr& msg) {
49 | pl_surf.clear();
50 | pl_corn.clear();
51 | pl_full.clear();
52 | int plsize = msg->point_num;
53 | std::vector is_valid_pt(plsize, false);
54 |
55 | pl_corn.reserve(plsize);
56 | pl_surf.reserve(plsize);
57 | pl_full.resize(plsize);
58 |
59 | for (int i = 0; i < N_SCANS; i++) {
60 | pl_buff[i].clear();
61 | pl_buff[i].reserve(plsize);
62 | }
63 | uint valid_num = 0;
64 |
65 | for (uint i = 1; i < plsize; i++) {
66 | if ((msg->points[i].line < N_SCANS) &&
67 | ((msg->points[i].tag & 0x30) == 0x10 || (msg->points[i].tag & 0x30) == 0x00)) {
68 | valid_num++;
69 | if (i % point_filter_num == 0) {
70 | pl_full[i].x = msg->points[i].x;
71 | pl_full[i].y = msg->points[i].y;
72 | pl_full[i].z = msg->points[i].z;
73 | pl_full[i].intensity = msg->points[i].reflectivity;
74 | pl_full[i].curvature = msg->points[i].offset_time /
75 | float(1000000); // use curvature as time of each laser points
76 |
77 | if ((abs(pl_full[i].x - pl_full[i - 1].x) > 1e-7) ||
78 | (abs(pl_full[i].y - pl_full[i - 1].y) > 1e-7) ||
79 | (abs(pl_full[i].z - pl_full[i - 1].z) > 1e-7) &&
80 | (pl_full[i].x * pl_full[i].x + pl_full[i].y * pl_full[i].y + pl_full[i].z +
81 | pl_full[i].z >
82 | blind * blind)) {
83 | is_valid_pt[i] = true;
84 | }
85 | }
86 | }
87 | }
88 |
89 | for (uint i = 1; i < plsize; i++) {
90 | if (is_valid_pt[i]) {
91 | pl_surf.points.push_back(pl_full[i]);
92 | }
93 | }
94 | }
95 |
96 | void Preprocess::oust64_handler(const sensor_msgs::PointCloud2::ConstPtr& msg) {
97 | pl_surf.clear();
98 | pl_corn.clear();
99 | pl_full.clear();
100 | pcl::PointCloud pl_orig;
101 | pcl::fromROSMsg(*msg, pl_orig);
102 | int plsize = pl_orig.size();
103 | pl_corn.reserve(plsize);
104 | pl_surf.reserve(plsize);
105 |
106 | double time_stamp = msg->header.stamp.toSec();
107 | // cout << "===================================" << endl;
108 | // printf("Pt size = %d, N_SCANS = %d\r\n", plsize, N_SCANS);
109 | for (int i = 0; i < pl_orig.points.size(); i++) {
110 | if (i % point_filter_num != 0)
111 | continue;
112 |
113 | double range = pl_orig.points[i].x * pl_orig.points[i].x +
114 | pl_orig.points[i].y * pl_orig.points[i].y +
115 | pl_orig.points[i].z * pl_orig.points[i].z;
116 |
117 | if (range < blind)
118 | continue;
119 |
120 | Eigen::Vector3d pt_vec;
121 | PointType added_pt;
122 | added_pt.x = pl_orig.points[i].x;
123 | added_pt.y = pl_orig.points[i].y;
124 | added_pt.z = pl_orig.points[i].z;
125 | added_pt.intensity = pl_orig.points[i].intensity;
126 | added_pt.normal_x = 0;
127 | added_pt.normal_y = 0;
128 | added_pt.normal_z = 0;
129 | double yaw_angle = atan2(added_pt.y, added_pt.x) * 57.3;
130 | if (yaw_angle >= 180.0)
131 | yaw_angle -= 360.0;
132 | if (yaw_angle <= -180.0)
133 | yaw_angle += 360.0;
134 |
135 | added_pt.curvature = pl_orig.points[i].t / 1e6;
136 |
137 | pl_surf.points.push_back(added_pt);
138 | }
139 | }
140 |
141 | void Preprocess::l515_handler(const sensor_msgs::PointCloud2::ConstPtr& msg) {
142 | pl_surf.clear();
143 | pcl::PointCloud pl_orig;
144 | pcl::fromROSMsg(*msg, pl_orig);
145 | int plsize = pl_orig.points.size();
146 | // pl_surf.reserve(plsize);
147 | for (int i = 0; i < pl_orig.size(); i++) {
148 | PointType added_pt;
149 | added_pt.x = pl_orig.points[i].x;
150 | added_pt.y = pl_orig.points[i].y;
151 | added_pt.z = pl_orig.points[i].z;
152 | added_pt.intensity = pl_orig.points[i].intensity;
153 | double range = pl_orig.points[i].x * pl_orig.points[i].x +
154 | pl_orig.points[i].y * pl_orig.points[i].y +
155 | pl_orig.points[i].z * pl_orig.points[i].z;
156 |
157 | if (range < blind)
158 | continue;
159 |
160 | if (i % point_filter_num == 0) {
161 | pl_surf.push_back(added_pt);
162 | }
163 | }
164 | }
165 |
166 | #define MAX_LINE_NUM 64
167 |
168 | void Preprocess::velodyne_handler(const sensor_msgs::PointCloud2::ConstPtr& msg) {
169 | pl_surf.clear();
170 | pl_corn.clear();
171 | pl_full.clear();
172 |
173 | pcl::PointCloud pl_orig;
174 | pcl::fromROSMsg(*msg, pl_orig);
175 | int plsize = pl_orig.points.size();
176 | // pl_surf.reserve(plsize);
177 | for (int i = 0; i < pl_orig.size(); i++) {
178 | PointType added_pt;
179 | added_pt.x = pl_orig.points[i].x;
180 | added_pt.y = pl_orig.points[i].y;
181 | added_pt.z = pl_orig.points[i].z;
182 | added_pt.intensity = pl_orig.points[i].intensity;
183 | float angle = atan(added_pt.z / sqrt(added_pt.x * added_pt.x + added_pt.y * added_pt.y)) * 180 /
184 | M_PI;
185 | int scanID = 0;
186 | if (angle >= -8.83)
187 | scanID = int((2 - angle) * 3.0 + 0.5);
188 | else
189 | scanID = N_SCANS / 2 + int((-8.83 - angle) * 2.0 + 0.5);
190 |
191 | // use [0 50] > 50 remove outlies
192 | if (angle > 2 || angle < -24.33 || scanID > 50 || scanID < 0) {
193 | continue;
194 | }
195 | pl_surf.push_back(added_pt);
196 | }
197 | }
198 |
199 | void Preprocess::velodyne_handler32(const sensor_msgs::PointCloud2::ConstPtr& msg) {
200 | pl_surf.clear();
201 | pl_corn.clear();
202 | pl_full.clear();
203 |
204 | pcl::PointCloud pl_orig;
205 | pcl::fromROSMsg(*msg, pl_orig);
206 | int plsize = pl_orig.points.size();
207 |
208 | /*** These variables only works when no point timestamps given ***/
209 | double omega_l = 3.61; // scan angular velocity
210 | std::vector is_first(N_SCANS, true);
211 | std::vector yaw_fp(N_SCANS, 0.0); // yaw of first scan point
212 | std::vector yaw_last(N_SCANS, 0.0); // yaw of last scan point
213 | std::vector time_last(N_SCANS, 0.0); // last offset time
214 | /*****************************************************************/
215 |
216 | if (pl_orig.points[plsize - 1].time > 0) {
217 | given_offset_time = true;
218 | } else {
219 | given_offset_time = false;
220 | double yaw_first = atan2(pl_orig.points[0].y, pl_orig.points[0].x) * 57.29578;
221 | double yaw_end = yaw_first;
222 | int layer_first = pl_orig.points[0].ring;
223 | for (uint i = plsize - 1; i > 0; i--) {
224 | if (pl_orig.points[i].ring == layer_first) {
225 | yaw_end = atan2(pl_orig.points[i].y, pl_orig.points[i].x) * 57.29578;
226 | break;
227 | }
228 | }
229 | }
230 |
231 | for (int i = 0; i < plsize; i++) {
232 | PointType added_pt;
233 |
234 | added_pt.normal_x = 0;
235 | added_pt.normal_y = 0;
236 | added_pt.normal_z = 0;
237 | added_pt.x = pl_orig.points[i].x;
238 | added_pt.y = pl_orig.points[i].y;
239 | added_pt.z = pl_orig.points[i].z;
240 | added_pt.intensity = pl_orig.points[i].intensity;
241 | added_pt.curvature = pl_orig.points[i].time * 1e-3; // curvature unit: ms
242 |
243 | if (!given_offset_time) {
244 | int layer = pl_orig.points[i].ring;
245 | double yaw_angle = atan2(added_pt.y, added_pt.x) * 57.2957;
246 |
247 | if (is_first[layer]) {
248 | yaw_fp[layer] = yaw_angle;
249 | is_first[layer] = false;
250 | added_pt.curvature = 0.0;
251 | yaw_last[layer] = yaw_angle;
252 | time_last[layer] = added_pt.curvature;
253 | continue;
254 | }
255 |
256 | // compute offset time
257 | if (yaw_angle <= yaw_fp[layer]) {
258 | added_pt.curvature = (yaw_fp[layer] - yaw_angle) / omega_l;
259 | } else {
260 | added_pt.curvature = (yaw_fp[layer] - yaw_angle + 360.0) / omega_l;
261 | }
262 |
263 | if (added_pt.curvature < time_last[layer])
264 | added_pt.curvature += 360.0 / omega_l;
265 |
266 | yaw_last[layer] = yaw_angle;
267 | time_last[layer] = added_pt.curvature;
268 | }
269 |
270 | if (i % point_filter_num == 0) {
271 | if (added_pt.x * added_pt.x + added_pt.y * added_pt.y + added_pt.z * added_pt.z >
272 | (blind * blind)) {
273 | pl_surf.push_back(added_pt);
274 | }
275 | }
276 | }
277 | }
278 |
--------------------------------------------------------------------------------
/src/preprocess.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | using namespace std;
7 |
8 | #define IS_VALID(a) ((abs(a) > 1e8) ? true : false)
9 |
10 | typedef pcl::PointXYZINormal PointType;
11 | typedef pcl::PointCloud PointCloudXYZI;
12 |
13 | enum LID_TYPE { AVIA = 1, VELO16, L515, OUSTER64, VELO32 }; //{1, 2, 3}
14 |
15 | namespace velodyne_ros {
16 | struct EIGEN_ALIGN16 Point {
17 | PCL_ADD_POINT4D;
18 | float intensity;
19 | float time;
20 | uint16_t ring;
21 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW
22 | };
23 | } // namespace velodyne_ros
24 | POINT_CLOUD_REGISTER_POINT_STRUCT(velodyne_ros::Point,
25 | (float, x, x)(float, y, y)(float, z, z)(
26 | float,
27 | intensity,
28 | intensity)(float, time, time)(std::uint16_t, ring, ring))
29 |
30 | namespace ouster_ros {
31 | struct EIGEN_ALIGN16 Point {
32 | PCL_ADD_POINT4D;
33 | float intensity;
34 | uint32_t t;
35 | uint16_t reflectivity;
36 | uint8_t ring;
37 | uint16_t ambient;
38 | uint32_t range;
39 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW
40 | };
41 | } // namespace ouster_ros
42 |
43 | // clang-format off
44 | POINT_CLOUD_REGISTER_POINT_STRUCT(ouster_ros::Point,
45 | (float, x, x)
46 | (float, y, y)
47 | (float, z, z)
48 | (float, intensity, intensity)
49 | // use std::uint32_t to avoid conflicting with pcl::uint32_t
50 | (std::uint32_t, t, t)
51 | (std::uint16_t, reflectivity, reflectivity)
52 | (std::uint8_t, ring, ring)
53 | (std::uint16_t, ambient, ambient)
54 | (std::uint32_t, range, range)
55 | )
56 |
57 | class Preprocess
58 | {
59 | public:
60 | // EIGEN_MAKE_ALIGNED_OPERATOR_NEW
61 |
62 | Preprocess();
63 | ~Preprocess();
64 |
65 | void process(const livox_ros_driver::CustomMsg::ConstPtr &msg, PointCloudXYZI::Ptr &pcl_out);
66 | void process(const sensor_msgs::PointCloud2::ConstPtr &msg, PointCloudXYZI::Ptr &pcl_out);
67 | void set(bool feat_en, int lid_type, double bld, int pfilt_num);
68 |
69 | // sensor_msgs::PointCloud2::ConstPtr pointcloud;
70 | PointCloudXYZI pl_full, pl_corn, pl_surf;
71 | PointCloudXYZI pl_buff[128]; //maximum 128 line lidar
72 | int lidar_type, point_filter_num, N_SCANS;;
73 | double blind;
74 | bool feature_enabled, given_offset_time;
75 | ros::Publisher pub_full, pub_surf, pub_corn;
76 |
77 |
78 | private:
79 | void avia_handler(const livox_ros_driver::CustomMsg::ConstPtr &msg);
80 | void oust64_handler(const sensor_msgs::PointCloud2::ConstPtr &msg);
81 | void l515_handler(const sensor_msgs::PointCloud2::ConstPtr &msg);
82 | void velodyne_handler(const sensor_msgs::PointCloud2::ConstPtr &msg);
83 | void velodyne_handler32(const sensor_msgs::PointCloud2::ConstPtr& msg);
84 |
85 | };
86 |
--------------------------------------------------------------------------------
/src/voxelMapping.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include