-
Notifications
You must be signed in to change notification settings - Fork 768
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix CombinedImuFactor #882
Changes from 29 commits
af714cd
e38ea50
3cee1b7
dfa32e5
40e6d8b
995710f
2d3859d
f0be857
8dbbb1f
ce7c71b
a17134d
cb75d92
bbd1e3f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,72 @@ | ||
%% This BibTeX bibliography file was created using BibDesk. | ||
%% https://bibdesk.sourceforge.io/ | ||
|
||
%% Created for Varun Agrawal at 2021-09-27 17:39:09 -0400 | ||
|
||
|
||
%% Saved with string encoding Unicode (UTF-8) | ||
|
||
|
||
|
||
@article{Lupton12tro, | ||
author = {Lupton, Todd and Sukkarieh, Salah}, | ||
date-added = {2021-09-27 17:38:56 -0400}, | ||
date-modified = {2021-09-27 17:39:09 -0400}, | ||
doi = {10.1109/TRO.2011.2170332}, | ||
journal = {IEEE Transactions on Robotics}, | ||
number = {1}, | ||
pages = {61-76}, | ||
title = {Visual-Inertial-Aided Navigation for High-Dynamic Motion in Built Environments Without Initial Conditions}, | ||
volume = {28}, | ||
year = {2012}, | ||
Bdsk-Url-1 = {https://doi.org/10.1109/TRO.2011.2170332}} | ||
|
||
@inproceedings{Forster15rss, | ||
author = {Christian Forster and Luca Carlone and Frank Dellaert and Davide Scaramuzza}, | ||
booktitle = {Robotics: Science and Systems}, | ||
date-added = {2021-09-26 20:44:41 -0400}, | ||
date-modified = {2021-09-26 20:45:03 -0400}, | ||
title = {IMU Preintegration on Manifold for Efficient Visual-Inertial Maximum-a-Posteriori Estimation}, | ||
year = {2015}} | ||
|
||
@article{Iserles00an, | ||
title = {Lie-group methods}, | ||
author = {Iserles, Arieh and Munthe-Kaas, Hans Z and | ||
N{\o}rsett, Syvert P and Zanna, Antonella}, | ||
journal = {Acta Numerica 2000}, | ||
volume = {9}, | ||
pages = {215--365}, | ||
year = {2000}, | ||
publisher = {Cambridge Univ Press} | ||
} | ||
author = {Iserles, Arieh and Munthe-Kaas, Hans Z and N{\o}rsett, Syvert P and Zanna, Antonella}, | ||
journal = {Acta Numerica 2000}, | ||
pages = {215--365}, | ||
publisher = {Cambridge Univ Press}, | ||
title = {Lie-group methods}, | ||
volume = {9}, | ||
year = {2000}} | ||
|
||
@book{Murray94book, | ||
title = {A mathematical introduction to robotic manipulation}, | ||
author = {Murray, Richard M and Li, Zexiang and Sastry, S | ||
Shankar and Sastry, S Shankara}, | ||
year = {1994}, | ||
publisher = {CRC press} | ||
} | ||
author = {Murray, Richard M and Li, Zexiang and Sastry, S Shankar and Sastry, S Shankara}, | ||
publisher = {CRC press}, | ||
title = {A mathematical introduction to robotic manipulation}, | ||
year = {1994}} | ||
|
||
@book{Spivak65book, | ||
title = {Calculus on manifolds}, | ||
author = {Spivak, Michael}, | ||
volume = {1}, | ||
year = {1965}, | ||
publisher = {WA Benjamin New York} | ||
} | ||
author = {Spivak, Michael}, | ||
publisher = {WA Benjamin New York}, | ||
title = {Calculus on manifolds}, | ||
volume = {1}, | ||
year = {1965}} | ||
|
||
@phdthesis{Nikolic16thesis, | ||
title={Characterisation, calibration, and design of visual-inertial sensor systems for robot navigation}, | ||
author={Nikolic, Janosch}, | ||
year={2016}, | ||
school={ETH Zurich} | ||
} | ||
|
||
@book{Simon06book, | ||
title={Optimal state estimation: Kalman, H infinity, and nonlinear approaches}, | ||
author={Simon, Dan}, | ||
year={2006}, | ||
publisher={John Wiley \& Sons} | ||
} | ||
|
||
@inproceedings{Trawny05report_IndirectKF, | ||
title={Indirect Kalman Filter for 3 D Attitude Estimation}, | ||
author={Nikolas Trawny and Stergios I. Roumeliotis}, | ||
year={2005} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -94,7 +94,7 @@ boost::shared_ptr<PreintegratedCombinedMeasurements::Params> imuParams() { | |
I_3x3 * 1e-8; // error committed in integrating position from velocities | ||
Matrix33 bias_acc_cov = I_3x3 * pow(accel_bias_rw_sigma, 2); | ||
Matrix33 bias_omega_cov = I_3x3 * pow(gyro_bias_rw_sigma, 2); | ||
Matrix66 bias_acc_omega_int = | ||
Matrix66 bias_acc_omega_init = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same |
||
I_6x6 * 1e-5; // error in the bias used for preintegration | ||
|
||
auto p = PreintegratedCombinedMeasurements::Params::MakeSharedD(0.0); | ||
|
@@ -110,7 +110,7 @@ boost::shared_ptr<PreintegratedCombinedMeasurements::Params> imuParams() { | |
// PreintegrationCombinedMeasurements params: | ||
p->biasAccCovariance = bias_acc_cov; // acc bias in continuous | ||
p->biasOmegaCovariance = bias_omega_cov; // gyro bias in continuous | ||
p->biasAccOmegaInt = bias_acc_omega_int; | ||
p->biasAccOmegaInit = bias_acc_omega_init; | ||
|
||
return p; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,7 +39,7 @@ void PreintegrationCombinedParams::print(const string& s) const { | |
<< endl; | ||
cout << "biasOmegaCovariance:\n[\n" << biasOmegaCovariance << "\n]" | ||
<< endl; | ||
cout << "biasAccOmegaInt:\n[\n" << biasAccOmegaInt << "\n]" | ||
cout << "biasAccOmegaInit:\n[\n" << biasAccOmegaInit << "\n]" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same |
||
<< endl; | ||
} | ||
|
||
|
@@ -52,7 +52,7 @@ bool PreintegrationCombinedParams::equals(const PreintegratedRotationParams& oth | |
tol) && | ||
equal_with_abs_tol(biasOmegaCovariance, e->biasOmegaCovariance, | ||
tol) && | ||
equal_with_abs_tol(biasAccOmegaInt, e->biasAccOmegaInt, tol); | ||
equal_with_abs_tol(biasAccOmegaInit, e->biasAccOmegaInit, tol); | ||
} | ||
|
||
//------------------------------------------------------------------------------ | ||
|
@@ -93,9 +93,14 @@ void PreintegratedCombinedMeasurements::resetIntegration() { | |
//------------------------------------------------------------------------------ | ||
void PreintegratedCombinedMeasurements::integrateMeasurement( | ||
const Vector3& measuredAcc, const Vector3& measuredOmega, double dt) { | ||
if (dt <= 0) { | ||
throw std::runtime_error( | ||
"PreintegratedCombinedMeasurements::integrateMeasurement: dt <=0"); | ||
} | ||
|
||
// Update preintegrated measurements. | ||
Matrix9 A; // overall Jacobian wrt preintegrated measurements (df/dx) | ||
Matrix93 B, C; | ||
Matrix9 A; // Jacobian wrt preintegrated measurements without bias (df/dx) | ||
Matrix93 B, C; // Jacobian of state wrpt accel bias and omega bias respectively. | ||
PreintegrationType::update(measuredAcc, measuredOmega, dt, &A, &B, &C); | ||
|
||
// Update preintegrated measurements covariance: as in [2] we consider a first | ||
|
@@ -105,47 +110,80 @@ void PreintegratedCombinedMeasurements::integrateMeasurement( | |
// and preintegrated measurements | ||
|
||
// Single Jacobians to propagate covariance | ||
// TODO(frank): should we not also account for bias on position? | ||
Matrix3 theta_H_biasOmega = -C.topRows<3>(); | ||
Matrix3 vel_H_biasAcc = -B.bottomRows<3>(); | ||
Matrix3 theta_H_omega = C.topRows<3>(); | ||
Matrix3 pos_H_acc = B.middleRows<3>(3); | ||
Matrix3 vel_H_acc = B.bottomRows<3>(); | ||
|
||
Matrix3 theta_H_biasOmegaInit = -theta_H_omega; | ||
Matrix3 pos_H_biasAccInit = -pos_H_acc; | ||
Matrix3 vel_H_biasAcc = -vel_H_acc; | ||
Matrix3 vel_H_biasAccInit = -vel_H_acc; | ||
|
||
// overall Jacobian wrt preintegrated measurements (df/dx) | ||
Eigen::Matrix<double, 15, 15> F; | ||
F.setZero(); | ||
F.block<9, 9>(0, 0) = A; | ||
F.block<3, 3>(0, 12) = theta_H_biasOmega; | ||
F.block<3, 3>(6, 9) = vel_H_biasAcc; | ||
F.block<3, 3>(0, 12) = theta_H_omega; | ||
F.block<3, 3>(3, 9) = pos_H_acc; | ||
F.block<3, 3>(6, 9) = vel_H_acc; | ||
F.block<6, 6>(9, 9) = I_6x6; | ||
|
||
// Update the uncertainty on the state (matrix F in [4]). | ||
preintMeasCov_ = F * preintMeasCov_ * F.transpose(); | ||
|
||
// propagate uncertainty | ||
// TODO(frank): use noiseModel routine so we can have arbitrary noise models. | ||
const Matrix3& aCov = p().accelerometerCovariance; | ||
const Matrix3& wCov = p().gyroscopeCovariance; | ||
const Matrix3& iCov = p().integrationCovariance; | ||
const Matrix6& bInitCov = p().biasAccOmegaInit; | ||
|
||
// first order uncertainty propagation | ||
// Optimized matrix multiplication (1/dt) * G * measurementCovariance * | ||
// G.transpose() | ||
// Optimized matrix mult: (1/dt) * G * measurementCovariance * G.transpose() | ||
Eigen::Matrix<double, 15, 15> G_measCov_Gt; | ||
G_measCov_Gt.setZero(15, 15); | ||
|
||
// BLOCK DIAGONAL TERMS | ||
D_t_t(&G_measCov_Gt) = dt * iCov; | ||
D_v_v(&G_measCov_Gt) = (1 / dt) * vel_H_biasAcc | ||
* (aCov + p().biasAccOmegaInt.block<3, 3>(0, 0)) | ||
* (vel_H_biasAcc.transpose()); | ||
D_R_R(&G_measCov_Gt) = (1 / dt) * theta_H_biasOmega | ||
* (wCov + p().biasAccOmegaInt.block<3, 3>(3, 3)) | ||
* (theta_H_biasOmega.transpose()); | ||
D_R_R(&G_measCov_Gt) = | ||
(theta_H_omega * (wCov / dt) * theta_H_omega.transpose()) // | ||
+ (theta_H_biasOmegaInit * (bInitCov.block<3, 3>(3, 3) / dt) * | ||
theta_H_biasOmegaInit.transpose()); | ||
|
||
D_t_t(&G_measCov_Gt) = | ||
(pos_H_acc * (aCov / dt) * pos_H_acc.transpose()) // | ||
+ (pos_H_biasAccInit * (bInitCov.block<3, 3>(0, 0) / dt) * | ||
pos_H_biasAccInit.transpose()) // | ||
+ (dt * iCov); | ||
|
||
D_v_v(&G_measCov_Gt) = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you restore the order in which these terms are computed for easier review, and comment on what has changed and why? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This order would be more aligned with the math and should make verifying it easier. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm saying it's harder for review. It's also not arbitrary. Maybe re-arrange the math. The order of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a bit confused. It's already in attitude-position-velocity order (D_R_R for attitude, D_t_t for position and D_v_v fro velocity). The prior code had it position-velocity-attitude which isn't the expected order. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @varunagrawal : besides the order of the pre-integrated measurements, can you point out what changed with respect to my (terrible) writeup? I think you added a second-order term in the position and changed how the covariances are discretized. were there other bugs you fixed with respect to my writeup? (i.e., was my writeup wrong, or only the implementation? or both? :-) ) also: is the order attitude-position-velocity now also used in the standard IMU factor? or only the combined? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe just the implementation was incorrect in certain places. @lucacarlone's overall writeup was pretty great and I just expanded upon that with additional information I picked up from other books and papers. :) As for the attitude-position-velocity order, this was not really an issue for ImuFactor since the expression for the jacobians was a lot simpler ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I looked at the differences again: I also changed the noise variable order from $$\epsilon_{b^{\omega}{init}}, \epsilon{\Delta b^{a}}, \epsilon_{\Delta b^{\omega}}$$ to $$\epsilon_{int}, \epsilon_{b^{a}{init}}, \epsilon{b^{\omega}_{init}}$$ (Apologies for the rendering issues. Seems like Github's Math mode is a bit buggy.) |
||
(vel_H_acc * (aCov / dt) * vel_H_acc.transpose()) // | ||
+ (vel_H_biasAccInit * (bInitCov.block<3, 3>(0, 0) / dt) * | ||
vel_H_biasAccInit.transpose()); | ||
|
||
D_a_a(&G_measCov_Gt) = dt * p().biasAccCovariance; | ||
D_g_g(&G_measCov_Gt) = dt * p().biasOmegaCovariance; | ||
|
||
// OFF BLOCK DIAGONAL TERMS | ||
Matrix3 temp = vel_H_biasAcc * p().biasAccOmegaInt.block<3, 3>(3, 0) | ||
* theta_H_biasOmega.transpose(); | ||
D_v_R(&G_measCov_Gt) = temp; | ||
D_R_v(&G_measCov_Gt) = temp.transpose(); | ||
preintMeasCov_ = F * preintMeasCov_ * F.transpose() + G_measCov_Gt; | ||
D_R_t(&G_measCov_Gt) = theta_H_biasOmegaInit * | ||
(bInitCov.block<3, 3>(3, 0) / dt) * | ||
pos_H_biasAccInit.transpose(); | ||
D_R_v(&G_measCov_Gt) = theta_H_biasOmegaInit * | ||
(bInitCov.block<3, 3>(3, 0) / dt) * | ||
vel_H_biasAccInit.transpose(); | ||
D_t_R(&G_measCov_Gt) = pos_H_biasAccInit * (bInitCov.block<3, 3>(0, 3) / dt) * | ||
theta_H_biasOmegaInit.transpose(); | ||
D_t_v(&G_measCov_Gt) = | ||
(pos_H_acc * (aCov / dt) * vel_H_acc.transpose()) + | ||
(pos_H_biasAccInit * (bInitCov.block<3, 3>(0, 0) / dt) * | ||
vel_H_biasAccInit.transpose()); | ||
D_v_R(&G_measCov_Gt) = vel_H_biasAccInit * (bInitCov.block<3, 3>(0, 3) / dt) * | ||
theta_H_biasOmegaInit.transpose(); | ||
D_v_t(&G_measCov_Gt) = | ||
(vel_H_acc * (aCov / dt) * pos_H_acc.transpose()) + | ||
(vel_H_biasAccInit * (bInitCov.block<3, 3>(0, 0) / dt) * | ||
pos_H_biasAccInit.transpose()); | ||
|
||
preintMeasCov_.noalias() += G_measCov_Gt; | ||
} | ||
|
||
//------------------------------------------------------------------------------ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -51,6 +51,7 @@ typedef ManifoldPreintegration PreintegrationType; | |
* TRO, 28(1):61-76, 2012. | ||
* [3] L. Carlone, S. Williams, R. Roberts, "Preintegrated IMU factor: | ||
* Computation of the Jacobian Matrices", Tech. Report, 2013. | ||
* Available in this repo as "PreintegratedIMUJacobians.pdf". | ||
* [4] C. Forster, L. Carlone, F. Dellaert, D. Scaramuzza, IMU Preintegration on | ||
* Manifold for Efficient Visual-Inertial Maximum-a-Posteriori Estimation, | ||
* Robotics: Science and Systems (RSS), 2015. | ||
|
@@ -61,19 +62,19 @@ typedef ManifoldPreintegration PreintegrationType; | |
struct GTSAM_EXPORT PreintegrationCombinedParams : PreintegrationParams { | ||
Matrix3 biasAccCovariance; ///< continuous-time "Covariance" describing accelerometer bias random walk | ||
Matrix3 biasOmegaCovariance; ///< continuous-time "Covariance" describing gyroscope bias random walk | ||
Matrix6 biasAccOmegaInt; ///< covariance of bias used for pre-integration | ||
Matrix6 biasAccOmegaInit; ///< covariance of bias used as initial estimate. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. etc... |
||
|
||
/// Default constructor makes uninitialized params struct. | ||
/// Used for serialization. | ||
PreintegrationCombinedParams() | ||
: biasAccCovariance(I_3x3), | ||
biasOmegaCovariance(I_3x3), | ||
biasAccOmegaInt(I_6x6) {} | ||
biasAccOmegaInit(I_6x6) {} | ||
|
||
/// See two named constructors below for good values of n_gravity in body frame | ||
PreintegrationCombinedParams(const Vector3& n_gravity) : | ||
PreintegrationParams(n_gravity), biasAccCovariance(I_3x3), | ||
biasOmegaCovariance(I_3x3), biasAccOmegaInt(I_6x6) { | ||
biasOmegaCovariance(I_3x3), biasAccOmegaInit(I_6x6) { | ||
|
||
} | ||
|
||
|
@@ -92,11 +93,11 @@ struct GTSAM_EXPORT PreintegrationCombinedParams : PreintegrationParams { | |
|
||
void setBiasAccCovariance(const Matrix3& cov) { biasAccCovariance=cov; } | ||
void setBiasOmegaCovariance(const Matrix3& cov) { biasOmegaCovariance=cov; } | ||
void setBiasAccOmegaInt(const Matrix6& cov) { biasAccOmegaInt=cov; } | ||
void setBiasAccOmegaInt(const Matrix6& cov) { biasAccOmegaInit=cov; } | ||
|
||
const Matrix3& getBiasAccCovariance() const { return biasAccCovariance; } | ||
const Matrix3& getBiasOmegaCovariance() const { return biasOmegaCovariance; } | ||
const Matrix6& getBiasAccOmegaInt() const { return biasAccOmegaInt; } | ||
const Matrix6& getBiasAccOmegaInt() const { return biasAccOmegaInit; } | ||
|
||
private: | ||
|
||
|
@@ -108,7 +109,7 @@ struct GTSAM_EXPORT PreintegrationCombinedParams : PreintegrationParams { | |
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(PreintegrationParams); | ||
ar & BOOST_SERIALIZATION_NVP(biasAccCovariance); | ||
ar & BOOST_SERIALIZATION_NVP(biasOmegaCovariance); | ||
ar & BOOST_SERIALIZATION_NVP(biasAccOmegaInt); | ||
ar & BOOST_SERIALIZATION_NVP(biasAccOmegaInit); | ||
} | ||
|
||
public: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renaming breaks API and I really think it was meant to be "int" for "integration"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, we have
integrationCovariance
inPreintegrationParams.h
for integration. This was a typo that I fixed.