├── CMakeLists.txt
├── README.md
├── config
├── exp_config
│ └── exp_port.yaml
└── rviz_config
│ └── lins_rviz_config.rviz
├── include
├── Estimator.h
├── KalmanFilter.hpp
├── LidarIris.h
├── MapRingBuffer.h
├── StateEstimator.hpp
├── fftm
│ └── fftm.hpp
├── gps_common
│ └── conversions.h
├── integrationBase.h
├── math_utils.h
├── parameters.h
├── sc_lego_loam
│ ├── KDTreeVectorOfVectorsAdaptor.h
│ ├── Scancontext.h
│ ├── nanoflann.hpp
│ └── tictoc.h
├── sensor_utils.hpp
├── tic_toc.h
├── utility.h
└── xmldom
│ └── XmlDomDocument.h
├── launch
├── ImuOdometry.rviz
├── exp_launch
│ ├── GDUTdemo.gps
│ ├── KITTIdemo.gps
│ ├── KITTIdemo2.gps
│ ├── demo.rviz
│ ├── run_port_exp.launch
│ └── satellite.rviz
├── imuOdometry.launch
├── localization.launch
├── localization_demo.rviz
└── staticTFpub.launch
├── lins.kdev4
├── log.md
├── package.xml
├── pic
├── GPSdetector1.png
├── GPSdetector2.png
├── IMU_GPS_LIDAR_Traj.png
├── global_graph.png
├── kitti_mapping_evo1.png
├── kitti_mapping_evo2.png
├── kitti_mapping_with_gps.png
├── kitti_mapping_without_gps.png
├── loop compared.png
├── vehicle and sensor mounting.png
└── 融合建图效果2.png
├── src
├── ImuFactorDemo.cpp
├── LidarIris.cpp
├── fftm.cpp
├── image_projection_node.cpp
├── lib
│ ├── Estimator.cpp
│ ├── Scancontext.cpp
│ ├── XmlDomDocument.cpp
│ └── parameters.cpp
├── lidar_mapping_node.cpp
├── lins_fusion_node.cpp
├── mapLocalization.cpp
├── staticTFpub_node.cpp
└── transform_fusion_node.cpp
└── urdf
└── smartcar.urdf
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.1.0)
2 | project(lins)
3 |
4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -O3")
5 | set(CMAKE_CXX_STANDARD 14)
6 | SET(CMAKE_BUILD_TYPE Release)
7 |
8 | # set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "/usr/lib/x86_64-linux-gnu/cmake")
9 | # set(OpenCV_DIR "/usr/local/share/OpenCV")
10 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "/usr/share/cmake/geographiclib/")
11 |
12 | find_package(catkin REQUIRED COMPONENTS
13 | cloud_msgs
14 | cv_bridge
15 | geometry_msgs
16 | image_transport
17 | nav_msgs
18 | pcl_conversions
19 | pcl_ros
20 | roscpp
21 | rospy
22 | sensor_msgs
23 | std_msgs
24 | tf
25 | sleipnir_msgs
26 | # livox_ros_driver
27 | )
28 |
29 | find_package(GTSAM REQUIRED QUIET)
30 | find_package(PCL REQUIRED QUIET)
31 | find_package(OpenCV 3 REQUIRED QUIET)
32 | find_package(Eigen3 3.3 REQUIRED)
33 | find_package (GeographicLib REQUIRED)
34 |
35 | # message(WARNING " OpenCV library status:")
36 | # message(WARNING " config: ${OpenCV_DIR}")
37 | # message(WARNING " version: ${OpenCV_VERSION}")
38 | # message(WARNING " libraries: ${OpenCV_LIBS}")
39 | # message(WARNING " include path: ${OpenCV_INCLUDE_DIRS}")
40 |
41 | catkin_package(
42 | INCLUDE_DIRS include
43 | CATKIN_DEPENDS cloud_msgs
44 | DEPENDS PCL
45 | )
46 |
47 |
48 | include_directories(
49 | include
50 | ${catkin_INCLUDE_DIRS}
51 | ${PCL_INCLUDE_DIRS}
52 | ${OpenCV_INCLUDE_DIRS}
53 | ${GTSAM_INCLUDE_DIR}
54 | ${EIGEN3_INCLUDE_DIR}
55 | )
56 |
57 | link_directories(
58 | include
59 | ${OpenCV_LIBRARY_DIRS}
60 | ${PCL_LIBRARY_DIRS}
61 | ${GTSAM_LIBRARY_DIRS}
62 | )
63 |
64 |
65 | list(APPEND SOURCE_FILES
66 | ${PROJECT_SOURCE_DIR}/src/lib/parameters.cpp
67 | )
68 |
69 | list(APPEND LINS_FILES
70 | ${PROJECT_SOURCE_DIR}/src/lins_fusion_node.cpp
71 | ${PROJECT_SOURCE_DIR}/src/lib/Estimator.cpp
72 | )
73 |
74 | list(APPEND LINK_LIBS
75 | ${OpenCV_LIBS}
76 | ${catkin_LIBRARIES}
77 | ${PCL_LIBRARIES}
78 | ${OpenCV_LIBRARY_DIRS}
79 | ${GeographicLib_LIBRARIES}
80 | )
81 |
82 | add_executable(lins_fusion_node ${LINS_FILES} ${SOURCE_FILES})
83 | target_link_libraries(lins_fusion_node ${LINK_LIBS})
84 |
85 | add_executable(image_projection_node src/image_projection_node.cpp ${SOURCE_FILES})
86 | # add_dependencies(image_projection_node ${catkin_EXPORTED_TARGETS} cloud_msgs_gencpp)
87 | target_link_libraries(image_projection_node ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${OpenCV_LIBRARIES})
88 |
89 | add_executable(lidar_mapping_node src/lidar_mapping_node.cpp ${SOURCE_FILES} src/lib/Scancontext.cpp src/LidarIris.cpp src/fftm.cpp)
90 | target_link_libraries(lidar_mapping_node ${LINK_LIBS} gtsam Eigen3::Eigen)
91 |
92 | add_executable(transform_fusion_node src/transform_fusion_node.cpp ${SOURCE_FILES})
93 | target_link_libraries(transform_fusion_node ${LINK_LIBS})
94 |
95 | add_executable(mapLocalization src/mapLocalization.cpp ${SOURCE_FILES})
96 | target_link_libraries(mapLocalization ${LINK_LIBS} gtsam Eigen3::Eigen)
97 |
98 | add_executable(ImuFactorDemo
99 | src/ImuFactorDemo.cpp
100 | )
101 | target_link_libraries(ImuFactorDemo
102 | ${catkin_LIBRARIES}
103 | ${PCL_LIBRARIES}
104 | ${OpenCV_LIBRARIES}
105 | gtsam
106 | Eigen3::Eigen
107 | )
108 |
109 | add_executable(staticTFpub_node src/staticTFpub_node.cpp src/lib/XmlDomDocument.cpp ${SOURCE_FILES})
110 | target_link_libraries(staticTFpub_node ${catkin_LIBRARIES} -lxerces-c)
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # lins-gps-iris
2 |
3 | We propose a system that can fuse IMU, LiDAR and intermittent GPS measurements to achieve high precision localization and mapping in large-scale environment. The Iterated Error-State Kalman Filter (IESKF) is used to fuse IMU and LiDAR measurements to estimate relative motion information quickly. Based on the factor graph, LiDAR, GPS measurements and loop-closure are transformed into constraints for joint-optimization to construct global map. A real-time GPS outlier detection method based on IMU pre-integration theory and residual chi-square test is designed. In addition, the use of robust kernel is supported to implicitly reduce the impact of undetected GPS outliers on the system. A LiDAR-based loop-closure detector is designed, which can search for a pair of point clouds with similar geometric information.
4 |
5 | 
6 |
7 | ## System architecture
8 |
9 | 
10 |
11 |
12 |
13 | The main contributions can be summarized as follows:
14 |
15 | 1) An IESKF is applied to tightly couple IMU and LiDAR to implement LIO algorithm. The motion information can be estimated by LIO quickly and accurately.
16 |
17 | 2) A robust and sensitive GPS outlier detection method is proposed. It can detect GPS outliers and reduce the impact of outliers on the system.
18 |
19 | 3) A lightweight and precise loop-closure detection method is proposed. It can evaluate the similarity between point clouds, and correct the error in pose graph.
20 |
21 | ## Dependency
22 |
23 | * [ROS](http://wiki.ros.org/ROS/Installation) (tested with Melodic)
24 | * [gtsam](https://github.com/borglab/gtsam/releases) (Georgia Tech Smoothing and Mapping library)
25 | * [cloud_msgs](https://github.com/RobustFieldAutonomyLab/LeGO-LOAM/tree/master/cloud_msgs)
26 | * [xw_gps_driver](https://github.com/kuzen/xw_gps_driver)
27 |
28 | ## Install
29 |
30 | ```
31 | cd ~/catkin_ws/stc
32 | git clone https://github.com/GDUT-Kyle/lins-gps-iris.git
33 | cd ..
34 | catkin build lins
35 | ```
36 |
37 | ## Notes
38 |
39 | 1. The system can set the dynamic parameter "useGPSfactor" in the launch file to determine whether it needs to integrate GPS data.
40 | 2. If the GPS data is integrated, the user needs to calibrate the GPS module and the external parameters of the LiDAR in advance.
41 | 3. After setting "SaveMap" to true, the mapping module of this system can save the feature point map for relocation.
42 | 4. In this system, GPS data is our custom ROS message type, users can refer to [xw_gps_driver](https://github.com/kuzen/xw_gps_driver).
43 |
44 | ## Sample datasets
45 |
46 | **Our own collected datasets contain high-precision mapping information. Since we do not have surveying and mapping qualifications, we do not share the dataset due to legal issues.**
47 |
48 | ## Run
49 |
50 | ### A. Mapping
51 |
52 | ```
53 | roslaunch lins imuOdometry.launch
54 | roslaunch lins run_port_exp.launch
55 | ```
56 |
57 | ### B. Localization
58 |
59 | ```
60 | roslaunch lins localization.launch
61 | ```
62 |
63 | ## Experimental results
64 |
65 | ### A. GPS-Challenge environment test (KITTI)
66 |
67 |
68 |
69 |
(a) Raw GPS measurements
70 |
71 |
72 |
73 | (b) Proposed method (with GPS)
74 |
75 | 
76 |
77 | (c) Mapping (without GPS)
78 |
79 | 
80 |
81 | (d) Mapping (with GPS)
82 |
83 | 
84 |
85 | 
86 |
87 | ### B. Loop-Closure test
88 |
89 |
90 |
91 | ## References
92 |
93 | [LeGO-LOAM](https://github.com/RobustFieldAutonomyLab/LeGO-LOAM)
94 |
95 | [LINS---LiDAR-inertial-SLAM](https://github.com/ChaoqinRobotics/LINS---LiDAR-inertial-SLAM)
96 |
97 | [SC-LeGO-LOAM](https://github.com/irapkaist/SC-LeGO-LOAM)
98 |
99 | [LiDAR-Iris](https://github.com/JoestarK/LiDAR-Iris)
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/config/exp_config/exp_port.yaml:
--------------------------------------------------------------------------------
1 | %YAML:1.0
2 |
3 | # settings
4 | calibrate_imu: 0 # 0: no imu calibration and use default values. 1: calibrate imu
5 | show_configuration: 0
6 | average_nums: 100
7 | imu_lidar_extrinsic_angle: 0.0
8 | imu_misalign_angle: 0.0
9 | line_num: 16
10 | scan_num: 1800
11 | scan_period: 0.1
12 | edge_threshold: 1.0
13 | surf_threshold: 0.1
14 | nearest_feature_search_sq_dist: 25
15 | verbose: 0
16 | icp_freq: 1
17 | max_lidar_nums: 200000
18 | num_iter: 30
19 | lidar_scale: 1
20 | lidar_std: 0.01
21 |
22 | # topic names
23 | imu_topic: "/imu/data"
24 | lidar_topic: "/sensing/lidar/rslidar_points"
25 | lidar_odometry_topic: "/laser_odom_to_init"
26 | lidar_mapping_topic: "/integrated_to_init"
27 |
28 | # kyle parameters
29 | # OriLon: 113.387985229
30 | # OriLat: 23.040807724
31 | # OriAlt: 2.96000003815
32 | # OriYaw: 76.1139984131
33 | # OriPitch: -1.33500003815
34 | # OriRoll: 1.82000005245
35 | # compensate_init_yaw: 0.03
36 | # compensate_init_pitch: 0.0
37 | # compensate_init_roll: 0.0
38 |
39 | # noice parameters
40 | acc_n: 70000
41 | gyr_n: 0.1
42 | acc_w: 500
43 | gyr_w: 0.05
44 |
45 | init_pos_std: !!opencv-matrix
46 | rows: 3
47 | cols: 1
48 | dt: d
49 | data: [0.0, 0.0, 0.0]
50 |
51 | init_vel_std: !!opencv-matrix
52 | rows: 3
53 | cols: 1
54 | dt: d
55 | data: [0.0, 0.0, 0.0]
56 |
57 | init_att_std: !!opencv-matrix
58 | rows: 3
59 | cols: 1
60 | dt: d
61 | data: [0.0, 0.0, 0.0]
62 |
63 | init_acc_std: !!opencv-matrix
64 | rows: 3
65 | cols: 1
66 | dt: d
67 | data: [0.01, 0.01, 0.02]
68 |
69 | init_gyr_std: !!opencv-matrix
70 | rows: 3
71 | cols: 1
72 | dt: d
73 | data: [0.002, 0.002, 0.002]
74 |
75 | # initial IMU biases
76 | init_ba: !!opencv-matrix
77 | rows: 3
78 | cols: 1
79 | dt: d
80 | data: [-0.015774,0.143237,-0.0263845]
81 |
82 | init_bw: !!opencv-matrix
83 | rows: 3
84 | cols: 1
85 | dt: d
86 | data: [-0.00275058,-0.000165954,0.00262913]
87 |
88 | # extrinsic parameters
89 | init_tbl: !!opencv-matrix
90 | rows: 3
91 | cols: 1
92 | dt: d
93 | data: [0.0,0.0,0.0]
94 |
95 | init_rbl: !!opencv-matrix
96 | rows: 3
97 | cols: 3
98 | dt: d
99 | data: [1, 0, 0,
100 | 0, 1, 0,
101 | 0, 0, 1]
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/include/Estimator.h:
--------------------------------------------------------------------------------
1 | // This file is part of LINS.
2 | //
3 | // Copyright (C) 2020 Chao Qin ,
4 | // Robotics and Multiperception Lab (RAM-LAB ),
5 | // The Hong Kong University of Science and Technology
6 | //
7 | // Redistribution and use in source and binary forms, with or without
8 | // modification, are permitted provided that the following conditions are met:
9 | // 1. Redistributions of source code must retain the above copyright notice,
10 | // this list of conditions and the following disclaimer.
11 | // 2. Redistributions in binary form must reproduce the above copyright notice,
12 | // this list of conditions and the following disclaimer in the documentation
13 | // and/or other materials provided with the distribution.
14 | // 3. Neither the name of the copyright holder nor the names of its
15 | // contributors may be used to endorse or promote products derived from this
16 | // software without specific prior written permission.
17 |
18 | #ifndef INCLUDE_ESTIMATOR_H_
19 | #define INCLUDE_ESTIMATOR_H_
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 |
41 | #include
42 | #include
43 | #include
44 | #include
45 | #include
46 | #include
47 |
48 | #include "cloud_msgs/cloud_info.h"
49 |
50 | using namespace std;
51 | using namespace Eigen;
52 | using namespace math_utils;
53 | using namespace sensor_utils;
54 |
55 | namespace fusion {
56 |
57 | class LinsFusion {
58 | public:
59 | LinsFusion(ros::NodeHandle& nh, ros::NodeHandle& pnh);
60 | // 析构函数,删除该对象
61 | ~LinsFusion();
62 |
63 | // 主功能函数
64 | void run();
65 | // 初始化函数,设置topic的定义和发布,开辟一些必要的空间,然后就一直等待回调函数
66 | void initialization();
67 | void publishTopics();
68 | // 发布lidar odometry的里程计信息和tf
69 | void publishOdometryYZX(double timeStamp);
70 | inline void publishCloudMsg(ros::Publisher& publisher,
71 | pcl::PointCloud::Ptr cloud,
72 | const ros::Time& stamp,
73 | const std::string& frameID) {
74 | sensor_msgs::PointCloud2 msg;
75 | pcl::toROSMsg(*cloud, msg);
76 | msg.header.stamp = stamp;
77 | msg.header.frame_id = frameID;
78 | publisher.publish(msg);
79 | }
80 |
81 | void imuCallback(const sensor_msgs::Imu::ConstPtr& imuIn);
82 | void laserCloudCallback(
83 | const sensor_msgs::PointCloud2ConstPtr& laserCloudMsg);
84 | void laserCloudInfoCallback(const cloud_msgs::cloud_infoConstPtr& msgIn);
85 | void outlierCloudCallback(
86 | const sensor_msgs::PointCloud2ConstPtr& laserCloudMsg);
87 | // Map-refined odom. feedback (1 Hz)
88 | void mapOdometryCallback(const nav_msgs::Odometry::ConstPtr& odometryMsg);
89 |
90 | // 执行IKF进行状态估计
91 | void performStateEstimation();
92 | void processFirstPointCloud();
93 | bool processPointClouds();
94 | void performImuBiasEstimation();
95 | void alignIMUtoVehicle(const V3D& rpy, const V3D& acc_in, const V3D& gyr_in,
96 | V3D& acc_out, V3D& gyr_out);
97 |
98 | private:
99 | ros::NodeHandle nh_;
100 | ros::NodeHandle pnh_;
101 |
102 | // !@StateEstimator
103 | StateEstimator* estimator;
104 |
105 | // !@Subscriber
106 | ros::Subscriber subLaserCloud;
107 | ros::Subscriber subLaserCloudInfo;
108 | ros::Subscriber subOutlierCloud;
109 | ros::Subscriber subImu;
110 | ros::Subscriber subGPS_;
111 | ros::Subscriber subMapOdom_;
112 |
113 | // !@Publishers
114 | ros::Publisher pubUndistortedPointCloud;
115 |
116 | ros::Publisher pubCornerPointsSharp;
117 | ros::Publisher pubCornerPointsLessSharp;
118 | ros::Publisher pubSurfPointsFlat;
119 | ros::Publisher pubSurfPointsLessFlat;
120 |
121 | ros::Publisher pubLaserCloudCornerLast;
122 | ros::Publisher pubLaserCloudSurfLast;
123 | ros::Publisher pubOutlierCloudLast;
124 |
125 | ros::Publisher pubLaserOdometry;
126 | ros::Publisher pubIMUOdometry;
127 | ros::Publisher pubGpsOdometry;
128 |
129 | ros::Publisher pubLaserOdom;
130 |
131 | // !@PointCloudPtrs
132 | pcl::PointCloud::Ptr distortedPointCloud; // 畸变点云?
133 | pcl::PointCloud::Ptr outlierPointCloud; // 局外点云
134 |
135 | // !@Messages
136 | nav_msgs::Odometry laserOdom;
137 | nav_msgs::Odometry laserOdometry;
138 | nav_msgs::Odometry imuOdometry;
139 | nav_msgs::Odometry gpsOdometry;
140 |
141 | // !@Buffers
142 | MapRingBuffer imuBuf_;
143 | MapRingBuffer pclBuf_;
144 | MapRingBuffer outlierBuf_;
145 | MapRingBuffer cloudInfoBuf_;
146 | MapRingBuffer gpsBuf_;
147 |
148 | // !@Time
149 | int scan_counter_;
150 | double duration_;
151 |
152 | // !@Measurements
153 | V3D acc_raw_;
154 | V3D gyr_raw_;
155 | V3D acc_aligned_;
156 | V3D gyr_aligned_;
157 | V3D misalign_euler_angles_;
158 | V3D ba_tmp_;
159 | V3D bw_tmp_;
160 | V3D ba_init_;
161 | V3D bw_init_;
162 | double scan_time_;
163 | double last_imu_time_;
164 | double last_scan_time_;
165 | int sample_counter_;
166 | bool isInititialized;
167 | bool isImuCalibrated;
168 | };
169 | } // namespace fusion
170 |
171 | #endif // INCLUDE_ESTIMATOR_H_
172 |
--------------------------------------------------------------------------------
/include/KalmanFilter.hpp:
--------------------------------------------------------------------------------
1 | // This file is part of LINS.
2 | //
3 | // Copyright (C) 2020 Chao Qin ,
4 | // Robotics and Multiperception Lab (RAM-LAB ),
5 | // The Hong Kong University of Science and Technology
6 | //
7 | // Redistribution and use in source and binary forms, with or without
8 | // modification, are permitted provided that the following conditions are met:
9 | // 1. Redistributions of source code must retain the above copyright notice,
10 | // this list of conditions and the following disclaimer.
11 | // 2. Redistributions in binary form must reproduce the above copyright notice,
12 | // this list of conditions and the following disclaimer in the documentation
13 | // and/or other materials provided with the distribution.
14 | // 3. Neither the name of the copyright holder nor the names of its
15 | // contributors may be used to endorse or promote products derived from this
16 | // software without specific prior written permission.
17 |
18 | #ifndef INCLUDE_KALMANFILTER_HPP_
19 | #define INCLUDE_KALMANFILTER_HPP_
20 |
21 | #include
22 | #include
23 |
24 | #include
25 | #include