2019-10-10 16:28:42 +00:00
|
|
|
// Copyright 2019, Collabora, Ltd.
|
|
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
|
|
/*!
|
|
|
|
* @file
|
2019-10-24 15:12:07 +00:00
|
|
|
* @brief IMU fusion implementation - for inclusion into the single
|
|
|
|
* kalman-incuding translation unit.
|
2019-10-10 16:28:42 +00:00
|
|
|
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
|
|
|
* @ingroup aux_tracking
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "t_imu.h"
|
|
|
|
#include "t_imu_fusion.h"
|
|
|
|
#include "math/m_eigen_interop.h"
|
2019-11-12 17:43:17 +00:00
|
|
|
#include "util/u_misc.h"
|
2019-10-10 16:28:42 +00:00
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
struct imu_fusion
|
|
|
|
{
|
2019-11-14 16:35:56 +00:00
|
|
|
public:
|
2019-11-11 17:55:39 +00:00
|
|
|
uint64_t time_ns{0};
|
2019-10-10 16:28:42 +00:00
|
|
|
|
|
|
|
xrt_fusion::SimpleIMUFusion simple_fusion;
|
2019-11-14 16:35:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
2019-10-10 16:28:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* API functions
|
|
|
|
*/
|
|
|
|
struct imu_fusion *
|
2019-10-29 20:08:44 +00:00
|
|
|
imu_fusion_create()
|
2019-10-10 16:28:42 +00:00
|
|
|
{
|
2019-10-29 20:08:44 +00:00
|
|
|
try {
|
|
|
|
auto fusion = std::make_unique<imu_fusion>();
|
|
|
|
return fusion.release();
|
|
|
|
} catch (...) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-10-10 16:28:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-10-29 20:08:44 +00:00
|
|
|
imu_fusion_destroy(struct imu_fusion *fusion)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
delete fusion;
|
|
|
|
} catch (...) {
|
|
|
|
assert(false && "Caught exception on destroy");
|
|
|
|
}
|
2019-10-10 16:28:42 +00:00
|
|
|
}
|
|
|
|
int
|
|
|
|
imu_fusion_incorporate_gyros(struct imu_fusion *fusion,
|
2019-11-11 17:55:39 +00:00
|
|
|
uint64_t timestamp_ns,
|
2019-10-10 16:28:42 +00:00
|
|
|
struct xrt_vec3 const *ang_vel,
|
2019-11-12 17:37:59 +00:00
|
|
|
struct xrt_vec3 const *ang_vel_variance)
|
2019-10-29 20:08:44 +00:00
|
|
|
{
|
|
|
|
try {
|
|
|
|
assert(fusion);
|
|
|
|
assert(ang_vel);
|
2019-11-12 17:37:59 +00:00
|
|
|
assert(ang_vel_variance);
|
2019-11-11 17:55:39 +00:00
|
|
|
assert(timestamp_ns != 0);
|
2019-10-29 20:08:44 +00:00
|
|
|
|
|
|
|
fusion->simple_fusion.handleGyro(
|
2019-11-11 22:32:04 +00:00
|
|
|
map_vec3(*ang_vel).cast<double>(), timestamp_ns);
|
2019-10-29 20:08:44 +00:00
|
|
|
return 0;
|
|
|
|
} catch (...) {
|
|
|
|
assert(false && "Caught exception on incorporate gyros");
|
|
|
|
return -1;
|
|
|
|
}
|
2019-10-10 16:28:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
imu_fusion_incorporate_accelerometer(struct imu_fusion *fusion,
|
2019-11-11 17:55:39 +00:00
|
|
|
uint64_t timestamp_ns,
|
2019-10-10 16:28:42 +00:00
|
|
|
struct xrt_vec3 const *accel,
|
2019-11-12 17:43:17 +00:00
|
|
|
struct xrt_vec3 const *accel_variance,
|
|
|
|
struct xrt_vec3 *out_world_accel)
|
2019-10-29 20:08:44 +00:00
|
|
|
{
|
|
|
|
try {
|
|
|
|
assert(fusion);
|
|
|
|
assert(accel);
|
2019-11-12 17:37:59 +00:00
|
|
|
assert(accel_variance);
|
2019-11-11 17:55:39 +00:00
|
|
|
assert(timestamp_ns != 0);
|
2019-11-12 18:14:24 +00:00
|
|
|
Eigen::Vector3d accelVec = map_vec3(*accel).cast<double>();
|
|
|
|
fusion->simple_fusion.handleAccel(accelVec, timestamp_ns);
|
2019-11-12 17:43:17 +00:00
|
|
|
if (out_world_accel != NULL) {
|
2019-11-12 18:14:24 +00:00
|
|
|
Eigen::Vector3d worldAccel =
|
|
|
|
fusion->simple_fusion.getCorrectedWorldAccel(
|
|
|
|
accelVec);
|
|
|
|
map_vec3(*out_world_accel) = worldAccel.cast<float>();
|
2019-11-12 17:43:17 +00:00
|
|
|
}
|
2019-10-29 20:08:44 +00:00
|
|
|
return 0;
|
|
|
|
} catch (...) {
|
|
|
|
assert(false &&
|
|
|
|
"Caught exception on incorporate accelerometer");
|
|
|
|
return -1;
|
|
|
|
}
|
2019-10-10 16:28:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
imu_fusion_get_prediction(struct imu_fusion const *fusion,
|
2019-11-11 17:55:39 +00:00
|
|
|
uint64_t timestamp_ns,
|
2019-10-10 16:28:42 +00:00
|
|
|
struct xrt_quat *out_quat,
|
2019-10-29 20:08:44 +00:00
|
|
|
struct xrt_vec3 *out_ang_vel)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
assert(fusion);
|
|
|
|
assert(out_quat);
|
|
|
|
assert(out_ang_vel);
|
2019-11-11 17:55:39 +00:00
|
|
|
assert(timestamp_ns != 0);
|
2019-10-29 20:08:44 +00:00
|
|
|
if (!fusion->simple_fusion.valid()) {
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
map_vec3(*out_ang_vel) =
|
|
|
|
fusion->simple_fusion.getAngVel().cast<float>();
|
2019-11-11 17:55:39 +00:00
|
|
|
|
|
|
|
if (timestamp_ns == fusion->time_ns) {
|
2019-10-29 20:08:44 +00:00
|
|
|
// No need to predict here.
|
|
|
|
map_quat(*out_quat) =
|
|
|
|
fusion->simple_fusion.getQuat().cast<float>();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
Eigen::Quaterniond predicted_quat =
|
2019-11-11 22:32:04 +00:00
|
|
|
fusion->simple_fusion.getPredictedQuat(timestamp_ns);
|
2019-10-29 20:08:44 +00:00
|
|
|
map_quat(*out_quat) = predicted_quat.cast<float>();
|
2019-10-10 16:28:42 +00:00
|
|
|
return 0;
|
2019-10-29 20:08:44 +00:00
|
|
|
|
|
|
|
} catch (...) {
|
|
|
|
assert(false && "Caught exception on getting prediction");
|
|
|
|
return -1;
|
2019-10-10 16:28:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
imu_fusion_get_prediction_rotation_vec(struct imu_fusion const *fusion,
|
2019-11-11 17:55:39 +00:00
|
|
|
uint64_t timestamp_ns,
|
2019-10-29 20:08:44 +00:00
|
|
|
struct xrt_vec3 *out_rotation_vec)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
assert(fusion);
|
|
|
|
assert(out_rotation_vec);
|
2019-11-11 17:55:39 +00:00
|
|
|
assert(timestamp_ns != 0);
|
2019-10-29 20:08:44 +00:00
|
|
|
|
|
|
|
if (!fusion->simple_fusion.valid()) {
|
|
|
|
return -2;
|
|
|
|
}
|
2019-11-11 17:55:39 +00:00
|
|
|
if (timestamp_ns == fusion->time_ns) {
|
2019-10-29 20:08:44 +00:00
|
|
|
// No need to predict here.
|
|
|
|
map_vec3(*out_rotation_vec) =
|
|
|
|
fusion->simple_fusion.getRotationVec()
|
|
|
|
.cast<float>();
|
|
|
|
} else {
|
|
|
|
Eigen::Quaterniond predicted_quat =
|
2019-11-11 22:32:04 +00:00
|
|
|
fusion->simple_fusion.getPredictedQuat(
|
|
|
|
timestamp_ns);
|
2019-10-29 20:08:44 +00:00
|
|
|
map_vec3(*out_rotation_vec) =
|
|
|
|
flexkalman::util::quat_ln(predicted_quat)
|
|
|
|
.cast<float>();
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
} catch (...) {
|
|
|
|
assert(false && "Caught exception on getting prediction");
|
|
|
|
return -1;
|
2019-10-10 16:28:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
imu_fusion_incorporate_gyros_and_accelerometer(
|
|
|
|
struct imu_fusion *fusion,
|
2019-11-11 17:55:39 +00:00
|
|
|
uint64_t timestamp_ns,
|
2019-10-10 16:28:42 +00:00
|
|
|
struct xrt_vec3 const *ang_vel,
|
|
|
|
struct xrt_vec3 const *ang_vel_variance,
|
|
|
|
struct xrt_vec3 const *accel,
|
2019-11-12 17:43:17 +00:00
|
|
|
struct xrt_vec3 const *accel_variance,
|
|
|
|
struct xrt_vec3 *out_world_accel)
|
2019-10-29 20:08:44 +00:00
|
|
|
{
|
|
|
|
try {
|
|
|
|
assert(fusion);
|
|
|
|
assert(ang_vel);
|
|
|
|
assert(ang_vel_variance);
|
|
|
|
assert(accel);
|
|
|
|
assert(accel_variance);
|
2019-11-11 17:55:39 +00:00
|
|
|
assert(timestamp_ns != 0);
|
2019-10-29 20:08:44 +00:00
|
|
|
|
|
|
|
Eigen::Vector3d accelVec = map_vec3(*accel).cast<double>();
|
|
|
|
Eigen::Vector3d angVelVec = map_vec3(*ang_vel).cast<double>();
|
2019-11-11 22:32:04 +00:00
|
|
|
fusion->simple_fusion.handleAccel(accelVec, timestamp_ns);
|
|
|
|
fusion->simple_fusion.handleGyro(angVelVec, timestamp_ns);
|
2019-10-29 20:08:44 +00:00
|
|
|
fusion->simple_fusion.postCorrect();
|
2019-11-12 18:14:24 +00:00
|
|
|
if (out_world_accel != NULL) {
|
|
|
|
Eigen::Vector3d worldAccel =
|
|
|
|
fusion->simple_fusion.getCorrectedWorldAccel(
|
|
|
|
accelVec);
|
|
|
|
map_vec3(*out_world_accel) = worldAccel.cast<float>();
|
|
|
|
}
|
2019-10-29 20:08:44 +00:00
|
|
|
return 0;
|
|
|
|
} catch (...) {
|
|
|
|
assert(
|
|
|
|
false &&
|
|
|
|
"Caught exception on incorporate gyros and accelerometer");
|
|
|
|
return -1;
|
|
|
|
}
|
2019-10-10 16:28:42 +00:00
|
|
|
}
|