Controlar el llenado de un tanque
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.
Preparar el tanque
Para comenzar, es necesario conseguir un recipiente que cumpla la función del tanque. Este debe tener una tapa, un agujero en la parte superior para el ingreso del agua, y otro en la parte inferior donde se colocará la llave de paso que controlará la distribución del agua.
Instalar el sensor ultrasónico y conectar la electroválvula
En este proyecto la ubicación de los distintos elementos en el prototipo es fundamental para el buen funcionamiento del mismo. Por lo tanto, organizamos la disposición de todos los componentes antes de realizar la conexión a la placa de control. Esta placa puede recibir datos de un sensor, así como enviar datos a un actuador, por medio de sus pines analógicos y digitales.
Para controlar el ingreso de agua y evitar que el tanque rebalse, colocamos en su entrada una electroválvulaElectroválvulaActuador que permite o interrumpe el paso de un fluido. Se acciona a través de su propia alimentación, por lo que tiene únicamente dos pines: sus estados posibles son activada o no, y se puede controlar mediante una salida digital y un relé. (válvula controlada electrónicamente, del tipo de las que suelen encontrarse en los lavarropas). Esta se abrirá cuando queramos llenar el tanque y se cerrará cuando el agua haya alcanzado un nivel determinado por nosotros. El original de 2019 usaba una válvula de 220 V; en esta reedición usamos una de 12 V, que enseña exactamente lo mismo sin meter tensión de red en la maqueta (el desvío está documentado en la ficha del proyecto).
Sujetamos el sensor ultrasónicoSensor de distancia ultrasónicoSensor que mide distancias emitiendo un pulso de sonido ultrasónico y midiendo el tiempo hasta que el eco regresa tras rebotar en un obstáculo. Tiene cuatro pines: VCC y GND para la alimentación, Trigger para disparar el pulso y Echo para detectar su llegada. en la parte interior de la tapa del tanque. Es importante que este apunte de manera perpendicular al fondo del tanque, para que las paredes no interfieran en la medición. Además, hay que asegurarnos de que el sensor no se moje cuando ingresa el agua. El sensor medirá la distancia a la que se encuentra el agua y, en función de eso, se activará o no la electroválvula.
Fijate en el esquema la lógica de la medición: el sensor mira al agua desde arriba, así que a menor distancia medida, más lleno está el tanque. Esa inversión va a aparecer todo el tiempo en el código y conviene tenerla clara desde ahora.
Verificá
Con el tanque armado: el sensor quedó firme bajo la tapa, apuntando perpendicular al fondo (no inclinado hacia una pared), fuera del chorro de entrada de agua; y la electroválvula quedó instalada en la entrada, con sus mangueras ajustadas. Todavía no hay nada conectado a la placa: eso llega en el paso 4.
Establecer la altura de corte
Para evitar que el tanque rebalse, el agua no puede superar la altura de ingreso. Por lo tanto, debemos detener la entrada de agua antes de que se alcance dicho nivel. Para asegurarnos de que eso suceda, es recomendable que el tanque se deje de llenar cuando el agua esté a unos 5 o 10 cm del ingreso. Una vez determinado este nivel, hay que medir la distancia desde este punto hasta la tapa donde se encuentra el sensor, y establecer este valor como la distancia mínima de desactivación de la válvula.
Ese número es la altura de corte de tu maqueta y es el que vas a cargar en la constante
DISTANCIA_MINIMA_CM del programa del paso 5. La guía original usa 40 cm como ejemplo para
un tanque real; en un recipiente de aula el valor va a ser mucho menor, y por eso se mide,
no se copia.
El margen de seguridad
Discutan en el grupo: ¿por qué la guía recomienda cortar 5 a 10 cm antes del ingreso y no justo en el borde? Piensen qué pasa con el agua que sigue entrando mientras la válvula termina de cerrarse, y qué pasaría si una medición del sensor viniera con error. Anoten sus hipótesis: el programa del paso 5 tiene una constante pensada exactamente para uno de esos problemas.
Conectar sensor, válvula y relé a la placa
Una vez que tengamos ubicados los distintos elementos del sistema, conectaremos el sensor ultrasónico, la electroválvula y el reléReléDispositivo electromagnético que funciona como un interruptor controlado por un circuito eléctrico: un electroimán abre o cierra contactos de otros circuitos independientes. Permite controlar con bajo voltaje dispositivos que utilizan mayor voltaje. a la placa de control, como indica la figura.
¡Atención! Agua y electricidad no se llevan bien. Todas las conexiones eléctricas van fuera del tanque y por encima del nivel del agua, los cables entran al tanque solo donde es imprescindible (el sensor, bajo la tapa), y siempre que manipules el circuito hacelo con las manos secas y con la maqueta desenchufada. El original trabajaba directamente con 220 V; en esta reedición la válvula es de 12 V, pero los hábitos de seguridad se practican igual, porque son los que te protegen cuando la instalación es real.
La conexión tiene dos partes:
- El circuito de potencia (12 V): la fuente de 12 V, el relé y la electroválvula. Conectamos un cable de la fuente de 12 V a la bornera COM del relé, un segundo cable desde la bornera NO del relé hasta un borne de la electroválvula, y un tercer cable que vuelve del otro borne de la electroválvula al otro polo de la fuente. Así, la válvula solo recibe energía cuando el relé cierra el contacto.
- El circuito de control (5 V): el sensor y la señal del relé hacia la placa, con cables dupont macho-hembra.
En el Arduino UNO, seguimos el esquema original: conectamos los pines Vcc, GND,
Trig y Echo del sensor a los pines 5V, GND, 8 y 9 de la placa,
respectivamente (en el código, los pines 8 y 9 son las constantes PIN_TRIG1 y
PIN_ECHO1). Del módulo relé, el pin + va a 5V, el pin - a GND y el pin
S al pin digital 4 (la constante PIN_RELE_VALVULA).
En el ESP32 el armado es el mismo, pero los pines se llaman GPIO y usamos otros números
(los GPIO 0, 2, 12 y 15 se reservan porque intervienen en el arranque de la placa). Los
números exactos están en las constantes PIN_TRIG1, PIN_ECHO1 y PIN_RELE_VALVULA al
comienzo del código del paso siguiente: conectá cada cable al GPIO que indica su constante.
Dos cuidados propios de esta placa: el pin Echo del HC-SR04 entrega 5 V, así que
interponé un divisor de dos resistencias antes del GPIO; y alimentá el módulo relé desde el
pin VIN (5 V del USB) si no conmuta con la señal de 3,3 V.
Para el aula
Este es el paso donde el docente marca la cancha en seguridad, aunque la válvula sea de 12 V: conexiones lejos y por encima del agua, manos secas para tocar el circuito, y la maqueta se modifica siempre desenchufada. Si más adelante se quisiera mostrar la versión de 220 V del original (válvula de lavarropas real), esa instalación es EXCLUSIVA del docente, supervisada y sin participación de estudiantes, tal como quedó registrado en los desvíos de la ficha. Vale también repetir la advertencia del original: las conexiones de potencia del relé nunca van sobre una protoboard.
Verificá
Antes de energizar, repasá cable por cable contra el esquema: los cuatro pines del sensor (Vcc, GND, Trig, Echo), los tres del relé (+, -, S) y el lazo de potencia fuente → COM → NO → válvula → fuente. La válvula todavía no va a moverse: falta el programa.
Programar el funcionamiento del dispositivo
La programación la realizaremos 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: setup(), que se ejecuta una sola vez al inicializarse
el dispositivo, y loop(), que se ejecuta repetidamente después. Los comentarios (todo lo
que sigue a //) no tienen efecto en el programa: están para que el código sea más fácil
de interpretar.
La lógica que queremos programar es la que definimos en los pasos anteriores: medir la distancia entre el sensor y la superficie del agua y, mientras esa distancia sea mayor que la altura de corte, mantener abierta la válvula para que se cargue el tanque; cuando el agua llega a la altura de corte, cerrarla.
Para medir, el programa dispara desde el pin Trig un pulso de sonido ultrasónico y mide
en el pin Echo cuánto tarda en volver el rebote: como el sonido recorre ida y vuelta
unos 58 microsegundos por cada centímetro, dividiendo el tiempo por ese valor se obtiene la
distancia. Esa cuenta vive en la función medirDistanciaCm() del código, comentada línea
por línea.
Ver el código completo · control-llenado.ino
// Control de llenado de un tanque: el sensor ultrasónico HC-SR04 mide la
// distancia entre la tapa y la superficie del agua; cuando el agua llega
// a la altura de corte, un relé cierra la electroválvula de entrada.
// Menor distancia = tanque más lleno: el sensor mira al agua desde arriba.
//
// SEGURIDAD: agua y electricidad no se llevan bien. Todas las conexiones
// eléctricas van fuera y POR ENCIMA del nivel del agua, y el sensor no se
// debe mojar. La práctica se realiza con una electroválvula de baja
// tensión (12 V); la conexión a 220 V de la guía original queda reservada
// al docente o a una instalación supervisada, y nunca sobre la protoboard
// (desvío pedagógico acordado).
//
// Plataforma: Arduino UNO.
// Conexión (la del esquema original): TRIG del sensor → pin 8, ECHO → pin 9,
// entrada "S" del módulo relé de la válvula → pin 4.
//
// Basado en: Fragmento de código 1 — Sistema de Tanques,
// Saberes Digitales (INET/EDUCAR 2019)
// Modernización: (1) se reemplazó el código generado por mBlock3 (_delay,
// _loop, pinMode dentro de la función de medición) por C++ idiomático con
// constantes nombradas y pinMode en setup(). (2) Se agregó una histéresis
// de 5 cm: el original abría y cerraba la válvula en el mismo valor exacto
// (40 cm), y el ruido de medición del HC-SR04 (±1 cm típico) haría
// traquetear el relé justo en el borde.
// Sensor ultrasónico del tanque (TRIG dispara el pulso, ECHO lo recibe).
const int PIN_TRIG1 = 8;
const int PIN_ECHO1 = 9;
// Relé que controla la electroválvula de entrada de agua.
const int PIN_RELE_VALVULA = 4;
// Módulo relé activo-alto, como en el original (HIGH = válvula abierta).
// Si tu módulo es activo-bajo, invertí solo estas dos constantes.
const int RELE_ENCENDIDO = HIGH; // válvula abierta: entra agua
const int RELE_APAGADO = LOW; // válvula cerrada
// Altura de corte del original: si el agua queda a menos de 40 cm del
// sensor, el tanque está lleno. Este valor NO se inventa: sale de medir
// en tu maqueta la distancia entre el sensor y el nivel máximo deseado
// (5 a 10 cm por debajo del ingreso de agua, dice la guía).
const float DISTANCIA_MINIMA_CM = 40.0;
// Colchón de la histéresis: la válvula cierra a 40 cm pero recién vuelve
// a abrir cuando el agua baja más allá de 45 cm. Sin este margen, una
// medición que oscile entre 39.5 y 40.5 abriría y cerraría el relé sin
// parar (modernización, ver encabezado).
const float MARGEN_HISTERESIS_CM = 5.0;
// El original medía una vez por segundo (_delay(1)).
const unsigned long INTERVALO_MEDICION_MS = 1000;
// El eco tarda 58 microsegundos por cada centímetro de distancia (ida y
// vuelta del sonido a ~343 m/s). El timeout evita quedar esperando para
// siempre un eco que no llega.
const float MICROSEGUNDOS_POR_CM = 58.0;
const unsigned long TIMEOUT_ECO_US = 30000;
// Mide la distancia en cm entre el sensor y la superficie del agua.
// Si en 30 ms no llega el eco (sensor desconectado o fuera de rango),
// pulseIn devuelve 0 y la distancia da 0: el programa lo interpreta como
// "tanque lleno" y cierra la válvula. Es una falla SEGURA: ante la duda,
// que no entre agua.
float medirDistanciaCm(int pinTrig, int pinEcho) {
digitalWrite(pinTrig, LOW);
delayMicroseconds(2);
digitalWrite(pinTrig, HIGH); // pulso de disparo de 10 microsegundos
delayMicroseconds(10);
digitalWrite(pinTrig, LOW);
return pulseIn(pinEcho, HIGH, TIMEOUT_ECO_US) / MICROSEGUNDOS_POR_CM;
}
void setup() {
pinMode(PIN_TRIG1, OUTPUT);
pinMode(PIN_ECHO1, INPUT);
pinMode(PIN_RELE_VALVULA, OUTPUT);
// Arrancamos con la válvula cerrada hasta la primera medición:
// el estado seguro de un tanque es "no entra agua".
digitalWrite(PIN_RELE_VALVULA, RELE_APAGADO);
}
void loop() {
float distancia = medirDistanciaCm(PIN_TRIG1, PIN_ECHO1);
if (distancia < DISTANCIA_MINIMA_CM) {
// El agua llegó a la altura de corte: cerrar la válvula.
digitalWrite(PIN_RELE_VALVULA, RELE_APAGADO);
} else if (distancia > DISTANCIA_MINIMA_CM + MARGEN_HISTERESIS_CM) {
// Hay lugar de sobra: abrir la válvula para cargar el tanque.
digitalWrite(PIN_RELE_VALVULA, RELE_ENCENDIDO);
}
// Entre 40 y 45 cm no escribimos nada: el relé conserva su último
// estado. Esa franja "muerta" es la histéresis que evita el traqueteo.
delay(INTERVALO_MEDICION_MS);
} // Control de llenado de un tanque: el sensor ultrasónico HC-SR04 mide la
// distancia entre la tapa y la superficie del agua; cuando el agua llega
// a la altura de corte, un relé cierra la electroválvula de entrada.
// Menor distancia = tanque más lleno: el sensor mira al agua desde arriba.
//
// SEGURIDAD: agua y electricidad no se llevan bien. Todas las conexiones
// eléctricas van fuera y POR ENCIMA del nivel del agua, y el sensor no se
// debe mojar. La práctica se realiza con una electroválvula de baja
// tensión (12 V); la conexión a 220 V de la guía original queda reservada
// al docente o a una instalación supervisada, y nunca sobre la protoboard
// (desvío pedagógico acordado).
//
// Plataforma: ESP32 (DevKit v1).
// Conexión: TRIG → GPIO 5, ECHO → GPIO 18 (¡leer nota!), relé de la
// válvula → GPIO 25.
// NOTA ELÉCTRICA (¡importante!): el ESP32 trabaja a 3,3 V. El HC-SR04
// clásico se alimenta con 5 V y su pin ECHO devuelve el eco a 5 V: eso
// dañaría el GPIO. Es OBLIGATORIO un divisor de tensión en ECHO
// (ECHO —1 kΩ— GPIO 18 —2 kΩ— GND), que baja los 5 V a ~3,3 V. Es la
// misma idea del divisor del LDR: dos resistencias que reparten la
// tensión. TRIG no necesita nada: los 3,3 V del GPIO alcanzan para
// dispararlo. Alternativa sin divisor: el modelo HC-SR04P, que puede
// alimentarse directamente con 3,3 V.
//
// Basado en: Fragmento de código 1 — Sistema de Tanques,
// Saberes Digitales (INET/EDUCAR 2019)
// Modernización: (1) se reemplazó el código generado por mBlock3 (_delay,
// _loop, pinMode dentro de la función de medición) por C++ idiomático con
// constantes nombradas y pinMode en setup(); se portó a ESP32 (el original
// usaba los pines 8/9/4 del UNO). (2) Se agregó una histéresis de 5 cm:
// el original abría y cerraba la válvula en el mismo valor exacto (40 cm),
// y el ruido de medición del HC-SR04 (±1 cm típico) haría traquetear el
// relé justo en el borde.
// Sensor ultrasónico del tanque (TRIG dispara el pulso, ECHO lo recibe).
const int PIN_TRIG1 = 5;
const int PIN_ECHO1 = 18; // con divisor de tensión 1 kΩ / 2 kΩ (ver nota)
// Relé que controla la electroválvula de entrada de agua.
const int PIN_RELE_VALVULA = 25;
// Módulo relé activo-alto, como en el original (HIGH = válvula abierta).
// Si tu módulo es activo-bajo, invertí solo estas dos constantes.
const int RELE_ENCENDIDO = HIGH; // válvula abierta: entra agua
const int RELE_APAGADO = LOW; // válvula cerrada
// Altura de corte del original: si el agua queda a menos de 40 cm del
// sensor, el tanque está lleno. Este valor NO se inventa: sale de medir
// en tu maqueta la distancia entre el sensor y el nivel máximo deseado
// (5 a 10 cm por debajo del ingreso de agua, dice la guía).
const float DISTANCIA_MINIMA_CM = 40.0;
// Colchón de la histéresis: la válvula cierra a 40 cm pero recién vuelve
// a abrir cuando el agua baja más allá de 45 cm. Sin este margen, una
// medición que oscile entre 39.5 y 40.5 abriría y cerraría el relé sin
// parar (modernización, ver encabezado).
const float MARGEN_HISTERESIS_CM = 5.0;
// El original medía una vez por segundo (_delay(1)).
const unsigned long INTERVALO_MEDICION_MS = 1000;
// El eco tarda 58 microsegundos por cada centímetro de distancia (ida y
// vuelta del sonido a ~343 m/s). El timeout evita quedar esperando para
// siempre un eco que no llega.
const float MICROSEGUNDOS_POR_CM = 58.0;
const unsigned long TIMEOUT_ECO_US = 30000;
// Mide la distancia en cm entre el sensor y la superficie del agua.
// Si en 30 ms no llega el eco (sensor desconectado o fuera de rango),
// pulseIn devuelve 0 y la distancia da 0: el programa lo interpreta como
// "tanque lleno" y cierra la válvula. Es una falla SEGURA: ante la duda,
// que no entre agua.
float medirDistanciaCm(int pinTrig, int pinEcho) {
digitalWrite(pinTrig, LOW);
delayMicroseconds(2);
digitalWrite(pinTrig, HIGH); // pulso de disparo de 10 microsegundos
delayMicroseconds(10);
digitalWrite(pinTrig, LOW);
return pulseIn(pinEcho, HIGH, TIMEOUT_ECO_US) / MICROSEGUNDOS_POR_CM;
}
void setup() {
pinMode(PIN_TRIG1, OUTPUT);
pinMode(PIN_ECHO1, INPUT);
pinMode(PIN_RELE_VALVULA, OUTPUT);
// Arrancamos con la válvula cerrada hasta la primera medición:
// el estado seguro de un tanque es "no entra agua".
digitalWrite(PIN_RELE_VALVULA, RELE_APAGADO);
}
void loop() {
float distancia = medirDistanciaCm(PIN_TRIG1, PIN_ECHO1);
if (distancia < DISTANCIA_MINIMA_CM) {
// El agua llegó a la altura de corte: cerrar la válvula.
digitalWrite(PIN_RELE_VALVULA, RELE_APAGADO);
} else if (distancia > DISTANCIA_MINIMA_CM + MARGEN_HISTERESIS_CM) {
// Hay lugar de sobra: abrir la válvula para cargar el tanque.
digitalWrite(PIN_RELE_VALVULA, RELE_ENCENDIDO);
}
// Entre 40 y 45 cm no escribimos nada: el relé conserva su último
// estado. Esa franja "muerta" es la histéresis que evita el traqueteo.
delay(INTERVALO_MEDICION_MS);
} Antes de cargarlo, acordate de reemplazar el valor de DISTANCIA_MINIMA_CM por la altura
de corte que mediste en el paso 3.
Hay un detalle del código que la guía original no tenía: la constante
MARGEN_HISTERESIS_CM. El original abría y cerraba la válvula comparando contra el mismo
valor exacto (40 cm), pero las mediciones del sensor tienen un pequeño ruido (±1 cm es
típico): justo en el borde, el relé quedaría abriendo y cerrando sin parar. Con el margen,
la válvula corta al llegar a la altura de corte y recién reabre cuando el agua bajó 5 cm
más: esa franja “muerta” es la histéresis, y es la respuesta al desafío del paso 3.
Podés ver el comportamiento completo —el tanque llenándose, el sensor midiendo y la válvula cortando en la altura de corte— en el simulador, antes de tocar el agua real:
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.
Para el aula
El material original de 2019 enseñaba este paso con bloques en mBlock3, hoy discontinuado. La función didáctica de los bloques —bajar la barrera de entrada— la cumple acá la combinación de un código corto con constantes nombradas, comentado línea por línea, y el simulador en el navegador. Sugerencia de lectura en el aula: taparle el “porqué” a cada línea y pedir a los grupos que lo reconstruyan; la estructura si/si no del control de la válvula es una oportunidad ideal para el primer condicional serio de la colección.
Verificá
En el Arduino IDE, apretá el botón de verificar (el tilde ✓). Si abajo aparece “Compilación completada” sin mensajes en rojo, tu programa está bien escrito. Si aparece un error, revisá los punto y coma al final de cada línea y que las llaves abran y cierren.
Subir el código a la placa
Para subir el código de nuestro programa 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 nuestro código, veremos el mensaje de carga completada en la barra inferior del IDE.
Verificá
Podés probar el sistema en seco, sin agua: con el tanque vacío (distancia grande), el LED del módulo relé tiene que indicar la válvula abierta. Acercale al sensor una superficie plana (un cuaderno) a menos de la altura de corte: el relé tiene que conmutar con un clic y cerrar la válvula; alejala más allá del margen de histéresis y tiene que reabrir. Recién después probá con agua de verdad: la válvula tiene que cortar cuando el nivel llega a la altura de corte que mediste.
Cierre del nivel
Al terminar este nivel, el tanque de Camilo se llena solo y sin rebalsar: el sensor ultrasónico mide desde la tapa la distancia hasta el agua, y la placa cierra la electroválvula cuando se alcanza la altura de corte que vos mismo mediste, con el margen de histéresis evitando el traqueteo del relé. Además, ya sabés subir programas desde el Arduino IDE 2.x, una herramienta que te va a acompañar el resto del proyecto. En el nivel intermedio el sistema crece a la escala de un edificio: un segundo tanque, una bomba sumergible y una regla nueva —la bomba jamás trabaja en seco—.
Evidencia de cierre
Al terminar este nivel, esto tiene que estar funcionando:
- El tanque tiene el sensor ultrasónico fijado bajo la tapa, apuntando perpendicular al fondo y protegido del agua, y la electroválvula instalada en su entrada.
- Mediste la altura de corte de tu tanque y ese valor está cargado en la constante DISTANCIA_MINIMA_CM del programa.
- La placa cierra la válvula cuando el agua llega a la altura de corte y la reabre cuando el nivel baja más allá del margen de histéresis.
- Sabés subir un programa desde el Arduino IDE 2.x: elegir la placa, elegir el puerto y verificar que el código quedó cargado.