1#include "../include/calibration/IMUCalibration.hpp"
13 params_.scale_matrix = Eigen::Matrix3d::Identity();
14 params_.misalignment = Eigen::Matrix3d::Identity();
43 std::vector<RawReading> readings;
45 readings.push_back(point.raw);
77 if (readings.size() < 6) {
78 std::cerr <<
"[IMUCalibration] Need at least 6 positions for accelerometer calibration"
91 const std::vector<double>& reference_rates) {
92 if (readings.empty()) {
97 if (reference_rates.empty()) {
107 const Eigen::Vector3d& reference_field) {
108 if (readings.size() < 6) {
109 std::cerr <<
"[IMUCalibration] Need at least 6 orientations for magnetometer calibration"
129 double temp_scale = 1.0;
130 if (std::abs(
params_.temperature_coeff) > 1e-6) {
132 temp_scale = 1.0 +
params_.temperature_coeff * temp_diff;
137 corrected *= temp_scale;
142 Eigen::Matrix3d::Identity() * (
params_.bias_uncertainty *
params_.bias_uncertainty +
169 params_.scale_matrix = Eigen::Matrix3d::Identity();
170 params_.misalignment = Eigen::Matrix3d::Identity();
174 if (readings.empty()) {
178 Eigen::Vector3d bias_sum = Eigen::Vector3d::Zero();
179 for (
const auto& reading : readings) {
180 bias_sum += reading.value;
182 params_.bias = bias_sum /
static_cast<double>(readings.size());
190 const double g = 9.81;
191 std::vector<CalibrationPoint> points;
193 for (
const auto& reading : readings) {
198 double magnitude = reading.
value.norm();
199 if (magnitude > 0.1) {
200 point.
reference = reading.value.normalized() *
g;
202 points.push_back(point);
206 if (points.size() < 6) {
219 Eigen::Vector3d variance = Eigen::Vector3d::Zero();
220 for (
const auto& reading : readings) {
221 Eigen::Vector3d
diff = reading.value -
params_.bias;
222 variance +=
diff.cwiseProduct(
diff);
224 variance /=
static_cast<double>(readings.size());
227 params_.scale_matrix = Eigen::Matrix3d::Identity();
234 const std::vector<double>& reference_rates) {
235 if (readings.size() != reference_rates.size()) {
243 Eigen::Vector3d scale = Eigen::Vector3d::Ones();
244 for (
size_t i = 0; i < readings.size(); ++i) {
245 Eigen::Vector3d corrected = readings[i].value -
params_.bias;
246 double magnitude = corrected.norm();
247 if (magnitude > 0.01 && std::abs(reference_rates[i]) > 0.01) {
248 scale = scale.cwiseProduct(Eigen::Vector3d::Constant(reference_rates[i] / magnitude));
252 params_.scale_matrix = scale.asDiagonal();
260 if (readings.size() < 6) {
272 params_.scale_matrix = Eigen::Matrix3d::Identity();
277 if (points.size() < 6) {
285 Eigen::MatrixXd A(points.size() * 3, 9);
286 Eigen::VectorXd
b(points.size() * 3);
288 for (
size_t i = 0; i < points.size(); ++i) {
289 const auto& point = points[i];
290 Eigen::Vector3d corrected = point.raw.value -
params_.bias;
294 for (
int row = 0; row < 3; ++row) {
295 int idx = i * 3 + row;
296 b(idx) = point.reference(row);
298 for (
int col = 0; col < 3; ++col) {
299 A(idx, row * 3 + col) = corrected(col);
305 Eigen::VectorXd scale_vec = A.colPivHouseholderQr().solve(
b);
308 for (
int i = 0; i < 3; ++i) {
309 for (
int j = 0; j < 3; ++j) {
310 params_.scale_matrix(i, j) = scale_vec(i * 3 + j);
321 double total_error = 0.0;
327 Eigen::Vector3d error =
calibrated.value - point.reference;
328 total_error += error.norm();
337 double avg_error = total_error /
count;
339 double quality = 1.0 / (1.0 + avg_error);
340 return std::clamp(quality, 0.0, 1.0);
352 Eigen::Vector3d mean = Eigen::Vector3d::Zero();
358 Eigen::Vector3d
diff = reading.
value - mean;
359 double distance =
diff.norm();
364 return distance > threshold;
379 case SensorType::ACCELEROMETER:
381 case SensorType::GYROSCOPE:
383 case SensorType::MAGNETOMETER:
390 const std::vector<IMUCalibration::RawReading>& accel_readings,
391 const std::vector<IMUCalibration::RawReading>& gyro_readings,
392 const std::vector<IMUCalibration::RawReading>& mag_readings,
393 const Eigen::Vector3d& reference_magnetic_field) {
397 if (!accel_readings.empty()) {
398 for (
const auto& reading : accel_readings) {
408 if (!gyro_readings.empty()) {
409 for (
const auto& reading : gyro_readings) {
418 if (!mag_readings.empty()) {
419 for (
const auto& reading : mag_readings) {
422 point.
reference = reference_magnetic_field;
std::shared_ptr< IMUCalibration > gyro_calibrator_
std::shared_ptr< IMUCalibration > mag_calibrator_
std::shared_ptr< IMUCalibration > getCalibrator(SensorType type)
Get calibrator for specific sensor.
CalibrationStatus getStatus() const
std::shared_ptr< IMUCalibration > accel_calibrator_
bool calibrateAll(const std::vector< IMUCalibration::RawReading > &accel_readings, const std::vector< IMUCalibration::RawReading > &gyro_readings, const std::vector< IMUCalibration::RawReading > &mag_readings, const Eigen::Vector3d &reference_magnetic_field)
Calibrate all sensors.
CalibratedIMU calibrateIMU(const IMUCalibration::RawReading &accel, const IMUCalibration::RawReading &gyro, const IMUCalibration::RawReading &mag) const
bool calibrate()
Perform calibration.
void reset()
Reset calibration.
CalibrationParams params_
bool calibrateMagEllipsoidFit(const std::vector< RawReading > &readings)
void estimateBias(const std::vector< RawReading > &readings)
void estimateScaleAndMisalignment(const std::vector< CalibrationPoint > &points)
double computeCalibrationQuality() const
std::vector< CalibrationPoint > calibration_data_
CalibrationStatus
Calibration status.
IMUCalibration(SensorType type)
bool calibrateGyroZeroVelocity(const std::vector< RawReading > &readings)
bool calibrateMagnetometer(const std::vector< RawReading > &readings, const Eigen::Vector3d &reference_field)
Calibrate magnetometer using known field.
std::vector< RawReading > recent_readings_
bool calibrateGyroscope(const std::vector< RawReading > &readings, const std::vector< double > &reference_rates={})
Calibrate gyroscope using rotation rates.
CalibratedReading calibrateReading(const RawReading &raw) const
Apply calibration to raw reading.
bool detectDrift(const RawReading &reading) const
CalibrationParams getCalibrationParams() const
Get calibration parameters.
CalibrationStatus status_
CalibrationStatus getStatus() const
Get calibration status.
bool calibrateAccelStatic(const std::vector< RawReading > &readings)
void initialize(const CalibrationParams &initial_params=CalibrationParams{})
Initialize calibration.
bool calibrateGyroRotation(const std::vector< RawReading > &readings, const std::vector< double > &reference_rates)
bool calibrateAccelerometer(const std::vector< RawReading > &readings)
Calibrate accelerometer using static positions.
void addCalibrationPoint(const CalibrationPoint &point)
Add calibration data point.
bool isValid() const
Check if calibration is valid.
*brief create JSON pointer *sa reference_tokens const string_t const string_t & b
size_type count(const key_type &key) const
Output smoothing for calibrated PT pressure, per sensor uid (ESP32 and LabJack T7 alike).
Motorized ball valve position: raw ADC counts -> % open.
Apply calibration to IMU reading.
Get calibration status for all sensors.
double reference_uncertainty
Eigen::Vector3d reference
static int32_t diff(uint32_t a, uint32_t b)