├── .vscode
└── settings.json
├── CMakeLists.txt
├── LICENSE
├── README.md
├── config
├── brief_k10L6.bin
├── brief_pattern.yml
├── params_camera.yaml
├── params_camera1.yaml
├── params_camera2.yaml
└── params_lidar.yaml
├── doc
├── demo.gif
└── device.png
├── include
└── ikd-Tree
│ ├── README.md
│ ├── ikd_Tree.cpp
│ └── ikd_Tree.h
├── launch
├── include
│ ├── config
│ │ ├── newRviz.rviz
│ │ ├── robot.urdf.xacro
│ │ └── rviz.rviz
│ ├── module_robot_state_publisher.launch
│ ├── module_rviz.launch
│ ├── module_sam.launch
│ ├── module_sam_bak.launch
│ ├── module_sam_hesai.launch
│ └── rosconsole
│ │ ├── rosconsole_error.conf
│ │ ├── rosconsole_info.conf
│ │ └── rosconsole_warn.conf
└── run.launch
├── lvi_params_for_zju_data
├── msg
└── cloud_info.msg
├── package.xml
└── src
├── lidar_odometry
├── featureExtraction.cpp
├── imageProjection.cpp
├── imuPreintegration.cpp
├── imu_tracker.cc
├── imu_tracker.h
├── mapOptmization.cpp
└── utility.h
└── visual_odometry
├── visual_estimator
├── estimator.cpp
├── estimator.h
├── estimator_node.cpp
├── factor
│ ├── imu_factor.h
│ ├── integration_base.h
│ ├── marginalization_factor.cpp
│ ├── marginalization_factor.h
│ ├── pose_local_parameterization.cpp
│ ├── pose_local_parameterization.h
│ ├── projection_factor.cpp
│ ├── projection_factor.h
│ ├── projection_td_factor.cpp
│ └── projection_td_factor.h
├── feature_manager.cpp
├── feature_manager.h
├── initial
│ ├── initial_aligment.cpp
│ ├── initial_alignment.h
│ ├── initial_ex_rotation.cpp
│ ├── initial_ex_rotation.h
│ ├── initial_sfm.cpp
│ ├── initial_sfm.h
│ ├── solve_5pts.cpp
│ └── solve_5pts.h
├── parameters.cpp
├── parameters.h
└── utility
│ ├── CameraPoseVisualization.cpp
│ ├── CameraPoseVisualization.h
│ ├── tic_toc.h
│ ├── utility.cpp
│ ├── utility.h
│ ├── visualization.cpp
│ └── visualization.h
├── visual_feature
├── camera_models
│ ├── Camera.cc
│ ├── Camera.h
│ ├── CameraFactory.cc
│ ├── CameraFactory.h
│ ├── CataCamera.cc
│ ├── CataCamera.h
│ ├── CostFunctionFactory.cc
│ ├── CostFunctionFactory.h
│ ├── EquidistantCamera.cc
│ ├── EquidistantCamera.h
│ ├── PinholeCamera.cc
│ ├── PinholeCamera.h
│ ├── ScaramuzzaCamera.cc
│ ├── ScaramuzzaCamera.h
│ ├── gpl.cc
│ └── gpl.h
├── feature_tracker.cpp
├── feature_tracker.h
├── feature_tracker_node.cpp
├── parameters.cpp
├── parameters.h
└── tic_toc.h
└── visual_loop
├── ThirdParty
├── DBoW
│ ├── BowVector.cpp
│ ├── BowVector.h
│ ├── DBoW2.h
│ ├── FBrief.cpp
│ ├── FBrief.h
│ ├── FClass.h
│ ├── FeatureVector.cpp
│ ├── FeatureVector.h
│ ├── QueryResults.cpp
│ ├── QueryResults.h
│ ├── ScoringObject.cpp
│ ├── ScoringObject.h
│ ├── TemplatedDatabase.h
│ └── TemplatedVocabulary.h
├── DUtils
│ ├── DException.h
│ ├── DUtils.h
│ ├── Random.cpp
│ ├── Random.h
│ ├── Timestamp.cpp
│ └── Timestamp.h
├── DVision
│ ├── BRIEF.cpp
│ ├── BRIEF.h
│ └── DVision.h
├── VocabularyBinary.cpp
└── VocabularyBinary.hpp
├── keyframe.cpp
├── keyframe.h
├── loop_detection.cpp
├── loop_detection.h
├── loop_detection_node.cpp
└── parameters.h
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.associations": {
3 | "array": "cpp",
4 | "deque": "cpp",
5 | "list": "cpp",
6 | "vector": "cpp",
7 | "string_view": "cpp"
8 | }
9 | }
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(emv_lio)
3 |
4 | ######################
5 | ### Cmake flags
6 | ######################
7 | set(CMAKE_BUILD_TYPE "Release")
8 | set(CMAKE_CXX_FLAGS "-std=c++14")
9 | set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wall -g -pthread -w")
10 |
11 | ######################
12 | ### Packages
13 | ######################
14 | find_package(catkin REQUIRED COMPONENTS
15 | tf
16 | roscpp
17 | rospy
18 | roslib
19 | # msg
20 | std_msgs
21 | sensor_msgs
22 | geometry_msgs
23 | nav_msgs
24 | # cv
25 | cv_bridge
26 | # pcl
27 | pcl_conversions
28 | # msg generation
29 | message_generation
30 | )
31 |
32 | find_package(OpenMP REQUIRED)
33 | find_package(PCL REQUIRED)
34 | find_package(OpenCV REQUIRED)
35 | find_package(Ceres REQUIRED)
36 | find_package(GTSAM REQUIRED QUIET)
37 | find_package(Boost REQUIRED COMPONENTS filesystem program_options system)
38 |
39 |
40 | ######################
41 | ### Message generation
42 | ######################
43 | add_message_files(
44 | DIRECTORY msg
45 | FILES
46 | cloud_info.msg
47 | )
48 |
49 | generate_messages(
50 | DEPENDENCIES
51 | geometry_msgs
52 | std_msgs
53 | nav_msgs
54 | sensor_msgs
55 | )
56 |
57 | ######################
58 | ### Catkin
59 | ######################
60 | catkin_package(
61 | INCLUDE_DIRS include
62 | DEPENDS PCL GTSAM
63 | )
64 |
65 | include_directories(
66 | include
67 | ${catkin_INCLUDE_DIRS}
68 | ${PCL_INCLUDE_DIRS}
69 | ${OpenCV_INCLUDE_DIRS}
70 | ${CERES_INCLUDE_DIRS}
71 | ${Boost_INCLUDE_DIRS}
72 | ${GTSAM_INCLUDE_DIR}
73 | )
74 |
75 | link_directories(
76 | include
77 | ${PCL_LIBRARY_DIRS}
78 | ${OpenCV_LIBRARY_DIRS}
79 | ${GTSAM_LIBRARY_DIRS}
80 | )
81 |
82 | ######################
83 | ### visual odometry
84 | ######################
85 | file(GLOB visual_feature_files
86 | "src/visual_odometry/visual_feature/*.cpp"
87 | "src/visual_odometry/visual_feature/camera_models/*.cc"
88 | )
89 | file(GLOB visual_odometry_files
90 | "src/visual_odometry/visual_estimator/*.cpp"
91 | "src/visual_odometry/visual_estimator/factor/*.cpp"
92 | "src/visual_odometry/visual_estimator/initial/*.cpp"
93 | "src/visual_odometry/visual_estimator/utility/*.cpp"
94 | )
95 | file(GLOB visual_loop_files
96 | "src/visual_odometry/visual_loop/*.cpp"
97 | "src/visual_odometry/visual_loop/utility/*.cpp"
98 | "src/visual_odometry/visual_loop/ThirdParty/*.cpp"
99 | "src/visual_odometry/visual_loop/ThirdParty/DBoW/*.cpp"
100 | "src/visual_odometry/visual_loop/ThirdParty/DUtils/*.cpp"
101 | "src/visual_odometry/visual_loop/ThirdParty/DVision/*.cpp"
102 | "src/visual_odometry/visual_feature/camera_models/*.cc"
103 | )
104 | # Visual Feature Tracker
105 | add_executable(${PROJECT_NAME}_visual_feature ${visual_feature_files})
106 | target_link_libraries(${PROJECT_NAME}_visual_feature ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${OpenCV_LIBS} ${CERES_LIBRARIES})
107 | # Visual Odometry
108 | add_executable(${PROJECT_NAME}_visual_odometry ${visual_odometry_files})
109 | target_link_libraries(${PROJECT_NAME}_visual_odometry ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${OpenCV_LIBS} ${CERES_LIBRARIES})
110 | # Visual Lopp
111 | add_executable(${PROJECT_NAME}_visual_loop ${visual_loop_files})
112 | target_link_libraries(${PROJECT_NAME}_visual_loop ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${OpenCV_LIBS} ${CERES_LIBRARIES})
113 |
114 | ######################
115 | ### lidar odometry
116 | ######################
117 |
118 | # IMU Preintegration
119 | add_executable(${PROJECT_NAME}_imuPreintegration src/lidar_odometry/imuPreintegration.cpp src/lidar_odometry/imu_tracker.cc)
120 | target_link_libraries(${PROJECT_NAME}_imuPreintegration ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${OpenCV_LIBRARIES} gtsam)
121 | # Range Image Projection
122 | add_executable(${PROJECT_NAME}_imageProjection src/lidar_odometry/imageProjection.cpp src/lidar_odometry/imu_tracker.cc)
123 | add_dependencies(${PROJECT_NAME}_imageProjection ${catkin_EXPORTED_TARGETS} ${PROJECT_NAME}_generate_messages_cpp)
124 | target_link_libraries(${PROJECT_NAME}_imageProjection ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${OpenCV_LIBRARIES})
125 | # Feature Association
126 | add_executable(${PROJECT_NAME}_featureExtraction src/lidar_odometry/featureExtraction.cpp)
127 | add_dependencies(${PROJECT_NAME}_featureExtraction ${catkin_EXPORTED_TARGETS} ${PROJECT_NAME}_generate_messages_cpp)
128 | target_link_libraries(${PROJECT_NAME}_featureExtraction ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${OpenCV_LIBRARIES})
129 | # Mapping Optimization
130 | add_executable(${PROJECT_NAME}_mapOptmization src/lidar_odometry/mapOptmization.cpp include/ikd-Tree/ikd_Tree.cpp)
131 | add_dependencies(${PROJECT_NAME}_mapOptmization ${catkin_EXPORTED_TARGETS} ${PROJECT_NAME}_generate_messages_cpp)
132 | target_compile_options(${PROJECT_NAME}_mapOptmization PRIVATE ${OpenMP_CXX_FLAGS})
133 | target_link_libraries(${PROJECT_NAME}_mapOptmization PRIVATE ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${OpenCV_LIBRARIES} ${OpenMP_CXX_FLAGS} gtsam)
134 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2023, Bingqi Shen
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EMV-LIO
2 | ## An Efficient Multiple Vision aided LiDAR-Inertial Odometry
3 |
4 | **EMV-LIO** is an Efficient Multiple vision aided LiDAR-inertial odometry system based on **LVI-SAM**, which introduces multiple cameras in the VIO subsystem to expand the range of visual observation to guarantee the whole system can still maintain the relatively high accuracy in case of the failure of the monocular visual observation. Apart from this, an efficiency-enhanced LVIO system is also introduced to increase the system’s efficiency, including removing LiDAR’s noise via range image, setting condition for nearest neighbor search, and replacing kd-Tree with ikd-Tree.
5 |
6 | Our implementation will be available upon acceptance
7 |
8 |
9 |
10 |
11 |
12 | ---
13 |
14 | ## 1. Prerequisites
15 |
16 | ### 1.1 **Ubuntu** and **ROS**
17 | Ubuntu 64-bit 16.04 or 18.04.
18 | ROS Kinetic or Melodic. [ROS Installation](http://wiki.ros.org/ROS/Installation) and its additional ROS pacakge:
19 |
20 | ### 1.2. **Ceres Solver**
21 | Follow [Ceres Installation](http://ceres-solver.org/installation.html).
22 |
23 | ```
24 | sudo apt-get install -y libgoogle-glog-dev
25 | sudo apt-get install -y libatlas-base-dev
26 | wget -O ~/Downloads/ceres.zip https://github.com/ceres-solver/ceres-solver/archive/1.14.0.zip
27 | cd ~/Downloads/ && unzip ceres.zip -d ~/Downloads/
28 | cd ~/Downloads/ceres-solver-1.14.0
29 | mkdir ceres-bin && cd ceres-bin
30 | cmake ..
31 | sudo make install -j4
32 | ```
33 |
34 | ### 1.3. **GTSAM**
35 |
36 | Install the dependencies
37 | ```
38 | sudo apt-get install libboost-all-dev
39 | sudo apt-get install cmake
40 | sudo apt-get install libtbb-dev
41 | ```
42 | Compile the GTSAM's code
43 | ```
44 | git clone https://bitbucket.org/gtborg/gtsam.git
45 | cd gtsam/
46 | mkdir build &&cd build
47 | cmake ..
48 | make check
49 | sudo make install
50 | ```
51 |
52 | ---
53 |
54 | ## 2. Compile
55 | You can use the following commands to download and compile the package.
56 |
57 | ```
58 | cd ~/emv_ws/src
59 | git clone https://github.com/BingqiShen/EMV-LIO.git
60 | cd ..
61 | catkin_make -j4
62 | ```
63 |
64 | ---
65 |
66 | ## 3. Run our examples
67 |
68 |
69 | ### 3.1 Download our rosbag files
70 |
71 |
72 |
73 |
74 |
75 | The datasets used in the paper can be downloaded from Baidu Drive. The data-gathering sensor suite includes: HESAI PandarXT-32 LiDAR, DAHENG MER2-202 camera, and Xsens MTi-300 IMU.
76 |
77 | ```
78 | url:https://pan.baidu.com/s/1QjQzn1ZwN1SHqHPghYN2tw
79 |
80 | code:sreu
81 | ```
82 |
83 | ### 3.2 Run the package
84 |
85 | 1. Configure parameters:
86 |
87 | ```
88 | Configure sensor parameters in the .yaml files in the ```config``` folder.
89 |
90 | You can select the number of camera used by change NUM_OF_CAM in params_lidar.yaml
91 | ```
92 |
93 | 2. Run the launch file:
94 |
95 | ```
96 | roslaunch emv_lio run.launch
97 | ```
98 |
99 | 3. Play existing bag files:
100 | ```
101 | rosbag play iplus.bag
102 | ```
103 |
104 | ---
105 |
106 | ## 4. Acknowledgement
107 | Our repository mainly develops from [LVI-SAM](https://github.com/TixiaoShan/LVI-SAM), where the visual-inertial odometry module is adapted from [Vins-Mono](https://github.com/HKUST-Aerial-Robotics/VINS-Mono) and the lidar-inertial odometry module is adapted from [LIO-SAM](https://github.com/TixiaoShan/LIO-SAM/tree/a246c960e3fca52b989abf888c8cf1fae25b7c25). Besides, our implementation also use the codes of [ikd-Tree](https://github.com/hku-mars/ikd-Tree), [M-LOAM](https://github.com/gogojjh/M-LOAM), and [Cartographer](https://github.com/cartographer-project/cartographer).
108 |
--------------------------------------------------------------------------------
/config/brief_k10L6.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BingqiShen/EMV-LIO/efc31dc812ad2d3cfcf3f6227ca921474e76f54f/config/brief_k10L6.bin
--------------------------------------------------------------------------------
/config/params_camera.yaml:
--------------------------------------------------------------------------------
1 | %YAML:1.0
2 |
3 | # Project
4 | project_name: "emv_lio"
5 |
6 | #common parameters
7 | imu_topic: "/imu_data"
8 | image_topic: "/camera2/camera2_resize"
9 | point_cloud_topic: "/hesai/pandar"
10 |
11 | # Lidar Params
12 | use_lidar: 1 # whether use depth info from lidar or not
13 | lidar_skip: 3 # skip this amount of scans
14 | align_camera_lidar_estimation: 1 # align camera and lidar estimation for visualization
15 |
16 | # cam's number
17 | # num_of_cam: 1
18 |
19 | # camera to lidar extrinsic
20 | cam_to_lidar_tx: -0.1338
21 | cam_to_lidar_ty: 0.0959
22 | cam_to_lidar_tz: -0.1029
23 | cam_to_lidar_rx: -1.5837
24 | cam_to_lidar_ry: 0.0104
25 | cam_to_lidar_rz: 1.0541
26 | # camera model
27 | model_type: PINHOLE
28 | camera_name: camera
29 |
30 | # Mono camera config
31 | image_width: 1224
32 | image_height: 1024
33 | mirror_parameters:
34 | xi: 1.9926618269451453
35 | distortion_parameters:
36 | k1: -0.0383
37 | k2: 0.2589
38 | p1: 0.0
39 | p2: 0.0
40 | projection_parameters:
41 | gamma1: 1222.0
42 | gamma2: 1221.6
43 | u0: 628.5
44 | v0: 484.7
45 | fx: 1222.0
46 | fy: 1221.6
47 | cx: 628.5
48 | cy: 484.7
49 | fisheye_mask: "/config/fisheye_mask_720x540.jpg"
50 |
51 | #imu parameters The more accurate parameters you provide, the worse performance
52 | imu_freq: 400
53 | acc_n: 0.03015059 # accelerometer measurement noise standard deviation.
54 | gyr_n: 0.42306179 # gyroscope measurement noise standard deviation.
55 | acc_w: 0.00198931 # accelerometer bias random work noise standard deviation.
56 | gyr_w: 0.00015932 # gyroscope bias random work noise standard deviation.
57 | g_norm: 9.79 #
58 |
59 | # Extrinsic parameter between IMU and Camera.
60 | estimate_extrinsic: 0 # 0 Have an accurate extrinsic parameters. We will trust the following imu^R_cam, imu^T_cam, don't change it.
61 | # 1 Have an initial guess about extrinsic parameters. We will optimize around your initial guess.
62 | # 2 Don't know anything about extrinsic parameters. You don't need to give R,T. We will try to calibrate it. Do some rotation movement at beginning.
63 | #Rotation from camera frame to imu frame, imu^R_cam
64 | extrinsicRotation: !!opencv-matrix
65 | rows: 3
66 | cols: 3
67 | dt: d
68 | data: [ -0.2846, -0.0102, 0.9586,
69 | -0.9586, -0.0010, -0.2846,
70 | 0.0038, -0.9999, -0.0095]
71 |
72 | #Translation from camera frame to imu frame, imu^T_cam
73 | extrinsicTranslation: !!opencv-matrix
74 | rows: 3
75 | cols: 1
76 | dt: d
77 | data: [0.1316, -0.0471, -0.0379]
78 |
79 | #feature tracker paprameters
80 | max_cnt: 100 # max feature number in feature tracking
81 | min_dist: 20 # min distance between two features
82 | freq: 0 # frequence (Hz) of publish tracking result. At least 10Hz for good estimation. If set 0, the frequence will be same as raw image
83 | F_threshold: 1.0 # ransac threshold (pixel)
84 | show_track: 1 # publish tracking image as topic
85 | equalize: 1 # if image is too dark or light, trun on equalize to find enough features
86 | fisheye: 0 # if using fisheye, trun on it. A circle mask will be loaded to remove edge noisy points
87 |
88 | #optimization parameters
89 | max_solver_time: 0.035 # max solver itration time (ms), to guarantee real time
90 | max_num_iterations: 10 # max solver itrations, to guarantee real time
91 | keyframe_parallax: 10.0 # keyframe selection threshold (pixel)
92 |
93 | #unsynchronization parameters
94 | estimate_td: 0 # online estimate time offset between camera and imu
95 | td: 0 # initial value of time offset. unit: s. readed image clock + td = real image clock (IMU clock)
96 |
97 | #rolling shutter parameters
98 | rolling_shutter: 0 # 0: global shutter camera, 1: rolling shutter camera
99 | rolling_shutter_tr: 0 # unit: s. rolling shutter read out time per frame (from data sheet).
100 |
101 | #loop closure parameters
102 | loop_closure: 0 # start loop closure
103 | skip_time: 0.0
104 | skip_dist: 0.0
105 | debug_image: 0 # save raw image in loop detector for visualization prupose; you can close this function by setting 0
106 | match_image_scale: 0.5
107 | vocabulary_file: "/config/brief_k10L6.bin"
108 | brief_pattern_file: "/config/brief_pattern.yml"
109 |
--------------------------------------------------------------------------------
/config/params_camera1.yaml:
--------------------------------------------------------------------------------
1 | %YAML:1.0
2 |
3 | # Project
4 | project_name: "emv_lio"
5 |
6 | #common parameters
7 | imu_topic: "/imu_data"
8 | image_topic: "/camera3/camera3_resize"
9 | point_cloud_topic: "/hesai/pandar"
10 |
11 | # Lidar Params
12 | use_lidar: 1 # whether use depth info from lidar or not
13 | lidar_skip: 3 # skip this amount of scans
14 | align_camera_lidar_estimation: 1 # align camera and lidar estimation for visualization
15 |
16 | # cam's number
17 | #num_of_cam: 1
18 |
19 | # camera to lidar extrinsic
20 | cam_to_lidar_tx: 0.1285
21 | cam_to_lidar_ty: 0.1073
22 | cam_to_lidar_tz: -0.0957
23 | cam_to_lidar_rx: -1.5883
24 | cam_to_lidar_ry: -0.0093
25 | cam_to_lidar_rz: -1.0618
26 | # camera model
27 | model_type: PINHOLE
28 | camera_name: camera
29 |
30 | # Mono camera config
31 | image_width: 1224
32 | image_height: 1024
33 | mirror_parameters:
34 | xi: 1.9926618269451453
35 | distortion_parameters:
36 | k1: -0.0250
37 | k2: 0.1441
38 | p1: 0.0
39 | p2: 0.0
40 | projection_parameters:
41 | fx: 1202.0
42 | fy: 1204.0
43 | cx: 615.2
44 | cy: 480.4
45 | fisheye_mask: "/config/fisheye_mask_720x540.jpg"
46 |
47 | #imu parameters The more accurate parameters you provide, the worse performance
48 | acc_n: 0.03015059 # accelerometer measurement noise standard deviation.
49 | gyr_n: 0.42306179 # gyroscope measurement noise standard deviation.
50 | acc_w: 0.00198931 # accelerometer bias random work noise standard deviation.
51 | gyr_w: 0.00015932 # gyroscope bias random work noise standard deviation.
52 | g_norm: 9.80 #
53 |
54 | # Extrinsic parameter between IMU and Camera.
55 | estimate_extrinsic: 0 # 0 Have an accurate extrinsic parameters. We will trust the following imu^R_cam, imu^T_cam, don't change it.
56 | # 1 Have an initial guess about extrinsic parameters. We will optimize around your initial guess.
57 | # 2 Don't know anything about extrinsic parameters. You don't need to give R,T. We will try to calibrate it. Do some rotation movement at beginning.
58 | #Rotation from camera frame to imu frame, imu^R_cam
59 | extrinsicRotation: !!opencv-matrix
60 | rows: 3
61 | cols: 3
62 | dt: d
63 | data: [ -0.6727, 0.0004, -0.7399,
64 | 0.7399, 0.0070, -0.6727,
65 | 0.0049, -1.0000, -0.0051]
66 |
67 | #Translation from camera frame to imu frame, imu^T_cam
68 | extrinsicTranslation: !!opencv-matrix
69 | rows: 3
70 | cols: 1
71 | dt: d
72 | data: [-0.1201, -0.0628, -0.0320]
73 |
74 | #feature tracker paprameters
75 | max_cnt: 100 # max feature number in feature tracking
76 | min_dist: 20 # min distance between two features
77 | freq: 0 # frequence (Hz) of publish tracking result. At least 10Hz for good estimation. If set 0, the frequence will be same as raw image
78 | F_threshold: 1.0 # ransac threshold (pixel)
79 | show_track: 1 # publish tracking image as topic
80 | equalize: 1 # if image is too dark or light, trun on equalize to find enough features
81 | fisheye: 0 # if using fisheye, trun on it. A circle mask will be loaded to remove edge noisy points
82 |
83 | #optimization parameters
84 | max_solver_time: 0.035 # max solver itration time (ms), to guarantee real time
85 | max_num_iterations: 10 # max solver itrations, to guarantee real time
86 | keyframe_parallax: 10.0 # keyframe selection threshold (pixel)
87 |
88 | #unsynchronization parameters
89 | estimate_td: 0 # online estimate time offset between camera and imu
90 | td: 0 # initial value of time offset. unit: s. readed image clock + td = real image clock (IMU clock)
91 |
92 | #rolling shutter parameters
93 | rolling_shutter: 0 # 0: global shutter camera, 1: rolling shutter camera
94 | rolling_shutter_tr: 0 # unit: s. rolling shutter read out time per frame (from data sheet).
95 |
96 | #loop closure parameters
97 | loop_closure: 1 # start loop closure
98 | skip_time: 0.0
99 | skip_dist: 0.0
100 | debug_image: 0 # save raw image in loop detector for visualization prupose; you can close this function by setting 0
101 | match_image_scale: 0.5
102 | vocabulary_file: "/config/brief_k10L6.bin"
103 | brief_pattern_file: "/config/brief_pattern.yml"
104 |
--------------------------------------------------------------------------------
/config/params_camera2.yaml:
--------------------------------------------------------------------------------
1 | %YAML:1.0
2 |
3 | # Project
4 | project_name: "emv_lio"
5 |
6 | #common parameters
7 | imu_topic: "/imu_data"
8 | image_topic: "/camera1/camera1_resize"
9 | point_cloud_topic: "/hesai/pandar"
10 |
11 | # Lidar Params
12 | use_lidar: 1 # whether use depth info from lidar or not
13 | lidar_skip: 3 # skip this amount of scans
14 | align_camera_lidar_estimation: 1 # align camera and lidar estimation for visualization
15 |
16 |
17 | # camera to lidar extrinsic
18 | cam_to_lidar_tx: -0.0102
19 | cam_to_lidar_ty: -0.1885
20 | cam_to_lidar_tz: -0.1003
21 | cam_to_lidar_rx: -1.5399
22 | cam_to_lidar_ry: 0.0052
23 | cam_to_lidar_rz: 3.1229
24 | # camera model
25 | model_type: PINHOLE
26 | camera_name: camera
27 |
28 | # Mono camera config
29 | image_width: 1224
30 | image_height: 1024
31 | mirror_parameters:
32 | xi: 1.9926618269451453
33 | distortion_parameters:
34 | k1: -0.0223
35 | k2: 0.1693
36 | p1: 0.0
37 | p2: 0.0
38 | projection_parameters:
39 | fx: 1207.2
40 | fy: 1206.9
41 | cx: 610.0
42 | cy: 491.0
43 | fisheye_mask: "/config/fisheye_mask_720x540.jpg"
44 |
45 | #imu parameters The more accurate parameters you provide, the worse performance
46 | acc_n: 0.03015059 # accelerometer measurement noise standard deviation.
47 | gyr_n: 0.42306179 # gyroscope measurement noise standard deviation.
48 | acc_w: 0.00198931 # accelerometer bias random work noise standard deviation.
49 | gyr_w: 0.00015932 # gyroscope bias random work noise standard deviation.
50 | g_norm: 9.80 #
51 |
52 | # Extrinsic parameter between IMU and Camera.
53 | estimate_extrinsic: 0 # 0 Have an accurate extrinsic parameters. We will trust the following imu^R_cam, imu^T_cam, don't change it.
54 | # 1 Have an initial guess about extrinsic parameters. We will optimize around your initial guess.
55 | # 2 Don't know anything about extrinsic parameters. You don't need to give R,T. We will try to calibrate it. Do some rotation movement at beginning.
56 | #Rotation from camera frame to imu frame, imu^R_cam
57 | extrinsicRotation: !!opencv-matrix
58 | rows: 3
59 | cols: 3
60 | dt: d
61 | data: [ 0.9781, -0.0123, -0.2076,
62 | 0.2077, 0.0144, 0.9781,
63 | -0.0090, -0.9998, 0.0167]
64 |
65 | #Translation from camera frame to imu frame, imu^T_cam
66 | extrinsicTranslation: !!opencv-matrix
67 | rows: 3
68 | cols: 1
69 | dt: d
70 | data: [-0.0332, 0.1919, -0.0388]
71 |
72 | #feature tracker paprameters
73 | max_cnt: 150 # max feature number in feature tracking
74 | min_dist: 20 # min distance between two features
75 | freq: 0 # frequence (Hz) of publish tracking result. At least 10Hz for good estimation. If set 0, the frequence will be same as raw image
76 | F_threshold: 1.0 # ransac threshold (pixel)
77 | show_track: 1 # publish tracking image as topic
78 | equalize: 1 # if image is too dark or light, trun on equalize to find enough features
79 | fisheye: 0 # if using fisheye, trun on it. A circle mask will be loaded to remove edge noisy points
80 |
81 | #optimization parameters
82 | max_solver_time: 0.035 # max solver itration time (ms), to guarantee real time
83 | max_num_iterations: 10 # max solver itrations, to guarantee real time
84 | keyframe_parallax: 10.0 # keyframe selection threshold (pixel)
85 |
86 | #unsynchronization parameters
87 | estimate_td: 0 # online estimate time offset between camera and imu
88 | td: 0 # initial value of time offset. unit: s. readed image clock + td = real image clock (IMU clock)
89 |
90 | #rolling shutter parameters
91 | rolling_shutter: 0 # 0: global shutter camera, 1: rolling shutter camera
92 | rolling_shutter_tr: 0 # unit: s. rolling shutter read out time per frame (from data sheet).
93 |
94 | #loop closure parameters
95 | loop_closure: 0 # start loop closure
96 | skip_time: 0.0
97 | skip_dist: 0.0
98 | debug_image: 0 # save raw image in loop detector for visualization prupose; you can close this function by setting 0
99 | match_image_scale: 0.5
100 | vocabulary_file: "/config/brief_k10L6.bin"
101 | brief_pattern_file: "/config/brief_pattern.yml"
102 |
--------------------------------------------------------------------------------
/config/params_lidar.yaml:
--------------------------------------------------------------------------------
1 | # project name
2 | PROJECT_NAME: "emv_lio"
3 |
4 | emv_lio:
5 |
6 | # Topics
7 | pointCloudTopic: "/hesai/pandar" # Point cloud data
8 | imuTopic: "/imu_data" # IMU data
9 |
10 | # Heading
11 | useImuHeadingInitialization: true # if using GPS data, set to "true"
12 |
13 | # Export settings
14 | savePCD: false # https://github.com/TixiaoShan/LIO-SAM/issues/3
15 | savePCDDirectory: "/Downloads/LOAM/" # in your home folder, starts and ends with "/". Warning: the code deletes "LOAM" folder then recreates it. See "mapOptimization" for implementation
16 |
17 | # lidar Settings
18 | N_SCAN: 32 # number of lidar channel (i.e., 16, 32, 64, 128)
19 | Horizon_SCAN: 2000 # lidar horizontal resolution (Velodyne:1800, Ouster:512,1024,2048)
20 | ang_res_y: 1.0 # vertical resolution of lidar
21 | lidar_type: 2 # 1 for ouster, 2 for hesai, 3 for velodyne
22 | timeField: "timestamp" # point timestamp field, Velodyne - "time", Ouster - "t", hesai - "timestamp"
23 | downsampleRate: 2 # default: 1. Downsample your data if too many points. i.e., 16 = 64 / 4, 16 = 16 / 1
24 | lidarMaxRange: 50.0
25 | lidarMinRange: 0.5
26 | NUM_OF_CAM: 2
27 | feature_enable: 0
28 | remove_noise: 0
29 |
30 | # noise removal setting
31 | min_cluster_size: 10
32 | segment_valid_point_num: 5
33 | segment_valid_line_num: 3
34 |
35 | # IMU Settings
36 | imuAccNoise: 0.03015059
37 | imuGyrNoise: 0.42306179
38 | imuAccBiasN: 0.00198931
39 | imuGyrBiasN: 0.00015932
40 | imuGravity: 9.80
41 |
42 | # Extrinsics (lidar -> IMU)
43 | extrinsicTrans: [-0.0204, 0.0175, 0.0642]
44 | extrinsicRot: [-0.9741, 0.2262, 0.0008, -0.2261, -0.9740, 0.0147, 0.0041, 0.0141, 0.9999]
45 | #extrinsicTrans: [-0.0162, 0.0207, -0.0644]
46 | #extrinsicRot: [-0.9741, -0.2262, 0.0041, 0.2261, -0.9740, 0.0141, 0.0008, 0.0147, 0.9999]
47 | # extrinsicRPY: [0, 1, 0, -1, 0, 0, 0, 0, 1]
48 | extrinsicRPY: [0, -1, 0, -1, 0, 0, 0, 0, -1]
49 | # LOAM feature threshold
50 | edgeThreshold: 1.0
51 | surfThreshold: 0.1
52 | edgeFeatureMinValidNum: -1
53 | surfFeatureMinValidNum: 100
54 |
55 | # voxel filter paprams
56 | odometrySurfLeafSize: 0.4 # default: 0.4
57 | mappingCornerLeafSize: 0.2 # default: 0.2
58 | mappingSurfLeafSize: 0.4 # default: 0.4
59 |
60 | # robot motion constraint (in case you are using a 2D robot)
61 | z_tollerance: 1000 # meters
62 | rotation_tollerance: 1000 # radians
63 |
64 | # CPU Params
65 | numberOfCores: 4 # number of cores for mapping optimization
66 | mappingProcessInterval: 0.05 # seconds, regulate mapping frequency
67 |
68 | # Surrounding map
69 | surroundingkeyframeAddingDistThreshold: 1.0 # meters, regulate keyframe adding threshold
70 | surroundingkeyframeAddingAngleThreshold: 0.2 # radians, regulate keyframe adding threshold
71 | surroundingKeyframeDensity: 2.0 # meters, downsample surrounding keyframe poses
72 | surroundingKeyframeSearchRadius: 50.0 # meters, within n meters scan-to-map optimization (when loop closure disabled)
73 |
74 | # Loop closure
75 | loopClosureEnableFlag: False
76 | surroundingKeyframeSize: 25 # submap size (when loop closure enabled)
77 | historyKeyframeSearchRadius: 20.0 # meters, key frame that is within n meters from current pose will be considerd for loop closure
78 | historyKeyframeSearchTimeDiff: 30.0 # seconds, key frame that is n seconds older will be considered for loop closure
79 | historyKeyframeSearchNum: 25 # number of hostory key frames will be fused into a submap for loop closure
80 | historyKeyframeFitnessScore: 0.3 # icp threshold, the smaller the better alignment
81 |
82 | # Visualization
83 | globalMapVisualizationSearchRadius: 1000.0 # meters, global map visualization radius
84 | globalMapVisualizationPoseDensity: 10.0 # meters, global map visualization keyframe density
85 | globalMapVisualizationLeafSize: 1.0 # meters, global map visualization cloud density
86 |
87 |
--------------------------------------------------------------------------------
/doc/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BingqiShen/EMV-LIO/efc31dc812ad2d3cfcf3f6227ca921474e76f54f/doc/demo.gif
--------------------------------------------------------------------------------
/doc/device.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BingqiShen/EMV-LIO/efc31dc812ad2d3cfcf3f6227ca921474e76f54f/doc/device.png
--------------------------------------------------------------------------------
/include/ikd-Tree/README.md:
--------------------------------------------------------------------------------
1 | # ikd-Tree
2 | ikd-Tree is an incremental k-d tree for robotic applications.
3 |
--------------------------------------------------------------------------------
/launch/include/config/robot.urdf.xacro:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/launch/include/module_robot_state_publisher.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/launch/include/module_rviz.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/launch/include/module_sam.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/launch/include/module_sam_bak.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/launch/include/module_sam_hesai.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/launch/include/rosconsole/rosconsole_error.conf:
--------------------------------------------------------------------------------
1 | # Set the default ros output to warning and higher
2 | log4j.logger.ros = ERROR
--------------------------------------------------------------------------------
/launch/include/rosconsole/rosconsole_info.conf:
--------------------------------------------------------------------------------
1 | # Set the default ros output to warning and higher
2 | log4j.logger.ros = INFO
--------------------------------------------------------------------------------
/launch/include/rosconsole/rosconsole_warn.conf:
--------------------------------------------------------------------------------
1 | # Set the default ros output to warning and higher
2 | log4j.logger.ros = WARN
--------------------------------------------------------------------------------
/launch/run.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/lvi_params_for_zju_data:
--------------------------------------------------------------------------------
1 | cam2lidar:
2 | [0.4940 0.0061 -0.8694 -0.1338
3 | 0.8694 -0.0154 0.4939 0.0959
4 | -0.0104 -0.9999 -0.0129 -0.1029
5 | 0 0 0 1.0000]
6 |
7 | quat(w,x,y,z): [0.6053 -0.6169 -0.3548 0.3566]
8 | eul(yaw,pitch.roll) :[ 1.0542 0.0105 -1.5837]
9 |
10 | Eigen::Quaterniond cam2lidar_q (0.6053,-0.6169,-0.3548,0.3566);
11 | Eigen::Vector3d cam2lidar_t (-0.1338, 0.0959,-0.1029);
12 |
13 | lidar2cam:
14 | [0.4940 0.8694 -0.0104 -0.0183
15 | 0.0061 -0.0154 -0.9999 -0.1006
16 | -0.8694 0.4939 -0.0129 -0.1650
17 | 0 0 0 1.0000]
18 | quat(w,x,y,z): [0.6053 0.6169 0.3548 -0.3566]
19 | eul(yaw,pitch.roll) :[ 0.0123 1.0542 1.5969]
20 |
21 | cam2imu:
22 | [-0.2846, -0.0102, 0.9586, 0.1316;
23 | -0.9586, -0.0010, -0.2846 , -0.0471;
24 | 0.0038, -0.9999, -0.0095,-0.0379
25 | 0 0 0 1]
26 | quat: [0.4198 -0.4260 0.5686 -0.5648]
27 | eul(yaw,pitch.roll) :[-1.8594 -0.0038 -1.5803]
28 |
29 | imu2cam:
30 | [ -0.2846 -0.9587 0.0039 -0.0076
31 | -0.0102 -0.0009 -1.0000 -0.0366
32 | 0.9586 -0.2846 -0.0095 -0.1399
33 | 0 0 0 1.0000]
34 |
35 | quat: [0.4198 0.4260 -0.5686 0.5648]
36 | eul(yaw,pitch.roll) :[-3.1056 -1.2820 -1.6043]
37 |
38 | lidar2imu:
39 | [-0.9741 0.2262 0.0008 -0.0203
40 | -0.2261 -0.9739 0.0147 0.0175
41 | 0.0041 0.0140 0.9998 0.0642
42 | 0 0 0 1.0000]
43 | quat:[0.1138 -0.0012 -0.0072 -0.9935]
44 | eul(yaw,pitch.roll) :[-2.9135 -0.0040 0.0140]
45 |
46 | imu2lidar:
47 | [-0.9741 -0.2261 0.0041 -0.0161
48 | 0.2262 -0.9740 0.0141 0.0207
49 | 0.0008 0.0146 0.9999 -0.0644
50 | 0 0 0 1.0000]
51 | quat: [0.1138 0.0012 0.0072 0.9935]
52 | eul(yaw,pitch.roll) :[2.9135 -0.0007 0.0146]
53 |
54 |
--------------------------------------------------------------------------------
/msg/cloud_info.msg:
--------------------------------------------------------------------------------
1 | # Cloud Info
2 | Header header
3 |
4 | int32[] startRingIndex
5 | int32[] endRingIndex
6 |
7 | int32[] pointColInd # point column index in range image
8 | float32[] pointRange # point range
9 |
10 | int64 imuAvailable
11 | int64 odomAvailable
12 |
13 | # Attitude for lidar odometry initialization
14 | float32 imuRollInit
15 | float32 imuPitchInit
16 | float32 imuYawInit
17 |
18 | # Odometry
19 | float32 odomX
20 | float32 odomY
21 | float32 odomZ
22 | float32 odomRoll
23 | float32 odomPitch
24 | float32 odomYaw
25 |
26 | # Odometry reset ID
27 | int64 odomResetId
28 |
29 | # Point cloud messages
30 | sensor_msgs/PointCloud2 cloud_deskewed # original cloud deskewed
31 | sensor_msgs/PointCloud2 cloud_corner # extracted corner feature
32 | sensor_msgs/PointCloud2 cloud_surface # extracted surface feature
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | emv_lio
4 | 0.0.0
5 | A package
6 | lalala
7 | Bingqi Shen
8 | BSD-3
9 |
10 |
11 | catkin
12 |
13 | roscpp
14 | roscpp
15 | rospy
16 | rospy
17 |
18 | tf
19 | tf
20 |
21 | cv_bridge
22 | cv_bridge
23 |
24 | pcl_conversions
25 | pcl_conversions
26 |
27 | std_msgs
28 | std_msgs
29 | sensor_msgs
30 | sensor_msgs
31 | geometry_msgs
32 | geometry_msgs
33 | nav_msgs
34 | nav_msgs
35 |
36 | message_generation
37 | message_generation
38 | message_runtime
39 | message_runtime
40 |
41 | GTSAM
42 | GTSAM
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/lidar_odometry/imu_tracker.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 The Cartographer Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #include "imu_tracker.h"
18 | #include
19 | #include
20 | #include "glog/logging.h"
21 | ImuTracker::ImuTracker(const double imu_gravity_time_constant,
22 | const double time)
23 | : imu_gravity_time_constant_(imu_gravity_time_constant), time_(time),
24 | last_linear_acceleration_time_(0.),
25 | orientation_(Eigen::Quaterniond::Identity()),
26 | gravity_vector_(Eigen::Vector3d::UnitZ()),
27 | imu_angular_velocity_(Eigen::Vector3d::Zero())
28 | {
29 | }
30 |
31 | void ImuTracker::Advance(const double time)
32 | {
33 | const double delta_t = (time - time_);
34 | const Eigen::Quaterniond rotation = AngleAxisVectorToRotationQuaternion(
35 | Eigen::Vector3d(imu_angular_velocity_ * delta_t));
36 | orientation_ = (orientation_ * rotation).normalized();
37 | gravity_vector_ = rotation.conjugate() * gravity_vector_;
38 | time_ = time;
39 | }
40 |
41 | void ImuTracker::AddImuLinearAccelerationObservation(
42 | const Eigen::Vector3d& imu_linear_acceleration)
43 | {
44 | // Update the 'gravity_vector_' with an exponential moving average using the
45 | // 'imu_gravity_time_constant'.
46 | const double delta_t = last_linear_acceleration_time_ > 0
47 | ? (time_ - last_linear_acceleration_time_)
48 | : std::numeric_limits::infinity();
49 | last_linear_acceleration_time_ = time_;
50 | const double alpha = 1. - std::exp(-delta_t / imu_gravity_time_constant_);
51 | gravity_vector_ =
52 | (1. - alpha) * gravity_vector_ + alpha * imu_linear_acceleration;
53 |
54 | // Change the 'orientation_' so that it agrees with the current
55 | // 'gravity_vector_'.
56 | const Eigen::Quaterniond rotation = Eigen::Quaterniond::FromTwoVectors(
57 | gravity_vector_, orientation_.conjugate() * (Eigen::Vector3d::UnitZ()));
58 | orientation_ = (orientation_ * rotation).normalized();
59 | }
60 |
61 | void ImuTracker::AddImuAngularVelocityObservation(
62 | const Eigen::Vector3d& imu_angular_velocity)
63 | {
64 | imu_angular_velocity_ = imu_angular_velocity;
65 | }
66 |
--------------------------------------------------------------------------------
/src/lidar_odometry/imu_tracker.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 The Cartographer Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #ifndef CARTOGRAPHER_MAPPING_IMU_TRACKER_H_
18 | #define CARTOGRAPHER_MAPPING_IMU_TRACKER_H_
19 |
20 | #include "Eigen/Geometry"
21 | #include "Eigen/Eigen"
22 | // Keeps track of the orientation using angular velocities and linear
23 | // accelerations from an IMU. Because averaged linear acceleration (assuming
24 | // slow movement) is a direct measurement of gravity, roll/pitch does not drift,
25 | // though yaw does.
26 | class ImuTracker
27 | {
28 | public:
29 | ImuTracker(const double imu_gravity_time_constant, const double time);
30 |
31 | // Advances to the given 'time' and updates the orientation to reflect this.
32 | void Advance(const double time);
33 |
34 | // Updates from an IMU reading (in the IMU frame).
35 | void AddImuLinearAccelerationObservation(
36 | const Eigen::Vector3d& imu_linear_acceleration);
37 | void
38 | AddImuAngularVelocityObservation(const Eigen::Vector3d& imu_angular_velocity);
39 |
40 | // Query the current time.
41 | double time() const { return time_; }
42 |
43 | // Query the current orientation estimate.
44 | Eigen::Quaterniond orientation() const { return orientation_; }
45 |
46 | template
47 | Eigen::Quaternion
48 | AngleAxisVectorToRotationQuaternion(const Eigen::Matrix& angle_axis)
49 | {
50 | T scale = T(0.5);
51 | T w = T(1.);
52 | constexpr double kCutoffAngle = 1e-8; // We linearize below this angle.
53 | if (angle_axis.squaredNorm() > kCutoffAngle)
54 | {
55 | const T norm = angle_axis.norm();
56 | scale = sin(norm / 2.) / norm;
57 | w = cos(norm / 2.);
58 | }
59 | const Eigen::Matrix quaternion_xyz = scale * angle_axis;
60 | return Eigen::Quaternion(w, quaternion_xyz.x(), quaternion_xyz.y(),
61 | quaternion_xyz.z());
62 | }
63 |
64 | private:
65 | const double imu_gravity_time_constant_;
66 | double time_;
67 | double last_linear_acceleration_time_;
68 | Eigen::Quaterniond orientation_;
69 | Eigen::Vector3d gravity_vector_;
70 | Eigen::Vector3d imu_angular_velocity_;
71 | };
72 | #endif // CARTOGRAPHER_MAPPING_IMU_TRACKER_H_
73 |
--------------------------------------------------------------------------------
/src/visual_odometry/visual_estimator/estimator.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "parameters.h"
4 | #include "feature_manager.h"
5 | #include "utility/utility.h"
6 | #include "utility/tic_toc.h"
7 | #include "initial/solve_5pts.h"
8 | #include "initial/initial_sfm.h"
9 | #include "initial/initial_alignment.h"
10 | #include "initial/initial_ex_rotation.h"
11 | #include
12 | #include
13 |
14 | #include
15 | #include "factor/imu_factor.h"
16 | #include "factor/pose_local_parameterization.h"
17 | #include "factor/projection_factor.h"
18 | #include "factor/projection_td_factor.h"
19 | #include "factor/marginalization_factor.h"
20 |
21 | #include
22 | #include
23 | #include
24 |
25 | #include
26 | class Estimator
27 | {
28 | public:
29 | Estimator();
30 |
31 | void setParameter();
32 |
33 | // interface
34 | void processIMU(double t, const Vector3d &linear_acceleration, const Vector3d &angular_velocity);
35 | void processImage(const map>>> &image,
36 | const vector &lidar_initialization_info,
37 | const std_msgs::Header &header,
38 | int cam_id);
39 | void processImage2(const map>>> &image,
40 | const map>>> &image1,
41 | const vector &lidar_initialization_info,
42 | const vector &lidar_initialization_info_1,
43 | const std_msgs::Header &header);
44 | void processImage3(const map>>> &image,
45 | const map>>> &image1,
46 | const map>>> &image2,
47 | const vector &lidar_initialization_info,
48 | const vector &lidar_initialization_info_1,
49 | const vector &lidar_initialization_info_2,
50 | const std_msgs::Header &header);
51 |
52 | // internal
53 | void clearState();
54 | bool initialStructure(int cam_id);
55 | bool visualInitialAlign(int cam_id);
56 | // void visualInitialAlignWithDepth();
57 | bool relativePose(Matrix3d &relative_R, Vector3d &relative_T, int &l);
58 | void slideWindow(int cam_id);
59 | void solveOdometry();
60 | void slideWindowNew(int cam_id);
61 | void slideWindowOld(int cam_id);
62 | void optimization();
63 | void vector2double();
64 | void double2vector();
65 | bool failureDetection();
66 |
67 |
68 | enum SolverFlag
69 | {
70 | INITIAL,
71 | NON_LINEAR
72 | };
73 |
74 | enum MarginalizationFlag
75 | {
76 | MARGIN_OLD = 0,
77 | MARGIN_SECOND_NEW = 1
78 | };
79 |
80 | SolverFlag solver_flag;
81 | MarginalizationFlag marginalization_flag;
82 | Vector3d g;
83 | MatrixXd Ap[2], backup_A;
84 | VectorXd bp[2], backup_b;
85 |
86 | // transformation from cam to imu
87 | Matrix3d ric[NUM_OF_CAM_ALL];
88 | Vector3d tic[NUM_OF_CAM_ALL];
89 |
90 | Vector3d Ps[(WINDOW_SIZE + 1)];
91 | Vector3d Vs[(WINDOW_SIZE + 1)];
92 | Matrix3d Rs[(WINDOW_SIZE + 1)];
93 | Vector3d Bas[(WINDOW_SIZE + 1)];
94 | Vector3d Bgs[(WINDOW_SIZE + 1)];
95 | double td;
96 |
97 | Matrix3d back_R0, last_R, last_R0;
98 | Vector3d back_P0, last_P, last_P0;
99 | std_msgs::Header Headers[(WINDOW_SIZE + 1)];
100 |
101 | IntegrationBase *pre_integrations[(WINDOW_SIZE + 1)];
102 | Vector3d acc_0, gyr_0;
103 |
104 | vector dt_buf[(WINDOW_SIZE + 1)];
105 | vector linear_acceleration_buf[(WINDOW_SIZE + 1)];
106 | vector angular_velocity_buf[(WINDOW_SIZE + 1)];
107 |
108 | int frame_count;
109 |
110 | int sum_of_outlier, sum_of_back, sum_of_front, sum_of_invalid;
111 |
112 | FeatureManager f_manager;
113 | MotionEstimator m_estimator;
114 | InitialEXRotation initial_ex_rotation;
115 |
116 | bool first_imu;
117 | bool is_valid, is_key;
118 | bool failure_occur;
119 |
120 | vector point_cloud;
121 | vector margin_cloud;
122 | vector key_poses;
123 | double initial_timestamp;
124 |
125 |
126 | double para_Pose[WINDOW_SIZE + 1][SIZE_POSE];
127 | double para_SpeedBias[WINDOW_SIZE + 1][SIZE_SPEEDBIAS];
128 | double para_Feature[NUM_OF_F][SIZE_FEATURE];
129 | double para_Ex_Pose[NUM_OF_CAM_ALL][SIZE_POSE];
130 | double para_Retrive_Pose[SIZE_POSE];
131 | double para_Td[1][1];
132 | double para_Tr[1][1];
133 |
134 | int loop_window_index;
135 |
136 | MarginalizationInfo *last_marginalization_info;
137 | vector last_marginalization_parameter_blocks;
138 |
139 | map all_image_frame;
140 | IntegrationBase *tmp_pre_integration;
141 |
142 | int failureCount;
143 | };
144 |
--------------------------------------------------------------------------------
/src/visual_odometry/visual_estimator/factor/marginalization_factor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include "../utility/utility.h"
11 | #include "../utility/tic_toc.h"
12 |
13 | const int NUM_THREADS = 4;
14 |
15 | struct ResidualBlockInfo
16 | {
17 | ResidualBlockInfo(ceres::CostFunction *_cost_function, ceres::LossFunction *_loss_function, std::vector _parameter_blocks, std::vector _drop_set)
18 | : cost_function(_cost_function), loss_function(_loss_function), parameter_blocks(_parameter_blocks), drop_set(_drop_set) {}
19 |
20 | void Evaluate();
21 |
22 | ceres::CostFunction *cost_function;
23 | ceres::LossFunction *loss_function;
24 | std::vector parameter_blocks;
25 | std::vector drop_set;
26 |
27 | double **raw_jacobians;
28 | std::vector> jacobians;
29 | Eigen::VectorXd residuals;
30 |
31 | int localSize(int size)
32 | {
33 | return size == 7 ? 6 : size;
34 | }
35 | };
36 |
37 | struct ThreadsStruct
38 | {
39 | std::vector sub_factors;
40 | Eigen::MatrixXd A;
41 | Eigen::VectorXd b;
42 | std::unordered_map parameter_block_size; //global size
43 | std::unordered_map parameter_block_idx; //local size
44 | };
45 |
46 | class MarginalizationInfo
47 | {
48 | public:
49 | ~MarginalizationInfo();
50 | int localSize(int size) const;
51 | int globalSize(int size) const;
52 | void addResidualBlockInfo(ResidualBlockInfo *residual_block_info);
53 | void preMarginalize();
54 | void marginalize();
55 | std::vector getParameterBlocks(std::unordered_map &addr_shift);
56 |
57 | std::vector factors;
58 | int m, n;
59 | std::unordered_map parameter_block_size; //global size
60 | int sum_block_size;
61 | std::unordered_map parameter_block_idx; //local size
62 | std::unordered_map parameter_block_data;
63 |
64 | std::vector keep_block_size; //global size
65 | std::vector keep_block_idx; //local size
66 | std::vector keep_block_data;
67 |
68 | Eigen::MatrixXd linearized_jacobians;
69 | Eigen::VectorXd linearized_residuals;
70 | const double eps = 1e-8;
71 |
72 | };
73 |
74 | class MarginalizationFactor : public ceres::CostFunction
75 | {
76 | public:
77 | MarginalizationFactor(MarginalizationInfo* _marginalization_info);
78 | virtual bool Evaluate(double const *const *parameters, double *residuals, double **jacobians) const;
79 |
80 | MarginalizationInfo* marginalization_info;
81 | };
82 |
--------------------------------------------------------------------------------
/src/visual_odometry/visual_estimator/factor/pose_local_parameterization.cpp:
--------------------------------------------------------------------------------
1 | #include "pose_local_parameterization.h"
2 |
3 | bool PoseLocalParameterization::Plus(const double *x, const double *delta, double *x_plus_delta) const
4 | {
5 | Eigen::Map _p(x);
6 | Eigen::Map _q(x + 3);
7 |
8 | Eigen::Map dp(delta);
9 |
10 | Eigen::Quaterniond dq = Utility::deltaQ(Eigen::Map(delta + 3));
11 |
12 | Eigen::Map p(x_plus_delta);
13 | Eigen::Map q(x_plus_delta + 3);
14 |
15 | p = _p + dp;
16 | q = (_q * dq).normalized();
17 |
18 | return true;
19 | }
20 | bool PoseLocalParameterization::ComputeJacobian(const double *x, double *jacobian) const
21 | {
22 | Eigen::Map> j(jacobian);
23 | j.topRows<6>().setIdentity();
24 | j.bottomRows<1>().setZero();
25 |
26 | return true;
27 | }
28 |
--------------------------------------------------------------------------------
/src/visual_odometry/visual_estimator/factor/pose_local_parameterization.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include "../utility/utility.h"
6 |
7 | class PoseLocalParameterization : public ceres::LocalParameterization
8 | {
9 | virtual bool Plus(const double *x, const double *delta, double *x_plus_delta) const;
10 | virtual bool ComputeJacobian(const double *x, double *jacobian) const;
11 | virtual int GlobalSize() const { return 7; };
12 | virtual int LocalSize() const { return 6; };
13 | };
14 |
--------------------------------------------------------------------------------
/src/visual_odometry/visual_estimator/factor/projection_factor.cpp:
--------------------------------------------------------------------------------
1 | #include "projection_factor.h"
2 |
3 | Eigen::Matrix2d ProjectionFactor::sqrt_info;
4 | double ProjectionFactor::sum_t;
5 |
6 | ProjectionFactor::ProjectionFactor(const Eigen::Vector3d &_pts_i, const Eigen::Vector3d &_pts_j, int _cam_id) : pts_i(_pts_i), pts_j(_pts_j), cam_id(_cam_id)
7 | {
8 | #ifdef UNIT_SPHERE_ERROR
9 | Eigen::Vector3d b1, b2;
10 | Eigen::Vector3d a = pts_j.normalized();
11 | Eigen::Vector3d tmp(0, 0, 1);
12 | if(a == tmp)
13 | tmp << 1, 0, 0;
14 | b1 = (tmp - a * (a.transpose() * tmp)).normalized();
15 | b2 = a.cross(b1);
16 | tangent_base.block<1, 3>(0, 0) = b1.transpose();
17 | tangent_base.block<1, 3>(1, 0) = b2.transpose();
18 | #endif
19 | };
20 |
21 | bool ProjectionFactor::Evaluate(double const *const *parameters, double *residuals, double **jacobians) const
22 | {
23 | TicToc tic_toc;
24 | Eigen::Vector3d Pi(parameters[0][0], parameters[0][1], parameters[0][2]);
25 | Eigen::Quaterniond Qi(parameters[0][6], parameters[0][3], parameters[0][4], parameters[0][5]);
26 |
27 | Eigen::Vector3d Pj(parameters[1][0], parameters[1][1], parameters[1][2]);
28 | Eigen::Quaterniond Qj(parameters[1][6], parameters[1][3], parameters[1][4], parameters[1][5]);
29 |
30 | Eigen::Vector3d tic[NUM_OF_CAM_ALL];
31 | Eigen::Quaterniond qic[NUM_OF_CAM_ALL];
32 | for(int i = 0; i < NUM_OF_CAM; i++)
33 | {
34 | tic[i] << parameters[2][0+7*i], parameters[2][1+7*i], parameters[2][2+7*i];
35 | qic[i].w() = parameters[2][6+7*i]; qic[i].x() = parameters[2][3+7*i];
36 | qic[i].y() = parameters[2][4+7*i]; qic[i].z() = parameters[2][5+7*i];
37 | }
38 |
39 |
40 | // std::cout << "projection tic: " << parameters[2][7] << " " << parameters[2][8] << " " << parameters[2][9] << std::endl;
41 |
42 | //pts_i 是i时刻归一化相机坐标系下的3D坐标
43 | //第i帧相机坐标系下的的逆深度
44 | double inv_dep_i = parameters[3][0];
45 | //第i帧相机坐标系下的3D坐标
46 | Eigen::Vector3d pts_camera_i = pts_i / inv_dep_i;
47 | //第i帧IMU坐标系下的3D坐标
48 | Eigen::Vector3d pts_imu_i = qic[cam_id] * pts_camera_i + tic[cam_id];
49 | //世界坐标系下的3D坐标
50 | Eigen::Vector3d pts_w = Qi * pts_imu_i + Pi;
51 | //第j帧imu坐标系下的3D坐标
52 | Eigen::Vector3d pts_imu_j = Qj.inverse() * (pts_w - Pj);
53 | //第j帧相机坐标系下的3D坐标
54 | Eigen::Vector3d pts_camera_j = qic[cam_id].inverse() * (pts_imu_j - tic[cam_id]);
55 | Eigen::Map residual(residuals);
56 |
57 | #ifdef UNIT_SPHERE_ERROR
58 | residual = tangent_base * (pts_camera_j.normalized() - pts_j.normalized());
59 | #else
60 | double dep_j = pts_camera_j.z();
61 | residual = (pts_camera_j / dep_j).head<2>() - pts_j.head<2>();
62 | #endif
63 |
64 | residual = sqrt_info * residual;
65 |
66 | //reduce 表示残差residual对fci(pts_camera_j)的导数,同样根据不同的相机模型
67 | if (jacobians)
68 | {
69 | Eigen::Matrix3d Ri = Qi.toRotationMatrix();
70 | Eigen::Matrix3d Rj = Qj.toRotationMatrix();
71 | Eigen::Matrix3d ric = qic[cam_id].toRotationMatrix();
72 | Eigen::Matrix reduce(2, 3);
73 | #ifdef UNIT_SPHERE_ERROR
74 | double norm = pts_camera_j.norm();
75 | Eigen::Matrix3d norm_jaco;
76 | double x1, x2, x3;
77 | x1 = pts_camera_j(0);
78 | x2 = pts_camera_j(1);
79 | x3 = pts_camera_j(2);
80 | norm_jaco << 1.0 / norm - x1 * x1 / pow(norm, 3), - x1 * x2 / pow(norm, 3), - x1 * x3 / pow(norm, 3),
81 | - x1 * x2 / pow(norm, 3), 1.0 / norm - x2 * x2 / pow(norm, 3), - x2 * x3 / pow(norm, 3),
82 | - x1 * x3 / pow(norm, 3), - x2 * x3 / pow(norm, 3), 1.0 / norm - x3 * x3 / pow(norm, 3);
83 | reduce = tangent_base * norm_jaco;
84 | #else
85 | reduce << 1. / dep_j, 0, -pts_camera_j(0) / (dep_j * dep_j),
86 | 0, 1. / dep_j, -pts_camera_j(1) / (dep_j * dep_j);
87 | #endif
88 | reduce = sqrt_info * reduce;
89 |
90 | // 残差项的Jacobian
91 | // 先求fci对各项的Jacobian,然后用链式法则乘起来
92 | // 对第i帧的位姿 pbi,qbi 2X7的矩阵 最后一项是0
93 | if (jacobians[0])
94 | {
95 | Eigen::Map> jacobian_pose_i(jacobians[0]);
96 |
97 | Eigen::Matrix jaco_i;
98 | jaco_i.leftCols<3>() = ric.transpose() * Rj.transpose();
99 | jaco_i.rightCols<3>() = ric.transpose() * Rj.transpose() * Ri * -Utility::skewSymmetric(pts_imu_i);
100 |
101 | jacobian_pose_i.leftCols<6>() = reduce * jaco_i;
102 | jacobian_pose_i.rightCols<1>().setZero();
103 | }
104 | // 对第j帧的位姿 pbj,qbj
105 | if (jacobians[1])
106 | {
107 | Eigen::Map> jacobian_pose_j(jacobians[1]);
108 |
109 | Eigen::Matrix jaco_j;
110 | jaco_j.leftCols<3>() = ric.transpose() * -Rj.transpose();
111 | jaco_j.rightCols<3>() = ric.transpose() * Utility::skewSymmetric(pts_imu_j);
112 |
113 | jacobian_pose_j.leftCols<6>() = reduce * jaco_j;
114 | jacobian_pose_j.rightCols<1>().setZero();
115 | }
116 | // 对相机到IMU的外参 pbc,qbc (qic,tic)
117 | if (jacobians[2])
118 | {
119 | Eigen::Map> jacobian_ex_pose(jacobians[2]);
120 | Eigen::Matrix jaco_ex;
121 | jaco_ex.leftCols<3>() = ric.transpose() * (Rj.transpose() * Ri - Eigen::Matrix3d::Identity());
122 | Eigen::Matrix3d tmp_r = ric.transpose() * Rj.transpose() * Ri * ric;
123 | jaco_ex.rightCols<3>() = -tmp_r * Utility::skewSymmetric(pts_camera_i) + Utility::skewSymmetric(tmp_r * pts_camera_i) +
124 | Utility::skewSymmetric(ric.transpose() * (Rj.transpose() * (Ri * tic[cam_id] + Pi - Pj) - tic[cam_id]));
125 | jacobian_ex_pose.leftCols<6>() = reduce * jaco_ex;
126 | jacobian_ex_pose.rightCols<1>().setZero();
127 | }
128 | // 对逆深度 \lambda (inv_dep_i)
129 | if (jacobians[3])
130 | {
131 | Eigen::Map jacobian_feature(jacobians[3]);
132 | #if 1
133 | jacobian_feature = reduce * ric.transpose() * Rj.transpose() * Ri * ric * pts_i * -1.0 / (inv_dep_i * inv_dep_i);
134 | #else
135 | jacobian_feature = reduce * ric.transpose() * Rj.transpose() * Ri * ric * pts_i;
136 | #endif
137 | }
138 | }
139 | sum_t += tic_toc.toc();
140 |
141 | return true;
142 | }
--------------------------------------------------------------------------------
/src/visual_odometry/visual_estimator/factor/projection_factor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include "../utility/utility.h"
7 | #include "../utility/tic_toc.h"
8 | #include "../parameters.h"
9 |
10 | class ProjectionFactor : public ceres::SizedCostFunction<2, 7, 7, 7, 1>
11 | {
12 | public:
13 | ProjectionFactor(const Eigen::Vector3d &_pts_i, const Eigen::Vector3d &_pts_j, int _cam_id);
14 | virtual bool Evaluate(double const *const *parameters, double *residuals, double **jacobians) const;
15 | void check(double **parameters);
16 |
17 | Eigen::Vector3d pts_i, pts_j;
18 | int cam_id;
19 | Eigen::Matrix tangent_base;
20 | static Eigen::Matrix2d sqrt_info;
21 | static double sum_t;
22 | };
23 |
--------------------------------------------------------------------------------
/src/visual_odometry/visual_estimator/factor/projection_td_factor.cpp:
--------------------------------------------------------------------------------
1 | #include "projection_td_factor.h"
2 |
3 | Eigen::Matrix2d ProjectionTdFactor::sqrt_info;
4 | double ProjectionTdFactor::sum_t;
5 |
6 | ProjectionTdFactor::ProjectionTdFactor(const Eigen::Vector3d &_pts_i, const Eigen::Vector3d &_pts_j,
7 | const Eigen::Vector2d &_velocity_i, const Eigen::Vector2d &_velocity_j,
8 | const double _td_i, const double _td_j, const double _row_i, const double _row_j) :
9 | pts_i(_pts_i), pts_j(_pts_j),
10 | td_i(_td_i), td_j(_td_j)
11 | {
12 | velocity_i.x() = _velocity_i.x();
13 | velocity_i.y() = _velocity_i.y();
14 | velocity_i.z() = 0;
15 | velocity_j.x() = _velocity_j.x();
16 | velocity_j.y() = _velocity_j.y();
17 | velocity_j.z() = 0;
18 | row_i = _row_i - ROW / 2;
19 | row_j = _row_j - ROW / 2;
20 |
21 | #ifdef UNIT_SPHERE_ERROR
22 | Eigen::Vector3d b1, b2;
23 | Eigen::Vector3d a = pts_j.normalized();
24 | Eigen::Vector3d tmp(0, 0, 1);
25 | if(a == tmp)
26 | tmp << 1, 0, 0;
27 | b1 = (tmp - a * (a.transpose() * tmp)).normalized();
28 | b2 = a.cross(b1);
29 | tangent_base.block<1, 3>(0, 0) = b1.transpose();
30 | tangent_base.block<1, 3>(1, 0) = b2.transpose();
31 | #endif
32 | };
33 |
34 | bool ProjectionTdFactor::Evaluate(double const *const *parameters, double *residuals, double **jacobians) const
35 | {
36 | TicToc tic_toc;
37 | Eigen::Vector3d Pi(parameters[0][0], parameters[0][1], parameters[0][2]);
38 | Eigen::Quaterniond Qi(parameters[0][6], parameters[0][3], parameters[0][4], parameters[0][5]);
39 |
40 | Eigen::Vector3d Pj(parameters[1][0], parameters[1][1], parameters[1][2]);
41 | Eigen::Quaterniond Qj(parameters[1][6], parameters[1][3], parameters[1][4], parameters[1][5]);
42 |
43 | Eigen::Vector3d tic(parameters[2][0], parameters[2][1], parameters[2][2]);
44 | Eigen::Quaterniond qic(parameters[2][6], parameters[2][3], parameters[2][4], parameters[2][5]);
45 |
46 | double inv_dep_i = parameters[3][0];
47 |
48 | double td = parameters[4][0];
49 |
50 | Eigen::Vector3d pts_i_td, pts_j_td;
51 | pts_i_td = pts_i - (td - td_i + TR / ROW * row_i) * velocity_i;
52 | pts_j_td = pts_j - (td - td_j + TR / ROW * row_j) * velocity_j;
53 | Eigen::Vector3d pts_camera_i = pts_i_td / inv_dep_i;
54 | Eigen::Vector3d pts_imu_i = qic * pts_camera_i + tic;
55 | Eigen::Vector3d pts_w = Qi * pts_imu_i + Pi;
56 | Eigen::Vector3d pts_imu_j = Qj.inverse() * (pts_w - Pj);
57 | Eigen::Vector3d pts_camera_j = qic.inverse() * (pts_imu_j - tic);
58 | Eigen::Map residual(residuals);
59 |
60 | #ifdef UNIT_SPHERE_ERROR
61 | residual = tangent_base * (pts_camera_j.normalized() - pts_j_td.normalized());
62 | #else
63 | double dep_j = pts_camera_j.z();
64 | residual = (pts_camera_j / dep_j).head<2>() - pts_j_td.head<2>();
65 | #endif
66 |
67 | residual = sqrt_info * residual;
68 |
69 | if (jacobians)
70 | {
71 | Eigen::Matrix3d Ri = Qi.toRotationMatrix();
72 | Eigen::Matrix3d Rj = Qj.toRotationMatrix();
73 | Eigen::Matrix3d ric = qic.toRotationMatrix();
74 | Eigen::Matrix reduce(2, 3);
75 | #ifdef UNIT_SPHERE_ERROR
76 | double norm = pts_camera_j.norm();
77 | Eigen::Matrix3d norm_jaco;
78 | double x1, x2, x3;
79 | x1 = pts_camera_j(0);
80 | x2 = pts_camera_j(1);
81 | x3 = pts_camera_j(2);
82 | norm_jaco << 1.0 / norm - x1 * x1 / pow(norm, 3), - x1 * x2 / pow(norm, 3), - x1 * x3 / pow(norm, 3),
83 | - x1 * x2 / pow(norm, 3), 1.0 / norm - x2 * x2 / pow(norm, 3), - x2 * x3 / pow(norm, 3),
84 | - x1 * x3 / pow(norm, 3), - x2 * x3 / pow(norm, 3), 1.0 / norm - x3 * x3 / pow(norm, 3);
85 | reduce = tangent_base * norm_jaco;
86 | #else
87 | reduce << 1. / dep_j, 0, -pts_camera_j(0) / (dep_j * dep_j),
88 | 0, 1. / dep_j, -pts_camera_j(1) / (dep_j * dep_j);
89 | #endif
90 | reduce = sqrt_info * reduce;
91 |
92 | if (jacobians[0])
93 | {
94 | Eigen::Map> jacobian_pose_i(jacobians[0]);
95 |
96 | Eigen::Matrix jaco_i;
97 | jaco_i.leftCols<3>() = ric.transpose() * Rj.transpose();
98 | jaco_i.rightCols<3>() = ric.transpose() * Rj.transpose() * Ri * -Utility::skewSymmetric(pts_imu_i);
99 |
100 | jacobian_pose_i.leftCols<6>() = reduce * jaco_i;
101 | jacobian_pose_i.rightCols<1>().setZero();
102 | }
103 |
104 | if (jacobians[1])
105 | {
106 | Eigen::Map> jacobian_pose_j(jacobians[1]);
107 |
108 | Eigen::Matrix jaco_j;
109 | jaco_j.leftCols<3>() = ric.transpose() * -Rj.transpose();
110 | jaco_j.rightCols<3>() = ric.transpose() * Utility::skewSymmetric(pts_imu_j);
111 |
112 | jacobian_pose_j.leftCols<6>() = reduce * jaco_j;
113 | jacobian_pose_j.rightCols<1>().setZero();
114 | }
115 | if (jacobians[2])
116 | {
117 | Eigen::Map> jacobian_ex_pose(jacobians[2]);
118 | Eigen::Matrix jaco_ex;
119 | jaco_ex.leftCols<3>() = ric.transpose() * (Rj.transpose() * Ri - Eigen::Matrix3d::Identity());
120 | Eigen::Matrix3d tmp_r = ric.transpose() * Rj.transpose() * Ri * ric;
121 | jaco_ex.rightCols<3>() = -tmp_r * Utility::skewSymmetric(pts_camera_i) + Utility::skewSymmetric(tmp_r * pts_camera_i) +
122 | Utility::skewSymmetric(ric.transpose() * (Rj.transpose() * (Ri * tic + Pi - Pj) - tic));
123 | jacobian_ex_pose.leftCols<6>() = reduce * jaco_ex;
124 | jacobian_ex_pose.rightCols<1>().setZero();
125 | }
126 | if (jacobians[3])
127 | {
128 | Eigen::Map jacobian_feature(jacobians[3]);
129 | jacobian_feature = reduce * ric.transpose() * Rj.transpose() * Ri * ric * pts_i_td * -1.0 / (inv_dep_i * inv_dep_i);
130 | }
131 | if (jacobians[4])
132 | {
133 | Eigen::Map jacobian_td(jacobians[4]);
134 | jacobian_td = reduce * ric.transpose() * Rj.transpose() * Ri * ric * velocity_i / inv_dep_i * -1.0 +
135 | sqrt_info * velocity_j.head(2);
136 | }
137 | }
138 | sum_t += tic_toc.toc();
139 |
140 | return true;
141 | }
--------------------------------------------------------------------------------
/src/visual_odometry/visual_estimator/factor/projection_td_factor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include "../utility/utility.h"
7 | #include "../utility/tic_toc.h"
8 | #include "../parameters.h"
9 |
10 | //对imu-camera 时间戳不完全同步和 Rolling shutter 相机的支持
11 | class ProjectionTdFactor : public ceres::SizedCostFunction<2, 7, 7, 7, 1, 1>
12 | {
13 | public:
14 | ProjectionTdFactor(const Eigen::Vector3d &_pts_i, const Eigen::Vector3d &_pts_j,
15 | const Eigen::Vector2d &_velocity_i, const Eigen::Vector2d &_velocity_j,
16 | const double _td_i, const double _td_j, const double _row_i, const double _row_j);
17 | virtual bool Evaluate(double const *const *parameters, double *residuals, double **jacobians) const;
18 | void check(double **parameters);
19 |
20 | Eigen::Vector3d pts_i, pts_j;//角点在归一化平面的坐标
21 | Eigen::Vector3d velocity_i, velocity_j;//角点在归一化平面的速度
22 | double td_i, td_j;//处理IMU数据时用到的时间同步误差
23 | Eigen::Matrix tangent_base;
24 | double row_i, row_j;//角点图像坐标的纵坐标
25 | static Eigen::Matrix2d sqrt_info;
26 | static double sum_t;
27 | };
28 |
--------------------------------------------------------------------------------
/src/visual_odometry/visual_estimator/feature_manager.h:
--------------------------------------------------------------------------------
1 | #ifndef FEATURE_MANAGER_H
2 | #define FEATURE_MANAGER_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | using namespace std;
9 |
10 | #include
11 | using namespace Eigen;
12 |
13 | #include
14 | #include
15 |
16 | #include "parameters.h"
17 |
18 | class FeaturePerFrame
19 | {
20 | public:
21 | FeaturePerFrame(const Eigen::Matrix &_point, double td)
22 | {
23 | point.x() = _point(0);
24 | point.y() = _point(1);
25 | point.z() = _point(2);
26 | uv.x() = _point(3);
27 | uv.y() = _point(4);
28 | velocity.x() = _point(5);
29 | velocity.y() = _point(6);
30 | depth = _point(7);
31 | cur_td = td;
32 | }
33 | double cur_td;
34 | Vector3d point;
35 | Vector2d uv;
36 | Vector2d velocity;
37 | double z;
38 | bool is_used;
39 | double parallax;
40 | MatrixXd A;
41 | VectorXd b;
42 | double dep_gradient;
43 | double depth; // lidar depth, initialized with -1 from feature points in feature tracker node
44 | };
45 |
46 | class FeaturePerId
47 | {
48 | public:
49 | const int feature_id;
50 | const int cam_id;
51 | int start_frame;
52 | vector feature_per_frame;
53 |
54 | int used_num;
55 | bool is_outlier;
56 | bool is_margin;
57 | double estimated_depth;
58 | bool lidar_depth_flag;
59 | int solve_flag; // 0 haven't solve yet; 1 solve succ; 2 solve fail;
60 |
61 | Vector3d gt_p;
62 |
63 | FeaturePerId(int _feature_id, int _start_frame, double _measured_depth, int _cam_id)
64 | : feature_id(_feature_id), start_frame(_start_frame), cam_id(_cam_id),
65 | used_num(0), estimated_depth(-1.0), lidar_depth_flag(false), solve_flag(0)
66 | {
67 | if (_measured_depth > 0)
68 | {
69 | estimated_depth = _measured_depth;
70 | lidar_depth_flag = true;
71 | }
72 | else
73 | {
74 | estimated_depth = -1;
75 | lidar_depth_flag = false;
76 | }
77 | }
78 |
79 | int endFrame();
80 | };
81 |
82 | class FeatureManager
83 | {
84 | public:
85 | FeatureManager(Matrix3d _Rs[]);
86 |
87 | void setRic(Matrix3d _ric[]);
88 |
89 | void clearState();
90 |
91 | int getFeatureCount();
92 |
93 | bool addFeatureCheckParallax(int frame_count, const map>>> &image, double td);
94 | void debugShow();
95 | vector> getCorresponding(int frame_count_l, int frame_count_r);
96 |
97 | //void updateDepth(const VectorXd &x);
98 | void setDepth(const VectorXd &x);
99 | void removeFailures();
100 | void clearDepth(const VectorXd &x);
101 | VectorXd getDepthVector();
102 | void triangulate(Vector3d Ps[], Vector3d tic[], Matrix3d ric[]);
103 | void removeBackShiftDepth(Eigen::Matrix3d marg_R, Eigen::Vector3d marg_P, Eigen::Matrix3d new_R, Eigen::Vector3d new_P);
104 | void removeBack();
105 | void removeFront(int frame_count);
106 | void removeOutlier();
107 | list feature;
108 | int last_track_num;
109 |
110 | private:
111 | double compensatedParallax2(const FeaturePerId &it_per_id, int frame_count);
112 | const Matrix3d *Rs;
113 | Matrix3d ric[NUM_OF_CAM_ALL];
114 | };
115 |
116 | #endif
--------------------------------------------------------------------------------
/src/visual_odometry/visual_estimator/initial/initial_ex_rotation.cpp:
--------------------------------------------------------------------------------
1 | #include "initial_ex_rotation.h"
2 |
3 | InitialEXRotation::InitialEXRotation(){
4 | frame_count = 0;
5 | Rc.push_back(Matrix3d::Identity());
6 | Rc_g.push_back(Matrix3d::Identity());
7 | Rimu.push_back(Matrix3d::Identity());
8 | ric = Matrix3d::Identity();
9 | }
10 |
11 | bool InitialEXRotation::CalibrationExRotation(vector> corres, Quaterniond delta_q_imu, Matrix3d &calib_ric_result)
12 | {
13 | frame_count++;
14 | Rc.push_back(solveRelativeR(corres));
15 | Rimu.push_back(delta_q_imu.toRotationMatrix());
16 | Rc_g.push_back(ric.inverse() * delta_q_imu * ric);
17 |
18 | Eigen::MatrixXd A(frame_count * 4, 4);
19 | A.setZero();
20 | int sum_ok = 0;
21 | for (int i = 1; i <= frame_count; i++)
22 | {
23 | Quaterniond r1(Rc[i]);
24 | Quaterniond r2(Rc_g[i]);
25 |
26 | double angular_distance = 180 / M_PI * r1.angularDistance(r2);
27 | ROS_DEBUG(
28 | "%d %f", i, angular_distance);
29 |
30 | double huber = angular_distance > 5.0 ? 5.0 / angular_distance : 1.0;
31 | ++sum_ok;
32 | Matrix4d L, R;
33 |
34 | double w = Quaterniond(Rc[i]).w();
35 | Vector3d q = Quaterniond(Rc[i]).vec();
36 | L.block<3, 3>(0, 0) = w * Matrix3d::Identity() + Utility::skewSymmetric(q);
37 | L.block<3, 1>(0, 3) = q;
38 | L.block<1, 3>(3, 0) = -q.transpose();
39 | L(3, 3) = w;
40 |
41 | Quaterniond R_ij(Rimu[i]);
42 | w = R_ij.w();
43 | q = R_ij.vec();
44 | R.block<3, 3>(0, 0) = w * Matrix3d::Identity() - Utility::skewSymmetric(q);
45 | R.block<3, 1>(0, 3) = q;
46 | R.block<1, 3>(3, 0) = -q.transpose();
47 | R(3, 3) = w;
48 |
49 | A.block<4, 4>((i - 1) * 4, 0) = huber * (L - R);
50 | }
51 |
52 | JacobiSVD svd(A, ComputeFullU | ComputeFullV);
53 | Matrix x = svd.matrixV().col(3);
54 | Quaterniond estimated_R(x);
55 | ric = estimated_R.toRotationMatrix().inverse();
56 | //cout << svd.singularValues().transpose() << endl;
57 | //cout << ric << endl;
58 | Vector3d ric_cov;
59 | ric_cov = svd.singularValues().tail<3>();
60 | if (frame_count >= WINDOW_SIZE && ric_cov(1) > 0.25)
61 | {
62 | calib_ric_result = ric;
63 | return true;
64 | }
65 | else
66 | return false;
67 | }
68 |
69 | Matrix3d InitialEXRotation::solveRelativeR(const vector> &corres)
70 | {
71 | if (corres.size() >= 9)
72 | {
73 | vector ll, rr;
74 | for (int i = 0; i < int(corres.size()); i++)
75 | {
76 | ll.push_back(cv::Point2f(corres[i].first(0), corres[i].first(1)));
77 | rr.push_back(cv::Point2f(corres[i].second(0), corres[i].second(1)));
78 | }
79 | cv::Mat E = cv::findFundamentalMat(ll, rr);
80 | cv::Mat_ R1, R2, t1, t2;
81 | decomposeE(E, R1, R2, t1, t2);
82 |
83 | if (determinant(R1) + 1.0 < 1e-09)
84 | {
85 | E = -E;
86 | decomposeE(E, R1, R2, t1, t2);
87 | }
88 | double ratio1 = max(testTriangulation(ll, rr, R1, t1), testTriangulation(ll, rr, R1, t2));
89 | double ratio2 = max(testTriangulation(ll, rr, R2, t1), testTriangulation(ll, rr, R2, t2));
90 | cv::Mat_ ans_R_cv = ratio1 > ratio2 ? R1 : R2;
91 |
92 | Matrix3d ans_R_eigen;
93 | for (int i = 0; i < 3; i++)
94 | for (int j = 0; j < 3; j++)
95 | ans_R_eigen(j, i) = ans_R_cv(i, j);
96 | return ans_R_eigen;
97 | }
98 | return Matrix3d::Identity();
99 | }
100 |
101 | double InitialEXRotation::testTriangulation(const vector &l,
102 | const vector &r,
103 | cv::Mat_ R, cv::Mat_ t)
104 | {
105 | cv::Mat pointcloud;
106 | cv::Matx34f P = cv::Matx34f(1, 0, 0, 0,
107 | 0, 1, 0, 0,
108 | 0, 0, 1, 0);
109 | cv::Matx34f P1 = cv::Matx34f(R(0, 0), R(0, 1), R(0, 2), t(0),
110 | R(1, 0), R(1, 1), R(1, 2), t(1),
111 | R(2, 0), R(2, 1), R(2, 2), t(2));
112 | cv::triangulatePoints(P, P1, l, r, pointcloud);
113 | int front_count = 0;
114 | for (int i = 0; i < pointcloud.cols; i++)
115 | {
116 | double normal_factor = pointcloud.col(i).at(3);
117 |
118 | cv::Mat_ p_3d_l = cv::Mat(P) * (pointcloud.col(i) / normal_factor);
119 | cv::Mat_ p_3d_r = cv::Mat(P1) * (pointcloud.col(i) / normal_factor);
120 | if (p_3d_l(2) > 0 && p_3d_r(2) > 0)
121 | front_count++;
122 | }
123 | ROS_DEBUG("MotionEstimator: %f", 1.0 * front_count / pointcloud.cols);
124 | return 1.0 * front_count / pointcloud.cols;
125 | }
126 |
127 | void InitialEXRotation::decomposeE(cv::Mat E,
128 | cv::Mat_ &R1, cv::Mat_ &R2,
129 | cv::Mat_ &t1, cv::Mat_ &t2)
130 | {
131 | cv::SVD svd(E, cv::SVD::MODIFY_A);
132 | cv::Matx33d W(0, -1, 0,
133 | 1, 0, 0,
134 | 0, 0, 1);
135 | cv::Matx33d Wt(0, 1, 0,
136 | -1, 0, 0,
137 | 0, 0, 1);
138 | R1 = svd.u * cv::Mat(W) * svd.vt;
139 | R2 = svd.u * cv::Mat(Wt) * svd.vt;
140 | t1 = svd.u.col(2);
141 | t2 = -svd.u.col(2);
142 | }
143 |
--------------------------------------------------------------------------------
/src/visual_odometry/visual_estimator/initial/initial_ex_rotation.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include "../parameters.h"
5 | using namespace std;
6 |
7 | #include
8 |
9 | #include
10 | using namespace Eigen;
11 | #include
12 |
13 | /* This class help you to calibrate extrinsic rotation between imu and camera when your totally don't konw the extrinsic parameter */
14 | class InitialEXRotation
15 | {
16 | public:
17 | InitialEXRotation();
18 | bool CalibrationExRotation(vector> corres, Quaterniond delta_q_imu, Matrix3d &calib_ric_result);
19 | private:
20 | Matrix3d solveRelativeR(const vector> &corres);
21 |
22 | double testTriangulation(const vector &l,
23 | const vector &r,
24 | cv::Mat_ R, cv::Mat_ t);
25 | void decomposeE(cv::Mat E,
26 | cv::Mat_ &R1, cv::Mat_ &R2,
27 | cv::Mat_ &t1, cv::Mat_ &t2);
28 | int frame_count;
29 |
30 | vector< Matrix3d > Rc;
31 | vector< Matrix3d > Rimu;
32 | vector< Matrix3d > Rc_g;
33 | Matrix3d ric;
34 | };
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/visual_odometry/visual_estimator/initial/initial_sfm.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include