Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

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

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:

Detector de gestos funcionando
[Imagen del proyecto]

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)

Principio de funcionamiento PIR
[Imagen explicativa]

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.

Módulo TPA81
[Imagen]

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

Esquema con TPA81
[Imagen del 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!

Alternativa con 8 sensores PIR individuales
[Imagen del circuito alternativo]

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:

  1. Ve a arduino.cc y descarga el software para tu SO. Instala el IDE.
  2. Ejecuta el IDE Arduino, limpia el editor y copia el siguiente código.
  3. Ve a Programa > Incluir librería > Añadir librería ZIP y añade las librerías descargadas.
  4. En Herramientas > Placa, selecciona Arduino Nano.
  5. Conecta Arduino a tu PC y configura el puerto COM en Herramientas > Puerto.
  6. Pulsa Subir (icono flecha).
  7. ¡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);
}
Salida Monitor Serie - Temperaturas raw
[Animación GIF]

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);
}
Detección de mano en Monitor Serie
[Animación GIF]

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);
}
Demostración control de volumen por gestos
[Animación GIF]

¿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

Ambas librerías solo disponibles para descarga (no hay vista previa en el proyecto original).

Proceso de manufactura

  1. Controle un LED con Sensor PIR de Movimiento en Raspberry Pi
  2. Domina GPIO de Raspberry Pi: interfaz sensor PIR movimiento en B+/Model 2
  3. Cómo Conectar, Calibrar y Programar el Sensor PIR HC‑SR501 con Raspberry Pi
  4. Proyecto Sensor DHT11 Temperatura y Humedad con Indicadores LED y Altavoz Piezo
  5. Robot de Detección Humana con Arduino Uno: Integración de Sensores Paso a Paso
  6. Construye un tarro inteligente IoT con ESP8266, Arduino y sensor ultrasónico: Monitorización en tiempo real
  7. Pantalla LED Matricial Interactiva en Puerta con Sensor PIR - Saludo Navideño Arduino
  8. Construye una Torre de Sensores con Arduino Cloud: Temperatura, Movimiento y Gas
  9. Pistola de Agua Inteligente Activada por Movimiento con Arduino Nano
  10. Sensores para Arduino: Tipos, Aplicaciones y Proyectos Reales
  11. Cómo Funcionan los Circuitos de Sensor PIR: Diseño, Operación y Aplicaciones Reales