# IKFoM **Repository Path**: marslab/IKFoM ## Basic Information - **Project Name**: IKFoM - **Description**: No description available - **Primary Language**: C++ - **License**: GPL-2.0 - **Default Branch**: hdj-test - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2022-01-07 - **Last Updated**: 2025-07-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## IKFoM **IKFoM** (Iterated Kalman Filters on Manifolds) is a computationally efficient and convenient toolkit for deploying iterated Kalman filters on various robotic systems, especially systems operating on high-dimension manifold. It implements a manifold-embedding Kalman filter which separates the menifold structures from system descriptions and is able to be used by only defining the system in a canonical form and calling the respective steps accordingly. The current implementation supports the full iterated Kalman filtering for systems on manifold and any of its sub-manifolds, and it is extendable to other types of manifold when necessary. **Developers** [Dongjiao He](https://github.com/Joanna-HE) **Our related video**: https://youtu.be/sz_ZlDkl6fA **Our related paper**: https://arxiv.org/pdf/2102.03804.pdf ## 1. Prerequisites ### 1.1. **Eigen && Boost** Eigen >= 3.3.4, Follow [Eigen Installation](http://eigen.tuxfamily.org/index.php?title=Main_Page). Boost >= 1.65. ## 2. Usage when the measurement is of constant dimension and type. Clone the repository: ``` git clone https://github.com/hku-mars/IKFoM.git ``` 1. include the necessary head file: ``` #include ``` 2. Select and instantiate the primitive manifolds: ``` typedef MTK::SO3 SO3; // scalar type of variable: double typedef MTK::vect<3, double> vect3; // dimension of the defined Euclidean variable: 3 typedef MTK::S2 S2; // length of the S2 variable: 98/10; choose e1 as the original point of rotation: 1 ``` 3. Build system state, input and measurement as compound manifolds which are composed of the primitive manifolds: ``` MTK_BUILD_MANIFOLD(state, // name of compound manifold: state ((vect3, pos)) // ((primitive manifold type, name of variable)) ((vect3, vel)) ((SO3, rot)) ((vect3, bg)) ((vect3, ba)) ((S2, grav)) ((SO3, offset_R_L_I)) ((vect3, offset_T_L_I)) ); ``` 4. Implement the vector field and its differentiation , : ``` Eigen::Matrix f(state &s, const input &i) {} Eigen::Matrix df_dx(state &s, const input &i) {} //notice S2 has length of 3 and dimension of 2 Eigen::Matrix df_dw(state &s, const input &i) {} ``` 5. Implement the output equation and its differentiation , : ``` measurement h(state &s, bool &valid) {} //the iteration stops before convergence when valid is false Eigen::Matrix dh_dx(state &s, bool &valid) {} Eigen::Matrix dh_dv(state &s, bool &valid) {} ``` 6. Instantiate an **esekf** object **kf** and initialize it with initial or default state and covariance. 1) initial state or covariance: ``` state init_state; esekfom::esekf::cov init_P; esekfom::esekf kf(init_state,init_P); ``` 2) default state and covariance ``` esekfom::esekf kf; ``` 7. Deliver the defined models, maximum iteration numbers **Maximum_iter**, and the std array for testing convergence **limit** into the **esekf** object: ``` kf.init(f, df_dx, df_dw, h, dh_dx, dh_dv, Maximum_iter, limit); ``` 8. In the running time, once an input **in** is received with time interval **dt**, a propagation is executed: ``` kf.predict(dt, Q, in); // process noise covariance: Q ``` 9. Once a measurement **z** is received, an iterated update is executed: ``` kf.update_iterated(z, R); // measurement noise covariance: R ``` *Remarks:* - We also combine the output equation and its differentiation into an union function, whose usage is the same as the above steps 1-4, and steps 5-9 are shown as follows. 5. Implement the output equation and its differentiation , : ``` measurement h_share(state &s, esekfom::share_datastruct &share_data) { if(share_data.converge) {} // this value is true means iteration is converged share_data.valid = false; // the iteration stops before convergence when this value is false share_data.h_x = H_x; // H_x is the result matrix of the first differentiation share_data.h_v = H_v; // H_v is the result matrix of the second differentiation share_data.R = R; // R is the measurement noise covariance share_data.z = z; // z is the obtained measurement } ``` 6. Instantiate an **esekf** object **kf** and initialize it with initial or default state and covariance. 1) initial state or convariance: ``` state init_state; esekfom::esekf::cov init_P; esekfom::esekf kf(init_state,init_P); ``` 2) default state and covariance: ``` esekfom::esekf kf; ``` 7. Deliver the defined models, maximum iteration numbers **Maximum_iter**, and the std array for testing convergence **limit** into the **esekf** object: ``` kf.init_share(f, df_dx, df_dw, h_share, Maximum_iter, limit); ``` 8. In the running time, once an input **in** is received with time interval **dt**, a propagation is executed: ``` kf.predict(dt, Q, in); // process noise covariance: Q ``` 9. Once a measurement **z** is received, an iterated update is executed: ``` kf.update_iterated_share(); ``` ## 3. Usage when the measurement is an Eigen vector of changing dimension. Clone the repository: ``` git clone https://github.com/hku-mars/IKFoM.git ``` 1. include the necessary head file: ``` #include ``` 2. Select and instantiate the primitive manifolds: ``` typedef MTK::SO3 SO3; // scalar type of variable: double typedef MTK::vect<3, double> vect3; // dimension of the defined Euclidean variable: 3 typedef MTK::S2 S2; // length of the S2 variable: 98/10; choose e1 as the original point of rotation: 1 ``` 3. Build system state and input as compound manifolds which are composed of the primitive manifolds: ``` MTK_BUILD_MANIFOLD(state, // name of compound manifold: state ((vect3, pos)) // ((primitive manifold type, name of variable)) ((vect3, vel)) ((SO3, rot)) ((vect3, bg)) ((vect3, ba)) ((S2, grav)) ((SO3, offset_R_L_I)) ((vect3, offset_T_L_I)) ); ``` 4. Implement the vector field and its differentiation , : ``` Eigen::Matrix f(state &s, const input &i) {} Eigen::Matrix df_dx(state &s, const input &i) {} //notice S2 has length of 3 and dimension of 2 Eigen::Matrix df_dw(state &s, const input &i) {} ``` 5. Implement the output equation and its differentiation , : ``` Eigen::Matrix h(state &s, bool &valid) {} //the iteration stops before convergence when valid is false Eigen::Matrix dh_dx(state &s, bool &valid) {} Eigen::Matrix dh_dv(state &s, bool &valid) {} ``` 6. Instantiate an **esekf** object **kf** and initialize it with initial or default state and covariance. 1) initial state or cavariance: ``` state init_state; esekfom::esekf::cov init_P; esekfom::esekf kf(init_state,init_P); ``` 2) default state and covariance: ``` esekfom::esekf kf; ``` 7. Deliver the defined models, maximum iteration numbers **Maximum_iter**, and the std array for testing convergence **limit** into the **esekf** object: ``` kf.init_dyn(f, df_dx, df_dw, h, dh_dx, dh_dv, Maximum_iter, limit); ``` 8. In the running time, once an input **in** is received with time interval **dt**, a propagation is executed: ``` kf.predict(dt, Q, in); // process noise covariance: Q ``` 9. Once a measurement **z** is received, an iterated update is executed: ``` kf.update_iterated_dyn(z, R); // measurement noise covariance: R ``` *Remarks:* - We also combine the output equation and its differentiation into an union function, whose usage is the same as the above steps 1-4, and steps 5-9 are shown as follows. 5. Implement the output equation and its differentiation , : ``` Eigen::Matrix h_dyn_share(state &s, esekfom::dyn_share_datastruct &dyn_share_data) { if(dyn_share_data.converge) {} // this value is true means iteration is converged dyn_share_data.valid = false; // the iteration stops before convergence when this value is false dyn_share_data.h_x = H_x; // H_x is the result matrix of the first differentiation dyn_share_data.h_v = H_v; // H_v is the result matrix of the second differentiation dyn_share_data.R = R; // R is the measurement noise covariance dyn_share_data.z = z; // z is the obtained measurement } ``` 6. Instantiate an **esekf** object **kf** and initialize it with initial or default state and covariance. 1) initial state or cavariance: ``` state init_state; esekfom::esekf::cov init_P; esekfom::esekf kf(init_state,init_P); ``` 2) default state and covariance: ``` esekfom::esekf kf; ``` 7. Deliver the defined models, maximum iteration numbers **Maximum_iter**, and the std array for testing convergence **limit** into the **esekf** object: ``` kf.init_dyn_share(f, df_dx, df_dw, h_dyn_share, Maximum_iter, limit); ``` 8. In the running time, once an input **in** is received with time interval **dt**, a propagation is executed: ``` kf.predict(dt, Q, in); // process noise covariance: Q ``` 9. Once a measurement **z** is received, an iterated update is executed: ``` kf.update_iterated_dyn_share(); ``` ## 4. Usage when the measurement is a changing manifold during the run time. Clone the repository: ``` git clone https://github.com/hku-mars/IKFoM.git ``` 1. include the necessary head file: ``` #include ``` 2. Select and instantiate the primitive manifolds: ``` typedef MTK::SO3 SO3; // scalar type of variable: double typedef MTK::vect<3, double> vect3; // dimension of the defined Euclidean variable: 3 typedef MTK::S2 S2; // length of the S2 variable: 98/10; choose e1 as the original point of rotation: 1 ``` 3. Build system state and input as compound manifolds which are composed of the primitive manifolds: ``` MTK_BUILD_MANIFOLD(state, // name of compound manifold: state ((vect3, pos)) // ((primitive manifold type, name of variable)) ((vect3, vel)) ((SO3, rot)) ((vect3, bg)) ((vect3, ba)) ((S2, grav)) ((SO3, offset_R_L_I)) ((vect3, offset_T_L_I)) ); ``` 4. Implement the vector field and its differentiation , : ``` Eigen::Matrix f(state &s, const input &i) {} Eigen::Matrix df_dx(state &s, const input &i) {} //notice S2 has length of 3 and dimension of 2 Eigen::Matrix df_dw(state &s, const input &i) {} ``` 5. Implement the differentiation of the output equation , : ``` Eigen::Matrix dh_dx(state &s, bool &valid) {} //the iteration stops before convergence when valid is false Eigen::Matrix dh_dv(state &s, bool &valid) {} ``` 6. Instantiate an **esekf** object **kf** and initialize it with initial or default state and covariance. 1) initial state or covariance: ``` state init_state; esekfom::esekf::cov init_P; esekfom::esekf kf(init_state,init_P); ``` 2) default state and covariance: ``` esekfom::esekf kf; ``` 7. Deliver the defined models, maximum iteration numbers **Maximum_iter**, and the std array for testing convergence **limit** into the **esekf** object: ``` kf.init_dyn_runtime(f, df_dx, df_dw, dh_dx, dh_dv, Maximum_iter, limit); ``` 8. In the running time, once an input **in** is received with time interval **dt**, a propagation is executed: ``` kf.predict(dt, Q, in); // process noise covariance: Q ``` 9. Once a measurement **z** is received, build system measurement as compound manifolds following step 3 and implement the output equation : ``` measurement h(state &s, bool &valid) {} //the iteration stops before convergence when valid is false ``` then an iterated update is executed: ``` kf.update_iterated_dyn_runtime(z, R, h); // measurement noise covariance: R ``` *Remarks:* - We also combine the output equation and its differentiation into an union function, whose usage is the same as the above steps 1-4, and steps 5-9 are shown as follows. 5. Instantiate an **esekf** object **kf** and initialize it with initial or default state and covariance. 1) initial state or covariance: ``` state init_state; esekfom::esekf::cov init_P; esekfom::esekf kf(init_state,init_P); ``` 2) default state and covariance: ``` esekfom::esekf kf; ``` 6. Deliver the defined models, maximum iteration numbers **Maximum_iter**, and the std array for testing convergence **limit** into the **esekf** object: ``` kf.init_dyn_runtime_share(f, df_dx, df_dw, Maximum_iter, limit); ``` 7. In the running time, once an input **in** is received with time interval **dt**, a propagation is executed: ``` kf.predict(dt, Q, in); // process noise covariance: Q ``` 8. Once a measurement **z** is received, build system measurement as compound manifolds following step 3 and implement the output equation and its differentiation , : ``` measurement h_dyn_runtime_share(state &s, esekfom::dyn_runtime_share_datastruct &dyn_runtime_share_data) { if(dyn_runtime_share_data.converge) {} // this value is true means iteration is converged dyn_runtime_share_data.valid = false; // the iteration stops before convergence when this value is false dyn_runtime_share_data.h_x = H_x; // H_x is the result matrix of the first differentiation dyn_runtime_share_data.h_v = H_v; // H_v is the result matrix of the second differentiation dyn_runtime_share_data.R = R; // R is the measurement noise covariance } ``` then an iterated update is executed: ``` kf.update_iterated_dyn_runtime_share(z, h_dyn_runtime_share); ``` ## 5. Run the sample Clone the repository: ``` git clone https://github.com/hku-mars/IKFoM.git ``` In the **Samples** file folder, there is the scource code that applys the **IKFoM** on the original source code from [FAST LIO](https://github.com/hku-mars/FAST_LIO). Please follow the README.md shown in that repository excepting the step **2. Build**, which is modified as: ``` cd ~/catkin_ws/src cp -r ~/IKFoM/Samples/FAST_LIO-stable FAST_LIO-stable cd .. catkin_make source devel/setup.bash ``` ## 6.Acknowledgments Thanks for C. Hertzberg, R. Wagner, U. Frese, and L. Schroder. Integratinggeneric sensor fusion algorithms with sound state representationsthrough encapsulation of manifolds.