EDGE IMPULSでモーション特徴量をArduino向けにビルド
初めに
Gesture Controlled Drone with M5Stack and Edge Impulse - Hackster.io を参考に、 M5StickCで取得したモーションデータ(加速度/ジャイロ/姿勢)を学習し、判定できるようにする
チュートリアルを試す
上記URLに従いスマホでforward / right / leftにスマホを動かしデータ収集、分類、テストしてみた。 結果、認識率は100%と高精度。
int8でも精度は落ちないが、floatの方がspeed(認識速度?)が早いようだ。 どちらの型を使うかは、Flash容量、計算リソースに応じて決定したい。
Arduino Nano 33 BLE ソースコード
buildされたコードを参考までに載せる。
/* Includes ---------------------------------------------------------------- */ #include <uecken-project-1_inferencing.h> #include <Arduino_LSM9DS1.h> /* Constant defines -------------------------------------------------------- */ #define CONVERT_G_TO_MS2 9.80665f #define MAX_ACCEPTED_RANGE 2.0f // starting 03/2022, models are generated setting range to +-2, but this example use Arudino library which set range to +-4g. If you are using an older model, ignore this value and use 4.0f instead /* ** NOTE: If you run into TFLite arena allocation issue. ** ** This may be due to may dynamic memory fragmentation. ** Try defining "-DEI_CLASSIFIER_ALLOCATION_STATIC" in boards.local.txt (create ** if it doesn't exist) and copy this file to ** `<ARDUINO_CORE_INSTALL_PATH>/arduino/hardware/<mbed_core>/<core_version>/`. ** ** See ** (https://support.arduino.cc/hc/en-us/articles/360012076960-Where-are-the-installed-cores-located-) ** to find where Arduino installs cores on your machine. ** ** If the problem persists then there's not enough memory for this model and application. */ /* Private variables ------------------------------------------------------- */ static bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal /** * @brief Arduino setup function */ void setup() { // put your setup code here, to run once: Serial.begin(115200); Serial.println("Edge Impulse Inferencing Demo"); if (!IMU.begin()) { ei_printf("Failed to initialize IMU!\r\n"); } else { ei_printf("IMU initialized\r\n"); } if (EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME != 3) { ei_printf("ERR: EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME should be equal to 3 (the 3 sensor axes)\n"); return; } } /** * @brief Return the sign of the number * * @param number * @return int 1 if positive (or 0) -1 if negative */ float ei_get_sign(float number) { return (number >= 0.0) ? 1.0 : -1.0; } /** * @brief Get data and run inferencing * * @param[in] debug Get debug info if true */ void loop() { ei_printf("\nStarting inferencing in 2 seconds...\n"); delay(2000); ei_printf("Sampling...\n"); // Allocate a buffer here for the values we'll read from the IMU float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = { 0 }; for (size_t ix = 0; ix < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; ix += 3) { // Determine the next tick (and then sleep later) uint64_t next_tick = micros() + (EI_CLASSIFIER_INTERVAL_MS * 1000); IMU.readAcceleration(buffer[ix], buffer[ix + 1], buffer[ix + 2]); for (int i = 0; i < 3; i++) { if (fabs(buffer[ix + i]) > MAX_ACCEPTED_RANGE) { buffer[ix + i] = ei_get_sign(buffer[ix + i]) * MAX_ACCEPTED_RANGE; } } buffer[ix + 0] *= CONVERT_G_TO_MS2; buffer[ix + 1] *= CONVERT_G_TO_MS2; buffer[ix + 2] *= CONVERT_G_TO_MS2; delayMicroseconds(next_tick - micros()); } // Turn the raw buffer in a signal which we can the classify signal_t signal; int err = numpy::signal_from_buffer(buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal); if (err != 0) { ei_printf("Failed to create signal from buffer (%d)\n", err); return; } // Run the classifier ei_impulse_result_t result = { 0 }; err = run_classifier(&signal, &result, debug_nn); if (err != EI_IMPULSE_OK) { ei_printf("ERR: Failed to run classifier (%d)\n", err); return; } // print the predictions ei_printf("Predictions "); ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)", result.timing.dsp, result.timing.classification, result.timing.anomaly); ei_printf(": \n"); for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) { ei_printf(" %s: %.5f\n", result.classification[ix].label, result.classification[ix].value); } #if EI_CLASSIFIER_HAS_ANOMALY == 1 ei_printf(" anomaly score: %.3f\n", result.anomaly); #endif } #if !defined(EI_CLASSIFIER_SENSOR) || EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_ACCELEROMETER #error "Invalid model for current sensor" #endif
Data Forwarder
M5Cからcsvデータをweb Serialにより収集できるようだが、Installation - Edge Impulse Documentation してedge-impulse-data-forwarderを実行すると、nodejsのbinding絡みのエラーで上手く出来ない。 Referenceボードが来てから再度試す。