Radar de movimiento con ESP32

Introducción

¿Alguna vez has querido construir tu propio sistema de detección de movimiento con una pantalla que te avise visualmente y una alarma sonora? Este proyecto te guiará paso a paso para crear un «Radar de Movimiento» utilizando la potente placa ESP32, conocida por sus capacidades de Wi-Fi y Bluetooth, un sensor PIR para detectar movimiento y una pequeña pantalla TFT para mostrar los estados. Es un proyecto divertido y educativo, perfecto para principiantes en electrónica y programación con Arduino.

Materiales Necesarios

  • Placa de desarrollo ESP32 (por ejemplo, ESP32 DevKitC)
  • Sensor de movimiento PIR (HC-SR501)
  • Pantalla TFT de 1.8 pulgadas ST7735 (o similar, compatible con SPI)
  • Zumbador (Buzzer) activo
  • Protoboard
  • Cables jumper macho-macho
  • Cable USB para la placa ESP32

Esquema del montaje

El montaje de este proyecto se realiza sobre una protoboard para facilitar las conexiones temporales. El ESP32 será el cerebro, procesando la información del sensor PIR y controlando la pantalla TFT y el zumbador. Asegúrate de que todas las conexiones sean firmes para evitar problemas.

Conexiones:

  • Sensor PIR (HC-SR501):
    • Pin VCC del PIR a 3.3V del ESP32
    • Pin GND del PIR a GND del ESP32
    • Pin OUT del PIR a GPIO 18 del ESP32
  • Zumbador (Buzzer activo):
    • Pin positivo del Buzzer a GPIO 19 del ESP32
    • Pin negativo del Buzzer a GND del ESP32
  • Pantalla TFT 1.8″ ST7735 (SPI):
    • Pin VCC del TFT a 3.3V del ESP32
    • Pin GND del TFT a GND del ESP32
    • Pin SCK (SCLK) del TFT a GPIO 14 del ESP32
    • Pin SDA (MOSI) del TFT a GPIO 13 del ESP32
    • Pin RES (RST) del TFT a GPIO 27 del ESP32
    • Pin DC (A0) del TFT a GPIO 26 del ESP32
    • Pin CS del TFT a GPIO 5 del ESP32

Codigo Arduino

Asegúrate de tener instaladas las bibliotecas «Adafruit GFX Library» y «Adafruit ST7735 Library» en tu IDE de Arduino. Puedes instalarlas desde el Administrador de Bibliotecas.


#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>

// Definiciones de pines para el sensor PIR y el Buzzer
#define PIR_PIN 18     // Pin GPIO donde está conectado el sensor PIR
#define BUZZER_PIN 19  // Pin GPIO donde está conectado el Buzzer

// Definiciones de pines para la pantalla TFT (ST7735)
#define TFT_CS    5   // Chip Select (CS)
#define TFT_DC    26  // Data/Command (DC)
#define TFT_RST   27  // Reset (RST)

// Configuración de la pantalla TFT
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

// Variables de estado
int pirState = LOW;             // Estado inicial del sensor PIR
unsigned long lastMotionTime = 0; // Tiempo en que se detectó el último movimiento
const unsigned long motionTimeout = 5000; // Tiempo en milisegundos para volver a escanear (5 segundos)

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

  // Inicializar pines
  pinMode(PIR_PIN, INPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  digitalWrite(BUZZER_PIN, LOW); // Asegurarse de que el buzzer esté apagado al inicio

  // Inicializar pantalla TFT
  tft.initR(INITR_18GREENTAB); // Inicializar para 1.8" Green Tab
  tft.setRotation(3);          // Rotar la pantalla para que el texto sea legible
  tft.fillScreen(ST77XX_BLACK); // Limpiar la pantalla de negro

  tft.setTextColor(ST77XX_GREEN);
  tft.setTextSize(1);
  tft.setCursor(0, 0);
  tft.print("Iniciando...");
  delay(1000);
}

void loop() {
  int val = digitalRead(PIR_PIN); // Leer el estado del sensor PIR

  if (val == HIGH) { // Si se detecta movimiento
    if (pirState == LOW) { // Si el movimiento es una nueva detección
      Serial.println("¡Movimiento detectado!");
      tft.fillScreen(ST77XX_RED);
      tft.setCursor(10, tft.height() / 2 - 10);
      tft.setTextColor(ST77XX_WHITE);
      tft.setTextSize(2);
      tft.print("INTRUDER !");
      digitalWrite(BUZZER_PIN, HIGH); // Activar el zumbador
      pirState = HIGH;
    }
    lastMotionTime = millis(); // Actualizar el tiempo del último movimiento
  } else { // No hay movimiento detectado
    if (pirState == HIGH && (millis() - lastMotionTime > motionTimeout)) {
      // Si antes había movimiento y ha pasado el tiempo de espera
      Serial.println("Volviendo a escanear...");
      tft.fillScreen(ST77XX_BLACK);
      digitalWrite(BUZZER_PIN, LOW); // Desactivar el zumbador
      pirState = LOW;
    }
    // Si no hay movimiento y estamos en estado de "escaneo" o recién cambiamos
    if (pirState == LOW) {
      drawScanningArea(); // Dibujar animación de escaneo
    }
  }
  delay(50); // Pequeña pausa para evitar lecturas demasiado rápidas
}

// Función para dibujar la animación de escaneo del radar
void drawScanningArea() {
  static int angle = 0; // Ángulo actual del "rayo" del radar
  static unsigned long lastDrawTime = 0;
  const unsigned long drawInterval = 50; // Intervalo para actualizar el dibujo del radar

  if (millis() - lastDrawTime < drawInterval) return;
  lastDrawTime = millis();

  // Borrar el "rayo" anterior si es necesario (o dejar que se sobrescriba)
  // Para una animación más fluida, se podría dibujar una línea negra antes de la verde.
  // Pero para simplicidad y velocidad, dejaremos que la nueva línea sobrescriba la anterior.

  tft.setCursor(0, 0);
  tft.setTextColor(ST77XX_GREEN);
  tft.setTextSize(1);
  tft.println("SCANNING AREA...");

  int centerX = tft.width() / 2;
  int centerY = tft.height() / 2;
  int radius = min(centerX, centerY) - 5; // Radio del radar

  // Dibujar el fondo del radar
  tft.fillCircle(centerX, centerY, radius, ST77XX_BLACK);
  tft.drawCircle(centerX, centerY, radius, ST77XX_DARKGREY); // Borde del radar

  // Calcular las coordenadas del final del "rayo"
  float radAngle = radians(angle);
  int x2 = centerX + (int)(radius * cos(radAngle));
  int y2 = centerY + (int)(radius * sin(radAngle));

  // Dibujar el "rayo" actual en verde
  tft.drawLine(centerX, centerY, x2, y2, ST77XX_GREEN);

  angle = (angle + 5) % 360; // Incrementar el ángulo y reiniciar a 0 después de 360
}

Como funciona

Detección de Movimiento

El corazón de este sistema de detección es el sensor PIR (Passive Infrared). Este sensor es capaz de detectar cambios en los niveles de radiación infrarroja en su campo de visión, lo cual ocurre cuando una persona o animal se mueve por delante de él. Cuando el sensor PIR detecta un movimiento, su pin de salida (OUT) cambia de un estado bajo (LOW) a un estado alto (HIGH). El ESP32 monitoriza continuamente este pin.

Visualización en Pantalla

La pantalla TFT, conectada al ESP32 a través de la interfaz SPI, es la encargada de la retroalimentación visual. Cuando no se detecta movimiento, la pantalla muestra el texto «SCANNING AREA…» en verde sobre un fondo negro y una animación simple de «radar» donde una línea verde barre un círculo, simulando un escaneo constante. Al detectar movimiento, la pantalla cambia drásticamente: se pone completamente roja y muestra un gran mensaje de «INTRUDER!» en blanco, alertando de una posible intrusión.

Alarma Sonora

Además de la alerta visual, el proyecto incorpora un zumbador activo. Cuando el sensor PIR detecta movimiento, el ESP32 no solo cambia el estado de la pantalla, sino que también activa el zumbador, produciendo un sonido agudo que sirve como una alarma sonora. Esta alarma permanece activa mientras haya movimiento o hasta que transcurra un breve periodo de tiempo sin detección (5 segundos en nuestro código), tras lo cual el sistema vuelve a su estado de escaneo silencioso y visual.

Potencial de conectividad (ESP32)

Aunque en este proyecto nos centramos en la detección y alerta local, la elección del ESP32 es estratégica. Gracias a sus capacidades integradas de Wi-Fi y Bluetooth, este sistema podría expandirse fácilmente para enviar notificaciones a tu smartphone, subir datos a la nube, o integrarse en un sistema domótico más complejo. Por ejemplo, podrías recibir un correo electrónico o un mensaje en tu teléfono cada vez que se detecte un intruso, haciendo de este un primer paso hacia un sistema de seguridad inteligente.

Material

Aquí os dejamos los materiales que nosotros compramos cuando empezamos. Si quieres darnos una pequeña ayuda puedes comprar desde este link. Gracias por leernos!