Загрузка данных


#include "FastIMU.h"
#include "Madgwick.h"
#include "EEPROM.h"
#include <Wire.h>
#include "HID.h" 

// Конфигурация IMU
#define IMU_ADDRESS 0x68
MPU6050 IMU;

#define IMU_GEOMETRY 0

// Параметры фильтра Madgwick
#define FILTER_MAX_BETA 0.15
#define FILTER_MIN_BETA 0.015
#define FILTER_DROPOFF  0.85

calData calib = { 0 };
AccelData IMUAccel;
GyroData IMUGyro;
MagData IMUMag;
GyroData GyroVel;

Madgwick filter;
bool flag = false;

// HID-дескриптор для SteamVR (Relativty)
static const uint8_t _hidReportDescriptor[] PROGMEM = {
  0x06, 0x03, 0x00, 0x09, 0x00, 0xa1, 0x01, 0x15, 0x00, 0x26, 0xff, 0x00,
  0x85, 0x01, 0x75, 0x08, 0x95, 0x3f, 0x09, 0x00, 0x81, 0x02, 0xc0
};

float quat[4];
uint8_t reportBuffer[63]; 

void setup() {
  // Настройка I2C для STM32 (Blue Pill: PB6 - SCL, PB7 - SDA)
  Wire.setSDA(PB7);
  Wire.setSCL(PB6);
  Wire.begin();
  Wire.setClock(400000);

  Serial.begin(115200);

  // Инициализация USB HID
  static HIDSubDescriptor node(_hidReportDescriptor, sizeof(_hidReportDescriptor));
  HID().AppendDescriptor(&node);
  
  // Чтение калибровки из EEPROM
  int calStatus = 0;
  EEPROM.get(100, calStatus);
  if (calStatus == 99) {
    EEPROM.get(200, calib);
  }
  
  IMU.setIMUGeometry(IMU_GEOMETRY);
  int err = IMU.init(calib, IMU_ADDRESS);
  
  if (err != 0) {
    while(!Serial) { delay(10); }
    Serial.print("Error initializing IMU! e:");
    Serial.println(err);
    while (true) { delay(100); }
  }

  filter.begin(2.0f);
  
  // Разогрев фильтра
  for (int i = 0; i < 2000; i++) {
    IMU.update();
    IMU.getAccel(&IMUAccel);
    IMU.getGyro(&IMUGyro);
    if (IMU.hasMagnetometer()) {
      IMU.getMag(&IMUMag);
      filter.update(IMUGyro.gyroX, IMUGyro.gyroY, IMUGyro.gyroZ, IMUAccel.accelX, IMUAccel.accelY, IMUAccel.accelZ, IMUMag.magX, IMUMag.magY, IMUMag.magZ);
    } else {
      filter.updateIMU(IMUGyro.gyroX, IMUGyro.gyroY, IMUGyro.gyroZ, IMUAccel.accelX, IMUAccel.accelY, IMUAccel.accelZ);
    }
  }
}

void loop() {
  // Вход в режим калибровки через терминал
  if (Serial) {
    if (!flag) {
      Serial.println("Send 'y' to enter calibration mode.");
    }
    flag = true;
    
    if (Serial.available() > 0 && Serial.read() == 'y') {
      calib = { 0 };
      IMU.init(calib, IMU_ADDRESS);
      Serial.println("Calibrating... Keep it still!");
      delay(5000);
      IMU.calibrateAccelGyro(&calib);
      
      if (IMU.hasMagnetometer()) {
        Serial.println("Calibrating Mag... Move in figure 8!");
        delay(2000);
        IMU.calibrateMag(&calib);
      }
      
      EEPROM.put(200, calib);
      EEPROM.put(100, 99);
      Serial.println("Done! Resetting...");
      delay(1000);
      NVIC_SystemReset(); // Перезагрузка STM32
    }
  }
  
  IMU.update();
  IMU.getAccel(&IMUAccel);
  IMU.getGyro(&IMUGyro);

  // Динамическое изменение Beta фильтра
  float Av = GyroVel.gyroX * GyroVel.gyroX + GyroVel.gyroY * GyroVel.gyroY + GyroVel.gyroZ * GyroVel.gyroZ;
  if (Av > 100.f) Av = 100.f;
  filter.changeBeta(Av * (FILTER_MAX_BETA - FILTER_MIN_BETA) / 100 + FILTER_MIN_BETA);

  if (IMU.hasMagnetometer()) {
    IMU.getMag(&IMUMag);
    filter.update(IMUGyro.gyroX, IMUGyro.gyroY, IMUGyro.gyroZ, IMUAccel.accelX, IMUAccel.accelY, IMUAccel.accelZ, IMUMag.magX, IMUMag.magY, IMUMag.magZ);
  } else {
    filter.updateIMU(IMUGyro.gyroX, IMUGyro.gyroY, IMUGyro.gyroZ, IMUAccel.accelX, IMUAccel.accelY, IMUAccel.accelZ);
  }

  // Обновление угловой скорости для фильтра
  GyroVel.gyroX = (GyroVel.gyroX + IMUGyro.gyroX * filter.delta_t) * FILTER_DROPOFF;
  GyroVel.gyroY = (GyroVel.gyroY + IMUGyro.gyroY * filter.delta_t) * FILTER_DROPOFF;
  GyroVel.gyroZ = (GyroVel.gyroZ + IMUGyro.gyroZ * filter.delta_t) * FILTER_DROPOFF;

  // Формирование кватерниона
  quat[0] = filter.getQuatW();
  quat[1] = filter.getQuatX();
  quat[2] = filter.getQuatY();
  quat[3] = filter.getQuatZ();

  // Отправка через HID (63 байта данных)
  memset(reportBuffer, 0, sizeof(reportBuffer));
  memcpy(reportBuffer, quat, sizeof(quat));
  HID().SendReport(1, reportBuffer, 63);
}