Saltar al contenido
Nivel avanzado

Pulverizador por movimiento: el sensor PIR

Conexión del sensor PIR

Para detectar el movimiento usaremos un sensor piroeléctrico (habitualmente llamado PIR). Estos sensores reaccionan ante el calor que emite el cuerpo humano o el de los animales, y reconocen el movimiento de una persona en un rango de un par de metros. Solo detectan presencia o ausencia de movimiento, sin medir nada más.

Dos vistas de un sensor PIR: al frente, la placa con los pines VCC, señal (OUT) y GND rotulados; al dorso, los dos trimmers naranjas de ajuste de sensibilidad y de tiempo.
El sensor PIR por delante y por detrás: los tres pines de conexión y los dos trimmers de ajuste de sensibilidad y de tiempo (figura original del proyecto).

El sensor tiene tres pines: dos de alimentación (VCC y GND) y un tercero de salida de información, que entrega la señal de movimiento a una entrada digital de la placa.

En el Arduino UNO, la salida del PIR va al pin 4 —el que indica la constante PIN_PIR—, y la alimentación a 5 V y GND de la placa. El servo sigue conectado como en el nivel inicial (señal al pin 3).

En el ESP32, la salida del PIR va al GPIO 27 (el que indica PIN_PIR). Tené en cuenta que el ESP32 trabaja a 3,3 V en sus entradas: si tu módulo PIR entrega la salida a 5 V, conviene alimentarlo a 3,3 V o adaptar esa señal para no exigir el GPIO. El servo sigue en el GPIO 13, con su alimentación de 5 V desde la fuente aparte.

Calibración del sensor PIR

Antes de usar el sensor para accionar el pulverizador, tenemos que familiarizarnos con su forma de medición: el PIR indica el valor 1 cuando detecta movimiento y 0 cuando no lo hace. Es una lectura digital, igual que preguntar si un pin está en alto o en bajo.

El módulo trae dos trimmers de ajuste (los dos tornillos naranjas del dorso que viste en la figura del paso 1): uno regula la sensibilidad de la detección y el otro el tiempo que el sensor sostiene el 1 después de detectar algo. Vamos a calibrarlos observando las lecturas en la computadora, cosa que haremos en el paso siguiente.

Activar el envío de datos a la consola

Para ver los valores del sensor necesitamos que la placa nos los mande a la computadora. La idea es leer el pin del PIR y escribir el resultado por la conexión serie, una y otra vez dentro de loop(): así el valor se actualiza constantemente. Con la placa conectada, abrimos la consola —en el Arduino IDE 2.x se llama monitor serie— con el ícono de la lupa en el extremo superior derecho (o desde Herramientas → Monitor Serie). Asegurate de que la velocidad seleccionada abajo a la derecha coincida con la del código (el valor de Serial.begin, típicamente 9600 baudios).

Vas a ver una columna de 1 y 0 que se actualiza sola. Movete frente al sensor, quedate quieto, alejate: la columna cuenta la historia. Con esa columna a la vista, ahora sí podés girar los trimmers de sensibilidad y de tiempo del paso anterior hasta que la detección responda como necesitás.

Accionar el pulverizador al detectar movimiento

Ahora unimos las dos mitades: el sensor de entrada y el servo de salida. Con la estructura if (si… entonces) accionamos el servomotor cuando el sensor detecte movimiento, es decir, cuando la lectura del PIR sea igual a 1. Si no hay movimiento, el programa no hace nada y vuelve a consultar el sensor.

Esquema del circuito completo del nivel avanzado: Arduino UNO con el sensor PIR conectado al pin 4 y el servomotor conectado al pin 3, ambos alimentados desde la placa a través de la protoboard.
El circuito completo del nivel: el sensor PIR en la entrada y el servomotor del gatillo en la salida, conectados a la vez (figura original del proyecto).

Ciclos repetitivos (3 pulverizaciones)

Una sola pulverización por detección quedaría corta. Para asegurar el rociado, cada vez que el sensor detecta movimiento hacemos una tanda de 3 pulverizaciones seguidas. Esto se programa con un ciclo que repite el disparo del servo (apretar el gatillo a 90°, soltarlo a 0°) la cantidad de veces que indiquemos. Entre un disparo y el siguiente dejamos apenas un segundo, para que no haya tanta espera dentro de la tanda.

Esperar antes de accionar el pulverizador

Falta el detalle más importante de la situación: el pulverizador se activa al detectar movimiento, pero es probable que la persona todavía esté cerca de las góndolas. Por eso, antes de rociar, dejamos pasar un intervalo de tiempo para que el cliente se aleje. El original usa una espera de 60 segundos. Así queda el programa completo: si el PIR detecta movimiento, esperamos, y recién entonces hacemos la tanda de 3 pulverizaciones.

Ver el código completo · pulverizador-pir.ino
pulverizador-pir.ino Arduino UNO
// Pulverizador por movimiento (PIR): en lugar de pulverizar a ciegas cada
// tantos segundos, el sistema espera a detectar movimiento con un sensor PIR
// (un cliente que retira frutas o verduras) y recién entonces acciona el
// gatillo. Así no se desperdicia agua: se riega cuando hace falta.
//
// Detalle clave del original: al detectar movimiento NO se pulveriza de
// inmediato. Primero se deja pasar un tiempo de espera (para no rociar a la
// persona que todavía está frente a la góndola) y después se hace una tanda
// de 3 pulverizaciones seguidas sobre las frutas que quedaron.
//
// SEGURIDAD: es una práctica de baja tensión. El servo y el PIR trabajan a
// 5 V; el agua pulverizada sale a baja presión y NO debe tocar la placa, el
// servo, el sensor ni las conexiones. Ubicar el circuito lejos del chorro.
//
// Plataforma: Arduino UNO.
// Conexión: señal del servo (amarillo) → pin 3; salida de datos del PIR →
// pin 4; alimentaciones a 5V y GND.
//
// Basado en: código de los Pasos 4 a 6, Nivel Avanzado — Pulverizador
// Automatizado, Saberes Digitales (INET/EDUCAR 2019).
// Modernización: se elimina el C generado por mBlock3 (angle_rad/angle_deg,
// _delay, _loop) y se usan constantes nombradas. Se mantiene la estructura
// bloqueante del original (delay()): es fiel a lo que la guía enseña en este
// proyecto y hace el flujo de "esperar y luego repetir" fácil de leer.

// En el UNO la librería es Servo.h; el #if mantiene el mismo archivo válido
// si se compilara para ESP32 (donde la librería correcta es ESP32Servo.h).
#if defined(ESP32)
  #include <ESP32Servo.h>
#else
  #include <Servo.h>
#endif

const int PIN_SERVO = 3;
const int PIN_PIR   = 4;

// Ángulos del gatillo (iguales al nivel inicial y al original).
const int ANGULO_REPOSO  = 0;
const int ANGULO_DISPARO = 90;

// Cantidad de pulverizaciones por detección: el original repite el disparo
// 3 veces para asegurar el rociado.
const int CICLOS_POR_DETECCION = 3;

// Tiempos. El original: esperar antes de accionar y, dentro de la tanda,
// pulverizaciones cortas y seguidas (1 s entre una y otra).
// NOTA DE AULA: son valores cortos a propósito para probar sin esperar. La
// espera real del original es de 60 s (para que el cliente se aleje antes de
// rociar); si querés ver el ciclo completo rápido en el aula, bajá
// temporalmente TIEMPO_ESPERA_MS (por ejemplo a 5000 = 5 s).
const unsigned long TIEMPO_ESPERA_MS        = 60000;  // antes de pulverizar
const unsigned long TIEMPO_DISPARO_MS       = 1000;   // gatillo apretado
const unsigned long TIEMPO_ENTRE_CICLOS_MS  = 1000;   // reposo entre disparos

Servo servoGatillo;

void setup() {
  pinMode(PIN_PIR, INPUT);
  servoGatillo.attach(PIN_SERVO);
  servoGatillo.write(ANGULO_REPOSO);
}

void loop() {
  // El PIR devuelve HIGH (1) cuando detecta movimiento.
  if (digitalRead(PIN_PIR) == HIGH) {
    // Esperar antes de accionar: le damos tiempo a la persona para retirarse
    // de la góndola y así no la rociamos (Paso 6 del original).
    delay(TIEMPO_ESPERA_MS);

    // Tanda de pulverizaciones sobre las frutas que quedaron (Paso 5).
    for (int i = 0; i < CICLOS_POR_DETECCION; i++) {
      servoGatillo.write(ANGULO_DISPARO);
      delay(TIEMPO_DISPARO_MS);
      servoGatillo.write(ANGULO_REPOSO);
      delay(TIEMPO_ENTRE_CICLOS_MS);
    }
  }
  // Sin movimiento: loop() vuelve a empezar y consulta el sensor de nuevo.
}
pulverizador-pir.ino ESP32
// Pulverizador por movimiento (PIR): en lugar de pulverizar a ciegas cada
// tantos segundos, el sistema espera a detectar movimiento con un sensor PIR
// (un cliente que retira frutas o verduras) y recién entonces acciona el
// gatillo. Así no se desperdicia agua: se riega cuando hace falta.
//
// Detalle clave del original: al detectar movimiento NO se pulveriza de
// inmediato. Primero se deja pasar un tiempo de espera (para no rociar a la
// persona que todavía está frente a la góndola) y después se hace una tanda
// de 3 pulverizaciones seguidas sobre las frutas que quedaron.
//
// SEGURIDAD: es una práctica de baja tensión. El servo y el PIR trabajan a
// baja tensión; el agua pulverizada sale a baja presión y NO debe tocar la
// placa, el servo, el sensor ni las conexiones. Ubicar el circuito lejos del
// chorro.
//
// Plataforma: ESP32 (DevKit v1).
// Conexión: señal del servo (amarillo) → GPIO 13; salida de datos del PIR →
// GPIO 27. Nota eléctrica: el ESP32 trabaja a 3,3 V en sus GPIO; el servo se
// alimenta a 5 V desde una fuente aparte con GND común, y el PIR debe entregar
// su salida a 3,3 V (o adaptarla). Nunca inyectar 5 V en un GPIO.
//
// Basado en: código de los Pasos 4 a 6, Nivel Avanzado — Pulverizador
// Automatizado, Saberes Digitales (INET/EDUCAR 2019).
// Modernización: se elimina el C generado por mBlock3 (angle_rad/angle_deg,
// _delay, _loop) y se usan constantes nombradas. Portado a ESP32 con la
// librería ESP32Servo y GPIO seguros (servo 13, PIR 27) en lugar de los
// pines 3 y 4 del UNO. Se mantiene la estructura bloqueante del original
// (delay()): es fiel a lo que la guía enseña en este proyecto.

// En el ESP32 la librería correcta es ESP32Servo.h; el #if selecciona la
// librería según la placa para mantener un único archivo válido en ambas.
#if defined(ESP32)
  #include <ESP32Servo.h>
#else
  #include <Servo.h>
#endif

const int PIN_SERVO = 13;
const int PIN_PIR   = 27;

// Ángulos del gatillo (iguales al nivel inicial y al original).
const int ANGULO_REPOSO  = 0;
const int ANGULO_DISPARO = 90;

// Cantidad de pulverizaciones por detección: el original repite el disparo
// 3 veces para asegurar el rociado.
const int CICLOS_POR_DETECCION = 3;

// Tiempos. El original: esperar antes de accionar y, dentro de la tanda,
// pulverizaciones cortas y seguidas (1 s entre una y otra).
// NOTA DE AULA: son valores cortos a propósito para probar sin esperar. La
// espera real del original es de 60 s (para que el cliente se aleje antes de
// rociar); si querés ver el ciclo completo rápido en el aula, bajá
// temporalmente TIEMPO_ESPERA_MS (por ejemplo a 5000 = 5 s).
const unsigned long TIEMPO_ESPERA_MS        = 60000;  // antes de pulverizar
const unsigned long TIEMPO_DISPARO_MS       = 1000;   // gatillo apretado
const unsigned long TIEMPO_ENTRE_CICLOS_MS  = 1000;   // reposo entre disparos

Servo servoGatillo;

void setup() {
  pinMode(PIN_PIR, INPUT);
  servoGatillo.attach(PIN_SERVO);
  servoGatillo.write(ANGULO_REPOSO);
}

void loop() {
  // El PIR devuelve HIGH (1) cuando detecta movimiento.
  if (digitalRead(PIN_PIR) == HIGH) {
    // Esperar antes de accionar: le damos tiempo a la persona para retirarse
    // de la góndola y así no la rociamos (Paso 6 del original).
    delay(TIEMPO_ESPERA_MS);

    // Tanda de pulverizaciones sobre las frutas que quedaron (Paso 5).
    for (int i = 0; i < CICLOS_POR_DETECCION; i++) {
      servoGatillo.write(ANGULO_DISPARO);
      delay(TIEMPO_DISPARO_MS);
      servoGatillo.write(ANGULO_REPOSO);
      delay(TIEMPO_ENTRE_CICLOS_MS);
    }
  }
  // Sin movimiento: loop() vuelve a empezar y consulta el sensor de nuevo.
}
Pulverizador por movimiento: al detectar (PIR = 1), el sistema espera 60 s para no rociar a la persona y luego dispara 3 pulverizaciones sobre los productos que quedaron.

Compará el comportamiento de tu circuito con el del simulador:

Simulación del comportamiento

La misma máquina de estados del firmware, portada a TypeScript, maneja el comportamiento del dispositivo. No se ejecuta el binario real: la ejecución del .hex con avr8js está en el roadmap.

Simulación lista. Presioná «Iniciar» para arrancar la secuencia.

Cierre del nivel

Al terminar este nivel, el pulverizador dejó de rociar a ciegas: el sensor PIR —ya calibrado y verificado en el monitor serie— detecta cuándo un cliente retira productos de la góndola, el sistema espera un tiempo para no mojarlo y recién entonces hace su tanda de tres pulverizaciones sobre lo que quedó. Con esto queda cerrado el recorrido del proyecto. Si el grupo quiere seguir, en la ficha están las extensiones sugeridas: un sensor de humedad que decida solo cuándo pulverizar, un sensor de nivel de líquido con aviso de recarga, y el cálculo de pulverizaciones restantes publicado a través de IoT.

Evidencia de cierre

Al terminar este nivel, esto tiene que estar funcionando:

  • El sensor PIR está conectado y calibrado: sus lecturas (1 con movimiento, 0 sin movimiento) se ven en el monitor serie del Arduino IDE.
  • El pulverizador se acciona cuando el PIR detecta movimiento y no antes: al detectar, espera un tiempo (para no rociar a la persona) y luego hace una tanda de 3 pulverizaciones.
  • El sistema vuelve a quedar a la espera de un nuevo movimiento después de cada tanda, sin desperdiciar agua cuando no hay nadie en la góndola.