Program Listing for File imu_covariance_factory.cpp
↰ Return to documentation for file (src/imu_covariance_factory.cpp)
// Copyright 2025 Analog Devices, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "adi_imu/imu_covariance_factory.h"
#include <stdexcept>
#include "adi_imu/ewma_covariance_provider.h"
#include "adi_imu/kalman_covariance_provider.h"
#include "adi_imu/motion_detector.h"
#include "adi_imu/sliding_window_covariance_provider.h"
#include "adi_imu/static_covariance_provider.h"
#include "adi_imu/welford_covariance_provider.h"
namespace adi_imu
{
CovarianceAlgorithm ImuCovarianceFactory::parseAlgorithm(const std::string & algorithm_str)
{
if (algorithm_str == "static") return CovarianceAlgorithm::STATIC;
if (algorithm_str == "welford") return CovarianceAlgorithm::WELFORD_ONLINE;
if (algorithm_str == "sliding_window") return CovarianceAlgorithm::SLIDING_WINDOW;
if (algorithm_str == "ewma") return CovarianceAlgorithm::EWMA;
if (algorithm_str == "kalman") return CovarianceAlgorithm::KALMAN;
throw std::invalid_argument("Unknown covariance algorithm: " + algorithm_str);
}
std::unique_ptr<ImuCovarianceInterface> ImuCovarianceFactory::createFromParameters(
const std::shared_ptr<rclcpp::Node> & node)
{
//Declare parameters with defaults
node->declare_parameter("covariance.enable", false);
node->declare_parameter("covariance.algorithm", "welford");
// Welford parameters
node->declare_parameter(
"covariance.welford.calibration_samples",
static_cast<int64_t>(WelfordCovarianceProvider::DEFAULT_CALIBRATION_SAMPLES));
node->declare_parameter(
"covariance.welford.min_variance", WelfordCovarianceProvider::DEFAULT_MIN_VARIANCE);
// Sliding window parameters
node->declare_parameter(
"covariance.sliding_window.window_size",
static_cast<int64_t>(SlidingWindowCovarianceProvider::DEFAULT_WINDOW_SIZE));
node->declare_parameter(
"covariance.sliding_window.min_samples",
static_cast<int64_t>(SlidingWindowCovarianceProvider::DEFAULT_MIN_SAMPLES));
node->declare_parameter(
"covariance.sliding_window.min_variance",
SlidingWindowCovarianceProvider::DEFAULT_MIN_VARIANCE);
// Static covariance parameters (diagonal values)
node->declare_parameter(
"covariance.static.accel_variance_x",
StaticCovarianceProvider::DEFAULT_STATIC_ACCEL_COVARIANCE);
node->declare_parameter(
"covariance.static.accel_variance_y",
StaticCovarianceProvider::DEFAULT_STATIC_ACCEL_COVARIANCE);
node->declare_parameter(
"covariance.static.accel_variance_z",
StaticCovarianceProvider::DEFAULT_STATIC_ACCEL_COVARIANCE);
node->declare_parameter(
"covariance.static.gyro_variance_x", StaticCovarianceProvider::DEFAULT_STATIC_GYRO_COVARIANCE);
node->declare_parameter(
"covariance.static.gyro_variance_y", StaticCovarianceProvider::DEFAULT_STATIC_GYRO_COVARIANCE);
node->declare_parameter(
"covariance.static.gyro_variance_z", StaticCovarianceProvider::DEFAULT_STATIC_GYRO_COVARIANCE);
// Exponentially-Weighted moving average (EWMA) covariance parameters
node->declare_parameter("covariance.ewma.alpha", EwmaCovarianceProvider::DEFAULT_ALPHA);
node->declare_parameter(
"covariance.ewma.warmup_samples",
static_cast<int64_t>(EwmaCovarianceProvider::DEFAULT_WARMUP_SAMPLES));
node->declare_parameter(
"covariance.ewma.min_variance", EwmaCovarianceProvider::DEFAULT_MIN_VARIANCE);
// Kalman filter covariance parameters
node->declare_parameter(
"covariance.kalman.process_noise_q", KalmanCovarianceProvider::DEFAULT_PROCESS_NOISE_Q);
node->declare_parameter(
"covariance.kalman.measurement_noise_r", KalmanCovarianceProvider::DEFAULT_MEASUREMENT_NOISE_R);
node->declare_parameter(
"covariance.kalman.initial_variance", KalmanCovarianceProvider::DEFAULT_INITIAL_VARIANCE);
node->declare_parameter(
"covariance.kalman.warmup_samples",
static_cast<int64_t>(KalmanCovarianceProvider::DEFAULT_WARMUP_SAMPLES));
node->declare_parameter(
"covariance.kalman.min_variance", KalmanCovarianceProvider::DEFAULT_MIN_VARIANCE);
// Motion detection parameters (for adaptive algorithms)
node->declare_parameter("covariance.motion_detection.enable", true);
node->declare_parameter(
"covariance.motion_detection.gyro_threshold", MotionDetector::DEFAULT_GYRO_THRESHOLD);
node->declare_parameter(
"covariance.motion_detection.accel_threshold", MotionDetector::DEFAULT_ACCEL_THRESHOLD);
// Check if covariance is enabled
bool enable = node->get_parameter("covariance.enable").as_bool();
if (!enable) {
RCLCPP_INFO(node->get_logger(), "Covariance computation disabled.");
return nullptr;
}
std::string algorithm_str = node->get_parameter("covariance.algorithm").as_string();
CovarianceAlgorithm algorithm = parseAlgorithm(algorithm_str);
RCLCPP_INFO(node->get_logger(), "Creating covariance provider: %s", algorithm_str.c_str());
return create(algorithm, node);
}
std::unique_ptr<ImuCovarianceInterface> ImuCovarianceFactory::create(
CovarianceAlgorithm algorithm, const std::shared_ptr<rclcpp::Node> & node)
{
// Create motion detector from parameters
bool motion_detection_enable =
node->get_parameter("covariance.motion_detection.enable").as_bool();
double gyro_threshold =
node->get_parameter("covariance.motion_detection.gyro_threshold").as_double();
double accel_threshold =
node->get_parameter("covariance.motion_detection.accel_threshold").as_double();
MotionDetector motion_detector(gyro_threshold, accel_threshold);
motion_detector.setEnabled(motion_detection_enable);
if (motion_detection_enable) {
RCLCPP_INFO(
node->get_logger(),
"Motion detection enabled (gyro_threshold=%.4f rad/s, accel_threshold=%.4f m/s^2)",
gyro_threshold, accel_threshold);
}
switch (algorithm) {
case CovarianceAlgorithm::STATIC: {
Vec3 accel_var;
accel_var.x = node->get_parameter("covariance.static.accel_variance_x").as_double();
accel_var.y = node->get_parameter("covariance.static.accel_variance_y").as_double();
accel_var.z = node->get_parameter("covariance.static.accel_variance_z").as_double();
Vec3 gyro_var;
gyro_var.x = node->get_parameter("covariance.static.gyro_variance_x").as_double();
gyro_var.y = node->get_parameter("covariance.static.gyro_variance_y").as_double();
gyro_var.z = node->get_parameter("covariance.static.gyro_variance_z").as_double();
return std::make_unique<StaticCovarianceProvider>(accel_var, gyro_var);
}
case CovarianceAlgorithm::WELFORD_ONLINE: {
size_t calibration_samples =
static_cast<size_t>(node->get_parameter("covariance.welford.calibration_samples").as_int());
double min_variance = node->get_parameter("covariance.welford.min_variance").as_double();
return std::make_unique<WelfordCovarianceProvider>(calibration_samples, min_variance);
}
case CovarianceAlgorithm::SLIDING_WINDOW: {
size_t window_size =
static_cast<size_t>(node->get_parameter("covariance.sliding_window.window_size").as_int());
size_t min_samples =
static_cast<size_t>(node->get_parameter("covariance.sliding_window.min_samples").as_int());
double min_variance =
node->get_parameter("covariance.sliding_window.min_variance").as_double();
return std::make_unique<SlidingWindowCovarianceProvider>(
window_size, min_samples, min_variance, motion_detector);
}
case CovarianceAlgorithm::EWMA: {
double alpha = node->get_parameter("covariance.ewma.alpha").as_double();
size_t warmup_samples =
static_cast<size_t>(node->get_parameter("covariance.ewma.warmup_samples").as_int());
double min_variance = node->get_parameter("covariance.ewma.min_variance").as_double();
return std::make_unique<EwmaCovarianceProvider>(
alpha, warmup_samples, min_variance, motion_detector);
}
case CovarianceAlgorithm::KALMAN: {
double process_noise_q = node->get_parameter("covariance.kalman.process_noise_q").as_double();
double measurement_noise_r =
node->get_parameter("covariance.kalman.measurement_noise_r").as_double();
double initial_variance =
node->get_parameter("covariance.kalman.initial_variance").as_double();
size_t warmup_samples =
static_cast<size_t>(node->get_parameter("covariance.kalman.warmup_samples").as_int());
double min_variance = node->get_parameter("covariance.kalman.min_variance").as_double();
return std::make_unique<KalmanCovarianceProvider>(
process_noise_q, measurement_noise_r, initial_variance, warmup_samples, min_variance,
motion_detector);
}
}
return nullptr;
}
} // namespace adi_imu