From d78696f0e2ecf791be5ae6da37bf4126d379d622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Jel=C3=ADnek?= <jelinva4@fel.cvut.cz> Date: Fri, 7 Mar 2025 11:01:59 +0100 Subject: [PATCH] Add reading IMU data from FIFO to prevent data loss due to i2c bus being used by display --- menu_programs/cube_gyro_acc.py | 5 +- micropython/modules/lib/ICM42688.c | 122 +++++++++++++++++++---------- micropython/modules/lib/ICM42688.h | 13 +-- 3 files changed, 89 insertions(+), 51 deletions(-) diff --git a/menu_programs/cube_gyro_acc.py b/menu_programs/cube_gyro_acc.py index cb98614..6492fab 100644 --- a/menu_programs/cube_gyro_acc.py +++ b/menu_programs/cube_gyro_acc.py @@ -57,10 +57,7 @@ def cube_gyro_acc_run(robot): robot.display.text('< exit mode', 0, 54, 1) robot.display.draw_arrow(74, 56, robot.display.UP, 1) robot.display.draw_arrow(84, 61, robot.display.DOWN, 1) - if counter % 2 == 0: - time = ticks_ms() - robot.display.show() - print("tim:", (ticks_ms() - time)) + robot.display.show() # Exit program if left cube button is pressed_since pressed = robot.buttons.pressed_since() diff --git a/micropython/modules/lib/ICM42688.c b/micropython/modules/lib/ICM42688.c index 1d6ab87..d65d16e 100644 --- a/micropython/modules/lib/ICM42688.c +++ b/micropython/modules/lib/ICM42688.c @@ -18,7 +18,8 @@ static ICM42688_t sensor; static void ICM42688_read_data_irq(void); // Read data from sensor and update AHRS algorithm static void ICM42688_drdy_callback(void); -static void ICM42688_calibrate_cycle(void); +static void ICM42688_calibrate_cycle(int16_t gyro_x_raw, int16_t gyro_y_raw, int16_t gyro_z_raw); +static void ICM42688_read_fifo(void); static void ICM42688_fusion_cycle(void); void ICM42688_init() @@ -41,12 +42,12 @@ void ICM42688_init() ICM42688_write_register(ICM42688_PWR_MGMT0, 0x0F); // Set to 0x0F to activate the sensor sleep_ms(10); // Configure the accelerometer - ICM42688_write_register(ICM42688_ACCEL_CONFIG0, 0x4F); // Set to 0x2F for +/- 4g range, 500 Hz ODR - ICM42688_write_register(ICM42688_ACCEL_CONFIG1, 0x10); // Set UI filter to 3rd order + ICM42688_write_register(ICM42688_ACCEL_CONFIG0, 0x47); // Set to 0x4F for +/- 4g range, 200 Hz ODR + ICM42688_write_register(ICM42688_ACCEL_CONFIG1, 0x08); // Set UI filter to 2nd order // Configure the gyroscope - ICM42688_write_register(ICM42688_GYRO_CONFIG0, 0x2F); // Set to 0x2F for +/- 500 deg/s range, 500 Hz ODR - ICM42688_write_register(ICM42688_GYRO_CONFIG1, 0x08); // Set UI filter to 3rd order + ICM42688_write_register(ICM42688_GYRO_CONFIG0, 0x47); // Set to 0x4F for +/- 500 deg/s range, 200 Hz ODR + ICM42688_write_register(ICM42688_GYRO_CONFIG1, 0x08); // Set UI filter to 2nd order ICM42688_write_register(ICM42688_GYROACCEL_CONFIG0, 0x00); // BW=ODR/2 @@ -55,21 +56,23 @@ void ICM42688_init() ICM42688_write_register(ICM42688_INT_CONFIG0, 0x00); // Clear drdy int on Status Bit Read ICM42688_write_register(ICM42688_INT_CONFIG1, 0x00); // Set int async reset to 0 ICM42688_write_register(ICM42688_INT_SOURCE0, 0x08); // Set to 0x10 to enable drdy interrupt - ICM42688_write_register(ICM42688_INT_SOURCE3, 0x08); // Set to 0x10 to enable drdy interrupt // Configure FIFO ICM42688_write_register(ICM42688_FIFO_CONFIG, 0x40); // Set to 0x40 to stream-to-FIFO - ICM42688_write_register(ICM42688_FIFO_CONFIG1, 0x43); // Enable partial reading and gyro and accel data in FIFO + ICM42688_write_register(ICM42688_FIFO_CONFIG1, 0x03); // Enable partial reading and gyro and accel data in FIFO opencube_unlock_i2c(); for (int i = 0; i < 3; i++) { sensor.accel_offset[i] = 0.0; sensor.gyro_offset[i] = 0.0; + sensor.accel[i] = 0.0; + sensor.gyro[i] = 0.0; + sensor.gyro_offset[i] = 0; } // Set the scale factors for the accelerometer and gyroscope sensor.accel_scale = 4.0 / 32768.0; // +/- 4g range - sensor.gyro_scale = 500.0 / 32768.0; // +/- 1000 deg/s range + sensor.gyro_scale = 500.0 / 32768.0; // +/- 500 deg/s range sensor.calibrated = false; sensor.calibrating = false; @@ -134,6 +137,8 @@ void ICM42688_off() opencube_lock_i2c_or_raise(); ICM42688_disable_interrupt(sensor); ICM42688_bank_select(0); + ICM42688_write_register(ICM42688_DEVICE_CONFIG, 0x01); // Set reset bit + sleep_ms(2); ICM42688_write_register(ICM42688_PWR_MGMT0, 0x00); // Disable gyro and accelerometer opencube_unlock_i2c(); } @@ -216,14 +221,12 @@ void ICM42688_read_data_irq(void) opencube_unlock_i2c(); ICM42688_convert_accel_raw_to_float(accel_x_raw, accel_y_raw, accel_z_raw, &sensor.accel[0], &sensor.accel[1], &sensor.accel[2]); ICM42688_convert_gyro_raw_to_float(gyro_x_raw, gyro_y_raw, gyro_z_raw, &sensor.gyro[0], &sensor.gyro[1], &sensor.gyro[2]); - } else { - } } void ICM42688_start_fusion(void) { sensor.ahrs_enabled = true; - FusionOffsetInitialise(&sensor.offset, 500); + FusionOffsetInitialise(&sensor.offset, ICM42688_ODR); FusionAhrsInitialise(&sensor.ahrs); } @@ -267,28 +270,22 @@ bool ICM42688_calibrate_gyro(void) { } } -void ICM42688_calibrate_cycle(void) { - if (opencube_try_lock_i2c()) { - int16_t gyro_x_raw, gyro_y_raw, gyro_z_raw; - ICM42688_read_data_raw(NULL, NULL, NULL, &gyro_x_raw, &gyro_y_raw, &gyro_z_raw); - opencube_unlock_i2c(); - sensor.gyro_cal_sum[0] += gyro_x_raw; - sensor.gyro_cal_sum[1] += gyro_y_raw; - sensor.gyro_cal_sum[2] += gyro_z_raw; - sensor.calibration_cycles++; - if (sensor.calibration_cycles >= CALIBRATION_CYCLES) { - FusionOffsetInitialise(&sensor.offset, 500); - sensor.gyro_offset[0] = (float)sensor.gyro_cal_sum[0] / CALIBRATION_CYCLES * sensor.gyro_scale; - sensor.gyro_offset[1] = (float)sensor.gyro_cal_sum[1] / CALIBRATION_CYCLES * sensor.gyro_scale; - sensor.gyro_offset[2] = (float)sensor.gyro_cal_sum[2] / CALIBRATION_CYCLES * sensor.gyro_scale; - sensor.calibrating = false; - sensor.calibrated = true; - sensor.gyro_cal_sum[0] = 0; - sensor.gyro_cal_sum[1] = 0; - sensor.gyro_cal_sum[2] = 0; - sensor.calibration_cycles = 0; - } - +void ICM42688_calibrate_cycle(int16_t gyro_x_raw, int16_t gyro_y_raw, int16_t gyro_z_raw) { + sensor.gyro_cal_sum[0] += gyro_x_raw; + sensor.gyro_cal_sum[1] += gyro_y_raw; + sensor.gyro_cal_sum[2] += gyro_z_raw; + sensor.calibration_cycles++; + if (sensor.calibration_cycles >= CALIBRATION_CYCLES) { + FusionOffsetInitialise(&sensor.offset, ICM42688_ODR); + sensor.gyro_offset[0] = (float)sensor.gyro_cal_sum[0] / CALIBRATION_CYCLES * sensor.gyro_scale; + sensor.gyro_offset[1] = (float)sensor.gyro_cal_sum[1] / CALIBRATION_CYCLES * sensor.gyro_scale; + sensor.gyro_offset[2] = (float)sensor.gyro_cal_sum[2] / CALIBRATION_CYCLES * sensor.gyro_scale; + sensor.calibrating = false; + sensor.calibrated = true; + sensor.gyro_cal_sum[0] = 0; + sensor.gyro_cal_sum[1] = 0; + sensor.gyro_cal_sum[2] = 0; + sensor.calibration_cycles = 0; } } @@ -297,7 +294,7 @@ void ICM42688_fusion_cycle(void) { FusionVector gyroscope = { .axis = {.x = sensor.gyro[0], .y = sensor.gyro[1], .z = sensor.gyro[2]} }; gyroscope = FusionOffsetUpdate(&sensor.offset, gyroscope); - FusionAhrsUpdateNoMagnetometer(&sensor.ahrs, gyroscope, accelerometer, 1.0 / 500.0); + FusionAhrsUpdateNoMagnetometer(&sensor.ahrs, gyroscope, accelerometer, 1.0 / ((float)ICM42688_ODR + ICM42688_ODR_DIFF)); FusionQuaternion q = FusionAhrsGetQuaternion(&sensor.ahrs); q = FusionQuaternionMultiply(q, sensor.reset_quat); FusionQuaternionNormalise(q); @@ -306,16 +303,57 @@ void ICM42688_fusion_cycle(void) { sensor.euler = FusionQuaternionToEuler(q); } -void ICM42688_drdy_callback(void) { - uint32_t status = gpio_get_irq_event_mask(ICM42688_DRDY_PIN); +void ICM42688_read_fifo(void) { + uint8_t count_buffer[2] = {0}; + //uint8_t lost_count_buffer[2] = {0}; + if (opencube_try_lock_i2c()) { + ICM42688_read_multiple_registers(ICM42688_FIFO_COUNT_H, count_buffer, 2); + //ICM42688_read_multiple_registers(ICM42688_FIFO_LOST_PKT_CNT, lost_count_buffer, 2); + opencube_unlock_i2c(); + } + uint16_t fifo_count = ((uint16_t)(count_buffer[0] & 0x0F) << 8) | ((uint16_t)count_buffer[1]); // Convert to 16-bit + //uint16_t lost_count = ((uint16_t)(lost_count_buffer[0] & 0x0F) << 8) | ((uint16_t)lost_count_buffer[1]); + if (fifo_count > 16) { + //sensor.accel[1] += (float)fifo_count/ICM42688_PACKET_SIZE; + //sensor.accel[2] += (float)lost_count; + } - ICM42688_read_data_irq(); - if (sensor.calibrating) { - ICM42688_calibrate_cycle(); + if (fifo_count > 0) { + uint8_t fifo_data[fifo_count]; + if (opencube_try_lock_i2c()) { + ICM42688_read_multiple_registers(ICM42688_FIFO_DATA, fifo_data, fifo_count); + opencube_unlock_i2c(); + + + int num_samples = fifo_count / ICM42688_PACKET_SIZE; // Each sample is 16 bytes (1 header + 6 accel + 6 gyro + 1 temp + 2 timestamp) + for (int i = 0; i < num_samples; i++) { + int16_t accel_x = (fifo_data[i * ICM42688_PACKET_SIZE + 1] << 8) | fifo_data[i * ICM42688_PACKET_SIZE + 2]; + int16_t accel_y = (fifo_data[i * ICM42688_PACKET_SIZE + 3] << 8) | fifo_data[i * ICM42688_PACKET_SIZE + 4]; + int16_t accel_z = (fifo_data[i * ICM42688_PACKET_SIZE + 5] << 8) | fifo_data[i * ICM42688_PACKET_SIZE + 6]; + int16_t gyro_x = (fifo_data[i * ICM42688_PACKET_SIZE + 7] << 8) | fifo_data[i * ICM42688_PACKET_SIZE + 8]; + int16_t gyro_y = (fifo_data[i * ICM42688_PACKET_SIZE + 9] << 8) | fifo_data[i * ICM42688_PACKET_SIZE + 10]; + int16_t gyro_z = (fifo_data[i * ICM42688_PACKET_SIZE + 11] << 8) | fifo_data[i * ICM42688_PACKET_SIZE + 12]; + //int16_t timestamp = (fifo_data[i * ICM42688_PACKET_SIZE + 14] << 8) | fifo_data[i * ICM42688_PACKET_SIZE + 15]; // Convert to 16-bit + ICM42688_convert_accel_raw_to_float(accel_x, accel_y, accel_z, &sensor.accel[0], &sensor.accel[1], &sensor.accel[2]); + ICM42688_convert_gyro_raw_to_float(gyro_x, gyro_y, gyro_z,&sensor.gyro[0], &sensor.gyro[1], &sensor.gyro[2]); + + if (sensor.calibrating) { + ICM42688_calibrate_cycle(gyro_x, gyro_y, gyro_z); + } + + if (sensor.ahrs_enabled) { + ICM42688_fusion_cycle(); + //sensor.euler.angle.pitch = (float) fifo_data[13]; + //sensor.euler.angle.roll = (float) timestamp; + } + } + } } +} - if (sensor.ahrs_enabled) { - ICM42688_fusion_cycle(); - } +void ICM42688_drdy_callback(void) { + uint32_t status = gpio_get_irq_event_mask(ICM42688_DRDY_PIN); + + ICM42688_read_fifo(); gpio_acknowledge_irq(ICM42688_DRDY_PIN, status); } \ No newline at end of file diff --git a/micropython/modules/lib/ICM42688.h b/micropython/modules/lib/ICM42688.h index 417da18..f5cbd20 100644 --- a/micropython/modules/lib/ICM42688.h +++ b/micropython/modules/lib/ICM42688.h @@ -71,14 +71,17 @@ Based on the ICM42688 datasheet: https://invensense.tdk.com/wp-content/uploads/2 #define ICM42688_FIFO_CONFIG1 0x5F #define ICM42688_FIFO_CONFIG2 0x60 #define ICM42688_FIFO_CONFIG3 0x61 -#define ICM42688_FIFO_COUNT_H 0x70 -#define ICM42688_FIFO_COUNT_L 0x71 -#define ICM42688_FIFO_DATA 0x72 - +#define ICM42688_FIFO_COUNT_H 0x2E +#define ICM42688_FIFO_COUNT_L 0x2F +#define ICM42688_FIFO_DATA 0x30 +#define ICM42688_FIFO_LOST_PKT_CNT 0x6C +#define ICM42688_PACKET_SIZE 16 // Constants #define ICM42688_WHO_AM_I_VALUE 0x47 -#define CALIBRATION_CYCLES 1000 +#define ICM42688_ODR 200 +#define ICM42688_ODR_DIFF (-2.3) // Observed difference between set and actual ODR, used for more accurate position approximation +#define CALIBRATION_CYCLES (ICM42688_ODR*2) typedef struct { i2c_inst_t *i2c_port; // I2C port of the sensor -- GitLab