Integrate asynchronous GPS IMU fusion

This commit is contained in:
2026-07-16 23:49:43 +03:00
parent 38a96dd88f
commit 7cc3eb2a54
80 changed files with 3901 additions and 553 deletions
@@ -0,0 +1,33 @@
#ifndef IMU_CALIBRATION_H
#define IMU_CALIBRATION_H
#include <stdbool.h>
#include "imu/imu_sample.h"
/*
* Sensor-independent calibration in the IMU body frame.
*
* corrected = transform * (measured - bias - temperature_coefficient * dT)
*
* The transform can contain scale, cross-axis and mounting-axis corrections.
* Temperature correction is deliberately opt-in; collecting temperature does
* not change measurements unless temperature_compensation_enabled is true.
*/
typedef struct {
double accel_bias_mps2[3];
double gyro_bias_rps[3];
double accel_transform[3][3];
double gyro_transform[3][3];
double reference_temperature_c;
double accel_temperature_coefficient_mps2_per_c[3];
double gyro_temperature_coefficient_rps_per_c[3];
bool temperature_compensation_enabled;
} imu_calibration_t;
void imu_calibration_default(imu_calibration_t* calibration);
bool imu_calibration_is_valid(const imu_calibration_t* calibration);
bool imu_calibration_apply(const imu_calibration_t* calibration,
imu_sample_t* measurement);
#endif
@@ -0,0 +1,18 @@
#ifndef IMU_SAMPLE_H
#define IMU_SAMPLE_H
#include <stdint.h>
/*
* Sensor-independent, calibrated inertial sample in SI units. Drivers and
* IMU management publish this type without depending on GPS or ESKF headers.
*/
typedef struct {
uint64_t timestamp_ticks;
double accel_mps2[3];
double gyro_rps[3];
double temperature_c;
uint32_t sequence;
} imu_sample_t;
#endif
@@ -0,0 +1,68 @@
#ifndef IMU_SENSOR_H
#define IMU_SENSOR_H
#include <stdbool.h>
#include <stdint.h>
#include "imu/imu_calibration.h"
#include "imu/imu_sample.h"
typedef enum {
IMU_SENSOR_NONE = 0,
IMU_SENSOR_TDK_ICM42688,
IMU_SENSOR_ST_LSM6DSOX,
IMU_SENSOR_BACKEND_COUNT
} imu_sensor_backend_t;
typedef struct {
/* Zero selects the active backend's safe default. A non-zero target may
* be quantized to a nearby hardware ODR; diagnostics reports both values. */
uint32_t odr_hz;
unsigned int accel_full_scale_g;
unsigned int gyro_full_scale_dps;
/* Auto-detected devices must never share board-specific calibration. */
imu_calibration_t calibration_by_backend[IMU_SENSOR_BACKEND_COUNT];
} imu_sensor_config_t;
typedef struct {
uint64_t irq_count;
uint64_t sample_count;
uint64_t invalid_sample_count;
uint64_t spurious_irq_count;
uint64_t queue_overflow_count;
uint64_t estimated_missed_sample_count;
uint64_t last_timestamp_ticks;
uint32_t requested_odr_hz;
uint32_t configured_odr_hz;
uint8_t who_am_i;
imu_sensor_backend_t backend;
bool initialized;
bool running;
bool foreground_polling;
} imu_sensor_diagnostics_t;
void imu_sensor_default_config(imu_sensor_config_t* config);
/* Probe the compiled backend(s), select one, validate the requested ODR/range
* and prepare calibration. This does not enable data-ready interrupts. */
bool imu_sensor_init(const imu_sensor_config_t* config);
/* Configure streaming and enable BSP_PMOD_IRQ. The application must attach
* imu_sensor_irq_handler to the active machine-interrupt router first. */
bool imu_sensor_start(void);
void imu_sensor_stop(void);
/* PLIC/ISR half: read and timestamp one raw sample, then enqueue it. */
void imu_sensor_irq_handler(void);
/* Foreground half. Safe no-op for the current interrupt-driven backends. */
void imu_sensor_service(void);
bool imu_sensor_requires_foreground_service(void);
/* Pop the oldest sample, convert to SI/common axes and apply the selected
* backend's calibration. No averaging or motion decision occurs here. */
bool imu_sensor_take_measurement(imu_sample_t* measurement_out);
void imu_sensor_get_diagnostics(imu_sensor_diagnostics_t* diagnostics_out);
imu_sensor_backend_t imu_sensor_active_backend(void);
const char* imu_sensor_backend_name(imu_sensor_backend_t backend);
#endif