├── .clang-format
├── .gitignore
├── .gitmodules
├── CMakeLists.txt
├── EQVIO_config_template.yaml
├── LICENSE
├── README.md
├── configs
├── EQVIO_config_EuRoC_stationary.yaml
├── EQVIO_config_UZHFPV.yaml
├── EQVIO_results_EuRoC_stationary.yaml
└── EQVIO_results_UZHFPV.yaml
├── docs
├── intrin.png
├── main.md
└── run.png
├── include
└── eqvio
│ ├── LoopTimer.h
│ ├── VIOFilter.h
│ ├── VIOFilterSettings.h
│ ├── VIOSimulator.h
│ ├── VIOVisualiser.h
│ ├── VIOWriter.h
│ ├── common
│ ├── LieYaml.h
│ ├── aofstream.h
│ └── safeConfig.h
│ ├── csv
│ ├── CSVFile.h
│ ├── CSVLine.h
│ └── CSVReader.h
│ ├── dataserver
│ ├── APDatasetReader.h
│ ├── ASLDatasetReader.h
│ ├── DataServerBase.h
│ ├── DatasetReaderBase.h
│ ├── HiltiDatasetReader.h
│ ├── RosbagDatasetReader.h
│ ├── SimpleDataServer.h
│ ├── SimulationDataServer.h
│ ├── ThreadedDataServer.h
│ ├── UZHFPVDatasetReader.h
│ └── dataservers.h
│ └── mathematical
│ ├── EqFMatrices.h
│ ├── Geometry.h
│ ├── IMUVelocity.h
│ ├── VIOGroup.h
│ ├── VIOState.h
│ ├── VIO_eqf.h
│ └── VisionMeasurement.h
├── intrinsics.yaml
├── libs
├── CMakeLists.txt
└── visualisation
│ ├── CMakeLists.txt
│ ├── include
│ ├── PlotDataTypes.h
│ └── Plotter.h
│ └── src
│ ├── Plotter.cpp
│ └── main.cpp
├── scripts
├── DatasetInfo.py
├── analyse_timing_data.py
├── analysis_tools.py
├── euroc_sequences.yaml
├── run_and_analyse_dataset.py
└── summarise_results.py
├── src
├── LoopTimer.cpp
├── VIOFilter.cpp
├── VIOSimulator.cpp
├── VIOVisualiser.cpp
├── VIOWriter.cpp
├── dataserver
│ ├── APDatasetReader.cpp
│ ├── ASLDatasetReader.cpp
│ ├── DataServerBase.cpp
│ ├── HiltiDatasetReader.cpp
│ ├── RosbagDatasetReader.cpp
│ ├── SimpleDataServer.cpp
│ ├── SimulationDataServer.cpp
│ ├── ThreadedDataServer.cpp
│ └── UZHFPVDatasetReader.cpp
├── main_opt.cpp
├── main_sim.cpp
└── mathematical
│ ├── EqFMatrices.cpp
│ ├── Geometry.cpp
│ ├── IMUVelocity.cpp
│ ├── VIOGroup.cpp
│ ├── VIOState.cpp
│ ├── VIO_eqf.cpp
│ ├── VisionMeasurement.cpp
│ └── coordinateSuite
│ ├── euclid.cpp
│ ├── invdepth.cpp
│ └── normal.cpp
└── test
├── CMakeLists.txt
├── GTestCMakeLists.txt.in
├── PrepareGTest.cmake
├── test_CSVReader.cpp
├── test_CoordinateCharts.cpp
├── test_EqFMatrices.cpp
├── test_FilterStatistics.cpp
├── test_VIOGroup.cpp
├── test_VIOGroupActions.cpp
├── test_VIOLift.cpp
├── test_settings.cpp
├── testing_utilities.cpp
└── testing_utilities.h
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | Language: Cpp
3 | # BasedOnStyle: LLVM
4 | AccessModifierOffset: -2
5 | AlignAfterOpenBracket: AlwaysBreak
6 | AlignConsecutiveMacros: false
7 | AlignConsecutiveAssignments: false
8 | AlignConsecutiveDeclarations: false
9 | AlignEscapedNewlines: Right
10 | AlignOperands: true
11 | AlignTrailingComments: true
12 | AllowAllArgumentsOnNextLine: true
13 | AllowAllConstructorInitializersOnNextLine: true
14 | AllowAllParametersOfDeclarationOnNextLine: true
15 | AllowShortBlocksOnASingleLine: Never
16 | AllowShortCaseLabelsOnASingleLine: false
17 | AllowShortFunctionsOnASingleLine: All
18 | AllowShortLambdasOnASingleLine: All
19 | AllowShortIfStatementsOnASingleLine: Never
20 | AllowShortLoopsOnASingleLine: false
21 | AlwaysBreakAfterDefinitionReturnType: None
22 | AlwaysBreakAfterReturnType: None
23 | AlwaysBreakBeforeMultilineStrings: false
24 | AlwaysBreakTemplateDeclarations: MultiLine
25 | BinPackArguments: true
26 | BinPackParameters: true
27 | BraceWrapping:
28 | AfterCaseLabel: false
29 | AfterClass: false
30 | AfterControlStatement: false
31 | AfterEnum: false
32 | AfterFunction: false
33 | AfterNamespace: false
34 | AfterObjCDeclaration: false
35 | AfterStruct: false
36 | AfterUnion: false
37 | AfterExternBlock: false
38 | BeforeCatch: false
39 | BeforeElse: false
40 | IndentBraces: false
41 | SplitEmptyFunction: true
42 | SplitEmptyRecord: true
43 | SplitEmptyNamespace: true
44 | BreakBeforeBinaryOperators: None
45 | BreakBeforeBraces: Attach
46 | BreakBeforeInheritanceComma: false
47 | BreakInheritanceList: BeforeColon
48 | BreakBeforeTernaryOperators: true
49 | BreakConstructorInitializersBeforeComma: false
50 | BreakConstructorInitializers: BeforeColon
51 | BreakAfterJavaFieldAnnotations: false
52 | BreakStringLiterals: true
53 | ColumnLimit: 120
54 | CommentPragmas: '^ IWYU pragma:'
55 | CompactNamespaces: false
56 | ConstructorInitializerAllOnOneLineOrOnePerLine: false
57 | ConstructorInitializerIndentWidth: 4
58 | ContinuationIndentWidth: 4
59 | Cpp11BracedListStyle: true
60 | DeriveLineEnding: true
61 | DerivePointerAlignment: false
62 | DisableFormat: false
63 | ExperimentalAutoDetectBinPacking: false
64 | FixNamespaceComments: true
65 | ForEachMacros:
66 | - foreach
67 | - Q_FOREACH
68 | - BOOST_FOREACH
69 | IncludeBlocks: Preserve
70 | IncludeCategories:
71 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
72 | Priority: 2
73 | SortPriority: 0
74 | - Regex: '^(<|"(gtest|gmock|isl|json)/)'
75 | Priority: 3
76 | SortPriority: 0
77 | - Regex: '.*'
78 | Priority: 1
79 | SortPriority: 0
80 | IncludeIsMainRegex: '(Test)?$'
81 | IncludeIsMainSourceRegex: ''
82 | IndentCaseLabels: false
83 | IndentGotoLabels: true
84 | IndentPPDirectives: None
85 | IndentWidth: 4
86 | IndentWrappedFunctionNames: false
87 | JavaScriptQuotes: Leave
88 | JavaScriptWrapImports: true
89 | KeepEmptyLinesAtTheStartOfBlocks: true
90 | MacroBlockBegin: ''
91 | MacroBlockEnd: ''
92 | MaxEmptyLinesToKeep: 1
93 | NamespaceIndentation: None
94 | ObjCBinPackProtocolList: Auto
95 | ObjCBlockIndentWidth: 2
96 | ObjCSpaceAfterProperty: false
97 | ObjCSpaceBeforeProtocolList: true
98 | PenaltyBreakAssignment: 2
99 | PenaltyBreakBeforeFirstCallParameter: 19
100 | PenaltyBreakComment: 300
101 | PenaltyBreakFirstLessLess: 120
102 | PenaltyBreakString: 1000
103 | PenaltyBreakTemplateDeclaration: 10
104 | PenaltyExcessCharacter: 1000000
105 | PenaltyReturnTypeOnItsOwnLine: 60
106 | PointerAlignment: Left
107 | ReflowComments: true
108 | SortIncludes: true
109 | SortUsingDeclarations: true
110 | SpaceAfterCStyleCast: false
111 | SpaceAfterLogicalNot: false
112 | SpaceAfterTemplateKeyword: true
113 | SpaceBeforeAssignmentOperators: true
114 | SpaceBeforeCpp11BracedList: false
115 | SpaceBeforeCtorInitializerColon: true
116 | SpaceBeforeInheritanceColon: true
117 | SpaceBeforeParens: ControlStatements
118 | SpaceBeforeRangeBasedForLoopColon: true
119 | SpaceInEmptyBlock: false
120 | SpaceInEmptyParentheses: false
121 | SpacesBeforeTrailingComments: 1
122 | SpacesInAngles: false
123 | SpacesInConditionalStatement: false
124 | SpacesInContainerLiterals: true
125 | SpacesInCStyleCastParentheses: false
126 | SpacesInParentheses: false
127 | SpacesInSquareBrackets: false
128 | SpaceBeforeSquareBrackets: false
129 | Standard: Latest
130 | StatementMacros:
131 | - Q_UNUSED
132 | - QT_REQUIRE_VERSION
133 | TabWidth: 8
134 | UseCRLF: false
135 | UseTab: Never
136 | ...
137 |
138 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode/*
2 | build/*
3 | build_stable/*
4 | .cache/*
5 | cmake-build-Release/*
6 | *.swp
7 | EQVIO_output*
8 | *.zip
9 | *.bag
10 | !*.yaml
11 | data/euroc/*
12 | **.pyc
13 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "external/GIFT"]
2 | path = external/GIFT
3 | url = git@github.com:pvangoor/GIFT.git
4 | [submodule "external/argparse"]
5 | path = external/argparse
6 | url = git@github.com:p-ranav/argparse.git
7 | [submodule "external/LiePP"]
8 | path = external/LiePP
9 | url = git@github.com:pvangoor/LiePP
10 | branch = main
11 |
--------------------------------------------------------------------------------
/EQVIO_config_template.yaml:
--------------------------------------------------------------------------------
1 | eqf:
2 | initialVariance:
3 | attitude: 1.0
4 | position: 1.0
5 | velocity: 1.0
6 | point: 5000.0
7 | pointDepth: -1.0
8 | cameraAttitude: 0.1
9 | cameraPosition: 0.1
10 | biasGyr: 1.0
11 | biasAcc: 1.0
12 | processVariance:
13 | cameraPosition: 0.0001
14 | cameraAttitude: 0.0001
15 | biasGyr: 0.0001
16 | biasAcc: 0.0001
17 | attitude: 0.01
18 | position: 0.01
19 | velocity: 0.1
20 | point: 0.001
21 | initialValue:
22 | sceneDepth: 1.0
23 | cameraOffset:
24 | - xw
25 | - -0.0216401454975
26 | - -0.064676986768
27 | - 0.00981073058949
28 | - 0.7123014606690344
29 | - -0.007707179755538301
30 | - 0.010499323370588468
31 | - 0.7017528002920512
32 | measurementNoise:
33 | feature: 0.003
34 | featureOutlierAbs: 0.01
35 | featureOutlierProb: 3.0
36 | featureRetention: 0.2
37 | velocityNoise:
38 | gyr: 0.0001
39 | acc: 0.0001
40 | gyrBias: 0.0001
41 | accBias: 0.0001
42 | settings:
43 | fastRiccati: false
44 | useDiscreteInnovationLift: true
45 | useDiscreteVelocityLift: true
46 | coordinateChoice: Euclidean
47 | useMedianDepth: true
48 | useFeaturePredictions: false
49 | useEquivariantOutput: true
50 | removeLostLandmarks: true
51 | useDiscreteStateMatrix: false
52 | GIFT:
53 | intrinsicsFile: intrinsics_example.yaml
54 | maxFeatures: 30
55 | featureDist: 30
56 | minHarrisQuality: 0.05
57 | featureSearchThreshold: 0.8
58 | maxError: 1e8
59 | winSize: 21
60 | maxLevel: 3
61 | trackedFeatureDist: 20.0
62 | equaliseImageHistogram: false
63 | main:
64 | writeState: false
65 | showVisualisation: true
66 | limitRate: 20.0 # Hz
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EqVIO (Equivariant Visual Inertial Odometry)
2 |
3 | This repository contains the implementation of EqVIO: An Equivariant Filter (EqF) for Visual Inertial Odometry (VIO).
4 |
5 | Please see https://pvangoor.github.io/eqvio_docs/ for the documentation.
6 |
7 | ## Dependencies
8 |
9 | - Eigen 3: `sudo apt install libeigen3-dev`
10 | - Yaml-cpp: `sudo apt install libyaml-cpp-dev`
11 | - GIFT: https://github.com/pvangoor/GIFT
12 |
13 | ### Optional Dependencis
14 |
15 | - FreeGLUT (for visualisations): `sudo apt install freeglut3-dev`
16 | - ROS (for reading ROS-Bags): http://wiki.ros.org/ROS/Installation
17 | - Doxygen (for documentation): `sudo apt install doxygen`
18 |
19 | ### Build Guide (for ros users)
20 |
21 | Modify the following settings in cmake if you want ROS compatibility.
22 | You can use command-line cmake, use cmake-gui for convenience, or edit the CMakeLists.txt directly.
23 |
24 | ```
25 | EQVIO_BUILD_TESTS ON
26 | EQVIO_BUILD_VISUALISATION ON
27 | EQVIO_BUILD_ROSBAG ON
28 | EQVIO_SUPPORT_CONCEPTS OFF
29 | EXTRA_WARNINGS ON
30 | ```
31 |
32 | Then do the following commands from a terminal in the main directory to build EqVIO:
33 |
34 | ```
35 | mkdir build
36 | cd build
37 | cmake ..
38 | cmake --build . -j8
39 | ```
40 |
41 | ### Running Guide
42 |
43 | #### ASL Dataset Format
44 |
45 | The file `intrinsics.yaml` is not needed as the required data is included in each sensor folder. Run EqVIO with:
46 |
47 | ```
48 | ./build/eqvio_opt ~/datasets/euroc_asl/V1_01_easy/ configs/EQVIO_config_EuRoC_stationary.yaml --display --mode asl
49 | ```
50 |
51 | You will need to replace the dataset directory with a directory of your choice.
52 |
53 |
54 | #### ROS bag
55 |
56 | The `intrinsics.yaml` file is extracted from the sensors'.yaml files.
57 | Since all of the sensors in the EuRoC dataset are identical, one intrinsics.yaml suits all.
58 | If you plan to use a different dataset, you will need to change the intrinsics to match accordingly.
59 | The example file is located in the root folder.
60 | To use it, you should place the `intrinsics.yaml` file in the same folder as the ROSbags you wish to use:
61 |
62 | 
63 |
64 | Run EqVIO on ROSbags using:
65 |
66 | ```
67 | ./build/eqvio_opt ./data/euroc/MH_03_medium.bag configs/EQVIO_config_EuRoC_stationary.yaml --display --mode ros
68 |
69 | ./build/eqvio_opt ./data/euroc/V1_02_medium.bag configs/EQVIO_config_EuRoC_stationary.yaml --display --mode ros
70 | ```
71 |
72 | 
73 |
74 | And result can be seen in the output file.
75 |
--------------------------------------------------------------------------------
/configs/EQVIO_config_EuRoC_stationary.yaml:
--------------------------------------------------------------------------------
1 | GIFT:
2 | equaliseImageHistogram: false
3 | useFastFeatures: false
4 | featureDist: 79.80937096082073
5 | featureSearchThreshold: 0.8854861727179565
6 | maxError: 76.21556706799433
7 | maxFeatures: 40
8 | maxLevel: 3
9 | minHarrisQuality: 0.0792713927794865
10 | ransacParams:
11 | inlierThreshold: 0.0023121620935037416
12 | maxIterations: 34
13 | minDataPoints: 5
14 | minInliers: 30
15 | trackedFeatureDist: 30.79127938908608
16 | winSize: 21
17 | eqf:
18 | initialValue:
19 | sceneDepth: 5.00028218320243
20 | initialVariance:
21 | attitude: 0.13565029126052572
22 | biasAcc: 1.5813333765300104
23 | biasGyr: 97162.79515771076
24 | cameraAttitude: 0.0010228558965517584
25 | cameraPosition: 0.023501400846134893
26 | point: 129.90415638150924
27 | position: 0.1
28 | velocity: 8.974852995731e-08
29 | measurementNoise:
30 | feature: 1.9297839969591413
31 | featureOutlierAbs: 4.852186665580312
32 | featureOutlierProb: 0.03229809583062128
33 | featureRetention: 0.18594708334486176
34 | processVariance:
35 | attitude: 6.025875320811407e-05
36 | biasAcc: 0.0
37 | biasGyr: 0.0
38 | cameraAttitude: 5.075382174045239e-06
39 | cameraPosition: 1.2188313140115635e-05
40 | point: 0.00029845436136043135
41 | position: 9.981466095928483e-06
42 | velocity: 0.025317333863551263
43 | settings:
44 | coordinateChoice: InvDepth
45 | fastRiccati: true
46 | useDiscreteInnovationLift: false
47 | useDiscreteVelocityLift: true
48 | useEquivariantOutput: true
49 | useFeaturePredictions: false
50 | useInnovationLift: true
51 | useMedianDepth: false
52 | velocityNoise:
53 | acc: 0.012438843268295521
54 | accBias: 0.004462289865453429
55 | gyr: 0.000243153572917808
56 | gyrBias: 0.00013372703521098622
57 | main:
58 | limitRate: 0.0
59 | startTime: 0.0
60 | writeState: true
61 | cameraLag: 0.00
62 |
63 |
64 | sim:
65 | cameraOffset:
66 | - xw
67 | - -0.04844625116694773
68 | - -0.08142350220051031
69 | - 0.003102425417307478
70 | - 0.7021240268103595
71 | - -0.006484783602096129
72 | - 0.013217864997878212
73 | - 0.7017528002920512
74 | fieldOfView: 60
75 | maxFeatures: 40
76 | numPoints: 5000
77 | randomSeed: 0
78 | wallDistance: 1.0
--------------------------------------------------------------------------------
/configs/EQVIO_config_UZHFPV.yaml:
--------------------------------------------------------------------------------
1 | GIFT:
2 | equaliseImageHistogram: true
3 | useFastFeatures: false
4 | featureDist: 25.91373395034039
5 | featureSearchThreshold: 0.7
6 | maxError: 100.08998519259788
7 | maxFeatures: 40
8 | maxLevel: 3
9 | minHarrisQuality: 0.08859465154404257
10 | ransacParams:
11 | inlierThreshold: 0.000991045856248861
12 | maxIterations: 20
13 | minDataPoints: 10
14 | minInliers: 37
15 | trackedFeatureDist: 9.995503774595479
16 | winSize: 21
17 | eqf:
18 | initialValue:
19 | sceneDepth: 8.891397050194614
20 | initialVariance:
21 | attitude: 0.10282752317467045
22 | biasAcc: 1.2232071190499316
23 | biasGyr: 1.1673134780260075
24 | cameraAttitude: 1.727825980507864e-07
25 | cameraPosition: 3.349654391578276e-07
26 | point: 100.0
27 | position: 0.00011220184543019634
28 | velocity: 3.6517412725483775e-06
29 | measurementNoise:
30 | feature: 3.7583740428844425
31 | featureOutlierAbs: 5.4509224619256385
32 | featureOutlierProb: 0.23374912831534894
33 | featureRetention: 0.2
34 | processVariance:
35 | attitude: 6.219421634147766e-08
36 | biasAcc: 0.0
37 | biasGyr: 0.0
38 | cameraAttitude: 2.2630153511576583e-06
39 | cameraPosition: 6.853895838650084e-07
40 | point: 0.000530103448340995
41 | position: 1.2589961848499808e-05
42 | velocity: 0.012232071190499315
43 | settings:
44 | coordinateChoice: InvDepth
45 | fastRiccati: true
46 | useDiscreteInnovationLift: false
47 | useDiscreteVelocityLift: true
48 | useEquivariantOutput: true
49 | useFeaturePredictions: false
50 | useInnovationLift: true
51 | useMedianDepth: false
52 | velocityNoise:
53 | acc: 3.262345818455677e-05
54 | accBias: 0.0063404671195099425
55 | gyr: 0.0011913242870580211
56 | gyrBias: 0.00020008996495836354
57 | main:
58 | cameraLag: 0.012232071190499317
59 | limitRate: 0.0
60 | startTime: 0.0
61 | writeState: true
62 | sim:
63 | cameraOffset:
64 | - xw
65 | - -0.04844625116694773
66 | - -0.08142350220051031
67 | - 0.003102425417307478
68 | - 0.7021240268103595
69 | - -0.006484783602096129
70 | - 0.013217864997878212
71 | - 0.7017528002920512
72 | fieldOfView: 60
73 | maxFeatures: 40
74 | numPoints: 5000
75 | randomSeed: 0
76 | wallDistance: 1.0
--------------------------------------------------------------------------------
/configs/EQVIO_results_EuRoC_stationary.yaml:
--------------------------------------------------------------------------------
1 | Early Finish flag:
2 | MH_01_easy: false
3 | MH_02_easy: false
4 | MH_03_medium: false
5 | MH_04_difficult: false
6 | MH_05_difficult: false
7 | V1_01_easy: false
8 | V1_02_medium: false
9 | V1_03_difficult: false
10 | V2_01_easy: false
11 | V2_02_medium: false
12 | V2_03_difficult: false
13 | NaN flag:
14 | MH_01_easy: false
15 | MH_02_easy: false
16 | MH_03_medium: false
17 | MH_04_difficult: false
18 | MH_05_difficult: false
19 | V1_01_easy: false
20 | V1_02_medium: false
21 | V1_03_difficult: false
22 | V2_01_easy: false
23 | V2_02_medium: false
24 | V2_03_difficult: false
25 | Trajectory length:
26 | MH_01_easy: 73.0157421651321
27 | MH_02_easy: 63.70540216156182
28 | MH_03_medium: 127.35526466112435
29 | MH_04_difficult: 88.6148895748826
30 | MH_05_difficult: 94.27476179359579
31 | V1_01_easy: 58.56120400739347
32 | V1_02_medium: 75.85980647296816
33 | V1_03_difficult: 78.92019389844371
34 | V2_01_easy: 36.43699718581205
35 | V2_02_medium: 83.15172072264541
36 | V2_03_difficult: 85.98779430736637
37 | attitude (d)/rmse:
38 | MH_01_easy: 2.153860998826013
39 | MH_02_easy: 1.2320652677435886
40 | MH_03_medium: 1.1419450564319433
41 | MH_04_difficult: 1.0272909031453876
42 | MH_05_difficult: 1.2972947523513327
43 | V1_01_easy: 5.832888183647437
44 | V1_02_medium: 2.9020137064070517
45 | V1_03_difficult: 3.63610384089588
46 | V2_01_easy: 1.265665311915787
47 | V2_02_medium: 2.9879028298524353
48 | V2_03_difficult: 1.9263612537525863
49 | position (m)/rmse:
50 | MH_01_easy: 0.14338760371731546
51 | MH_02_easy: 0.20395310086981192
52 | MH_03_medium: 0.09429728852586221
53 | MH_04_difficult: 0.2191503660789769
54 | MH_05_difficult: 0.27743250446226775
55 | V1_01_easy: 0.056094933186874404
56 | V1_02_medium: 0.13614408692258764
57 | V1_03_difficult: 0.19352257604677903
58 | V2_01_easy: 0.10735199924969296
59 | V2_02_medium: 0.16664523361920217
60 | V2_03_difficult: 0.19504174366877391
61 | scale:
62 | MH_01_easy: 0.9927134620156396
63 | MH_02_easy: 0.9810458679656806
64 | MH_03_medium: 0.998029274494798
65 | MH_04_difficult: 0.9920449030297775
66 | MH_05_difficult: 0.9928695773268286
67 | V1_01_easy: 1.0026951383404439
68 | V1_02_medium: 1.0107298413927654
69 | V1_03_difficult: 0.9781572295343105
70 | V2_01_easy: 0.9720218391155905
71 | V2_02_medium: 0.9888353848354212
72 | V2_03_difficult: 0.9858589849207583
73 | velocity (m/s)/rmse:
74 | MH_01_easy: 0.035755731812501454
75 | MH_02_easy: 0.03441372962325925
76 | MH_03_medium: 0.07522252391388955
77 | MH_04_difficult: 0.0906762792011823
78 | MH_05_difficult: 0.07318917693516612
79 | V1_01_easy: 0.04847196341227278
80 | V1_02_medium: 0.0672761836181115
81 | V1_03_difficult: 0.08224278489042906
82 | V2_01_easy: 0.039575215434914275
83 | V2_02_medium: 0.065392077310591
84 | V2_03_difficult: 0.09388560858743868
--------------------------------------------------------------------------------
/configs/EQVIO_results_UZHFPV.yaml:
--------------------------------------------------------------------------------
1 | Early Finish flag:
2 | indoor_45_12_snapdragon_with_gt: false
3 | indoor_45_13_snapdragon_with_gt: false
4 | indoor_45_14_snapdragon_with_gt: false
5 | indoor_45_2_snapdragon_with_gt: false
6 | indoor_45_4_snapdragon_with_gt: false
7 | indoor_forward_10_snapdragon_with_gt: false
8 | indoor_forward_5_snapdragon_with_gt: false
9 | indoor_forward_6_snapdragon_with_gt: false
10 | indoor_forward_7_snapdragon_with_gt: false
11 | indoor_forward_9_snapdragon_with_gt: false
12 | NaN flag:
13 | indoor_45_12_snapdragon_with_gt: false
14 | indoor_45_13_snapdragon_with_gt: false
15 | indoor_45_14_snapdragon_with_gt: false
16 | indoor_45_2_snapdragon_with_gt: false
17 | indoor_45_4_snapdragon_with_gt: false
18 | indoor_forward_10_snapdragon_with_gt: false
19 | indoor_forward_5_snapdragon_with_gt: false
20 | indoor_forward_6_snapdragon_with_gt: false
21 | indoor_forward_7_snapdragon_with_gt: false
22 | indoor_forward_9_snapdragon_with_gt: false
23 | Trajectory length:
24 | indoor_45_12_snapdragon_with_gt: 110.66648335124499
25 | indoor_45_13_snapdragon_with_gt: 160.80586367285747
26 | indoor_45_14_snapdragon_with_gt: 215.75054657248796
27 | indoor_45_2_snapdragon_with_gt: 207.50865347649187
28 | indoor_45_4_snapdragon_with_gt: 164.7956481424701
29 | indoor_forward_10_snapdragon_with_gt: 129.66475213255444
30 | indoor_forward_5_snapdragon_with_gt: 52.816463619413106
31 | indoor_forward_6_snapdragon_with_gt: 208.33873697441672
32 | indoor_forward_7_snapdragon_with_gt: 314.45629158089594
33 | indoor_forward_9_snapdragon_with_gt: 123.47363034199418
34 | attitude (d)/rmse:
35 | indoor_45_12_snapdragon_with_gt: 0.7601312429661122
36 | indoor_45_13_snapdragon_with_gt: 2.0837812604451416
37 | indoor_45_14_snapdragon_with_gt: 1.43865736956725
38 | indoor_45_2_snapdragon_with_gt: 1.1780986394178516
39 | indoor_45_4_snapdragon_with_gt: 1.0921351182624517
40 | indoor_forward_10_snapdragon_with_gt: 1.1774945260559924
41 | indoor_forward_5_snapdragon_with_gt: 0.8617136493307842
42 | indoor_forward_6_snapdragon_with_gt: 1.8975488742169193
43 | indoor_forward_7_snapdragon_with_gt: 5.056901162447073
44 | indoor_forward_9_snapdragon_with_gt: 1.0673693477289414
45 | position (m)/rmse:
46 | indoor_45_12_snapdragon_with_gt: 0.26043674696194713
47 | indoor_45_13_snapdragon_with_gt: 0.28277875503947436
48 | indoor_45_14_snapdragon_with_gt: 0.2693560738772749
49 | indoor_45_2_snapdragon_with_gt: 0.310390329275013
50 | indoor_45_4_snapdragon_with_gt: 0.33019160528450936
51 | indoor_forward_10_snapdragon_with_gt: 0.1486559165293003
52 | indoor_forward_5_snapdragon_with_gt: 0.29492016107382074
53 | indoor_forward_6_snapdragon_with_gt: 0.22684750795762812
54 | indoor_forward_7_snapdragon_with_gt: 0.40450255719168765
55 | indoor_forward_9_snapdragon_with_gt: 0.16848383797122396
56 | scale:
57 | indoor_45_12_snapdragon_with_gt: 1.009918826995742
58 | indoor_45_13_snapdragon_with_gt: 1.0016408668046348
59 | indoor_45_14_snapdragon_with_gt: 1.00342718254213
60 | indoor_45_2_snapdragon_with_gt: 1.0194040400257687
61 | indoor_45_4_snapdragon_with_gt: 1.0085324036746115
62 | indoor_forward_10_snapdragon_with_gt: 1.0022815498812814
63 | indoor_forward_5_snapdragon_with_gt: 1.0194272432803142
64 | indoor_forward_6_snapdragon_with_gt: 0.9976690435759287
65 | indoor_forward_7_snapdragon_with_gt: 1.0010156159255423
66 | indoor_forward_9_snapdragon_with_gt: 0.9999800108982774
67 | velocity (m/s)/rmse:
68 | indoor_45_12_snapdragon_with_gt: 0.10819024224232712
69 | indoor_45_13_snapdragon_with_gt: 0.08060784439205018
70 | indoor_45_14_snapdragon_with_gt: 0.1320164605501463
71 | indoor_45_2_snapdragon_with_gt: 0.1575524213252414
72 | indoor_45_4_snapdragon_with_gt: 0.10704801174250202
73 | indoor_forward_10_snapdragon_with_gt: 0.12157834907261307
74 | indoor_forward_5_snapdragon_with_gt: 0.09570644246660577
75 | indoor_forward_6_snapdragon_with_gt: 0.15619279482207263
76 | indoor_forward_7_snapdragon_with_gt: 0.16267985083909958
77 | indoor_forward_9_snapdragon_with_gt: 0.15820046094497361
--------------------------------------------------------------------------------
/docs/intrin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pvangoor/eqvio/3bcc01a9501885d98d88c272229cf12ea7c7d3f3/docs/intrin.png
--------------------------------------------------------------------------------
/docs/main.md:
--------------------------------------------------------------------------------
1 | # EqVIO: An Equivariant Filter for Visual Inertial Odometry {#mainpage}
2 |
3 | This repository contains the implementation of EqVIO: An Equivariant Filter (EqF) for Visual Inertial Odometry (VIO).
4 |
5 | ## Dependencies
6 |
7 | - Eigen 3: `sudo apt install libeigen3-dev`
8 | - Yaml-cpp: `sudo apt install libyaml-cpp-dev`
9 | - GIFT: https://github.com/pvangoor/GIFT
10 |
11 | ### Optional Dependencis
12 |
13 | - FreeGLUT (for visualisations): `sudo apt install freeglut3-dev`
14 | - ROS (for reading ROS-Bags): http://wiki.ros.org/ROS/Installation
15 | - Doxygen (for documentation): `sudo apt install doxygen`
16 |
17 | ## Build Overview
18 |
19 | EqVIO is designed to be built as a cmake project rather than a ROS package.
20 | Assuming all prerequisites are installed and you are in the root folder of the repository, then you can follow these steps to build:
21 |
22 | ```
23 | mkdir build
24 | cd build
25 | cmake ..
26 | cmake --build . -j8
27 | ```
28 |
29 | Note: on older machines, it may be better to use `-j4` or even `-j2` instead of `-j8`.
30 | There are a number of flags that can be passed to cmake to influence the build process.
31 | The key flags related to eqvio are all prefixed `EQVIO_*`.
32 | For example, if you wish to build the documentation yourself, you could use `cmake .. -DEQVIO_BUILD_DOCS=1` instead of `cmake ..`.
33 |
34 | ### Common Issues
35 |
36 | Some of the geometry functions use c++20 concepts.
37 | If you cannot install a c++20 compatible compiler, then your other option is to disable concepts with `-DEQVIO_SUPPORT_CONCEPTS=0`.
38 | Note that this project still uses c++17 features, and there are no plans to create workarounds.
39 |
40 | ## Usage Overview
41 |
42 | The build process will create an executable called `eqvio_opt` in the build directory.
43 | To see the help, simply run `./build/eqvio_opt --help`.
44 | The required arguments are the dataset file/directory name, and the eqvio configuration file.
45 | There are also many optional arguments to adjust how the program runs.
46 | Different types of datasets are distinguished by providing a value to `--mode` (see the datasetReader page).
47 | An example command is
48 |
49 | ```
50 | ./build/eqvio_opt ~/datasets/V1_01_easy/ configs/EQVIO_config_EuRoC_stationary.yaml --display --mode asl
51 | ```
52 |
53 | This will create an output directory with a timestamp in the current directory, containing csv files with all the different states of eqvio.
54 | The `--display` flag is required to create live animations of the VIO state estimate.
55 |
56 | ### Running and Analysing Datasets
57 |
58 | There are a few python scripts provided to help with running and evaluating datasets.
59 | These are meant for evaluation of EqVIO over common robotics datasets, particularly over the EuRoC and UZHFPV datasets.
60 | They can also be used for some other datasets compatible with EqVIO.
61 |
62 | Suppose you want to run EqVIO over the EuRoC sequence V1_01_easy and analyse the results you could use:
63 |
64 | ```
65 | python3 scripts/run_and_analyse_dataset.py --mode=asl configs/EQVIO_config_EuRoC_stationary.yaml ~/datasets/V1_01_easy/
66 | ```
67 |
68 | This will first run EqVIO over the dataset and then analyse the results.
69 | Note that the `--display` option is not used and the usual EqVIO commandline output is suppressed, so there is no output until the running and analysis are complete.
70 | The results are then saved to a new directory created in the dataset directory. In this case, `~/datasets/V1_01_easy/results/`.
71 | The results directory includes a range of useful and interesting figures and information:
72 |
73 | - **biases.pdf**: The estimated gyroscope and accelerometer biases over time.
74 | - **camera_offset.pdf**: The estimated rotation and position of the camera frame relative to the IMU frame over time.
75 | - **features.pdf**: The number of features at any given time and the mean lifetime of all the features in the state over time.
76 | - **gravity_and_velocity.pdf**: The acceleration due to gravity and the linear velocity of the IMU, both expressed in the IMU frame, over time.
77 | - **results.yaml**: The numeric results of the algorithm, including position and attitude error statistics, scale error, mean processing time, etc.
78 | - **timing_boxplots.pdf**: A boxplot of the time taken for each step in the algorithm.
79 | - **timing_flamegraph.pdf**: A flamegraph showing how much time was spent on each step in the algorithm over time.
80 | - **timing_histograms.pdf**: Histograms showing the distribution of time spent on each step of the algorithm.
81 | - **trajectory_error.pdf**: The attitude and position errors over time, including x,y,z components as well as the norm.
82 | - **trajectory.pdf**: The true and estimated trajectories over time in terms of x,y,z position and Euler angles (roll, pitch, yaw).
83 | - **trajectory_xy.pdf**: A top-down (with respect to the z-axis of the true trajectory) view of the true and estimated trajectories.
84 |
85 | If no groundtruth is available, then the plots are all still generated, except for the trajectory_error.pdf.
86 | The true trajectory is obviously not shown in this case, since it is not known.
87 |
88 | #### Running Multiple Datasets
89 |
90 | The python scripts can also handle multiple sequences from the same dataset.
91 | Simply put the names of all the sequences you want to test in the command:
92 |
93 | ```
94 | python3 scripts/run_and_analyse_dataset.py --mode=asl configs/EQVIO_config_EuRoC_stationary.yaml ~/datasets/V1_01_easy/ ~/datasets/V1_02_medium/
95 | ```
96 |
97 | This will generate results for each dataset.
98 | These results can then be summarised into one file:
99 |
100 | ```
101 | python3 scripts/summarise_results.py --mode=asl ~/datasets/V1_01_easy/ ~/datasets/V1_02_medium/
102 | ```
103 |
104 | This generates a new file which collects all the most important results in one place for each dataset, such as position and attitude RMSE, mean processing time, and scale error.
105 |
106 | The other way to run multiple datasets is to create a yaml file with information on the datasets you wish to analyse.
107 | An example is provided in `scripts/euroc_sequences.yaml`.
108 | As shown, this also allows you to add information such as the desired dataset mode and start time.
109 | To run over all the EuRoC datasets and analyse the results:
110 |
111 | ```
112 | python3 scripts/run_and_analyse_dataset.py configs/EQVIO_config_EuRoC_stationary.yaml scripts/euroc_sequences.yaml
113 | python3 scripts/summarise_results.py scripts/euroc_sequences.yaml
114 | ```
115 |
--------------------------------------------------------------------------------
/docs/run.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pvangoor/eqvio/3bcc01a9501885d98d88c272229cf12ea7c7d3f3/docs/run.png
--------------------------------------------------------------------------------
/include/eqvio/LoopTimer.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of EqVIO.
3 |
4 | EqVIO is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | EqVIO is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with EqVIO. If not, see .
16 | */
17 |
18 | #pragma once
19 |
20 | #include "eqvio/common/aofstream.h"
21 |
22 | #include
23 | #include