Detector de Gestos y Movimiento con Sensor PIR y Arduino Nano
Componentes y materiales
| Componente | Cantidad | Notas |
|---|---|---|
| Arduino Nano R3 | 1 | |
| TPA81 Devantech Sensor Array Térmico 8 Pixeles | 1 | I2C, detecta IR 2-22µm |
| HC-SR505 Sensor PIR Infrarrojo Pasivo | 8 | Alternativa económica al TPA81 |
| Display OLED 0.96" SPI 128x64 | 1 | |
| Protoboard | 1 | |
| Cables Jumpers Macho/Hembra | 1 |
Aplicaciones y servicios
- Arduino IDE
Sobre este proyecto
En este artículo te mostraremos cómo hacer un detector de gestos con componentes simples como sensor PIR y Arduino Nano. Al final podrás:
- Explicar aplicaciones del sensor PIR y su funcionamiento
- Ejecutar un sensor PIR de 8 píxeles (TPA81)
- Usar sensor PIR para detectar movimiento y gestos con Arduino
- Crear un detector genial para subir/bajar volumen de altavoz
Sensor Infrarrojo Pasivo (PIR): ¿Cómo funciona?
Un sensor PIR (Passive Infrared Sensor) es un sensor electrónico que mide la luz infrarroja (IR) radiada por objetos en su campo de visión. Se usan comúnmente en detectores de movimiento basados en PIR.
Todos los objetos con temperatura superior al cero absoluto emiten energía térmica en forma de radiación. Normalmente esta radiación no es visible al ojo humano porque irradia en longitudes de onda infrarrojas, pero puede ser detectada por dispositivos electrónicos diseñados para tal propósito.
El término "pasivo" se refiere a que los dispositivos PIR no generan ni irradian energía para propósitos de detección. Funcionan enteramente detectando radiación infrarroja emitida o reflejada por objetos. No detectan ni miden calor directamente. (Fuente: Wikipedia)
El TPA81 es un array de termopilas que detecta infrarrojo en el rango 2µm-22µm (longitud de onda del calor radiante). Los sensores piroeléctricos usados en alarmas y luces exteriores detectan en la misma banda, pero solo detectan cambios en niveles de calor – por eso son detectores de movimiento. Aunque útiles en robótica, sus aplicaciones son limitadas al no poder detectar y medir la temperatura de una fuente de calor estática.
Otro tipo es el array de termopilas, usado en termómetros infrarrojos sin contacto. Tienen ángulo de detección muy amplio (FOV ~100°) y necesitan shrouding o lente para reducirlo a ~12°. Algunos tienen lente integrada. Recientemente han aparecido sensores con array de termopilas, electrónica integrada y lente de silicio. Este es el tipo usado en el TPA81. Tiene un array de 8 termopilas en fila. El TPA81 puede medir la temperatura de 8 puntos adyacentes simultáneamente. También puede controlar un servo para barrer el módulo y construir una imagen térmica. Detecta una llama de vela a 2 metros (6 pies) y no se ve afectado por luz ambiente.
Los sensores PIR son similares a cámaras que solo ven cosas calientes. Así que el TPA81 es una cámara térmica de 8 píxeles de resolución, y el cuerpo humano siempre emite calor. Si controlamos el sensor PIR con un controlador y definimos algunos gestos para el sensor PIR, podemos hacer un detector de gestos simple.
En este proyecto, decidimos hacer un sistema detector de gestos usando PIR y Arduino. Usamos TPA81 como PIR pero es algo costoso; si quieres ahorrar dinero, puedes usar 8 sensores PIR simples sin la cabeza blanca (la parte de enfoque). El TPA81 soporta protocolo I2C y es compatible con Arduino Nano. Este proyecto genial te ayuda a entender los fundamentos del procesamiento de imagen y detección de gestos. ¡Vamos a ello!
Circuito
Si quieres usar 8 sensores PIR en lugar del TPA81, debes conectar 8 sensores PIR individuales a una placa Arduino y leerlos uno tras otro. ¡Así ahorras dinero!
Código
Para el primer circuito (usando TPA81), copia el código en el IDE Arduino. Primero debes añadir la librería y luego subir el código. Descarga la librería TPA81 desde el enlace correspondiente. Si es tu primera vez con Arduino, sigue estos pasos:
- Ve a arduino.cc y descarga el software para tu SO. Instala el IDE.
- Ejecuta el IDE Arduino, limpia el editor y copia el siguiente código.
- Ve a Programa > Incluir librería > Añadir librería ZIP y añade las librerías descargadas.
- En Herramientas > Placa, selecciona Arduino Nano.
- Conecta Arduino a tu PC y configura el puerto COM en Herramientas > Puerto.
- Pulsa Subir (icono flecha).
- ¡Listo!
Test básico: Lectura de 8 píxeles TPA81
#include "Wire.h"
#include "TPA81.h"
// Crear instancia TPA81
TPA81 tpa;
void setup() {
Serial.begin(9600);
// Iniciar librería Wire para usar TPA81
Wire.begin();
}
void loop() {
// Imprimir temperatura ambiente
Serial.print(tpa.getAmbient());
Serial.print(" ");
// Imprimir los 8 puntos de temperatura
for (int i = 1; i <= 8; i++) {
Serial.print(tpa.getPoint(i));
Serial.print(" ");
}
Serial.println(" ");
delay(100);
}
Tras ejecutar, abre el Terminal Serie en el IDE Arduino y observa las 8 temperaturas del array. El primer número de cada línea es la temperatura ambiente. Pon tu mano frente al sensor y verás la temperatura de tu cuerpo. Para definir un gesto con la mano, debes conocer la temperatura de tu mano y establecerla como umbral. La fijamos a 29°C. Sube el siguiente código para ver el movimiento de tu mano frente al TPA81.
Visualización de detección (umbral 29°C)
#include "Wire.h"
#include "TPA81.h"
TPA81 tpa;
void setup() {
Serial.begin(9600);
Wire.begin();
}
void loop() {
Serial.print(tpa.getAmbient());
Serial.print(" ");
for (int i = 1; i <= 8; i++) {
if (tpa.getPoint(i) > 29) Serial.print("# ");
else Serial.print(". ");
}
Serial.println(" ");
delay(100);
}
Algoritmo detección gestos (Control volumen)
Escribimos un algoritmo para detectar gestos simples como subir/bajar volumen. Copia y prueba el siguiente código:
#include "Wire.h"
#include "TPA81.h"
#include "ssd1306.h"
#include "DHT.h"
TPA81 tpa;
#define VCCSTATE SSD1306_SWITCHCAPVCC
#define WIDTH 128
#define HEIGHT 64
#define PAGES 8
#define OLED_RST 9
#define OLED_DC 8
#define OLED_CS 10
#define SPI_MOSI 11 // Conectar a pin DIN del OLED
#define SPI_SCK 13
uint8_t oled_buf[WIDTH * HEIGHT / 8];
int gesture[8][20];
int tgesture[8];
int sum = 0;
int sflag; // bandera standby
int gcount;
int c;
int ex;
int vol = 5;
// Bitmaps para niveles de volumen 1-11 (almacenados en PROGMEM)
const uint8_t v1 [] PROGMEM = { ... }; // Datos bitmap volumén 1
const uint8_t v2 [] PROGMEM = { ... }; // Volumen 2
const uint8_t v3 [] PROGMEM = { ... }; // Volumen 3
const uint8_t v4 [] PROGMEM = { ... }; // Volumen 4
const uint8_t v5 [] PROGMEM = { ... }; // Volumen 5
const uint8_t v6 [] PROGMEM = { ... }; // Volumen 6
const uint8_t v7 [] PROGMEM = { ... }; // Volumen 7
const uint8_t v8 [] PROGMEM = { ... }; // Volumen 8
const uint8_t v9 [] PROGMEM = { ... }; // Volumen 9
const uint8_t v10 [] PROGMEM = { ... }; // Volumen 10
const uint8_t v11 [] PROGMEM = { ... }; // Volumen 11
void dsply(int input) {
int n1, n2;
if (input < 10) {
SSD1306_char3216(10, 25, '0', oled_buf);
switch(input) {
case 0: SSD1306_char3216(26, 25, '0', oled_buf); break;
case 1: SSD1306_char3216(26, 25, '1', oled_buf); break;
case 2: SSD1306_char3216(26, 25, '2', oled_buf); break;
case 3: SSD1306_char3216(26, 25, '3', oled_buf); break;
case 4: SSD1306_char3216(26, 25, '4', oled_buf); break;
case 5: SSD1306_char3216(26, 25, '5', oled_buf); break;
case 6: SSD1306_char3216(26, 25, '6', oled_buf); break;
case 7: SSD1306_char3216(26, 25, '7', oled_buf); break;
case 8: SSD1306_char3216(26, 25, '8', oled_buf); break;
case 9: SSD1306_char3216(26, 25, '9', oled_buf); break;
}
} else {
n1 = input / 10;
n2 = input % 10;
switch(n1) {
case 0: SSD1306_char3216(10, 25, '0', oled_buf); break;
case 1: SSD1306_char3216(10, 25, '1', oled_buf); break;
case 2: SSD1306_char3216(10, 25, '2', oled_buf); break;
case 3: SSD1306_char3216(10, 25, '3', oled_buf); break;
case 4: SSD1306_char3216(10, 25, '4', oled_buf); break;
case 5: SSD1306_char3216(10, 25, '5', oled_buf); break;
case 6: SSD1306_char3216(10, 25, '6', oled_buf); break;
case 7: SSD1306_char3216(10, 25, '7', oled_buf); break;
case 8: SSD1306_char3216(10, 25, '8', oled_buf); break;
case 9: SSD1306_char3216(10, 25, '9', oled_buf); break;
}
switch(n2) {
case 0: SSD1306_char3216(26, 25, '0', oled_buf); break;
case 1: SSD1306_char3216(26, 25, '1', oled_buf); break;
case 2: SSD1306_char3216(26, 25, '2', oled_buf); break;
case 3: SSD1306_char3216(26, 25, '3', oled_buf); break;
case 4: SSD1306_char3216(26, 25, '4', oled_buf); break;
case 5: SSD1306_char3216(26, 25, '5', oled_buf); break;
case 6: SSD1306_char3216(26, 25, '6', oled_buf); break;
case 7: SSD1306_char3216(26, 25, '7', oled_buf); break;
case 8: SSD1306_char3216(26, 25, '8', oled_buf); break;
case 9: SSD1306_char3216(26, 25, '9', oled_buf); break;
}
}
}
void setup() {
Serial.begin(9600);
Wire.begin();
SSD1306_begin();
SSD1306_clear(oled_buf);
}
void loop() {
// Lectura de 8 píxeles
for (int i = 0; i <= 7; i++) {
if (tpa.getPoint(i+1) > 29) {
Serial.print("#"); Serial.print(" ");
gesture[i][0] = 1;
} else {
Serial.print("."); Serial.print(" ");
gesture[i][0] = 0;
}
}
for (int y = 0; y <= 7; y++) sum += gesture[y][0];
Serial.println(sum); // Suma de 8 píxeles
Serial.println(" ");
delay(100); // Velocidad de lectura
////////////////////////////////////////////////////////////////////////////////////// Standby
if (sum == 8) {
sflag = 1;
Serial.println("standby");
} else {
sum = 0;
}
////////////////////////////////////////////////////////////////////////////////////// Progreso - Detección gesto
if (sflag == 1 && sum != 8) {
Serial.println("inicio gesto");
gcount = 0;
c = 0;
sum = 0;
while (sum < 8) {
sum = 0;
for (int i = 0; i <= 7; i++) {
if (tpa.getPoint(i+1) > 29) {
Serial.print("#"); Serial.print(" ");
gesture[i][gcount] = 1;
} else {
Serial.print("."); Serial.print(" ");
gesture[i][gcount] = 0;
}
}
for (int y = 0; y <= 7; y++) {
sum += gesture[y][gcount];
delay(5);
}
Serial.println(" ");
delay(50); // Velocidad de lectura
gcount++; // Longitud del gesto
}
Serial.print("sum: "); Serial.println(sum);
Serial.print("longitud gesto: "); Serial.println(gcount);
delay(5);
// Procesamiento del gesto
for (int c = 0; c <= 7; c++) {
for (int z = 0; z <= gcount; z++) {
tgesture[c] += gesture[c][z];
delay(5);
}
Serial.println("procesando");
}
// Agrupación: píxeles izquierdos vs derechos
tgesture[0] += tgesture[1];
tgesture[2] += tgesture[3];
tgesture[4] += tgesture[5];
tgesture[6] += tgesture[7];
tgesture[0] += tgesture[2]; // Lado izquierdo (píxeles 1-4)
tgesture[4] += tgesture[6]; // Lado derecho (píxeles 5-8)
if (tgesture[0] < tgesture[4]) {
vol += (gcount / 2);
Serial.print("volumen arriba");
}
if (tgesture[4] < tgesture[0]) {
vol -= (gcount / 2);
Serial.print("volumen abajo");
}
// Limitar volumen 1-11
if (vol < 1) vol = 1;
if (vol > 11) vol = 11;
sflag = 0;
}
sum = 0;
SSD1306_clear(oled_buf);
// Mostrar nivel volumen en OLED
switch (vol) {
case 1: SSD1306_bitmap(0, 0, v1, 128, 64, oled_buf); break;
case 2: SSD1306_bitmap(0, 0, v2, 128, 64, oled_buf); break;
case 3: SSD1306_bitmap(0, 0, v3, 128, 64, oled_buf); break;
case 4: SSD1306_bitmap(0, 0, v4, 128, 64, oled_buf); break;
case 5: SSD1306_bitmap(0, 0, v5, 128, 64, oled_buf); break;
case 6: SSD1306_bitmap(0, 0, v6, 128, 64, oled_buf); break;
case 7: SSD1306_bitmap(0, 0, v7, 128, 64, oled_buf); break;
case 8: SSD1306_bitmap(0, 0, v8, 128, 64, oled_buf); break;
case 9: SSD1306_bitmap(0, 0, v9, 128, 64, oled_buf); break;
case 10: SSD1306_bitmap(0, 0, v10, 128, 64, oled_buf); break;
case 11: SSD1306_bitmap(0, 0, v11, 128, 64, oled_buf); break;
}
SSD1306_display(oled_buf);
}
¿Qué sigue?
Usando el método anterior puedes extender el código para detectar otros gestos: tocar, arrastrar, soltar, estirar, etc. Luego define comandos para realizar ciertas tareas al detectar cada uno de estos movimientos y gestos.
Librerías necesarias
- TPA81 Library - Para sensor array térmico (descarga e instala como ZIP)
- SSD1306 Library - Para display OLED 128x64 (descarga e instala como ZIP)
Ambas librerías solo disponibles para descarga (no hay vista previa en el proyecto original).
Proceso de manufactura
- Controle un LED con Sensor PIR de Movimiento en Raspberry Pi
- Domina GPIO de Raspberry Pi: interfaz sensor PIR movimiento en B+/Model 2
- Cómo Conectar, Calibrar y Programar el Sensor PIR HC‑SR501 con Raspberry Pi
- Proyecto Sensor DHT11 Temperatura y Humedad con Indicadores LED y Altavoz Piezo
- Robot de Detección Humana con Arduino Uno: Integración de Sensores Paso a Paso
- Construye un tarro inteligente IoT con ESP8266, Arduino y sensor ultrasónico: Monitorización en tiempo real
- Pantalla LED Matricial Interactiva en Puerta con Sensor PIR - Saludo Navideño Arduino
- Construye una Torre de Sensores con Arduino Cloud: Temperatura, Movimiento y Gas
- Pistola de Agua Inteligente Activada por Movimiento con Arduino Nano
- Sensores para Arduino: Tipos, Aplicaciones y Proyectos Reales
- Cómo Funcionan los Circuitos de Sensor PIR: Diseño, Operación y Aplicaciones Reales