19#include <Eigen/Geometry>
34namespace xrt::tracking::constellation::optimizer {
41using Eigen::MatrixBase;
42using Eigen::Quaternion;
43using Eigen::Quaterniond;
59constexpr double kAccelBiasRandomWalkSigma = 1e-3;
60constexpr double kGyroBiasRandomWalkSigma = 1e-4;
61constexpr double kAccelScaleRandomWalkSigma = 1e-5;
64constexpr double kAccelBiasAnchorSigma = 0.687;
65constexpr double kGyroBiasAnchorSigma = 0.0175;
66constexpr double kAccelScaleAnchorSigma = 0.05;
74constexpr double kMinAccelScale = 0.8;
75constexpr double kMaxAccelScale = 1.0 / kMinAccelScale;
86enum class ImuBiasStateIndex :
int
103typedef ceres::Jet<double, static_cast<int>(ImuBiasStateIndex::NumIndices)> ImuBiasJet;
113 static_assert(!std::is_const_v<T>,
114 "block scalar must not be const — did a `T*` overload deduce T = const double?");
116 static constexpr int kNumParameters =
static_cast<int>(ImuBiasStateIndex::NumIndices);
118 static constexpr int kAccelBiasIndex =
static_cast<int>(ImuBiasStateIndex::AccelBiasX);
119 static constexpr int kGyroBiasIndex =
static_cast<int>(ImuBiasStateIndex::GyroBiasX);
120 static constexpr int kAccelScaleIndex =
static_cast<int>(ImuBiasStateIndex::AccelScaleX);
132 : accel_bias(accel_bias), gyro_bias(gyro_bias), accel_scale(accel_scale)
135 ImuBias(Eigen::Ref<
const Vector<T, kNumParameters>> parameters)
136 : accel_bias(parameters.template segment<3>(kAccelBiasIndex)),
137 gyro_bias(parameters.template segment<3>(kGyroBiasIndex)),
138 accel_scale(parameters.template segment<3>(kAccelScaleIndex))
142 pack(Eigen::Ref<Vector<T, kNumParameters>> parameters)
144 parameters.template segment<3>(kAccelBiasIndex) = this->accel_bias;
145 parameters.template segment<3>(kGyroBiasIndex) = this->gyro_bias;
146 parameters.template segment<3>(kAccelScaleIndex) = this->accel_scale;
153 seeded.accel_bias = {{this->accel_bias.x(), kAccelBiasIndex + 0},
154 {this->accel_bias.y(), kAccelBiasIndex + 1},
155 {this->accel_bias.z(), kAccelBiasIndex + 2}};
156 seeded.gyro_bias = {{this->gyro_bias.x(), kGyroBiasIndex + 0},
157 {this->gyro_bias.y(), kGyroBiasIndex + 1},
158 {this->gyro_bias.z(), kGyroBiasIndex + 2}};
159 seeded.accel_scale = {{this->accel_scale.x(), kAccelScaleIndex + 0},
160 {this->accel_scale.y(), kAccelScaleIndex + 1},
161 {this->accel_scale.z(), kAccelScaleIndex + 2}};
166enum class ImuBiasCovarianceIndex :
int
183static constexpr int kImuBiasRotCovIndex =
static_cast<int>(ImuBiasCovarianceIndex::RotX);
184static constexpr int kImuBiasVelCovIndex =
static_cast<int>(ImuBiasCovarianceIndex::VelocityX);
185static constexpr int kImuBiasPosCovIndex =
static_cast<int>(ImuBiasCovarianceIndex::PositionX);
186static constexpr int kNumImuBiasCovIndices =
static_cast<int>(ImuBiasCovarianceIndex::NumIndices);
193 static constexpr int kNumResiduals = 9;
207 Vector3d accel_bias_at_integration;
208 Vector3d gyro_bias_at_integration;
210 Vector3d accel_scale_at_integration;
231 .delta_velocity = Vector3d::Zero(),
232 .delta_position = Vector3d::Zero(),
234 .whitening = PreintegrationCovarianceMatrix::Zero(),
238 .accel_bias_at_integration = Vector3d::Zero(),
239 .gyro_bias_at_integration = Vector3d::Zero(),
240 .accel_scale_at_integration = Vector3d::Constant(1.0),
242 .J_R_bg = Matrix3d::Zero(),
243 .J_v_ba = Matrix3d::Zero(),
244 .J_v_sa = Matrix3d::Zero(),
245 .J_v_bg = Matrix3d::Zero(),
246 .J_p_ba = Matrix3d::Zero(),
247 .J_p_sa = Matrix3d::Zero(),
248 .J_p_bg = Matrix3d::Zero(),
264preintegrate(
const std::span<const xrt_imu_sample> &imu_samples,
284 Vector<T, PreintegratedImuSamples::kNumResiduals> &residual)
287 start_T_world_device.getQuaternion(Q_world_device_start);
288 auto start_Q_device_world = Q_world_device_start.conjugate();
291 end_T_world_device.getQuaternion(end_Q_world_device);
296 auto end_predicted_Q_start = start_Q_device_world * end_Q_world_device;
297 auto predicted_start_delta_velocity = start_Q_device_world *
298 (end_T_world_device.velocity -
299 start_T_world_device.velocity -
300 (gravity_vector * imu_preintegration.dt));
301 auto predicted_start_delta_position =
302 start_Q_device_world *
303 (end_T_world_device.translation -
304 start_T_world_device.translation -
305 start_T_world_device.velocity * imu_preintegration.dt -
306 (T(0.5) * gravity_vector * imu_preintegration.dt * imu_preintegration.dt));
309 Vector3<T> delta_accel_bias = imu_bias.accel_bias - imu_preintegration.accel_bias_at_integration.cast<T>();
310 Vector3<T> delta_gyro_bias = imu_bias.gyro_bias - imu_preintegration.gyro_bias_at_integration.cast<T>();
311 Vector3<T> delta_accel_scale = imu_bias.accel_scale - imu_preintegration.accel_scale_at_integration.cast<T>();
321 + imu_preintegration.
J_v_ba.cast<T>() * delta_accel_bias
322 + imu_preintegration.
J_v_bg.cast<T>() * delta_gyro_bias
323 + imu_preintegration.
J_v_sa.cast<T>() * delta_accel_scale;
327 + imu_preintegration.
J_p_ba.cast<T>() * delta_accel_bias
328 + imu_preintegration.
J_p_bg.cast<T>() * delta_gyro_bias
329 + imu_preintegration.
J_p_sa.cast<T>() * delta_accel_scale;
332 auto delta_rotation_error = corrected_Q_start_end.conjugate() * end_predicted_Q_start;
333 if (delta_rotation_error.w() < T(0)) {
334 delta_rotation_error.coeffs() = -delta_rotation_error.coeffs();
337 residual.template segment<3>(0) =
quat_ln_so3(delta_rotation_error);
338 residual.template segment<3>(3) = predicted_start_delta_velocity - corrected_start_delta_velocity;
339 residual.template segment<3>(6) = predicted_start_delta_position - corrected_start_delta_position;
353 template <
typename T>
355 operator()(
const T *
const world_gravity_parameters,
356 const T *
const imu_bias_parameters,
357 const T *
const start_keyframe_parameters,
358 const T *
const end_keyframe_parameters,
362 Map<const Vector<T, WorldGravity<T>::kNumParameters>>(world_gravity_parameters)};
364 const ImuBias<T> imu_bias{Map<const Vector<T, ImuBias<T>::kNumParameters>>(imu_bias_parameters)};
367 Map<const Vector<T, PoseWithVelocity<T>::kNumParameters>>(start_keyframe_parameters)};
369 Map<const Vector<T, PoseWithVelocity<T>::kNumParameters>>(end_keyframe_parameters)};
371 Vector<T, PreintegratedImuSamples::kNumResiduals> computed_residual;
372 computeImuResidual<T>(this->preintegration,
373 start_T_world_device,
379 Map<Vector<T, PreintegratedImuSamples::kNumResiduals>> out_residual(residuals);
380 out_residual = this->preintegration.
whitening.cast<T>() * computed_residual;
387 PreintegratedImuSamples::kNumResiduals,
402 template <
typename T>
404 operator()(
const T *
const start_bias_parameters,
405 const T *
const end_bias_parameters,
408 const ImuBias<T> start{Map<const Vector<T, ImuBias<T>::kNumParameters>>(start_bias_parameters)};
409 const ImuBias<T> end{Map<const Vector<T, ImuBias<T>::kNumParameters>>(end_bias_parameters)};
413 const T sqrt_dt = T(std::sqrt(this->dt));
415 Map<Vector3<T>> accel_residual(residuals + 0);
416 Map<Vector3<T>> gyro_residual(residuals + 3);
417 Map<Vector3<T>> scale_residual(residuals + 6);
423 accel_residual = (end.accel_bias - start.accel_bias) / (T(kAccelBiasRandomWalkSigma) * sqrt_dt);
424 gyro_residual = (end.gyro_bias - start.gyro_bias) / (T(kGyroBiasRandomWalkSigma) * sqrt_dt);
425 scale_residual = (end.accel_scale - start.accel_scale) / (T(kAccelScaleRandomWalkSigma) * sqrt_dt);
434 ImuBiasRandomWalkCostFunctor::kNumResiduals,
437 ImuBiasRandomWalkCostFunction;
446 template <
typename T>
448 operator()(
const T *
const bias_parameters,
451 const ImuBias<T> bias{Map<const Vector<T, ImuBias<T>::kNumParameters>>(bias_parameters)};
453 Map<Vector3<T>> accel_residual(residuals + 0);
454 Map<Vector3<T>> gyro_residual(residuals + 3);
455 Map<Vector3<T>> scale_residual(residuals + 6);
458 accel_residual = (bias.accel_bias - this->anchor.accel_bias) / T(kAccelBiasAnchorSigma);
459 gyro_residual = (bias.gyro_bias - this->anchor.gyro_bias) / T(kGyroBiasAnchorSigma);
460 scale_residual = (bias.accel_scale - this->anchor.accel_scale) / T(kAccelScaleAnchorSigma);
469 ImuBiasAnchorCostFunctor::kNumResiduals,
471 ImuBiasAnchorCostFunction;
Definition utility_northstar.h:779
Definition utility_northstar.h:16
int64_t timepoint_ns
Integer timestamp type.
Definition u_time.h:77
int64_t time_duration_ns
Integer duration type in nanoseconds.
Definition u_time.h:88
constexpr double kMaxGyroBias
Largest gyroscope bias to allow, in rad/s. The BMI055's zero-rate offset is +-1 deg/s,...
Definition imu_preintegration.hpp:71
constexpr time_duration_ns kKeyframeGroupingToleranceNs
Camera samples from the same mosaic closer together than this are treated as one keyframe.
Definition imu_preintegration.hpp:84
PreintegratedImuSamples preintegrate(const std::span< const xrt_imu_sample > &imu_samples, const xrt_imu_sample &first_sample_after_end_time, const ImuBias< ImuBiasJet > &imu_bias, timepoint_ns start_time_ns, timepoint_ns end_time_ns)
Does IMU pre-integration on a set of IMU samples, interpolates the starting sample to the start time,...
Definition internal_math.cpp:374
constexpr double kMaxAccelBias
Largest accelerometer bias to allow, in m/s^2. The BMI055's zero-g offset is +-70mg,...
Definition imu_preintegration.hpp:69
constexpr double kGyroNoiseDensity
BMI055 gyroscope noise density, 0.014 deg/s/sqrt(Hz) from the datasheet, in rad/s/sqrt(Hz).
Definition imu_preintegration.hpp:54
constexpr double kAccelNoiseDensity
BMI055 accelerometer noise density, 150 ug/sqrt(Hz) from the datasheet, in (m/s^2)/sqrt(Hz).
Definition imu_preintegration.hpp:56
Matrix< double, kNumImuBiasCovIndices, kNumImuBiasCovIndices > PreintegrationCovarianceMatrix
[rotation; velocity; position], the order computeImuResidual writes its residual in.
Definition imu_preintegration.hpp:189
Generic math helpers for constellation optimizer code.
Interoperability helpers connecting internal math types and Eigen.
Base implementations for math library.
Helpers for quatexpmap math for bigceres usage.
C++-only functionality in the Math helper library.
Definition m_documentation.hpp:15
Eigen::Quaternion< typename Derived::Scalar > quat_exp_so3(Eigen::MatrixBase< Derived > const &vec)
Fully-templated free function for quaternion exponentiation, SO(3) version as described by Grassia.
Definition m_quatexpmap.hpp:119
Eigen::Matrix< Scalar, 3, 1 > quat_ln_so3(Eigen::Quaternion< Scalar > const &quat)
Fully-templated free function for quaternion log map, SO(3) version.
Definition m_quatexpmap.hpp:148
Wrapper around OS native time functions.
IMU Bias anchor cost functor, to hold it at some value when marginalization has no guess for it.
Definition imu_preintegration.hpp:441
A full-state IMU bias, with Accelerometer Bias, Gyroscope Bias, and Accelerometer Scale.
Definition imu_preintegration.hpp:112
IMU Bias random walk cost functor, between each keyframe.
Definition imu_preintegration.hpp:396
double dt
Seconds spanned by this interval.
Definition imu_preintegration.hpp:400
IMU preintegration factor, between each camera keyframe.
Definition imu_preintegration.hpp:350
Pose with 9 degrees of freedom, translation, rotation, and linear velocity.
Definition internal_math.hpp:334
Definition imu_preintegration.hpp:192
Matrix3d J_p_sa
d(delta_position) / d(accel_scale)
Definition imu_preintegration.hpp:223
Matrix3d J_v_sa
d(delta_velocity) / d(accel_scale)
Definition imu_preintegration.hpp:219
Quaterniond Q_start_end
The preintegrated rotation from the IMU samples, as a quaternion.
Definition imu_preintegration.hpp:196
Matrix3d J_v_bg
d(delta_velocity) / d(gyro_bias)
Definition imu_preintegration.hpp:220
PreintegrationCovarianceMatrix whitening
The whitening matrix for this preintegration, the lower triangular.
Definition imu_preintegration.hpp:203
Matrix3d J_p_bg
d(delta_position) / d(gyro_bias)
Definition imu_preintegration.hpp:224
Matrix3d J_p_ba
d(delta_position) / d(accel_bias)
Definition imu_preintegration.hpp:222
Matrix3d J_v_ba
d(delta_velocity) / d(accel_bias)
Definition imu_preintegration.hpp:218
Vector3d delta_position
This is really "delta double-integrated specific force", but we call it delta_position for simplicity...
Definition imu_preintegration.hpp:200
Matrix3d J_R_bg
d(Q_start_cur) / d(gyro_bias)
Definition imu_preintegration.hpp:216
Vector3d delta_velocity
This is really "delta integrated specific force", but we call it delta_velocity for simplicity.
Definition imu_preintegration.hpp:198
The strength of gravity in the world, as a parameter block of its own.
Definition internal_math.hpp:187
Vector3< T > toVector() const
Gravity as a vector, which points along +Y since world up is -Y in the OpenCV space the optimizer wor...
Definition internal_math.hpp:213
IMU Sample.
Definition xrt_tracking.h:143
#define U_TIME_1MS_IN_NS
The number of nanoseconds in a millisecond.
Definition u_time.h:54