Manual del proyecto · Proyecto 13
Pulverizador Automatizado
Diseño y construcción de un prototipo de pulverizador de agua automático: un servomotor acciona el gatillo por tiempo (nivel inicial) y en función de un sensor de movimiento (nivel avanzado), pensado para mantener la humedad de las góndolas de frutas y verduras.
- Dificultad:
- Nivel educativo:
- Secundario. Ciclo Básico.
Contenido del manual
- 01 Materiales y equipamiento
- 02 Pulverizador automático por tiempo Nivel inicial
- 03 Pulverizador por movimiento: el sensor PIR Nivel avanzado
Materiales y equipamiento
Insumos
| Imagen | Insumo | Cantidad | Plataforma |
|---|---|---|---|
| Gatillo pulverizador estándar (con su botella) Es el pulverizador de gatillo común de limpieza. El mecanismo impreso en 3D se monta sobre él para que el servo apriete el gatillo. | 1 | Todas | |
| | Servomotor SG5010 (estándar, 0°–180°) Es el actuador que aprieta el gatillo. Sirve cualquier servo estándar de tamaño equivalente con torque suficiente. | 1 | Todas |
| | Sensor PIR (piroeléctrico) Solo se usa en el nivel avanzado, para detectar el movimiento del cliente frente a la góndola. | 1 | Todas |
| Filamento PLA para impresora 3D Para imprimir las piezas del mecanismo que acopla el servo al gatillo (el paquete de fabricación de esta reedición está a diseñar). | según modelo | Todas | |
| | Protoboard | 1 | Todas |
| | Cable dupont macho-hembra | 20 | Todas |
| | Cable dupont macho-macho | 20 | Todas |
| | Arduino UNO R3 | 1 | Arduino UNO R3 |
| | Cable USB tipo B | 1 | Arduino UNO R3 |
| | Fuente de 9 V 1 A (plug centro positivo, 5,5 x 2,1 mm) (opcional) Para alimentar la maqueta sin la computadora. El ESP32 se alimenta por USB con una fuente de 5 V. | 1 | Arduino UNO R3 |
| | Placa ESP32 DevKit v1 | 1 | ESP32 DevKit |
| | Cable micro USB (con línea de datos) | 1 | ESP32 DevKit |
| | Fuente externa de 5 V (con GND común) para el servo El GPIO del ESP32 entrega 3,3 V de señal; el servo se alimenta a 5 V desde una fuente aparte compartiendo GND con la placa. Nunca inyectar 5 V en un GPIO. | 1 | ESP32 DevKit |
Equipamiento del taller
- Computadora
- Impresora 3D
- Soldador
- Estaño
- Alicate
- Pinza de punta
- Pinza brusela
Plano de conexionado en protoboard
Deslizá horizontalmente para ver el plano completo
Deslizá horizontalmente para ver el plano completo
| Desde | Hacia | Color de cable |
|---|---|---|
| Arduino UNO · 5V | Bus + de la protoboard | rojo |
| Arduino UNO · GND | Bus − de la protoboard | negro |
| Servo del gatillo · VCC | Bus + de la protoboard | rojo |
| Servo del gatillo · GND | Bus − de la protoboard | negro |
| Servo del gatillo · señal | Arduino UNO · 3 | azul |
| Sensor PIR · VCC | Bus + de la protoboard | rojo |
| Sensor PIR · GND | Bus − de la protoboard | negro |
| Sensor PIR · OUT | Arduino UNO · 4 | amarillo |
| Desde | Hacia | Color de cable |
|---|---|---|
| Fuente externa 5 V | Bus + de la protoboard | rojo |
| ESP32 DevKit v1 · GND | Bus − de la protoboard | negro |
| Servo del gatillo · VCC | Bus + de la protoboard | rojo |
| Servo del gatillo · GND | Bus − de la protoboard | negro |
| Servo del gatillo · señal | ESP32 DevKit v1 · GPIO13 | azul |
| Sensor PIR · VCC | Bus + de la protoboard | rojo |
| Sensor PIR · GND | Bus − de la protoboard | negro |
| Sensor PIR · OUT | ESP32 DevKit v1 · GPIO27 | amarillo |
Pulverizador automático por tiempo
Conectar el servomotor
Empezamos conectando el servomotorServomotorMotor que se ubica en un ángulo específico (los comunes, de 0° a 180°) y se mantiene ahí. Se programa indicando el ángulo deseado; tiene tres cables: alimentación (VCC, GND) y señal., que será el encargado de apretar el gatillo del pulverizador. El servo es un motor con un sistema de control que le permite ubicarse en un ángulo específico y mantenerse ahí; tiene tres cables: dos de alimentación (negro/marrón para GND y rojo para VCC) y uno de señal (naranja o amarillo) que lleva la orden de ángulo desde 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, el cable de señal (amarillo) del servo va
al pin 3 —el que indica la constante PIN_SERVO al comienzo del código— y la
alimentación se toma directamente de la placa: el cable rojo al pin de 5 V y el negro a
GND.
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., el cable de señal del servo va al GPIO 13 (el
que indica PIN_SERVO), un pin seguro para esta salida. Una diferencia importante de
alimentación: el GPIO entrega 3,3 V de señal, que alcanza para controlar el servo, pero
el motor del servo consume más de lo que la placa puede dar. Por eso el servo se alimenta a
5 V desde una fuente aparte, compartiendo el GND con el ESP32. Nunca inyectes 5 V
en un GPIO.
Programar el servomotor (posición 90°)
Para mover el servo hay que programarlo. Lo haremos directamente en el lenguaje de Arduino
(C++), usando el Arduino IDE en su versión 2.x, que se descarga gratis desde
arduino.cc/en/software. Un programa de Arduino se
llama sketch y tiene dos bloques: la función setup(), que se ejecuta una sola vez al
inicializarse el dispositivo, y la función loop(), que se repite después. Después de //
se escriben comentarios para el lector, que no tienen efecto en el programa.
Controlar el servo es sencillo: se usa una librería que lo maneja, se le dice en el
setup() a qué pin está conectado (attach) y después se le ordena un ángulo con write.
Para empezar, vamos a llevarlo a 90° —la posición de disparo, con la que el mecanismo
apretará el gatillo— y a comprobar que responde.
En el Arduino UNO, la librería que maneja el servo es Servo.h (viene incluida con el
IDE). Con servoGatillo.attach(PIN_SERVO) le indicamos el pin y con
servoGatillo.write(90) lo mandamos a 90°.
En el ESP32, la Servo.h estándar no sirve (es solo para placas AVR como el UNO): se
usa la librería ESP32Servo, que se instala una vez desde el gestor de bibliotecas del
IDE (buscá “ESP32Servo”). El código es idéntico —attach y write—, solo cambia la
librería que se incluye al principio.
Subir el código a la placa
Para subir el código a la placa, necesitamos:
- Conectar la placa a la computadora con el cable USB.
- Chequear que en el selector de placa del Arduino IDE esté seleccionada la placa correcta.
- Seleccionar el puertoPuerto COMPuerto de comunicaciones por el cual el sistema operativo se comunica con un dispositivo externo, como la placa. Se asigna automáticamente al conectarla por USB y puede cambiar de número; en el IDE hay que indicar cuál usar. al que está conectada la placa.
- Cliquear el botón Subir (la flecha →) en la parte superior de la interfaz.
En el Arduino IDE 2.x, la placa y el puerto se eligen juntos en el menú desplegable de la barra superior: al conectar la placa suele aparecer directamente como opción. Si no aparece, entrá a “Select other board and port” y buscala por nombre.
Para el Arduino UNO: usá el cable USB tipo B, elegí la placa Arduino UNO y el puerto
que se agregó al conectarla (en Windows es un puerto COM numerado; en Linux suele llamarse
/dev/ttyACM0 o similar).
Para el ESP32 hay dos pasos previos que se hacen una sola vez: instalar el soporte de placas ESP32 desde el gestor de placas del IDE (buscá “esp32” e instalá el paquete de Espressif) y, si el puerto no aparece, instalar el driver del conversor USB-serie de tu placa (generalmente CP210x o CH340). Después, elegí la placa ESP32 Dev Module (o “DOIT ESP32 DEVKIT V1”) y el puerto correspondiente. Si al subir el IDE queda esperando en “Connecting…”, mantené apretado el botón BOOT de la placa hasta que empiece la carga.
Al terminar de subir, veremos el mensaje de carga completada en la barra inferior del IDE y el servo se moverá a la posición de 90°.
Movimiento del servomotor (90° ↔ 0° cada 5 segundos)
Para que se accione el gatillo, necesitamos que el servo vaya y vuelva: gire a 90° para
apretar (pulverizar) y regrese a 0° para soltar, respetando intervalos de tiempo.
Programaremos que lo haga cada 5 segundos para poder probarlo cómodamente; más adelante
podés modificar ese intervalo según la necesidad de las góndolas. Como queremos que la
acción se repita sin parar, va toda dentro de loop().
Ver el código completo · pulverizador-temporizado.ino
// Pulverizador temporizado: el servomotor acciona el gatillo del pulverizador
// a intervalos fijos, sin ningún sensor. Es el mecanismo automático más
// simple: cada cierto tiempo el servo va a la posición de disparo (90°) para
// pulverizar y vuelve al reposo (0°). Así se mantiene la humedad de las
// góndolas de frutas y verduras sin intervención humana.
//
// SEGURIDAD: es una práctica de baja tensión. El servo y su electrónica
// trabajan a 5 V; el agua pulverizada sale a baja presión y NO debe tocar la
// placa, el servo ni las conexiones. Ubicar el circuito lejos del chorro.
//
// Plataforma: Arduino UNO.
// Conexión: cable de señal del servo (amarillo) → pin 3; alimentación del
// servo a 5V y GND de la placa.
//
// Basado en: código del Paso 4, Nivel Inicial — 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 para los ángulos y tiempos.
// En este nivel el delay() bloqueante es la herramienta que ya conocemos y
// alcanza para un temporizador simple (fiel a la progresión original).
// 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;
// Ángulos del gatillo: 0° es el reposo (gatillo suelto) y 90° es el disparo
// (gatillo apretado = pulveriza). Son los ángulos del original.
const int ANGULO_REPOSO = 0;
const int ANGULO_DISPARO = 90;
// Tiempos del ciclo. El original mantiene el gatillo apretado ~1 s y luego
// espera ~5 s hasta la próxima pulverización.
// NOTA DE AULA: son valores cortos a propósito para poder probar el mecanismo
// sin esperar. En un uso real se alargarían (por ejemplo, pulverizar cada
// varios minutos según la necesidad de las góndolas).
const unsigned long TIEMPO_DISPARO_MS = 1000; // gatillo apretado
const unsigned long TIEMPO_ENTRE_DISPAROS_MS = 5000; // reposo entre riegos
Servo servoGatillo;
void setup() {
servoGatillo.attach(PIN_SERVO);
// Arranca en reposo para no pulverizar apenas se enciende.
servoGatillo.write(ANGULO_REPOSO);
}
void loop() {
// Aprieta el gatillo: pulveriza.
servoGatillo.write(ANGULO_DISPARO);
delay(TIEMPO_DISPARO_MS);
// Suelta el gatillo y espera hasta el próximo ciclo.
servoGatillo.write(ANGULO_REPOSO);
delay(TIEMPO_ENTRE_DISPAROS_MS);
} // Pulverizador temporizado: el servomotor acciona el gatillo del pulverizador
// a intervalos fijos, sin ningún sensor. Es el mecanismo automático más
// simple: cada cierto tiempo el servo va a la posición de disparo (90°) para
// pulverizar y vuelve al reposo (0°). Así se mantiene la humedad de las
// góndolas de frutas y verduras sin intervención humana.
//
// SEGURIDAD: es una práctica de baja tensión. El servo y su electrónica
// trabajan a baja tensión; el agua pulverizada sale a baja presión y NO debe
// tocar la placa, el servo ni las conexiones. Ubicar el circuito lejos del
// chorro.
//
// Plataforma: ESP32 (DevKit v1).
// Conexión: cable de señal del servo (amarillo) → GPIO 13; alimentación del
// servo (ver nota eléctrica). El ESP32 trabaja a 3,3 V en sus GPIO: la señal
// de control sale a 3,3 V. El servo se alimenta a 5 V desde una fuente aparte
// con GND común; nunca inyectar 5 V en un GPIO.
//
// Basado en: código del Paso 4, Nivel Inicial — 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 (la Servo.h estándar es solo para AVR) y un GPIO seguro
// (13) en lugar del pin 3 del UNO. En este nivel el delay() bloqueante es la
// herramienta que ya conocemos y alcanza para un temporizador simple.
// 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;
// Ángulos del gatillo: 0° es el reposo (gatillo suelto) y 90° es el disparo
// (gatillo apretado = pulveriza). Son los ángulos del original.
const int ANGULO_REPOSO = 0;
const int ANGULO_DISPARO = 90;
// Tiempos del ciclo. El original mantiene el gatillo apretado ~1 s y luego
// espera ~5 s hasta la próxima pulverización.
// NOTA DE AULA: son valores cortos a propósito para poder probar el mecanismo
// sin esperar. En un uso real se alargarían (por ejemplo, pulverizar cada
// varios minutos según la necesidad de las góndolas).
const unsigned long TIEMPO_DISPARO_MS = 1000; // gatillo apretado
const unsigned long TIEMPO_ENTRE_DISPAROS_MS = 5000; // reposo entre riegos
Servo servoGatillo;
void setup() {
servoGatillo.attach(PIN_SERVO);
// Arranca en reposo para no pulverizar apenas se enciende.
servoGatillo.write(ANGULO_REPOSO);
}
void loop() {
// Aprieta el gatillo: pulveriza.
servoGatillo.write(ANGULO_DISPARO);
delay(TIEMPO_DISPARO_MS);
// Suelta el gatillo y espera hasta el próximo ciclo.
servoGatillo.write(ANGULO_REPOSO);
delay(TIEMPO_ENTRE_DISPAROS_MS);
} Leelo como una receta: “apretá el gatillo, mantené un segundo, soltá, esperá cinco segundos… y volvé a empezar”. Podés explorar ese mismo comportamiento en el simulador antes de armarlo sobre la mesa:
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.
Impresión de las piezas del mecanismo
Con la electrónica funcionando, toca la parte mecánica: las piezas que acoplan el servo al gatillo del pulverizador se imprimen en 3D. El modelo original se descargaba de forma libre y gratuita; el paquete de fabricación de esta reedición está a diseñar (lo vas a encontrar en la ficha del proyecto cuando esté disponible).
Si querés modificar el modelo, sea cual sea el programa de diseño que uses, exportá las piezas en formato .stlFormato .stlFormato de archivo que contiene la forma de un objeto sólido 3D, sin color, texturas ni propiedades físicas. Es el más usado para intercambiar e imprimir modelos 3D; funciona como la 'exportación final' de un diseño, como un PDF de un documento de texto.. Ese es el formato que abre el software de la impresora para, desde ahí, generar el código GCódigo GConjunto de acciones que la impresora 3D (o cualquier máquina CNC) debe realizar para completar un trabajo. Se genera analizando un archivo STL, y es específico de cada modelo de impresora.: las instrucciones concretas de movimiento con las que la impresora convierte el modelo en la pieza física.
Ensamblaje del sistema mecánico con la parte electrónica
Último paso del nivel: montar las piezas impresas sobre el gatillo del pulverizador de modo que el brazo del servo, al girar a 90°, apriete el gatillo, y al volver a 0° lo suelte. El servo queda sujeto al soporte y conectado a la placa como en el paso 1.
Cuidado con el agua. Este es un proyecto de baja tensión, pero mezcla electrónica y líquido. El agua sale a baja presión y no debe tocar la placa, el servo, el sensor ni las conexiones: montá la electrónica del lado seco del mecanismo y orientá la boquilla hacia afuera, lejos de los cables.
Verificá
Con el programa por tiempo corriendo y el mecanismo montado, cada ciclo del servo aprieta y suelta el gatillo, y sale una pulverización. Si el gatillo no se aprieta del todo, revisá la sujeción del soporte y probá ajustar el ángulo de disparo.
Cierre del nivel
Al terminar este nivel, el pulverizador de las góndolas funciona solo: el servomotor —controlado con la librería de tu placa— aprieta y suelta el gatillo a intervalos de tiempo fijos, y las piezas impresas en 3D sostienen todo el mecanismo con la electrónica a salvo del agua. En el nivel avanzado el sistema va a dejar de pulverizar “a ciegas”: un sensor de movimiento va a detectar cuándo un cliente retira productos de la góndola, y recién entonces —y esperando un rato para no mojarlo— el pulverizador entrará en acción.
Evidencia de cierre
Al terminar este nivel, esto tiene que estar funcionando:
- El servomotor está conectado a la placa (señal, alimentación y tierra) y responde al código: al subir el programa, se mueve a la posición indicada.
- El programa mueve el servo de 0° (reposo) a 90° (disparo) y de vuelta, a intervalos de tiempo fijos, accionando el gatillo del pulverizador de forma automática.
- Las piezas del mecanismo están impresas y ensambladas sobre el gatillo del pulverizador, con la electrónica montada del lado seco, lejos del chorro de agua.
Pulverizador por movimiento: el sensor PIR
Situación problema
Para volver el sistema más eficiente y no desperdiciar agua, el dueño del supermercado pidió que el pulverizador se conecte a un sensor que detecte cuándo un cliente está sacando frutas o verduras de las góndolas. Así, a medida que los clientes retiran productos, el pulverizador se activa para rociar los que van quedando en la parte superior. Es importante también que el sistema espere un tiempo antes de activarse, para no rociar a los clientes con el líquido.
En esta instancia avanzada se propone sumar un sensor PIR (piroeléctrico) para detectar el movimiento de las manos de los clientes, y programar un temporizador que determine cuándo se acciona el servomotor.
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.
Verificá
Revisá la orientación de los tres pines contra el rotulado de tu módulo (no todos los
fabricantes usan el mismo orden): VCC a la alimentación, GND a tierra y la salida al pin
indicado en PIN_PIR. El servo queda conectado como en el nivel inicial.
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.
Para el aula
La calibración es el momento más experimental del nivel y conviene darle tiempo de juego: que cada grupo gire un trimmer por vez, anote qué cambió y lo cuente. Dos fenómenos que suelen desconcertar: el PIR necesita unos 30-60 segundos de “acomodamiento” al energizarse (lecturas erráticas al principio son normales), y el tiempo de disparo del propio módulo hace que el 1 se sostenga un rato aunque la persona ya se haya quedado quieta.
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.