Skip to content

Commit d08c72a

Browse files
authored
Merge pull request #2287 from scottiyio/centripetal
Use doublecross instead of cross(Cross(a, b)) in NavState
2 parents f706763 + 6f9a8f7 commit d08c72a

File tree

2 files changed

+46
-16
lines changed

2 files changed

+46
-16
lines changed

gtsam/navigation/NavState.cpp

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,13 @@ NavState NavState::update(const Vector3& b_acceleration, const Vector3& b_omega,
436436
}
437437

438438
//------------------------------------------------------------------------------
439+
440+
// Because our navigation frames are placed on a spinning Earth, we experience two apparent forces on our inertials
441+
// Let Omega be the Earth's rotation rate in the navigation frame
442+
// Coriolis acceleration = -2 * (omega X n_v)
443+
// Centrifugal acceleration (secondOrder) = -omega X (omega X n_t)
444+
// We would also experience a rotation of (omega*dt) over time - so, counteract by compensating rotation by (-omega * dt)
445+
// Integrate centrifugal & coriolis accelerations to yield position, velocity perturbations
439446
Vector9 NavState::coriolis(double dt, const Vector3& omega, bool secondOrder,
440447
OptionalJacobian<9, 9> H) const {
441448
Rot3 nRb = R_;
@@ -444,37 +451,42 @@ Vector9 NavState::coriolis(double dt, const Vector3& omega, bool secondOrder,
444451
const double dt2 = dt * dt;
445452
const Vector3 omega_cross_vel = omega.cross(n_v);
446453

447-
// Get perturbations in nav frame
448-
Vector9 n_xi, xi;
449-
Matrix3 D_dR_R, D_dP_R, D_dV_R, D_body_nav;
454+
Vector9 n_xi;
455+
// Coriolis (first order) acceleration corrections
450456
dR(n_xi) << ((-dt) * omega);
451457
dP(n_xi) << ((-dt2) * omega_cross_vel); // NOTE(luca): we got rid of the 2 wrt INS paper
452458
dV(n_xi) << ((-2.0 * dt) * omega_cross_vel);
459+
460+
// Centrifugal (second order) acceleration corrections
461+
Matrix3 D_c2_nt; // To store Jacobian (if needed/desired)
453462
if (secondOrder) {
454-
const Vector3 omega_cross2_t = omega.cross(omega.cross(n_t));
463+
const Vector3 omega_cross2_t = doubleCross(omega, n_t, nullptr, H ? &D_c2_nt : nullptr);
455464
dP(n_xi) -= (0.5 * dt2) * omega_cross2_t;
456465
dV(n_xi) -= dt * omega_cross2_t;
457466
}
458467

459-
// Transform n_xi into the body frame
460-
xi << nRb.unrotate(dR(n_xi), H ? &D_dR_R : 0, H ? &D_body_nav : 0),
461-
nRb.unrotate(dP(n_xi), H ? &D_dP_R : 0),
462-
nRb.unrotate(dV(n_xi), H ? &D_dV_R : 0);
468+
// Transform correction from navigation frame -> body frame and get Jacobians
469+
Vector9 xi;
470+
Matrix3 D_dR_R, D_dP_R, D_dV_R;
471+
dR(xi) = nRb.unrotate(dR(n_xi), H ? &D_dR_R : 0);
472+
dP(xi) = nRb.unrotate(dP(n_xi), H ? &D_dP_R : 0);
473+
dV(xi) = nRb.unrotate(dV(n_xi), H ? &D_dV_R : 0);
463474

475+
// Assemble Jacobians
464476
if (H) {
465477
H->setZero();
466-
const Matrix3 Omega = skewSymmetric(omega);
467-
const Matrix3 D_cross_state = Omega * R();
478+
const Vector3 omega_b = nRb.unrotate(omega);
479+
const Matrix3 D_c1_b = skewSymmetric(omega_b);
468480
H->setZero();
469481
D_R_R(H) << D_dR_R;
470-
D_t_v(H) << D_body_nav * (-dt2) * D_cross_state;
482+
D_t_v(H) << (-dt2) * D_c1_b;
471483
D_t_R(H) << D_dP_R;
472-
D_v_v(H) << D_body_nav * (-2.0 * dt) * D_cross_state;
484+
D_v_v(H) << (-2.0 * dt) * D_c1_b;
473485
D_v_R(H) << D_dV_R;
474486
if (secondOrder) {
475-
const Matrix3 D_cross2_state = Omega * D_cross_state;
476-
D_t_t(H) -= D_body_nav * (0.5 * dt2) * D_cross2_state;
477-
D_v_t(H) -= D_body_nav * dt * D_cross2_state;
487+
Matrix3 D_c2_b = D_c1_b * D_c1_b;
488+
D_t_t(H) -= (0.5 * dt2) * D_c2_b;
489+
D_v_t(H) -= dt * D_c2_b;
478490
}
479491
}
480492
return xi;

gtsam/navigation/tests/testNavState.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ TEST(NavState, Coriolis3) {
371371
double dt = 2.0, dt2 = dt * dt;
372372
Vector3 n_omega(0.0, 0.0, 1.0), n_t(1.0, 0.0, 0.0), n_v(0.0, 1.0, 0.0);
373373
Vector3 n_aCorr1 = -2.0 * n_omega.cross(n_v),
374-
n_aCorr2 = -n_omega.cross(n_omega.cross(n_t));
374+
n_aCorr2 = -doubleCross(n_omega, n_t);
375375
Rot3 nRb = Rot3(-1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0),
376376
bRn = nRb.inverse();
377377

@@ -402,6 +402,24 @@ TEST(NavState, Coriolis3) {
402402

403403
}
404404

405+
TEST(NavState, Coriolis4) {
406+
/** Consider a navigation frame with zero angular velocity.
407+
* We expect that the coriolis correction does nothing and the Jacobian is zero.
408+
*/
409+
const Vector3 omega(0.0, 0.0, 0.0);
410+
411+
const Vector9 expected_correction = Vector9::Zero();
412+
const Matrix9 expected_H = Matrix9::Zero();
413+
Matrix9 actual_H;
414+
415+
const Vector9 actual_correction =
416+
kState1.coriolis(dt, omega, true, actual_H);
417+
418+
EXPECT(assert_equal(expected_correction, actual_correction));
419+
EXPECT(assert_equal(expected_H, actual_H));
420+
}
421+
422+
405423
/* ************************************************************************* */
406424
TEST(NavState, CorrectPIM) {
407425
Vector9 xi;

0 commit comments

Comments
 (0)