Aprendizaje Automático con Wio Terminal – Reconocimiento de Gestos
Este tutorial demuestra cómo usar el Wio Terminal para configurar una demostración simple de reconocimiento de gestos con ayuda de TensorFlow Lite.

Este ejemplo está modificado a partir de la demostración oficial del equipo de Arduino en conjunto con el equipo de TensorFlow Lite. Para más información y referencias, visita: Get started with machine learning on Arduino. Se realizaron algunas modificaciones para hacerlo compatible con Wio Terminal.
Referencia: How-to Get Started with Machine Learning on Arduino
Lista de Componentes
Características
- Aprendizaje automático en Wio Terminal
- Reconocimiento de gestos
- TensorFlow Lite
Bibliotecas de Arduino necesarias
-
Instalar la biblioteca del acelerómetro integrado
Seeed_Arduino_LIS3DHTR
. Consulta Wio Terminal IMU para más información. -
Instalar la biblioteca Arduino TensorFlow Lite, consulta Wio Terminal TensorFlow Lite para más información.
Entrenamiento de datos IMU desde el Wio Terminal
Como en cualquier proyecto de aprendizaje automático, primero obtendremos datos del sensor para entrenar el modelo. Para ello, ejecutaremos un programa simple en Arduino que transmitirá los datos del sensor desde el Wio Terminal.
Copia y sube el siguiente código al Wio Terminal:
#include "LIS3DHTR.h"
LIS3DHTR<TwoWire> lis;
const float accelerationThreshold = 2; // Umbral significativo en G's
const int numSamples = 119;
int samplesRead = numSamples;
void setup() {
Serial.begin(9600);
lis.begin(Wire1);
if (!lis) {
Serial.println("ERROR");
while(1);
}
lis.setOutputDataRate(LIS3DHTR_DATARATE_25HZ); // Frecuencia de salida de datos
lis.setFullScaleRange(LIS3DHTR_RANGE_2G); // Rango de escala a 2g
Serial.println("Aceleración en G's");
Serial.println("X\tY\tZ");
}
void loop() {
float x, y, z;
while (samplesRead == numSamples) {
x = lis.getAccelerationX();
y = lis.getAccelerationY();
z = lis.getAccelerationZ();
float aSum = fabs(x) + fabs(y) + fabs(z);
// Verificar si supera el umbral
if (aSum >= accelerationThreshold) {
samplesRead = 0;
break;
}
}
while (samplesRead < numSamples) {
x = lis.getAccelerationX();
y = lis.getAccelerationY();
z = lis.getAccelerationZ();
samplesRead++;
Serial.print(x, 3);
Serial.print(',');
Serial.print(y, 3);
Serial.print(',');
Serial.print(z, 3);
Serial.println();
if (samplesRead == numSamples) {
Serial.println();
}
}
}
O descarga el código aquí y súbelo al Wio Terminal. Si abres el Monitor Serial, deberías ver los datos del IMU.
Captura de datos de entrenamiento de gestos
Captura los datos IMU en formato CSV para usar con TensorFlow:
- Abre el Monitor Serial y levanta el Wio Terminal.
- Realiza un gesto de puñetazo (punch) asegurándote de activar la captura.
- Repite el mismo movimiento al menos 10 veces. Cuantos más datos, mejor.
- Copia y pega los datos del Monitor Serial en un archivo de texto llamado
punch.csv
. - Reinicia el Wio Terminal y repite los pasos con un gesto de flexión (flex). Guarda como
flex.csv
.
Nota: Si usas Linux o Mac, puedes redirigir los datos del sensor directamente a un archivo .csv
con:
cat /dev/cu.usbmodem[nnnnn] > punch.csv

Verificación de los archivos .csv
Abre punch.csv
y flex.csv
y asegúrate de que la primera línea del archivo sea:
aX,aY,aZ, como en el ejemplo:

Entrenamiento de datos en TensorFlow
Usaremos el proyecto en Google Colab creado por el equipo de Arduino. Colab ofrece un notebook de Jupyter que permite entrenar el modelo TensorFlow desde el navegador. Este entorno también convierte el modelo a TensorFlow Lite y lo codifica como un archivo de cabecera compatible con Arduino.
Haz clic aquí para acceder al proyecto en Google Colab.
Modificaciones necesarias en el proyecto de Google Colab
Algunas modificaciones son necesarias para adaptar el proyecto al Wio Terminal:
- No es necesario hacer cambios en Setup the Python Environment.
- No se requieren cambios en Upload Data.
- En Graph Data, comenta todas las secciones relacionadas con giroscopio como se muestra:

- En Parse and prepare the data, comenta también las secciones del giroscopio:

-
No se requieren cambios en:
- Randomize and split the input and output pairs for training
- Build & Train the Model
- Graph the loss
- Graph the loss again, skipping a bit of the start
- Graph the mean absolute error
- Run with Test Data
- Convert the Trained Model to Tensor Flow Lite
- Encode the Model in an Arduino Header File
Una vez entrenado, descarga el archivo model.h
desde el panel lateral izquierdo.
Cargar el código en el Wio Terminal
- Una vez descargados los archivos del modelo en formato header (
model.h
), abre IMU_Classifier.ino o copia el siguiente código en el IDE de Arduino:
/*
Clasificador IMU
Este ejemplo utiliza el IMU integrado para comenzar a leer datos de aceleración y giroscopio
del IMU incorporado. Una vez que se han leído suficientes muestras, usa un
modelo de TensorFlow Lite (Micro) para intentar clasificar el movimiento como un gesto conocido.
Nota: El uso directo de punteros C/C++, espacios de nombres y memoria dinámica está generalmente
desaconsejado en ejemplos de Arduino. En el futuro, la librería TensorFlowLite podría cambiar
para simplificar el sketch.
El circuito:
- Arduino Nano 33 BLE o Arduino Nano 33 BLE Sense.
Creado por Don Coleman, Sandeep Mistry
Modificado por Dominic Pajak, Sandeep Mistry
Este código de ejemplo es de dominio público.
Modificado para adaptarse a Wio Terminal - Anson (Seeed Studio)
*/
#undef min
#undef max
#include <TensorFlowLite.h>
#include <tensorflow/lite/experimental/micro/kernels/all_ops_resolver.h>
#include <tensorflow/lite/experimental/micro/micro_error_reporter.h>
#include <tensorflow/lite/experimental/micro/micro_interpreter.h>
#include <tensorflow/lite/schema/schema_generated.h>
#include <tensorflow/lite/version.h>
#include "model.h"
#include "LIS3DHTR.h"
LIS3DHTR<TwoWire> lis;
const float accelerationThreshold = 2; // Umbral de aceleración significativa en G's
const int numSamples = 119;
int samplesRead = numSamples;
// Variables globales usadas por TensorFlow Lite (Micro)
tflite::MicroErrorReporter tflErrorReporter;
// Incluye todas las operaciones de TFLM; puedes remover esta línea e
// incluir solo las necesarias para reducir el tamaño del sketch compilado.
tflite::ops::micro::AllOpsResolver tflOpsResolver;
const tflite::Model* tflModel = nullptr;
tflite::MicroInterpreter* tflInterpreter = nullptr;
TfLiteTensor* tflInputTensor = nullptr;
TfLiteTensor* tflOutputTensor = nullptr;
// Crear buffer de memoria estática para TFLM. El tamaño puede necesitar
// ajustes según el modelo utilizado.
constexpr int tensorArenaSize = 8 * 1024;
byte tensorArena[tensorArenaSize];
// Arreglo para mapear los índices de gestos a sus nombres
const char* GESTURES[] = {
"punch",
"flex"
};
#define NUM_GESTURES (sizeof(GESTURES) / sizeof(GESTURES[0]))
void setup() {
Serial.begin(9600);
// while (!Serial);
lis.begin(Wire1);
// Inicializar IMU
if (!lis) {
Serial.println("¡Fallo al inicializar el IMU!");
while (1);
}
// Obtener la representación TFL del arreglo de bytes del modelo
tflModel = tflite::GetModel(model);
if (tflModel->version() != TFLITE_SCHEMA_VERSION) {
Serial.println("¡Incompatibilidad en el esquema del modelo!");
while (1);
}
// Crear intérprete para ejecutar el modelo
tflInterpreter = new tflite::MicroInterpreter(tflModel, tflOpsResolver, tensorArena, tensorArenaSize, &tflErrorReporter);
// Asignar memoria para los tensores de entrada y salida
tflInterpreter->AllocateTensors();
// Obtener punteros a los tensores
tflInputTensor = tflInterpreter->input(0);
tflOutputTensor = tflInterpreter->output(0);
}
void loop() {
float x, y, z;
// Esperar movimiento significativo
while (samplesRead == numSamples) {
x = lis.getAccelerationX();
y = lis.getAccelerationY();
z = lis.getAccelerationZ();
float aSum = fabs(x) + fabs(y) + fabs(z);
// Verificar si excede el umbral
if (aSum >= accelerationThreshold) {
samplesRead = 0;
break;
}
}
// Leer las muestras una vez detectado el movimiento
while (samplesRead < numSamples) {
x = lis.getAccelerationX();
y = lis.getAccelerationY();
z = lis.getAccelerationZ();
// Normalizar los datos entre 0 y 1 y almacenarlos en el tensor de entrada
tflInputTensor->data.f[samplesRead * 6 + 0] = (x + 4.0) / 8.0;
tflInputTensor->data.f[samplesRead * 6 + 1] = (y + 4.0) / 8.0;
tflInputTensor->data.f[samplesRead * 6 + 2] = (z + 4.0) / 8.0;
samplesRead++;
if (samplesRead == numSamples) {
// Ejecutar inferencia
TfLiteStatus invokeStatus = tflInterpreter->Invoke();
if (invokeStatus != kTfLiteOk) {
Serial.println("¡Error al invocar!");
while (1);
return;
}
// Mostrar los resultados
for (int i = 0; i < NUM_GESTURES; i++) {
Serial.print(GESTURES[i]);
Serial.print(": ");
Serial.println(tflOutputTensor->data.f[i], 6);
}
Serial.println();
}
}
}
-
Coloca el archivo
model.h
entrenado en la misma carpeta que el archivoIMU_Classifier.ino
y sube el código al Wio Terminal. -
Ahora, abre el Monitor Serial y realiza tus gestos. ¡Deberías ver la confianza (score) de cada gesto impresa (0 = baja, 1 = alta)!

Archivos de Modelo de Ejemplo
Como referencia, se adjunta el modelo entrenado model.h para descargar. Puedes usarlo con IMU_Classifier.ino
para realizar pruebas.
Desarrollo Futuro
Para un desarrollo más avanzado, puedes entrenar más gestos en el Wio Terminal usando el IMU, ¡y hacer que disparen diferentes acciones! Explora el aprendizaje automático en microcontroladores con TensorFlow Lite.