Pulverizador por movimiento: el sensor PIR
Recorrido del nivel
Esa barra de arriba te dice en qué paso estás. Tocala para ver el índice completo y saltar a cualquier paso.
Conexión del sensor PIR
Para detectar el movimiento usaremos un sensor piroeléctricoSensor PIRSensor de movimiento infrarrojo que reacciona ante fuentes de calor como el cuerpo humano o el de los animales. Solo detecta presencia o ausencia de movimiento (1 o 0), en un rango de un par de metros, y trae trimmers para regular sensibilidad y tiempo de disparo. (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.
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 ArduinoArduinoPlaca electrónica con un microcontrolador programable y comunicación USB/serial. Desde la computadora, un IDE permite escribir el código, compilarlo y cargarlo en la placa. Tiene entradas y salidas digitales (0 a 13) y entradas analógicas (A0 a A5). 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 ESP32ESP32Placa con un microcontrolador de Espressif que trae WiFi (y Bluetooth) integrados. Se programa desde el Arduino IDE igual que un Arduino, con pines llamados GPIO. En este proyecto reemplaza al conjunto Arduino UNO + módulo OBLOQ para el nivel IoT., 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.
Verificá
Con el sensor alimentado y en reposo unos segundos, ya está listo para leerse. Todavía no vas a ver los valores: aparecen recién cuando abramos la consola 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.
Verificá
Con el monitor serie abierto: al moverte frente al sensor aparece el 1, y al quedarte
quieto (pasado el tiempo del trimmer) vuelve el 0. Si la columna no cambia nunca, revisá el
pin de señal (PIN_PIR) y la velocidad del monitor.
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.
Verificá
Repasá contra el esquema: el PIR conserva su pin de entrada (PIN_PIR), el servo su pin de
salida (PIN_SERVO), y ambos comparten la alimentación y el GND. Es el circuito del nivel
inicial más el sensor de movimiento.
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.
Verificá
En el código del paso siguiente, la constante CICLOS_POR_DETECCION vale 3: cambiá ese
número si querés más o menos pulverizaciones por detección, y observá cómo cambia 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 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 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.
} 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.
Más allá de rociar a ciegas
El sistema todavía tiene un punto ciego: mientras espera los 60 segundos y mientras dispara la tanda, ignora nuevos movimientos. Debatan en grupo: ¿qué pasaría si llega otro cliente justo en ese momento? ¿Conviene reiniciar la espera, encolar la detección o dejarlo así? No hay que programarlo todavía —el original tampoco lo hace—, pero identificar el problema es parte de pensar el sistema.
Para el aula
Para probar el ciclo completo en el aula, 60 segundos de espera se hacen eternos: el código
trae la constante TIEMPO_ESPERA_MS justamente para eso, con la sugerencia de bajarla
temporalmente (por ejemplo a 5000 = 5 s) durante las pruebas y devolverla a 60 s para la
demostración final. Es una buena ocasión para hablar de por qué el valor “de verdad” y el
valor “para probar” no tienen por qué ser el mismo.
Verificá
Al pasar la mano frente al sensor, el sistema espera el intervalo y después el servo dispara tres pulverizaciones seguidas; luego vuelve a quedar a la espera. Si dispara de inmediato, revisá que la espera esté antes de la tanda; si nunca dispara, revisá la lectura del PIR en el monitor serie.
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.