13#error "This header is C++-only."
24#include <Eigen/Geometry>
26#include "flexkalman/EigenQuatExponentialMap.h"
28DEBUG_GET_ONCE_LOG_OPTION(simple_imu_log,
"SIMPLE_IMU_LOG",
U_LOGGING_WARN)
30#define SIMPLE_IMU_TRACE(...) U_LOG_IFL_T(log_level, __VA_ARGS__)
31#define SIMPLE_IMU_DEBUG(...) U_LOG_IFL_D(log_level, __VA_ARGS__)
32#define SIMPLE_IMU_INFO(...) U_LOG_IFL_I(log_level, __VA_ARGS__)
33#define SIMPLE_IMU_WARN(...) U_LOG_IFL_W(log_level, __VA_ARGS__)
34#define SIMPLE_IMU_ERROR(...) U_LOG_IFL_E(log_level, __VA_ARGS__)
36namespace xrt::auxiliary::tracking {
44 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
50 : gravity_scale_(gravity_rate), log_level(debug_get_log_option_simple_imu_log())
52 SIMPLE_IMU_DEBUG(
"Creating instance");
79 return flexkalman::util::quat_ln(quat_);
88 return quat_.toRotationMatrix();
105 Eigen::Vector3d
const &
147 Eigen::Vector3d adjusted_accel = accel * getAccelScaleFactor_();
148 return (quat_ * adjusted_accel) - (Eigen::Vector3d::UnitY() *
MATH_GRAVITY_M_S2);
169 getAccelScaleFactor_()
const
177 Eigen::Vector3d angVel_{Eigen::Vector3d::Zero()};
179 Eigen::Quaterniond quat_{Eigen::Quaterniond::Identity()};
180 double gravity_scale_;
190 math::LowPassIIRVectorFilter<3, double> accel_filter_{200 };
200 math::LowPassIIRFilter<double> gravity_filter_{1 };
201 uint64_t last_accel_timestamp_{0};
202 uint64_t last_gyro_timestamp_{0};
203 double gyro_min_squared_length_{1.e-8};
204 bool started_{
false};
208inline Eigen::Quaterniond
211 timepoint_ns state_time = std::max(last_accel_timestamp_, last_gyro_timestamp_);
212 if (state_time == 0) {
214 return Eigen::Quaterniond::Identity();
218 return quat_ * flexkalman::util::quat_exp(angVel_ * dt * 0.5);
226 "Discarding gyro report before first usable accel "
231 (last_gyro_timestamp_ == 0) ? (
time_duration_ns)1e6 : timestamp - last_gyro_timestamp_;
232 if (delta_ns > 1e10) {
234 SIMPLE_IMU_DEBUG(
"Clamping integration period");
240 last_gyro_timestamp_ = timestamp;
241 Eigen::Vector3d incRot = gyro * dt;
243 if (incRot.squaredNorm() < gyro_min_squared_length_) {
244 SIMPLE_IMU_TRACE(
"Discarding gyro data that is approximately zero");
251 quat_ = quat_ * flexkalman::util::quat_exp(incRot * 0.5);
258 uint64_t delta_ns = (last_accel_timestamp_ == 0) ? 1e6 : timestamp - last_accel_timestamp_;
266 "Can't start tracker with this accel "
267 "sample: we're moving too much.");
273 quat_ = Eigen::Quaterniond::FromTwoVectors(accel.normalized(), Eigen::Vector3d::UnitY());
274 accel_filter_.
addSample(accel, timestamp);
275 gravity_filter_.
addSample(accel.norm(), timestamp);
276 last_accel_timestamp_ = timestamp;
278 SIMPLE_IMU_DEBUG(
"Got a usable startup accel report");
281 last_accel_timestamp_ = timestamp;
282 accel_filter_.
addSample(accel, timestamp);
283 gravity_filter_.
addSample(accel.norm(), timestamp);
286 Eigen::Vector3d adjusted_accel = accel_filter_.
getState() * getAccelScaleFactor_();
290 auto scale = 1. - diff;
294 SIMPLE_IMU_TRACE(
"Too far from gravity to be useful/trusted.");
300 Eigen::Vector3d measuredGravityDirection = (quat_ * adjusted_accel).normalized();
301 auto incremental = Eigen::Quaterniond::FromTwoVectors(measuredGravityDirection, Eigen::Vector3d::UnitY());
303 double alpha = scale * gravity_scale_ * dt;
304 Eigen::Quaterniond scaledIncrementalQuat = Eigen::Quaterniond::Identity().slerp(alpha, incremental);
307 quat_ = scaledIncrementalQuat * quat_;
void addSample(Scalar sample, timepoint_ns timestamp_ns, Scalar weight=1)
Filter a sample, with an optional weight.
Definition: m_lowpass_float.hpp:143
Scalar getState() const noexcept
Get the filtered value.
Definition: m_lowpass_float.hpp:152
Vector const & getState() const noexcept
Get the filtered value.
Definition: m_lowpass_float_vector.hpp:74
void addSample(Vector const &sample, std::uint64_t timestamp_ns, Scalar weight=1)
Filter a sample, with an optional weight.
Definition: m_lowpass_float_vector.hpp:65
A simple IMU fusion class.
Definition: t_imu_fusion.hpp:42
Eigen::Quaterniond getPredictedQuat(timepoint_ns timestamp) const
Get the predicted orientation at some point in the future.
Definition: t_imu_fusion.hpp:209
bool valid() const noexcept
Definition: t_imu_fusion.hpp:59
bool handleAccel(Eigen::Vector3d const &accel, timepoint_ns timestamp)
Process an accelerometer report.
Definition: t_imu_fusion.hpp:256
void postCorrect()
Normalize internal state.
Definition: t_imu_fusion.hpp:158
Eigen::Matrix3d getRotationMatrix() const
Get the current state orientation as a rotation matrix.
Definition: t_imu_fusion.hpp:86
bool handleGyro(Eigen::Vector3d const &gyro, timepoint_ns timestamp)
Process a gyroscope report.
Definition: t_imu_fusion.hpp:221
Eigen::Vector3d const & getAngVel() const
Get the angular velocity in body space.
Definition: t_imu_fusion.hpp:106
Eigen::Vector3d getRotationVec() const
Get the current state orientation as a rotation vector.
Definition: t_imu_fusion.hpp:77
Eigen::Vector3d getCorrectedWorldAccel(Eigen::Vector3d const &accel) const
Use this to obtain the residual, world-space acceleration in m/s/s not associated with gravity,...
Definition: t_imu_fusion.hpp:145
EIGEN_MAKE_ALIGNED_OPERATOR_NEW SimpleIMUFusion(double gravity_rate=0.9)
Definition: t_imu_fusion.hpp:49
Eigen::Quaterniond getQuat() const
Get the current state orientation.
Definition: t_imu_fusion.hpp:68
u_logging_level
Logging level enum.
Definition: u_logging.h:40
@ U_LOGGING_WARN
Warning messages: indicating a potential problem.
Definition: u_logging.h:44
#define MATH_GRAVITY_M_S2
Standard gravity acceleration constant.
Definition: m_api.h:51
int64_t timepoint_ns
Integer timestamp type.
Definition: u_time.h:70
static double time_ns_to_s(time_duration_ns ns)
Convert nanoseconds duration to double seconds.
Definition: u_time.h:90
int64_t time_duration_ns
Integer duration type in nanoseconds.
Definition: u_time.h:81
C interface to math library.
Low-pass IIR filter on vectors.
Basic logging functionality.
Time-keeping: a clock that is steady, convertible to system time, and ideally high-resolution.