IMU
factors::imu — inertial preintegration. Two factors per group and nothing
else, so a choice here is two questions rather than a catalogue.
Preintegration
Integrating raw IMU samples between keyframes would re-integrate the whole interval every time the state changes. Preintegration instead accumulates the measurements into a relative quantity that does not depend on the states — only on the bias linearization point — so a keyframe pair can be re-evaluated in constant time.
ImuPreintegration::new(measurements, params, t0, t1, &bias_ref) accumulates
the delta , its covariance, and the bias-correction
Jacobians . Everything it produces is
gravity-free; the factors reinstate gravity when they build the
gravity-corrected state.
Two axes
Which group? se23 models a keyframe as ;
sgal3 adds a time coordinate, , making the
inter-keyframe interval an estimated quantity — pick it for time-offset or
rolling-shutter calibration, se23 otherwise.
Combined or not? This is the split GTSAM draws between ImuFactor and
CombinedImuFactor, and it decides the residual dimension.
ImuFactor | CombinedImuFactor | |
|---|---|---|
se23 | 9D, (SE23, SE23, bias) | 15D, (SE23, bias, SE23, bias) |
sgal3 | 10D, (SGal3, SGal3, bias) | 16D, (SGal3, bias, SGal3, bias) |
ImuFactor shares one bias variable across the interval and leaves its
evolution to a separate edge; CombinedImuFactor takes a bias per keyframe and
embeds the random walk in six extra residual rows. Doing both counts that
uncertainty twice.
Weighting follows the same split: the shared-bias form uses a information built from measurement noise alone, the combined form the full including the random walk.
A keyframe is a single variable on the group, not separate pose and
velocity blocks — the optimizer’s update is then a group right-plus, and the
pose/velocity coupling inertial integration produces is the group’s job. The
practical consequence is that aiding measurements attach to that state: an
SE(3)-only factor cannot connect to an SE23 variable, while
PriorFactor<SE23> and MarginalPriorFactor are generic and do.
Error
Folding gravity into the state rather than the residual is what makes the comparison a plain group right-minus. The bias correction is the first-order update of the preintegrated delta for a bias away from its linearization point,
The combined form appends (6 rows).
Jacobian
All four factors are thin wrappers over one evaluate, which returns the
residual and three tangent-space blocks. Write
for the two Jacobians
right_minus reports and for the tangent Jacobian of
right_plus. Then
The comes from differentiating with respect to the left argument: .
The bias block expands to
in the tangent order.
The lift from to the gravity-corrected state is a constant matrix, independent of the linearization point, because shares ’s rotation and shifts the rest by gravity terms only:
The combined form appends the bias-walk rows, whose Jacobian is constant:
Every above is reported by the group’s own right_plus, right_minus and
adjoint; none of it is hand-derived.
Bias evolution
The non-combined factors need a companion edge, which
factors::imu::bias builds as a BetweenFactor<Rn> with zero measurement:
#![allow(unused)]
fn main() {
use apex_solver::factors::imu::{se23, bias_random_walk, bias_random_walk_noise};
problem.add_residual_block(
&[state_i, state_j, bias],
Box::new(se23::ImuFactor::new(preintegration)),
None,
);
problem.add_residual_block_with_noise(
&[bias, bias_next],
Box::new(bias_random_walk()),
None,
bias_random_walk_noise(¶ms, dt)?,
);
}
An initial bias prior (an EuclideanPriorFactor on ) is required
for observability in every configuration.
SGal(3) and the time row
SGal(3)’s tangent carries a time coordinate, so the residual gains a row
, weighted by (with_time_sigma, default
100 µs). That row is the reason to choose SGal(3): it makes the interval a
quantity the optimizer can move.
Known limitation. SGal(3)’s group law is — the left operand’s time couples the right operand’s velocity into translation. The residual composes , so it depends on the absolute , while the preintegrated delta corresponds to . A single interval with is correct; chaining these factors across keyframes on a common absolute clock is not. Prefer the
se23factors for multi-keyframe chains until the residual is re-derived in terms of .