Machine Learning na Franzininho WiFi: Classificação de Movimento com Acelerômetro e LEDs (Parte 2)

Este post faz parte da série Machine Learning na Franzininho WiFi

Introdução

Na primeira parte deste projeto, realizamos a coleta dos dados e o treinamento do modelo de machine learning capaz de identificar diferentes tipos de movimento. Agora, na parte 2, vamos realizar a integração na Franzininho WiFi. Utilizando os novos dados lidos pelo acelerômetro LIS3DH, nosso objetivo é classificar movimentos como “caminhando”, “parado” e “pulando” em tempo real. Para tornar o feedback visual, três LEDs serão utilizados para indicar o movimento detectado.

Funcionamento Esperado

  • O acelerômetro LIS3DH será configurado para operar em modo normal com uma taxa de amostragem de 50 Hz.
  • Os dados dos eixos X, Y e Z serão lidos continuamente e armazenados em um buffer.
  • O classificador de machine learning processará esses dados para identificar o tipo de movimento.
  • Dependendo do resultado da inferência:
    • O LED vermelho acenderá para indicar “caminhando”.
    • O LED azul será ativado para “pulando”.
    • O LED verde representará “parado”.
    • Se a confiança da predição for baixa, todos os LEDs permanecerão apagados.

Hardware Necessário

Conexões:

  • LIS3DH:
    • MOSI: Pino 35
    • MISO: Pino 37
    • CLK: Pino 36
    • CS: Pino 34
  • LED RGB:
    • Vermelho (caminhando): Pino 14
    • Azul (pulando): Pino 12
    • Verde (parado): Pino 13

Importando Modelo ML

Na etapa 1, após o treinamento do modelo, realizamos o deploy, que gerou um arquivo ZIP contendo o modelo treinado. Para integrá-lo ao seu projeto na Arduino IDE, importe esse arquivo como uma biblioteca. Para isso, vá em Sketch > Include Library > Add .ZIP Library e selecione o arquivo ZIP correspondente ao modelo.

Código

Carregue o seguinte código em sua placa. Para isso, coloque a Franzininho Wifi em modo bootloader (explicação aqui). Depois escolha para Board Selection Franzininho Wifi, PSRAM como Enabled e Upload Speed 115200.

#include <accel_inferencing.h>


#include <Wire.h>
#include <SPI.h>
#include <Adafruit_LIS3DH.h>
#include <Adafruit_Sensor.h>


static bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal


#define LIS3DH_CLK 36
#define LIS3DH_MISO 37
#define LIS3DH_MOSI 35
#define LIS3DH_CS 34




#define LED_VERMELHO 14  // LED vermelho para "caminhando"
#define LED_AZUL 12      // LED azul para "pulando"
#define LED_VERDE 13     // LED verde para "parado"


// software SPI
Adafruit_LIS3DH lis = Adafruit_LIS3DH(LIS3DH_CS, LIS3DH_MOSI, LIS3DH_MISO, LIS3DH_CLK);


void setup(void) {
  Serial.begin(115200);


  // Inicializa LEDs
  pinMode(LED_VERMELHO, OUTPUT);
  pinMode(LED_AZUL, OUTPUT);
  pinMode(LED_VERDE, OUTPUT);
 
  // Apaga todos os LEDs inicialmente
  digitalWrite(LED_VERMELHO, LOW);
  digitalWrite(LED_AZUL, LOW);
  digitalWrite(LED_VERDE, LOW);


  if (!lis.begin(0x18)) {  
    Serial.println("Couldn't start");
    while (1) yield();
  }
  lis.setRange(LIS3DH_RANGE_2_G);   // 2, 4, 8 or 16 G
  lis.setPerformanceMode(LIS3DH_MODE_NORMAL); //LIS3DH_MODE_LOW_POWER, LIS3DH_MODE_NORMAL, LIS3DH_MODE_HIGH_RESOLUTION
  lis.setDataRate(LIS3DH_DATARATE_50_HZ); //1Hz (1 leitura por segundo), 10Hz, 25Hz, 50Hz, 100Hz, 200Hz, 400Hz, POWERDOWN, LOWPOWER_5KHZ, LOWPOWER_1K6HZ
 
  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;
  }


}


void loop() {


  ei_printf("\nClassificacao inicia em 2 segundos...\n");
  delay(2000);


  ei_printf("Sampling...\n");


  // buffer para leitura acelerometro
  float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = { 0 };
  for (size_t ix = 0; ix < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; ix += 3) {
    // proximo next tick
    uint64_t next_tick = micros() + (EI_CLASSIFIER_INTERVAL_MS * 1000);
    // captura accel X, Y e Z em m/s^2
    sensors_event_t event;
    lis.getEvent(&event);
    Serial.println("----------- Aceleracoes lidas -----------");
    Serial.print(event.acceleration.x);
    Serial.print(",");
    Serial.print(event.acceleration.y);
    Serial.print(",");
    Serial.println(event.acceleration.z);
    // coloca leituras no buffer
    buffer[ix + 0] = event.acceleration.x;
    buffer[ix + 1] = event.acceleration.y;
    buffer[ix + 2] = event.acceleration.z;
    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;
  }


  // roda classificador
  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;
  }


  // predicoes
  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);
  }


  // Controle dos LEDs com base nas predições
  if (result.classification[0].value > 0.8) {  // Label "caminhando"
    digitalWrite(LED_VERDE, LOW);
    digitalWrite(LED_VERMELHO, HIGH);
    digitalWrite(LED_AZUL, LOW);
  } else if (result.classification[1].value > 0.8) {  // Label "parado"
    digitalWrite(LED_VERDE, HIGH);
    digitalWrite(LED_VERMELHO, LOW);
    digitalWrite(LED_AZUL, LOW);
  } else if (result.classification[2].value > 0.8) {  // Label "pulando"
    digitalWrite(LED_VERDE, LOW);
    digitalWrite(LED_VERMELHO, LOW);
    digitalWrite(LED_AZUL, HIGH);
  } else {
    // Se nenhuma predição for suficientemente alta, desliga todos os LEDs
    digitalWrite(LED_VERDE, LOW);
    digitalWrite(LED_VERMELHO, LOW);
    digitalWrite(LED_AZUL, LOW);
  }


}

Lembre-se de substituir o nome da biblioteca pelo nome do arquivo que você importou. Caso ocorra algum erro durante a compilação, será necessário editar o arquivo "ei_classifier_config.h", localizado no diretório \Arduino\libraries\nome-da-sua-biblioteca\src\edge-impulse-sdk\classifier. Dentro desse arquivo, altere a linha #define EI_CLASSIFIER_TFLITE_ENABLE_ESP_NN 1 para #define EI_CLASSIFIER_TFLITE_ENABLE_ESP_NN 0, a fim de corrigir o problema de compatibilidade.

Compreendendo o código

  1. Antes do setup()
  • Inclusão de bibliotecas: O código importa bibliotecas essenciais, como Wire.h, SPI.h, Adafruit_LIS3DH.h e Adafruit_Sensor.h ei accel_inferencing.h.
  • Definição de pinos e constantes: Define pinos específicos para controlar o acelerômetro (SPI) e LEDs para indicar os resultados da classificação.
  • Inicialização do acelerômetro: Configura o acelerômetro LIS3DH usando SPI e especifica os pinos de comunicação.
  1. Dentro do setup()
  • Inicialização da comunicação serial: Inicia a comunicação serial com Serial.begin(115200) para enviar informações ao monitor serial.
  • Configuração dos LEDs: Define os pinos dos LEDs como saídas (pinMode), garantindo que o código possa controlá-los.
  • Apagamento inicial dos LEDs: Todos os LEDs são desligados inicialmente para garantir que o sistema comece em um estado neutro.
  • Inicialização do acelerômetro: Tenta inicializar o sensor LIS3DH e, caso falhe, imprime um erro e para a execução. O sensor é configurado para um alcance de 2G e taxa de amostragem de 50 Hz, com desempenho normal.
  • Verificação quadro de dados: Verifica se a quantidade de amostras por quadro do classificador de machine learning está configurada corretamente para o número de eixos do acelerômetro. 
  1. Dentro do loop()
  • Mensagem de início: Exibe uma mensagem informando que a classificação começará após 2 segundos.
  • Leitura do acelerômetro: Um buffer é preparado para armazenar os dados dos eixos X, Y e Z.
  • Os dados de aceleração são lidos continuamente do sensor e armazenados no buffer, com um atraso para sincronizar a coleta de dados.
  • As leituras de aceleração (X, Y, Z) são exibidas no monitor serial para depuração.
  • Classificação dos dados: Os dados brutos lidos do acelerômetro são convertidos em um sinal para o classificador de machine learning. O classificador de machine learning é executado nos dados, e as predições são geradas para os possíveis movimentos (caminhando, parado, pulando). As predições, tempos de processamento e valores de anomalia são exibidos no monitor serial.
  • Controle dos LEDs: Dependendo da predição com maior confiança, um dos três LEDs será aceso. Se nenhuma predição atingir o limite de confiança de 0,8, todos os LEDs permanecerão apagados.

Funcionamento

  1. Parado
  1. Caminhando
  1. Pulando

Conclusão

Neste segundo parte do projeto “Classificação de Movimento com Acelerômetro e LEDs”, conseguimos integrar o modelo de machine learning à Franzininho WiFi para realizar a classificação de movimentos em tempo real com base nos dados do acelerômetro LIS3DH. Os LEDs fornecem um retorno visual, tornando a identificação de ações como “caminhando”, “parado” e “pulando” acessível e interativa. Essa aplicação demonstra o potencial do machine learning embarcado, podendo ser base para diversas implementações. 

Machine Learning na Franzininho WiFi

Machine Learning na Franzininho WiFi: Classificação de Movimento com Acelerômetro e LEDs (Parte 1) Machine Learning na Franzininho WiFi:  Pulseira para crises de epilepsia – Parte 1
Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.
Comentários:
Notificações
Notificar
0 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
Home » Hardware » Microcontroladores » Machine Learning na Franzininho WiFi: Classificação de Movimento com Acelerômetro e LEDs (Parte 2)

EM DESTAQUE

WEBINARS

VEJA TAMBÉM

JUNTE-SE HOJE À COMUNIDADE EMBARCADOS

Talvez você goste: