Машинное обучение на Arduino Nano RP2040

imu arduino-nano-rp2040

Я пытаюсь использовать Arduino Nano RP2040 для распознавания жестов с помощью IMU. Эта плата поддерживает основные функции машинного обучения, предоставляемые LSM6DSOX.

Я протестировал пример, предоставленный производителем, и все работает нормально . Теперь я хочу создать новую модель машинного обучения для распознавания пользовательских жестов.

Я нашел это руководство по STM, которое очень полезно, но я не могу найти код представлено в 5:48, чтобы записывать движения.

Кто-нибудь знает, где я могу найти весь код или как мне это сделать?

, 👍0


1 ответ


Лучший ответ:

0

Отвечаю на вопрос сам, для тех, у кого такая же проблема, как и у меня.

Исходный код

#include "PluggableUSBMSD.h"
#include "FlashIAPBlockDevice.h"
#include "WiFiNINA.h"
#include "LSM6DSOXSensor.h"

#define INT_1 INT_IMU
#define SENSOR_ODR 104.0f // В герцах
#define ACC_FS 2 // В g
#define GYR_FS 2000 // В дпс
#define MEASUREMENT_TIME_INTERVAL (1000.0f/SENSOR_ODR) // В мс
#define FIFO_SAMPLE_THRESHOLD 199
#define FLASH_BUFF_LEN 8192

typedef enum {
  DATA_STORAGE_STATE,
  DATA_LOGGER_IDLE_STATE,
  DATA_LOGGER_RUNNING_STATE
} demo_state_e;

volatile demo_state_e demo_state = DATA_STORAGE_STATE;
volatile int mems_event = 0;
uint32_t file_count = 0;
unsigned long timestamp_count = 0;
bool acc_available = false;
bool gyr_available = false;
int32_t acc_value[3];
int32_t gyr_value[3];
char buff[FLASH_BUFF_LEN];
uint32_t pos = 0;

static FlashIAPBlockDevice bd(XIP_BASE + 0x100000, 0x100000);

LSM6DSOXSensor AccGyr(&Wire, LSM6DSOX_I2C_ADD_L);

USBMSD MassStorage(&bd);

rtos::Thread acquisition_th;

FILE *f = nullptr;

void INT1Event_cb()
{
  mems_event = 1;
}

void USBMSD::begin()
{
  int err = getFileSystem().mount(&bd);
  if (err) {
    err = getFileSystem().reformat(&bd);
  }
}

mbed::FATFileSystem &USBMSD::getFileSystem()
{
  static mbed::FATFileSystem fs("fs");
  return fs;
}

void led_green_thd()
{
  while (1) {
    if (demo_state == DATA_LOGGER_RUNNING_STATE) {
      digitalWrite(LEDG, HIGH);
      delay(100);
      digitalWrite(LEDG, LOW);
      delay(100);
    }
  }
}

void Read_FIFO_Data(uint16_t samples_to_read)
{
  uint16_t i;

  for (i = 0; i < samples_to_read; i++) {
    uint8_t tag;
    // Проверяем тег FIFO
    AccGyr.Get_FIFO_Tag(&tag);
    switch (tag) {
      // Если у нас есть тег гироскопа, читаем данные гироскопа
      case LSM6DSOX_GYRO_NC_TAG: {
          AccGyr.Get_FIFO_G_Axes(gyr_value);
          gyr_available = true;
          break;
        }
      // Если у нас есть тег аккаунта, читаем данные аккаунта
      case LSM6DSOX_XL_NC_TAG: {
          AccGyr.Get_FIFO_X_Axes(acc_value);
          acc_available = true;
          break;
        }
      // Мы можем отбросить другие теги
      default: {
          break;
        }
    }
    // Если у нас есть измерения акселератора и гироскопа, мы можем сохранить их с меткой времени
    if (acc_available && gyr_available) {
      int num_bytes;
      num_bytes = snprintf(&buff[pos], (FLASH_BUFF_LEN - pos), "%lu %d %d %d %d %d %d\n", (unsigned long)((float)timestamp_count * MEASUREMENT_TIME_INTERVAL), (int)acc_value[0], (int)acc_value[1], (int)acc_value[2], (int)gyr_value[0], (int)gyr_value[1], (int)gyr_value[2]);
      pos += num_bytes;
      timestamp_count++;
      acc_available = false;
      gyr_available = false;
    }
  }
  // Мы можем добавить в строку символ завершения, чтобы мы могли сохранить ее во флэш-памяти
  buff[pos] = '\0';
  pos = 0;
}

void setup()
{
  Serial.begin(115200);
  MassStorage.begin();
  pinMode(LEDB, OUTPUT);
  pinMode(LEDG, OUTPUT);
  digitalWrite(LEDB, LOW);
  digitalWrite(LEDG, LOW);

  // Инициализируем шину I2C.
  Wire.begin();
  Wire.setClock(400000);

  //Прерывания.
  attachInterrupt(INT_1, INT1Event_cb, RISING);

  // Инициализируем IMU.
  AccGyr.begin();
  AccGyr.Enable_X();
  AccGyr.Enable_G();
  // Настраиваем ODR и FS акселератора и гироскопа
  AccGyr.Set_X_ODR(SENSOR_ODR);
  AccGyr.Set_X_FS(ACC_FS);
  AccGyr.Set_G_ODR(SENSOR_ODR);
  AccGyr.Set_G_FS(GYR_FS);
  // Включаем событие двойного касания
  AccGyr.Enable_Double_Tap_Detection(LSM6DSOX_INT1_PIN);
  // Настраиваем FIFO BDR для акк и гироскопа
  AccGyr.Set_FIFO_X_BDR(SENSOR_ODR);
  AccGyr.Set_FIFO_G_BDR(SENSOR_ODR);
  // Запускаем поток мигания светодиодом
  acquisition_th.start(led_green_thd);
}

void loop()
{
  if (mems_event) {
    mems_event = 0;
    LSM6DSOX_Event_Status_t status;
    AccGyr.Get_X_Event_Status(&status);
    if (status.DoubleTapStatus) {
      switch (demo_state) {
        case DATA_STORAGE_STATE: {
            // Переходим в состояние DATA_LOGGER_IDLE_STATE
            demo_state = DATA_LOGGER_IDLE_STATE;
            digitalWrite(LEDG, HIGH);
            Serial.println("From DATA_STORAGE_STATE To DATA_LOGGER_IDLE_STATE");
            break;
          }
        case DATA_LOGGER_IDLE_STATE: {
            char filename[32];
            // Переход в состояние DATA_LOGGER_RUNNING_STATE
            snprintf(filename, 32, "/fs/data_%lu.txt", file_count);
            Serial.print("Start writing file ");
            Serial.println(filename);
            // открываем файл для записи данных
            // w+ означает перезапись, поэтому при каждой перезагрузке платы файл будет перезаписываться
            f = fopen(filename, "w+");
            if (f != nullptr) {
              // пишем заголовок
              fprintf(f, "Timestamp[ms] A_X [mg] A_Y [mg] A_Z [mg] G_X [mdps] G_Y [mdps] G_Z [mdps]\n");
              fflush(f);
              Serial.println("From DATA_LOGGER_IDLE_STATE To DATA_LOGGER_RUNNING_STATE");
              demo_state = DATA_LOGGER_RUNNING_STATE;
              digitalWrite(LEDG, LOW);
              timestamp_count = 0;
              pos = 0;
              acc_available = false;
              gyr_available = false;
              // Устанавливаем FIFO в непрерывный режим
              AccGyr.Set_FIFO_Mode(LSM6DSOX_STREAM_MODE);
            }
            break;
          }
        case DATA_LOGGER_RUNNING_STATE: {
            // Очищаем FIFO
            uint16_t fifo_samples;
            AccGyr.Get_FIFO_Num_Samples(&fifo_samples);
            Read_FIFO_Data(fifo_samples);
            // Сохраняем строку во флэш-памяти
            fprintf(f, "%s", buff);
            fflush(f);

            // Закрываем файл журнала и увеличиваем счетчик
            fclose(f);
            file_count++;
            // Устанавливаем FIFO в режим обхода
            AccGyr.Set_FIFO_Mode(LSM6DSOX_BYPASS_MODE);
            // Переходим в состояние DATA_LOGGER_IDLE_STATE
            demo_state = DATA_LOGGER_IDLE_STATE;
            // Подождем, пока светодиодный поток прекратит мигать
            delay(250);
            digitalWrite(LEDG, HIGH);
            Serial.println("From DATA_LOGGER_RUNNING_STATE To DATA_LOGGER_IDLE_STATE");
            break;
          }
        default:
          Serial.println("Error! Invalid state");
      }
    }
  }

  if (demo_state == DATA_LOGGER_RUNNING_STATE) {
    uint16_t fifo_samples;

    // Проверяем количество выборок внутри FIFO
    AccGyr.Get_FIFO_Num_Samples(&fifo_samples);

    // Если мы достигнем порога, мы сможем очистить FIFO
    if (fifo_samples > FIFO_SAMPLE_THRESHOLD) {
      // Очищаем FIFO
      Read_FIFO_Data(fifo_samples);
      // Сохраняем строку во флэш-памяти
      fprintf(f, "%s", buff);
      fflush(f);
    }
  }

  if (demo_state == DATA_STORAGE_STATE && millis() > 10000) {
    // Отключаем датчик и переходим в режим Mass Storage
    AccGyr.Disable_Double_Tap_Detection();
    AccGyr.Disable_X();
    AccGyr.Disable_G();
    while (1) {
      digitalWrite(LEDB, HIGH);
      delay(100);
      digitalWrite(LEDB, LOW);
      delay(100);
    }
  }
}
,