truth revealing unit test :-) re-established good functioning of IMU factor (TODO: fix CombinedImuFactor F & G)
parent
792d2656d0
commit
6d571ca6b9
|
|
@ -67,7 +67,8 @@ void ImuFactor::PreintegratedMeasurements::resetIntegration(){
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
void ImuFactor::PreintegratedMeasurements::integrateMeasurement(
|
void ImuFactor::PreintegratedMeasurements::integrateMeasurement(
|
||||||
const Vector3& measuredAcc, const Vector3& measuredOmega, double deltaT,
|
const Vector3& measuredAcc, const Vector3& measuredOmega, double deltaT,
|
||||||
boost::optional<const Pose3&> body_P_sensor) {
|
boost::optional<const Pose3&> body_P_sensor,
|
||||||
|
boost::optional<Matrix&> Fout, boost::optional<Matrix&> Gout) {
|
||||||
|
|
||||||
// NOTE: order is important here because each update uses old values (i.e., we have to update
|
// NOTE: order is important here because each update uses old values (i.e., we have to update
|
||||||
// jacobians and covariances before updating preintegrated measurements).
|
// jacobians and covariances before updating preintegrated measurements).
|
||||||
|
|
@ -87,6 +88,7 @@ void ImuFactor::PreintegratedMeasurements::integrateMeasurement(
|
||||||
// as in [2] we consider a first order propagation that can be seen as a prediction phase in an EKF framework
|
// as in [2] we consider a first order propagation that can be seen as a prediction phase in an EKF framework
|
||||||
/* ----------------------------------------------------------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------------------------------------------------------- */
|
||||||
const Vector3 theta_i = thetaRij(); // super-expensive parametrization of so(3)
|
const Vector3 theta_i = thetaRij(); // super-expensive parametrization of so(3)
|
||||||
|
const Matrix3 R_i = deltaRij();
|
||||||
const Matrix3 Jr_theta_i = Rot3::rightJacobianExpMapSO3(theta_i);
|
const Matrix3 Jr_theta_i = Rot3::rightJacobianExpMapSO3(theta_i);
|
||||||
|
|
||||||
// Update preintegrated measurements. TODO Frank moved from end of this function !!!
|
// Update preintegrated measurements. TODO Frank moved from end of this function !!!
|
||||||
|
|
@ -102,7 +104,7 @@ void ImuFactor::PreintegratedMeasurements::integrateMeasurement(
|
||||||
|
|
||||||
Matrix H_vel_pos = Z_3x3;
|
Matrix H_vel_pos = Z_3x3;
|
||||||
Matrix H_vel_vel = I_3x3;
|
Matrix H_vel_vel = I_3x3;
|
||||||
Matrix H_vel_angles = - deltaRij() * skewSymmetric(correctedAcc) * Jr_theta_i * deltaT;
|
Matrix H_vel_angles = - R_i * skewSymmetric(correctedAcc) * Jr_theta_i * deltaT;
|
||||||
// analytic expression corresponding to the following numerical derivative
|
// analytic expression corresponding to the following numerical derivative
|
||||||
// Matrix H_vel_angles = numericalDerivative11<Vector3, Vector3>(boost::bind(&PreIntegrateIMUObservations_delta_vel, correctedOmega, correctedAcc, deltaT, _1, deltaVij), theta_i);
|
// Matrix H_vel_angles = numericalDerivative11<Vector3, Vector3>(boost::bind(&PreIntegrateIMUObservations_delta_vel, correctedOmega, correctedAcc, deltaT, _1, deltaVij), theta_i);
|
||||||
|
|
||||||
|
|
@ -124,15 +126,20 @@ void ImuFactor::PreintegratedMeasurements::integrateMeasurement(
|
||||||
// Gt * Qt * G =(approx)= measurementCovariance_discrete * deltaT^2 = measurementCovariance_contTime * deltaT
|
// Gt * Qt * G =(approx)= measurementCovariance_discrete * deltaT^2 = measurementCovariance_contTime * deltaT
|
||||||
preintMeasCov_ = F * preintMeasCov_ * F.transpose() + measurementCovariance_ * deltaT ;
|
preintMeasCov_ = F * preintMeasCov_ * F.transpose() + measurementCovariance_ * deltaT ;
|
||||||
|
|
||||||
|
// Fout and Gout are used for testing purposes and are not needed by the factor
|
||||||
|
if(Fout){
|
||||||
|
Fout->resize(9,9);
|
||||||
|
(*Fout) << F;
|
||||||
|
}
|
||||||
|
if(Gout){
|
||||||
// Extended version, without approximation: Gt * Qt * G =(approx)= measurementCovariance_contTime * deltaT
|
// Extended version, without approximation: Gt * Qt * G =(approx)= measurementCovariance_contTime * deltaT
|
||||||
// This in only kept for documentation.
|
// This in only kept for testing.
|
||||||
//
|
Gout->resize(9,9);
|
||||||
// Matrix G(9,9);
|
(*Gout) << I_3x3 * deltaT, Z_3x3, Z_3x3,
|
||||||
// G << I_3x3 * deltaT, Z_3x3, Z_3x3,
|
Z_3x3, R_i * deltaT, Z_3x3,
|
||||||
// Z_3x3, deltaRij.matrix() * deltaT, Z_3x3,
|
Z_3x3, Z_3x3, Jrinv_theta_j * Jr_theta_incr * deltaT;
|
||||||
// Z_3x3, Z_3x3, Jrinv_theta_j * Jr_theta_incr * deltaT;
|
//preintMeasCov = F * preintMeasCov * F.transpose() + Gout * (1/deltaT) * measurementCovariance * Gout.transpose();
|
||||||
//
|
}
|
||||||
// preintMeasCov = F * preintMeasCov * F.transpose() + G * (1/deltaT) * measurementCovariance * G.transpose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -111,9 +111,11 @@ public:
|
||||||
* @param measuredOmega Measured angular velocity (as given by the sensor)
|
* @param measuredOmega Measured angular velocity (as given by the sensor)
|
||||||
* @param deltaT Time interval between two consecutive IMU measurements
|
* @param deltaT Time interval between two consecutive IMU measurements
|
||||||
* @param body_P_sensor Optional sensor frame (pose of the IMU in the body frame)
|
* @param body_P_sensor Optional sensor frame (pose of the IMU in the body frame)
|
||||||
|
* @param Fout, Gout Jacobians used internally (only needed for testing)
|
||||||
*/
|
*/
|
||||||
void integrateMeasurement(const Vector3& measuredAcc, const Vector3& measuredOmega, double deltaT,
|
void integrateMeasurement(const Vector3& measuredAcc, const Vector3& measuredOmega, double deltaT,
|
||||||
boost::optional<const Pose3&> body_P_sensor = boost::none);
|
boost::optional<const Pose3&> body_P_sensor = boost::none,
|
||||||
|
boost::optional<Matrix&> Fout = boost::none, boost::optional<Matrix&> Gout = boost::none);
|
||||||
|
|
||||||
/// methods to access class variables
|
/// methods to access class variables
|
||||||
Matrix measurementCovariance() const {return measurementCovariance_;}
|
Matrix measurementCovariance() const {return measurementCovariance_;}
|
||||||
|
|
|
||||||
|
|
@ -343,28 +343,6 @@ public:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
|
|
||||||
// This function is only used for test purposes (compare numerical derivatives wrt analytic ones)
|
|
||||||
static inline Vector PreIntegrateIMUObservations_delta_vel(const Vector& msr_gyro_t, const Vector& msr_acc_t, const double msr_dt,
|
|
||||||
const Vector3& delta_angles, const Vector& delta_vel_in_t0){
|
|
||||||
// Note: all delta terms refer to an IMU\sensor system at t0
|
|
||||||
Vector body_t_a_body = msr_acc_t;
|
|
||||||
Rot3 R_t_to_t0 = Rot3::Expmap(delta_angles);
|
|
||||||
return delta_vel_in_t0 + R_t_to_t0.matrix() * body_t_a_body * msr_dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function is only used for test purposes (compare numerical derivatives wrt analytic ones)
|
|
||||||
static inline Vector PreIntegrateIMUObservations_delta_angles(const Vector& msr_gyro_t, const double msr_dt,
|
|
||||||
const Vector3& delta_angles){
|
|
||||||
// Note: all delta terms refer to an IMU\sensor system at t0
|
|
||||||
// Calculate the corrected measurements using the Bias object
|
|
||||||
Vector body_t_omega_body= msr_gyro_t;
|
|
||||||
Rot3 R_t_to_t0 = Rot3::Expmap(delta_angles);
|
|
||||||
R_t_to_t0 = R_t_to_t0 * Rot3::Expmap( body_t_omega_body*msr_dt );
|
|
||||||
return Rot3::Logmap(R_t_to_t0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
|
|
||||||
private:
|
private:
|
||||||
/** Serialization function */
|
/** Serialization function */
|
||||||
friend class boost::serialization::access;
|
friend class boost::serialization::access;
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,23 @@ Rot3 evaluateRotationError(const ImuFactor& factor,
|
||||||
return Rot3::Expmap(factor.evaluateError(pose_i, vel_i, pose_j, vel_j, bias).tail(3) ) ;
|
return Rot3::Expmap(factor.evaluateError(pose_i, vel_i, pose_j, vel_j, bias).tail(3) ) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector PreIntegrateIMUObservations_delta_vel(const Vector3& msr_acc_t,
|
||||||
|
const double msr_dt, const Vector3& delta_angles, const Vector3& delta_vel_in_t0){
|
||||||
|
// Note: all delta terms refer to an IMU\sensor system at t0
|
||||||
|
Vector body_t_a_body = msr_acc_t;
|
||||||
|
Rot3 R_t_to_t0 = Rot3::Expmap(delta_angles);
|
||||||
|
return delta_vel_in_t0 + R_t_to_t0.matrix() * body_t_a_body * msr_dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector PreIntegrateIMUObservations_delta_angles(const Vector3& msr_gyro_t,
|
||||||
|
const double msr_dt, const Vector3& delta_angles){
|
||||||
|
// Note: all delta terms refer to an IMU\sensor system at t0
|
||||||
|
// Calculate the corrected measurements using the Bias object
|
||||||
|
Rot3 R_t_to_t0 = Rot3::Expmap(delta_angles) * Rot3::Expmap( msr_gyro_t * msr_dt );
|
||||||
|
Vector result = Rot3::Logmap(R_t_to_t0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
ImuFactor::PreintegratedMeasurements evaluatePreintegratedMeasurements(
|
ImuFactor::PreintegratedMeasurements evaluatePreintegratedMeasurements(
|
||||||
const imuBias::ConstantBias& bias,
|
const imuBias::ConstantBias& bias,
|
||||||
const list<Vector3>& measuredAccs,
|
const list<Vector3>& measuredAccs,
|
||||||
|
|
@ -423,6 +440,75 @@ TEST( ImuFactor, FirstOrderPreIntegratedMeasurements )
|
||||||
EXPECT(assert_equal(expectedDelRdelBiasOmega, preintegrated.delRdelBiasOmega(), 1e-3)); // 1e-3 needs to be added only when using quaternions for rotations
|
EXPECT(assert_equal(expectedDelRdelBiasOmega, preintegrated.delRdelBiasOmega(), 1e-3)); // 1e-3 needs to be added only when using quaternions for rotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
TEST( ImuFactor, JacobianPreintegratedCovariancePropagation )
|
||||||
|
{
|
||||||
|
// Linearization point
|
||||||
|
imuBias::ConstantBias bias; ///< Current estimate of acceleration and rotation rate biases
|
||||||
|
Pose3 body_P_sensor = Pose3(); // (Rot3::Expmap(Vector3(0,0.1,0.1)), Point3(1, 0, 1));
|
||||||
|
|
||||||
|
// Measurements
|
||||||
|
list<Vector3> measuredAccs, measuredOmegas;
|
||||||
|
list<double> deltaTs;
|
||||||
|
measuredAccs.push_back(Vector3(0.1, 0.0, 0.0));
|
||||||
|
measuredOmegas.push_back(Vector3(M_PI/100.0, 0.0, 0.0));
|
||||||
|
deltaTs.push_back(0.01);
|
||||||
|
measuredAccs.push_back(Vector3(0.1, 0.0, 0.0));
|
||||||
|
measuredOmegas.push_back(Vector3(M_PI/100.0, 0.0, 0.0));
|
||||||
|
deltaTs.push_back(0.01);
|
||||||
|
for(int i=1;i<100;i++)
|
||||||
|
{
|
||||||
|
measuredAccs.push_back(Vector3(0.05, 0.09, 0.01));
|
||||||
|
measuredOmegas.push_back(Vector3(M_PI/100.0, M_PI/300.0, 2*M_PI/100.0));
|
||||||
|
deltaTs.push_back(0.01);
|
||||||
|
}
|
||||||
|
// Actual preintegrated values
|
||||||
|
ImuFactor::PreintegratedMeasurements preintegrated =
|
||||||
|
evaluatePreintegratedMeasurements(bias, measuredAccs, measuredOmegas, deltaTs, Vector3(M_PI/100.0, 0.0, 0.0));
|
||||||
|
|
||||||
|
// so far we only created a nontrivial linearization point for the preintegrated measurements
|
||||||
|
// Now we add a new measurement and ask for Jacobians
|
||||||
|
const Vector3 newMeasuredAcc = Vector3(0.1, 0.0, 0.0);
|
||||||
|
const Vector3 newMeasuredOmega = Vector3(M_PI/100.0, 0.0, 0.0);
|
||||||
|
const double newDeltaT = 0.01;
|
||||||
|
const Vector3 theta_i = preintegrated.thetaRij(); // before adding new measurement
|
||||||
|
const Vector3 deltaVij = preintegrated.deltaVij();// before adding new measurement
|
||||||
|
|
||||||
|
Matrix Factual, Gactual;
|
||||||
|
preintegrated.integrateMeasurement(newMeasuredAcc, newMeasuredOmega, newDeltaT,
|
||||||
|
body_P_sensor, Factual, Gactual);
|
||||||
|
|
||||||
|
// Compute expected F
|
||||||
|
Matrix H_vel_angles_expected =
|
||||||
|
numericalDerivative11<Vector3, Vector3>(boost::bind(&PreIntegrateIMUObservations_delta_vel,
|
||||||
|
newMeasuredAcc, newDeltaT, _1, deltaVij), theta_i);
|
||||||
|
Matrix H_angles_angles_expected =
|
||||||
|
numericalDerivative11<Vector3, Vector3>(boost::bind(&PreIntegrateIMUObservations_delta_angles,
|
||||||
|
newMeasuredOmega, newDeltaT, _1), theta_i);
|
||||||
|
Matrix Fexpected(9,9);
|
||||||
|
Fexpected << I_3x3, I_3x3 * newDeltaT, Z_3x3,
|
||||||
|
Z_3x3, I_3x3, H_vel_angles_expected,
|
||||||
|
Z_3x3, Z_3x3, H_angles_angles_expected;
|
||||||
|
|
||||||
|
// verify F
|
||||||
|
EXPECT(assert_equal(Fexpected, Factual));
|
||||||
|
|
||||||
|
// Compute expected G
|
||||||
|
Matrix H_vel_noiseAcc_expected =
|
||||||
|
numericalDerivative11<Vector3, Vector3>(boost::bind(&PreIntegrateIMUObservations_delta_vel,
|
||||||
|
_1, newDeltaT, theta_i, deltaVij), newMeasuredAcc);
|
||||||
|
Matrix H_angles_noiseOmega_expected =
|
||||||
|
numericalDerivative11<Vector3, Vector3>(boost::bind(&PreIntegrateIMUObservations_delta_angles,
|
||||||
|
_1, newDeltaT, theta_i), newMeasuredOmega);
|
||||||
|
Matrix Gexpected(9,9);
|
||||||
|
// [integrationError measuredAcc measuredOmega]
|
||||||
|
Gexpected << I_3x3 * newDeltaT, Z_3x3, Z_3x3,
|
||||||
|
Z_3x3, H_vel_noiseAcc_expected, Z_3x3,
|
||||||
|
Z_3x3, Z_3x3, H_angles_noiseOmega_expected;
|
||||||
|
// verify G
|
||||||
|
EXPECT(assert_equal(Gexpected, Gactual,1e-7));
|
||||||
|
}
|
||||||
|
|
||||||
//#include <gtsam/linear/GaussianFactorGraph.h>
|
//#include <gtsam/linear/GaussianFactorGraph.h>
|
||||||
///* ************************************************************************* */
|
///* ************************************************************************* */
|
||||||
//TEST( ImuFactor, LinearizeTiming)
|
//TEST( ImuFactor, LinearizeTiming)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue