├── .gitignore
├── CMakeLists.txt
├── README.md
├── app
└── larvioMain.cpp
├── cmake
├── FindEigen3.cmake
└── FindSuiteSparse.cmake
├── config
├── euroc.yaml
└── mynteye.yaml
├── docker
└── Dockerfile
├── include
├── Initializer
│ ├── DynamicInitializer.h
│ ├── FlexibleInitializer.h
│ ├── ImuPreintegration.h
│ ├── StaticInitializer.h
│ ├── feature_manager.h
│ ├── initial_alignment.h
│ ├── initial_sfm.h
│ └── solve_5pts.h
├── ORB
│ └── ORBDescriptor.h
├── larvio
│ ├── feature.hpp
│ ├── feature_msg.h
│ ├── image_processor.h
│ ├── imu_state.h
│ ├── larvio.h
│ └── math_utils.hpp
├── sensors
│ ├── ImageData.hpp
│ └── ImuData.hpp
├── utils
│ └── DataReader.hpp
└── visualization
│ └── visualize.hpp
├── licenses
├── LICENCE_VINS_MONO.txt
├── LICENSE_MSCKF_VIO.txt
└── LICENSE_ORB_SLAM2.txt
├── results
├── TX2_result.png
├── comparison.jpg
├── euroc_x8.gif
├── tumvi_c_1.jpg
└── uzhfpv_o_f_3.jpg
├── ros_wrapper
└── src
│ └── larvio
│ ├── CMakeLists.txt
│ ├── include
│ ├── System.h
│ └── System_nodelet.h
│ ├── launch
│ ├── euroc
│ │ └── larvio_euroc.launch
│ └── rviz
│ │ ├── larvio.rviz
│ │ └── larvio_rviz.launch
│ ├── nodelets.xml
│ ├── package.xml
│ └── src
│ ├── System.cpp
│ └── System_nodelet.cpp
├── run.sh
└── src
├── DynamicInitializer.cpp
├── FlexibleInitializer.cpp
├── ORBDescriptor.cpp
├── StaticInitializer.cpp
├── feature_manager.cpp
├── image_processor.cpp
├── initial_alignment.cpp
├── initial_sfm.cpp
├── larvio.cpp
└── solve_5pts.cpp
/.gitignore:
--------------------------------------------------------------------------------
1 | **/build/
2 | **/devel/
3 | bin/
4 | .vscode/
5 | *.*~
6 | .DS_Store
7 | ros_wrapper/src/CMakeLists.txt
8 | ros_wrapper/.catkin_workspace
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | set(CMAKE_BUILD_TYPE "Release")
4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
5 |
6 | project(larvio)
7 |
8 | set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
9 | #set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
10 |
11 | find_package(OpenCV REQUIRED)
12 | find_package(Boost REQUIRED)
13 | find_package(Ceres REQUIRED)
14 | find_package(Eigen3 REQUIRED)
15 | find_package(SuiteSparse REQUIRED)
16 | find_package(Pangolin REQUIRED)
17 |
18 | include_directories(
19 | ${PROJECT_SOURCE_DIR}/include
20 | ${OpenCV_INCLUDE_DIRS}
21 | ${SUITESPARSE_INCLUDE_DIRS}
22 | ${CERES_INCLUDE_DIRS}
23 | ${Boost_INCLUDE_DIR}
24 | ${EIGEN3_INCLUDE_DIR}
25 | ${Pangolin_INCLUDE_DIRS}
26 | )
27 |
28 | # Image processor
29 | add_library(image_processor
30 | ${PROJECT_SOURCE_DIR}/src/image_processor.cpp
31 | ${PROJECT_SOURCE_DIR}/src/ORBDescriptor.cpp
32 | )
33 | target_link_libraries(image_processor
34 | ${OpenCV_LIBRARIES}
35 | )
36 |
37 | # Initializer
38 | # -- Static Initializer
39 | add_library(staticInitializer
40 | ${PROJECT_SOURCE_DIR}/src/StaticInitializer.cpp
41 | )
42 | target_link_libraries(staticInitializer
43 | ${SUITESPARSE_LIBRARIES}
44 | )
45 | # -- Dynamic Initializer
46 | add_library(dynamicInitializer
47 | ${PROJECT_SOURCE_DIR}/src/StaticInitializer.cpp
48 | ${PROJECT_SOURCE_DIR}/src/DynamicInitializer.cpp
49 | ${PROJECT_SOURCE_DIR}/src/feature_manager.cpp
50 | ${PROJECT_SOURCE_DIR}/src/initial_alignment.cpp
51 | ${PROJECT_SOURCE_DIR}/src/initial_sfm.cpp
52 | ${PROJECT_SOURCE_DIR}/src/solve_5pts.cpp
53 | )
54 | target_link_libraries(dynamicInitializer
55 | ${SUITESPARSE_LIBRARIES}
56 | ${CERES_LIBRARIES}
57 | ${OpenCV_LIBRARIES}
58 | )
59 | # -- Flexible Initializer
60 | add_library(flexibleInitializer
61 | ${PROJECT_SOURCE_DIR}/src/FlexibleInitializer.cpp
62 | )
63 | target_link_libraries(flexibleInitializer
64 | staticInitializer
65 | dynamicInitializer
66 | )
67 |
68 | # Estimator
69 | add_library(estimator
70 | ${PROJECT_SOURCE_DIR}/src/larvio.cpp
71 | )
72 | target_link_libraries(estimator
73 | flexibleInitializer
74 | ${SUITESPARSE_LIBRARIES}
75 | ${OpenCV_LIBRARIES}
76 | )
77 |
78 | # App
79 | add_executable(larvio app/larvioMain.cpp)
80 | target_link_libraries(larvio
81 | image_processor
82 | estimator
83 | ${OpenCV_LIBS}
84 | ${Pangolin_LIBRARIES}
85 | )
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LARVIO
2 | LARVIO is short for Lightweight, Accurate and Robust monocular Visual Inertial Odometry, which is based on hybrid EKF VIO. It is featured by augmenting features with long track length into the filter state of MSCKF by 1D IDP to provide accurate positioning results.
3 |
4 | The core algorithm of LARVIO depends on `Eigen`, `Boost`, `Suitesparse`, `Ceres` and `OpenCV`, making the algorithm of good portability.
5 |
6 | A single-thread toyish example as well as a ROS nodelet package for LARVIO is provided in this repo.
7 |
8 | Notice that Hamilton quaternion is utilized in LARVIO, which is a little bit different from the JPL quaternion used in traditional MSCKF community. The filter formulation is thus derivated from scratch. Please check our [CJA2020](https://www.sciencedirect.com/science/article/pii/S1000936120301722) and [Senors2019](https://www.mdpi.com/1424-8220/19/8/1941/htm) papers for details.
9 |
10 |
11 | ## Results
12 | #### 1) Demo on EuRoC
13 | 
14 |
15 | #### 2) Trajectories RMSEs
16 | This is the results of an earlier version of LARVIO. Due to the changes, the current repo might not reproduce the exact results as below.
17 |
18 | RMSE on EuRoC dataset are listed.
19 |
20 | Evaluations below are done using [PetWorm/sim3_evaluate_tool](https://github.com/PetWorm/sim3_evaluate_tool).
21 |
22 | In the newest update, online imu-cam extrinsic and timestamp error calibration in VINS-MONO are turned on to explore its extreme ability. While in this setup, the V102 sequence would somehow fail. The result of VINS-MONO in V102 below is of setup without online calibration.
23 |
24 | Results of our algorithm are repeatible in every run of every computer I tested so far.
25 |
26 | 
27 |
28 | #### 3) TUM-VI Dataset
29 |
30 |
31 | #### 4) UZH-FPV Dataset
32 |
33 |
34 |
35 | ## Cross Platform Performance
36 | This package has been successfully deployed on ARM (Jetson Nano and Jetson TX2, realtime without GPU refinement). The performances are comparable to the results on PCs.
37 |
38 | Below is the exper1ment result in our office. A TX2-based multi-thread CPU-only implementation without ROS was developed here. We used [MYNT-EYE-D](https://github.com/slightech/MYNT-EYE-D-SDK) camera SDK to collect monocular images and IMU data, and estimate the camera poses in realtime. We walk around out the office to the corridor or the neighbor room, and return to the start point (in white circle) for a couple of times.
39 |
40 | 
41 |
42 |
43 | ## Acknowledgement
44 | This repo is for academic use only.
45 |
46 | LARVIO is originally developed based on [MSCKF_VIO](https://github.com/KumarRobotics/msckf_vio). Tremendous changes has been made, including the interface, visualization, visual front-end and filter details.
47 |
48 | LARVIO also benefits from [VINS-MONO](https://github.com/HKUST-Aerial-Robotics/VINS-Mono) and [ORB_SLAM2](https://github.com/raulmur/ORB_SLAM2).
49 |
50 | We would like to thank the authors of repos above for their great contribution. We kept the copyright announcement of these repos.
51 |
52 |
53 | ## Introduction
54 | LARVIO is an EKF-based monocular VIO. Loop closure was not applied in our algorithm.
55 | #### 1) Hybrid EKF with 1D IDP
56 | A hybrid EKF architecture is utilized, which is based on the work of [Mingyang Li](http://roboticsproceedings.org/rss08/p31.pdf). It augments features with long track length into the filter state. In LARVIO, One-Dimensional Inverse Depth Parametrization is utilized to parametrize the augmented feature state, which is different from the original 3d solution by Li. This novelty improves the computational efficiency compare to the 3d solution. The positioning precision is also improved thanks to the utilization of complete constraints of features with long track length.
57 | #### 2) Online calibration
58 | It is capable of online imu-cam extrinsic calibration, online timestamp error calibration and online imu intrinsic calibration.
59 | #### 3) Automatic initialization
60 | LARVIO can be automatically initialized in either static or dynamic scenerios.
61 | #### 4) Robust visual front-end
62 | We applied a ORB-descriptor assisted optical flow tracking visual front-end to improve the feature tracking performances.
63 | #### 5) Closed-form ZUPT
64 | A closed-form ZUPT measurement update is proposed to cope with the static scene.
65 |
66 |
67 | ## Feasibility
68 | LARVIO is a feasible software.
69 |
70 | Users can change the settings in config file to set the VIO as MSCKF-only, 3d hybrid or 1d hybrid solutions. And all the online calibration functions can be turned on or off in each solution by the config file.
71 |
72 |
73 | ## Dependencies
74 | LARVIO depends on `Eigen`, `Boost`, `Suitesparse`, `Ceres` and `OpenCV` for the core algorithm.
75 | #### Toyish example
76 | The toyish example depends on `OpenCV` (4.1.2 on OSX and 3.4.6 on Ubuntu 16.04/18.04), `Pangolin` is needed for visualization. Notice that extra `gcc 7` installation is needed for Ubuntu 16.04.
77 | #### ROS nodelet
78 | The ROS nodelet package has been tested on `Kinetic` and `Melodic` for Ubuntu 16.04/18.04. Following ROS packages are needed: `tf`, `cv_bridge`, `message_filters` and `image_transport`.
79 |
80 |
81 | ## Usage
82 | This part show how to play LARVIO with [EuRoC dataset](https://projects.asl.ethz.ch/datasets/doku.php?id=kmavvisualinertialdatasets).
83 | #### Toyish example
84 | The toyish LARVIO example is a `CMake` based software. After install the dependencies, try commands below to compile the software:
85 | ```
86 | cd LARVIO
87 | mkdir build
88 | cd build
89 | cmake -D CMAKE_BUILD_TYPE=Release ..
90 | make
91 | ```
92 | An example is given in `LARVIO/run.sh` to show how to run the example.
93 | #### ROS nodelet
94 | A ROS nodelet package is provided in `LARVIO/ros_wrapper`. It has been tested on `Kinetic` and `Melodic`. Use commands below to compile the nodelet:
95 | ```
96 | cd YOUR_PATH/LARVIO/ros_wrapper
97 | catkin_make
98 | ```
99 | After building it, launch the LARVIO by:
100 | ```
101 | . YOUR_PATH/LARVIO/ros_wrapper/devel/setup.bash
102 | roslaunch larvio larvio_euroc.launch
103 | ```
104 | Open a new terminal, and launch the `rviz` for visualization by (optional):
105 | ```
106 | . YOUR_PATH/LARVIO/ros_wrapper/devel/setup.bash
107 | roslaunch larvio larvio_rviz.launch
108 | ```
109 | Open a new terminal to play the dataset:
110 | ```
111 | rosbag play MH_01_easy.bag
112 | ```
113 |
114 |
115 | ## Docker
116 | A `Dockerfile` is provided in `LARVIO/docker`. After building it, you need to load dateset and modify the `run.sh` in container to run toyish example, or use 'roslaunch' to run the ROS package. Also, GUI is needed in the host to display the Pangolin and rviz view.
117 |
118 | There is another VNC docker image which is convinent for monitoring the rviz view. Click [petworm/vnc-larvio-playground](https://hub.docker.com/r/petworm/vnc-larvio-playground) to directly pull this image, or build it from source with [PetWorm/docker-larvio-playground](https://github.com/PetWorm/docker-larvio-playground).
119 |
120 |
121 | ## Related Works
122 | Please cite our CJA paper if you use LARVIO in your research:
123 | ```txt
124 | @article{qiu2020lightweight,
125 | title={Lightweight hybrid Visual-Inertial Odometry with Closed-Form Zero Velocity Update},
126 | author={Qiu, Xiaochen and Zhang, Hai and Fu, Wenxing},
127 | journal={Chinese Journal of Aeronautics},
128 | year={2020},
129 | publisher={Elsevier}
130 | }
131 | ```
132 |
133 | Another earlier work illustrating some parts of LARVIO is as below:
134 | ```txt
135 | @article{qiu2019monocular,
136 | title={Monocular Visual-Inertial Odometry with an Unbiased Linear System Model and Robust Feature Tracking Front-End},
137 | author={Qiu, Xiaochen and Zhang, Hai and Fu, Wenxing and Zhao, Chenxu and Jin, Yanqiong},
138 | journal={Sensors},
139 | volume={19},
140 | number={8},
141 | pages={1941},
142 | year={2019},
143 | publisher={Multidisciplinary Digital Publishing Institute}
144 | }
145 | ```
--------------------------------------------------------------------------------
/app/larvioMain.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * @Descripttion: Main function to boost LARVIO.
3 | * @Author: Xiaochen Qiu
4 | */
5 |
6 |
7 | #include
8 |
9 | #include "utils/DataReader.hpp"
10 |
11 | #include "opencv2/core.hpp"
12 | #include "opencv2/highgui.hpp"
13 |
14 | #include "sensors/ImageData.hpp"
15 |
16 | #include "larvio/image_processor.h"
17 | #include "larvio/larvio.h"
18 |
19 | #include "Eigen/Dense"
20 |
21 | #include "visualization/visualize.hpp"
22 |
23 | using namespace std;
24 |
25 |
26 | int main(int argc, char **argv) {
27 | if(argc != 5) {
28 | cerr << endl << "Usage: ./larvio path_to_imu/data.csv path_to_cam0/data.csv path_to_cam0/data config_file_path" << endl;
29 | return 1;
30 | }
31 |
32 | // Read sensors
33 | vector allImuData;
34 | vector allImgInfo;
35 | larvio::loadImuFile(argv[1], allImuData);
36 | larvio::loadImageList(argv[2], allImgInfo);
37 |
38 | // Path of config file
39 | std::string config_file(argv[4]);
40 |
41 | // Initialize image processer.
42 | larvio::ImageProcessorPtr ImgProcesser;
43 | ImgProcesser.reset(new larvio::ImageProcessor(config_file));
44 | if (!ImgProcesser->initialize()) {
45 | cerr << "Image Processer initialization failed!" << endl;
46 | return 1;
47 | }
48 |
49 | // Initialize estimator.
50 | larvio::LarVioPtr Estimator;
51 | Estimator.reset(new larvio::LarVio(config_file));
52 | if (!Estimator->initialize()) {
53 | cerr << "Estimator initialization failed!" << endl;
54 | return 1;
55 | }
56 |
57 | // Initialize visualizer
58 | pangolin::CreateWindowAndBind("LARVIO Viewer",1024,768);
59 | glEnable(GL_DEPTH_TEST); // 3D Mouse handler requires depth testing to be enabled
60 | glEnable(GL_BLEND); // Issue specific OpenGl we might need
61 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
62 | pangolin::CreatePanel("menu").SetBounds(0.0,1.0,0.0,pangolin::Attach::Pix(175));
63 | pangolin::Var menuFollowCamera("menu.Follow Camera",true,true);
64 | pangolin::Var menuShowActivePoints("menu.Show Active Points",true,true);
65 | pangolin::Var menuShowStablePoints("menu.Show Stable Points",true,true);
66 | pangolin::Var menuShowSlideWindow("menu.Show Slide Window",true,true);
67 | pangolin::OpenGlRenderState s_cam( // Define Camera Render Object (for view / scene browsing)
68 | pangolin::ProjectionMatrix(1024,768,500,500,512,389,0.1,1000),
69 | pangolin::ModelViewLookAt(0,3.5,9, 0,0,0, 0,-1,0)
70 | );
71 | pangolin::View& d_cam = pangolin::CreateDisplay() // Add named OpenGL viewport to window and provide 3D Handler
72 | .SetBounds(0.0, 1.0, pangolin::Attach::Pix(175), 1.0, -1024.0f/768.0f)
73 | .SetHandler(new pangolin::Handler3D(s_cam));
74 | pangolin::View& d_image = pangolin::CreateDisplay() // Add named OpenGL viewport to image and provide 3D Handler
75 | .SetBounds(pangolin::Attach::Pix(0),1.0f,pangolin::Attach::Pix(175),1/3.5f,752.0/480)
76 | .SetLock(pangolin::LockLeft, pangolin::LockBottom);
77 | bool bFollow = true;
78 | pangolin::OpenGlMatrix Tbw_pgl;
79 | std::vector vPoses;
80 | std::vector vPoses_SW;
81 | std::map mActiveMapPoints;
82 | std::map mStableMapPoints;
83 |
84 | // Main loop
85 | int k = 0;
86 | std::vector imu_msg_buffer;
87 | for(size_t j=0; jtimeStampToSec = allImgInfo[j].timeStampToSec;
95 | imgPtr->image = cv::imread(fullPath,0);
96 |
97 | // get imus
98 | while (allImuData[k].timeStampToSec-imgPtr->timeStampToSec < 0.05 && kprocessImage(imgPtr, imu_msg_buffer, features); // process image
108 | int64 end_time_fe = cv::getTickCount();
109 | double processing_time_fe = (end_time_fe - start_time_fe)/cv::getTickFrequency();
110 | double processing_time_be;
111 | bool bPubOdo = false;
112 | if (bProcess) {
113 | int64 start_time_be = cv::getTickCount();
114 | bPubOdo = Estimator->processFeatures(features, imu_msg_buffer); // state estimation
115 | int64 end_time_be = cv::getTickCount();
116 | processing_time_be = (end_time_be - start_time_be)/cv::getTickFrequency();
117 | }
118 | if (bPubOdo) { // Visualization
119 | // draw 3D
120 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
121 | larvio::visualize::GetCurrentOpenGLPoseMatrix(Tbw_pgl, Estimator->getTbw());
122 | if(menuFollowCamera && bFollow) {
123 | s_cam.Follow(Tbw_pgl);
124 | }
125 | else if(menuFollowCamera && !bFollow) {
126 | s_cam.SetModelViewMatrix(pangolin::ModelViewLookAt(0,3.5,9, 0,0,0, 0,-1,0));
127 | s_cam.Follow(Tbw_pgl);
128 | bFollow = true;
129 | }
130 | else if(!menuFollowCamera && bFollow) {
131 | bFollow = false;
132 | }
133 | d_cam.Activate(s_cam);
134 | glClearColor(0.0f,0.0f,0.0f,1.0f);
135 | larvio::visualize::DrawCurrentPose(Tbw_pgl);
136 | larvio::visualize::DrawKeyFrames(vPoses);
137 | if (menuShowSlideWindow) {
138 | vector swPoses;
139 | Estimator->getSwPoses(swPoses);
140 | larvio::visualize::GetSwOpenGLPoseMatrices(vPoses_SW, swPoses);
141 | larvio::visualize::DrawSlideWindow(vPoses_SW);
142 | }
143 | if (menuShowActivePoints) {
144 | Estimator->getActiveeMapPointPositions(mActiveMapPoints);
145 | larvio::visualize::DrawActiveMapPoints(mActiveMapPoints);
146 | mActiveMapPoints.clear();
147 | }
148 | if (menuShowStablePoints) {
149 | Estimator->getStableMapPointPositions(mStableMapPoints);
150 | larvio::visualize::DrawStableMapPoints(mStableMapPoints);
151 | }
152 |
153 | // draw tracking image
154 | cv::Mat img4Show;
155 | ImgProcesser->getVisualImg().copyTo(img4Show);
156 | stringstream ss;
157 | ss << "fps: " << 1.0/(processing_time_fe+processing_time_be) << " HZ";
158 | string msg = ss.str();
159 | int baseLine=0;
160 | cv::Size textSize = cv::getTextSize(msg, 0, 0.01, 10, &baseLine);
161 | cv::Point textOrigin(2*baseLine,textSize.height+4*baseLine);
162 | putText(img4Show, msg, textOrigin, 1, 2, cv::Scalar(0,165,255), 2);
163 | pangolin::GlTexture imageTexture(img4Show.cols,img4Show.rows);;
164 | imageTexture.Upload(img4Show.data,GL_BGR,GL_UNSIGNED_BYTE);
165 | d_image.Activate();
166 | glColor3f(1.0,1.0,1.0);
167 | imageTexture.RenderToViewportFlipY();
168 |
169 | pangolin::FinishFrame();
170 |
171 | vPoses.push_back(Tbw_pgl);
172 | }
173 | }
174 |
175 | cout << "Totally " << mStableMapPoints.size() << " SLAM points" << endl;
176 |
177 | // keep the final scene in pangolin
178 | while (!pangolin::ShouldQuit()) {
179 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
180 | if(menuFollowCamera && bFollow) {
181 | s_cam.Follow(Tbw_pgl);
182 | }
183 | else if(menuFollowCamera && !bFollow) {
184 | s_cam.SetModelViewMatrix(pangolin::ModelViewLookAt(0,3.5,9, 0,0,0, 0,-1,0));
185 | s_cam.Follow(Tbw_pgl);
186 | bFollow = true;
187 | }
188 | else if(!menuFollowCamera && bFollow) {
189 | bFollow = false;
190 | }
191 | d_cam.Activate(s_cam);
192 | glClearColor(0.0f,0.0f,0.0f,1.0f);
193 | larvio::visualize::DrawCurrentPose(Tbw_pgl);
194 | larvio::visualize::DrawKeyFrames(vPoses);
195 | if (menuShowSlideWindow) {
196 | larvio::visualize::DrawSlideWindow(vPoses_SW);
197 | }
198 | if (menuShowStablePoints) {
199 | larvio::visualize::DrawStableMapPoints(mStableMapPoints);
200 | }
201 | pangolin::FinishFrame();
202 | }
203 |
204 | return 0;
205 | }
--------------------------------------------------------------------------------
/cmake/FindEigen3.cmake:
--------------------------------------------------------------------------------
1 | # - Try to find Eigen3 lib
2 | #
3 | # This module supports requiring a minimum version, e.g. you can do
4 | # find_package(Eigen3 3.1.2)
5 | # to require version 3.1.2 or newer of Eigen3.
6 | #
7 | # Once done this will define
8 | #
9 | # EIGEN3_FOUND - system has eigen lib with correct version
10 | # EIGEN3_INCLUDE_DIR - the eigen include directory
11 | # EIGEN3_VERSION - eigen version
12 |
13 | # Copyright (c) 2006, 2007 Montel Laurent,
14 | # Copyright (c) 2008, 2009 Gael Guennebaud,
15 | # Copyright (c) 2009 Benoit Jacob
16 | # Redistribution and use is allowed according to the terms of the 2-clause BSD license.
17 |
18 | if(NOT Eigen3_FIND_VERSION)
19 | if(NOT Eigen3_FIND_VERSION_MAJOR)
20 | set(Eigen3_FIND_VERSION_MAJOR 2)
21 | endif(NOT Eigen3_FIND_VERSION_MAJOR)
22 | if(NOT Eigen3_FIND_VERSION_MINOR)
23 | set(Eigen3_FIND_VERSION_MINOR 91)
24 | endif(NOT Eigen3_FIND_VERSION_MINOR)
25 | if(NOT Eigen3_FIND_VERSION_PATCH)
26 | set(Eigen3_FIND_VERSION_PATCH 0)
27 | endif(NOT Eigen3_FIND_VERSION_PATCH)
28 |
29 | set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}")
30 | endif(NOT Eigen3_FIND_VERSION)
31 |
32 | macro(_eigen3_check_version)
33 | file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header)
34 |
35 | string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}")
36 | set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}")
37 | string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}")
38 | set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}")
39 | string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}")
40 | set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}")
41 |
42 | set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION})
43 | if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
44 | set(EIGEN3_VERSION_OK FALSE)
45 | else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
46 | set(EIGEN3_VERSION_OK TRUE)
47 | endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
48 |
49 | if(NOT EIGEN3_VERSION_OK)
50 |
51 | message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, "
52 | "but at least version ${Eigen3_FIND_VERSION} is required")
53 | endif(NOT EIGEN3_VERSION_OK)
54 | endmacro(_eigen3_check_version)
55 |
56 | if (EIGEN3_INCLUDE_DIR)
57 |
58 | # in cache already
59 | _eigen3_check_version()
60 | set(EIGEN3_FOUND ${EIGEN3_VERSION_OK})
61 |
62 | else (EIGEN3_INCLUDE_DIR)
63 |
64 | # specific additional paths for some OS
65 | if (WIN32)
66 | set(EIGEN_ADDITIONAL_SEARCH_PATHS ${EIGEN_ADDITIONAL_SEARCH_PATHS} "C:/Program Files/Eigen/include" "C:/Program Files (x86)/Eigen/include")
67 | endif(WIN32)
68 |
69 | find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library
70 | PATHS
71 | ${CMAKE_INSTALL_PREFIX}/include
72 | ${EIGEN_ADDITIONAL_SEARCH_PATHS}
73 | ${KDE4_INCLUDE_DIR}
74 | PATH_SUFFIXES eigen3 eigen
75 | )
76 |
77 | if(EIGEN3_INCLUDE_DIR)
78 | _eigen3_check_version()
79 | endif(EIGEN3_INCLUDE_DIR)
80 |
81 | include(FindPackageHandleStandardArgs)
82 | find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK)
83 |
84 | mark_as_advanced(EIGEN3_INCLUDE_DIR)
85 |
86 | endif(EIGEN3_INCLUDE_DIR)
87 |
88 |
--------------------------------------------------------------------------------
/config/euroc.yaml:
--------------------------------------------------------------------------------
1 | %YAML:1.0
2 |
3 | # output directory
4 | output_dir: "/root/larvio_results/"
5 |
6 | # switches
7 | if_FEJ: 1 # 0(false) or 1(true)
8 | estimate_extrin: 1 # 0(false) or 1(true)
9 | estimate_td: 1 # 0(false) or 1(true)
10 | calib_imu_instrinsic: 0 # 0(false) or 1(true)
11 |
12 | # camera instrinsic
13 | camera_model: "pinhole" # only support "pinhole"
14 | distortion_model: "radtan" # only support "radtan" and "equidistant"
15 | resolution_width: 752
16 | resolution_height: 480
17 | intrinsics:
18 | fx: 458.654
19 | fy: 457.296
20 | cx: 367.215
21 | cy: 248.375
22 | distortion_coeffs:
23 | k1: -0.28340811
24 | k2: 0.07395907
25 | p1: 0.00019359
26 | p2: 1.76187114e-05
27 |
28 | # imu-camera extrinsic, including spacial and temporal parameters
29 | T_cam_imu: !!opencv-matrix
30 | rows: 4
31 | cols: 4
32 | dt: d
33 | data:
34 | [0.014865542981794, 0.999557249008346, -0.025774436697440, 0.065222909535531,
35 | -0.999880929698575, 0.014967213324719, 0.003756188357967, -0.020706385492719,
36 | 0.004140296794224, 0.025715529947966, 0.999660727177902, -0.008054602460030,
37 | 0, 0, 0, 1.000000000000000]
38 | td: 0.0
39 |
40 | # TODO: if calibrate camera instrinsic online
41 |
42 | # visual front-end parameters
43 | pyramid_levels: 2
44 | patch_size: 21
45 | fast_threshold: 30
46 | max_iteration: 30
47 | track_precision: 0.01
48 | ransac_threshold: 1
49 | max_features_num: 200
50 | min_distance: 20
51 | flag_equalize: 1 # 0(false) or 1(true)
52 | pub_frequency: 10
53 |
54 | # window size
55 | sw_size: 20
56 |
57 | # online reset thresholds
58 | position_std_threshold: 8.0
59 | rotation_threshold: 0.2618
60 | translation_threshold: 0.4
61 | tracking_rate_threshold: 0.5
62 |
63 | # feature triangulation parameters
64 | least_observation_number: 3
65 | max_track_len: 6
66 | feature_translation_threshold: -1.0
67 |
68 | # imu and camera measurement noise parameters
69 | noise_gyro: 0.004
70 | noise_acc: 0.08
71 | noise_gyro_bias: 2e-6
72 | noise_acc_bias: 4e-5
73 | noise_feature: 0.008
74 |
75 | # filter intial covariance
76 | initial_covariance_orientation: 4e-4
77 | initial_covariance_velocity: 0.25
78 | initial_covariance_position: 1.0
79 | initial_covariance_gyro_bias: 4e-4
80 | initial_covariance_acc_bias: 0.01
81 | initial_covariance_extrin_rot: 3.0462e-8
82 | initial_covariance_extrin_trans: 9e-8
83 |
84 | # fej settings
85 | reset_fej_threshold: 10.11
86 |
87 | # zupt settings
88 | if_ZUPT_valid: 1 # 0(false) or 1(true)
89 | zupt_max_feature_dis: 2e-3
90 | zupt_noise_v: 1e-2 # std
91 | zupt_noise_p: 1e-2
92 | zupt_noise_q: 3.4e-2
93 |
94 | # static initialization setting
95 | static_duration: 1.0
96 |
97 | # measurement rate
98 | imu_rate: 200
99 | img_rate: 20
100 |
101 | # augmented feature state settings
102 | max_features_in_one_grid: 1 # pure msckf if set to 0
103 | aug_grid_rows: 5
104 | aug_grid_cols: 6
105 | feature_idp_dim: 1 # 1 or 3
106 |
107 | # if apply Schmidt filter
108 | use_schmidt: 0 # 0(false) or 1(true)
109 |
--------------------------------------------------------------------------------
/config/mynteye.yaml:
--------------------------------------------------------------------------------
1 | %YAML:1.0
2 |
3 | # output directory
4 | output_dir: "/Users/aresqiu/workSpace/larvio_results/"
5 |
6 | # switches
7 | if_FEJ: 1 # 0(false) or 1(true)
8 | estimate_extrin: 1 # 0(false) or 1(true)
9 | estimate_td: 1 # 0(false) or 1(true)
10 | calib_imu_instrinsic: 0 # 0(false) or 1(true)
11 |
12 | # camera instrinsic
13 | camera_model: "pinhole" # only support "pinhole"
14 | distortion_model: "equidistant" # only support "radtan" and "equidistant"
15 | resolution_width: 1280
16 | resolution_height: 720
17 | intrinsics:
18 | fx: 712.6506687297613
19 | fy: 713.3381366201213
20 | cx: 639.2566285415327
21 | cy: 377.90328510285144
22 | distortion_coeffs:
23 | k1: -0.015661749636940888
24 | k2: 0.0028974710951617955
25 | p1: 0.0034539528765559204
26 | p2: -0.006466223707507623
27 |
28 | # imu-camera extrinsic, including spacial and temporal parameters
29 | T_cam_imu: !!opencv-matrix
30 | rows: 4
31 | cols: 4
32 | dt: d
33 | data:
34 | [0.9999851351447288, -0.0010261392271367887, 0.005355046952563305, 0.04918070909625808,
35 | -0.0010359006126353073, -0.999997806554969, 0.001820383248210167, 0.003166959323659525,
36 | 0.0053531672399027685, -0.001825903484895496, -0.9999840047105576, -0.01496732752058007,
37 | 0, 0, 0, 1.000000000000000]
38 | td: 0.0
39 |
40 | # TODO: if calibrate camera instrinsic online
41 |
42 | # visual front-end parameters
43 | pyramid_levels: 2
44 | patch_size: 21
45 | fast_threshold: 30
46 | max_iteration: 30
47 | track_precision: 0.01
48 | ransac_threshold: 1
49 | max_features_num: 300
50 | min_distance: 15
51 | flag_equalize: 1 # 0(false) or 1(true)
52 | pub_frequency: 20
53 |
54 | # window size
55 | sw_size: 20
56 |
57 | # online reset thresholds
58 | position_std_threshold: 8.0
59 | rotation_threshold: 0.2618
60 | translation_threshold: 0.4
61 | tracking_rate_threshold: 0.5
62 |
63 | # feature triangulation parameters
64 | least_observation_number: 3
65 | max_track_len: 6
66 | feature_translation_threshold: -1.0
67 |
68 | # imu and camera measurement noise parameters
69 | noise_gyro: 0.01
70 | noise_acc: 0.1
71 | noise_gyro_bias: 2e-5
72 | noise_acc_bias: 4e-4
73 | noise_feature: 0.008
74 |
75 | # filter intial covariance
76 | initial_covariance_orientation: 4e-4
77 | initial_covariance_velocity: 0.25
78 | initial_covariance_position: 0.0
79 | initial_covariance_gyro_bias: 4e-4
80 | initial_covariance_acc_bias: 0.01
81 | initial_covariance_extrin_rot: 3.0462e-8
82 | initial_covariance_extrin_trans: 9e-8
83 |
84 | # fej settings
85 | reset_fej_threshold: 10.11
86 |
87 | # zupt settings
88 | if_ZUPT_valid: 1 # 0(false) or 1(true)
89 | zupt_max_feature_dis: 2e-3
90 | zupt_noise_v: 1e-2 # std
91 | zupt_noise_p: 1e-2
92 | zupt_noise_q: 3.4e-2
93 |
94 | # static initialization setting
95 | static_duration: 1.0
96 |
97 | # measurement rate
98 | imu_rate: 200
99 | img_rate: 30
100 |
101 | # augmented feature state settings
102 | max_features_in_one_grid: 1 # pure msckf if set to 0
103 | aug_grid_rows: 5
104 | aug_grid_cols: 7
105 | feature_idp_dim: 1 # 1 or 3
106 |
107 | # if apply Schmidt filter
108 | use_schmidt: 0 # 0(false) or 1(true)
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ros:melodic-perception
2 | MAINTAINER QIU Xiaochen
3 |
4 | ENV CERES_VERSION="1.14.0"
5 | ENV JOBS_NUM="4"
6 |
7 | RUN apt-get -y update && apt-get install -y \
8 | libboost-all-dev \
9 | cmake git \
10 | libgoogle-glog-dev \
11 | libeigen3-dev \
12 | libsuitesparse-dev \
13 | libgl1-mesa-dev \
14 | libglew-dev \
15 | libxkbcommon-x11-dev \
16 | ros-${ROS_DISTRO}-tf-conversions \
17 | ros-${ROS_DISTRO}-rviz && \
18 | rm -rf /var/lib/apt/lists/*
19 |
20 | RUN cd /root && \
21 | git clone https://github.com/ceres-solver/ceres-solver.git && \
22 | cd ceres-solver && git checkout tags/${CERES_VERSION} && \
23 | mkdir build && cd build && \
24 | cmake .. && make -j${JOBS_NUM} install && \
25 | cd /root && \
26 | git clone https://github.com/stevenlovegrove/Pangolin.git && \
27 | cd Pangolin && mkdir build && cd build && \
28 | cmake .. && make -j${JOBS_NUM} install && \
29 | rm -rf /root/*
30 |
31 | RUN cd /root && \
32 | git clone https://github.com/PetWorm/LARVIO.git && \
33 | cd LARVIO && mkdir build && cd build && \
34 | cmake -D CMAKE_BUILD_TYPE=Release .. && make -j${JOBS_NUM} && \
35 | cd ../ros_wrapper && . /opt/ros/${ROS_DISTRO}/setup.sh && \
36 | catkin_make -j${JOBS_NUM}
--------------------------------------------------------------------------------
/include/Initializer/DynamicInitializer.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by xiaochen at 19-8-13.
3 | // A vio initializer that utlize dynamic imu and img data to initialize.
4 | // The core method comes from VINS-MONO (https://github.com/HKUST-Aerial-Robotics/VINS-Mono)
5 | //
6 |
7 | #ifndef DYNAMIC_INITIALIZER_H
8 | #define DYNAMIC_INITIALIZER_H
9 |
10 | #include