Saltar al contenido
Volver a la ficha del proyecto

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.

Arduino UNO R3 ESP32 DevKit
Dificultad:
Nivel educativo:
Secundario. Ciclo Básico.
Electrónica Programación Mecánica

Saberes Digitales

INET / EDUCAR — Ministerio de Educación, Cultura, Ciencia y Tecnología de la Nación Argentina

2019

Contenido del manual

  1. 01 Materiales y equipamiento
  2. 02 Pulverizador automático por tiempo Nivel inicial
  3. 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
Foto de Servomotor 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
Foto de Sensor PIR de movimiento 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
Foto de Protoboard Protoboard 1 Todas
Foto de Cables dupont macho-macho Cable dupont macho-hembra 20 Todas
Foto de Cables dupont macho-macho Cable dupont macho-macho 20 Todas
Foto de Arduino UNO R3 Arduino UNO R3 1 Arduino UNO R3
Foto de Cable USB tipo B Cable USB tipo B 1 Arduino UNO R3
Foto de Fuente de alimentación 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
Foto de Placa ESP32 DevKit Placa ESP32 DevKit v1 1 ESP32 DevKit
Foto de Cable micro USB Cable micro USB (con línea de datos) 1 ESP32 DevKit
Foto de Servomotor 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

Arduino UNO Conexionado en protoboard · Pulverizador automático: el servo del gatillo se acciona cuando el PIR detecta movimiento.

Deslizá horizontalmente para ver el plano completo

Arduino UNO
Servo del gatillo (SG90)
SG90
VCCseñalGND
Sensor PIR (HC-SR501)
VCCOUTGND
ESP32 DevKit v1 Conexionado en protoboard · Pulverizador automático: el servo del gatillo se acciona cuando el PIR detecta movimiento.

Deslizá horizontalmente para ver el plano completo

ESP32 DevKit v1
Servo del gatillo (SG90)
SG90
VCCseñalGND
Sensor PIR (HC-SR501)
VCCOUTGND
Arduino UNOConexionado en protoboard
Conexiones · Arduino UNO. Convención de colores: alimentación VCC = rojo, GND = negro; señal del servo = azul; salida OUT del sensor PIR = amarillo. En el ESP32 el servo se alimenta desde una fuente externa de 5 V (no desde el pin 3V3), con GND compartido.
Desde Hacia Color de cable
Arduino UNO · 5VBus + de la protoboardrojo
Arduino UNO · GNDBus − de la protoboardnegro
Servo del gatillo · VCCBus + de la protoboardrojo
Servo del gatillo · GNDBus − de la protoboardnegro
Servo del gatillo · señalArduino UNO · 3azul
Sensor PIR · VCCBus + de la protoboardrojo
Sensor PIR · GNDBus − de la protoboardnegro
Sensor PIR · OUTArduino UNO · 4amarillo
ESP32 DevKit v1Conexionado en protoboard
Conexiones · ESP32 DevKit v1. Convención de colores: alimentación VCC = rojo, GND = negro; señal del servo = azul; salida OUT del sensor PIR = amarillo. En el ESP32 el servo se alimenta desde una fuente externa de 5 V (no desde el pin 3V3), con GND compartido.
Desde Hacia Color de cable
Fuente externa 5 VBus + de la protoboardrojo
ESP32 DevKit v1 · GNDBus − de la protoboardnegro
Servo del gatillo · VCCBus + de la protoboardrojo
Servo del gatillo · GNDBus − de la protoboardnegro
Servo del gatillo · señalESP32 DevKit v1 · GPIO13azul
Sensor PIR · VCCBus + de la protoboardrojo
Sensor PIR · GNDBus − de la protoboardnegro
Sensor PIR · OUTESP32 DevKit v1 · GPIO27amarillo
Nivel inicial

Pulverizador automático por tiempo

Conectar el servomotor

Empezamos conectando el servomotor, 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.

Esquema de conexión: placa Arduino UNO con el cable de señal del servo (amarillo) al pin 3, y la alimentación del servo (rojo y negro) a los pines 5V y GND a través de la protoboard.
Conexión del servomotor a la placa: la señal al pin indicado por PIN_SERVO y la alimentación a 5V y GND (figura original del proyecto).

En el Arduino 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 ESP32, 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:

  1. Conectar la placa a la computadora con el cable USB.
  2. Chequear que en el selector de placa del Arduino IDE esté seleccionada la placa correcta.
  3. Seleccionar el puerto al que está conectada la placa.
  4. 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 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.ino Arduino UNO
// 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.ino ESP32
// 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);
}
Pulverizador por tiempo: el servo aprieta el gatillo (90°), lo mantiene un segundo, lo suelta (0°) y espera 5 segundos antes del próximo disparo.

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 .stl. Ese es el formato que abre el software de la impresora para, desde ahí, generar el código G: 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.

Vista del mecanismo impreso en 3D montado sobre la botella del pulverizador: el servo, sujeto al soporte, acciona el gatillo mediante un brazo articulado; los cables de señal y alimentación bajan hacia la placa Arduino.
El sistema ensamblado: el servo apoyado en el soporte impreso acciona el gatillo del pulverizador, con la electrónica del lado seco (figura original del proyecto).

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.

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.
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.