Un dosificador de alimento impreso en 3D
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.
Imprimir las partes
El dosificador se fabrica con impresión 3D. Si querés modificar el modelo, sea cual sea el programa de modelado que uses, tenés que exportar 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.: es el formato que abre el software de impresión (el laminador o slicer) 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. que la impresora ejecuta capa por capa.
Armar el mecanismo
Con las piezas listas, armamos el mecanismo del dosificador. La idea es que el motor DC con reducciónMotor DCMotor eléctrico de dos terminales (+ y −), común en vehículos y ventiladores. Gira mientras recibe corriente y su velocidad depende de la potencia entregada. Requiere un circuito intermediario (driver) que le dé la potencia que la placa no puede entregar por sí sola. haga girar la parte móvil del dosificador (un tambor o tornillo con alimento): en cada giro cae una porción de comida a la pecera. El motor se aloja en el cuerpo impreso y se fija de modo que su eje mueva la pieza dosificadora.
La reducción del motor (su caja de engranajes) es importante acá: baja la velocidad y aumenta la fuerza, que es justo lo que necesita un mecanismo que empuja alimento, no algo que gire rápido.
Conectar el motor del dosificador a la placa
Acá aparece un componente nuevo. El motor no se puede conectar directo a un pin de la placa: un motor consume más corriente de la que un pin es capaz de entregar. Por eso usamos un ULN2003ULN2003Circuito integrado que actúa como driver de motores: convierte la señal de control de baja potencia de la placa (una salida digital) en la potencia necesaria para mover un motor DC. No invierte el giro: enciende y apaga el motor en un solo sentido., un circuito integrado que actúa de intermediario: recibe la señal débil del pin en su entrada IN1 y, con ella, deja pasar hacia el motor la corriente que necesita, tomada de una fuente aparte.
Lo usamos como un simple interruptor de motor: con el pin en alto (HIGH) el motor gira y dosifica; en bajo (LOW), se detiene. El cableado es: pin de la placa → IN1 del ULN2003, salida OUT1 → un borne del motor, el otro borne del motor → la fuente del motor, y la masa (GND) en común entre la placa, el ULN2003 y la fuente.
En el Arduino UNO, siguiendo el esquema original: el relé del aireador va al pin 2 y el
de la bomba al pin 3 (como en el nivel inicial), y la entrada IN1 del ULN2003 al pin
4 (la constante PIN_DOSIFICADOR del código).
En el ESP32, los relés del aireador y la bomba van a GPIO 25 y GPIO 26, y la entrada
IN1 del ULN2003 a GPIO 27 (la constante PIN_DOSIFICADOR). Recordá alimentar los
módulos relé con 5 V (VCC al 5V/VIN) y compartir GND; la señal la toman del GPIO de 3,3 V.
¡Atención! La advertencia de seguridad del nivel inicial sigue vigente: el aireador y la bomba son cargas que pueden ser de 220 V, con el relé fuera de la protoboard y las conexiones lejos y por encima del agua; la bomba nunca en seco. El motor del dosificador, en cambio, es de baja tensión y no maneja 220 V.
Verificá
Repasá el cableado contra el esquema: los dos relés en sus pines (2 y 3, o GPIO 25 y 26), el ULN2003 con su IN1 al pin del dosificador (4 o GPIO 27), el motor entre OUT1 y su fuente, y la masa común. Todavía no va a moverse nada: falta el programa.
Programar los tiempos del dosificador
Queremos que el dosificador se encienda 1 segundo por cada ciclo de 60 segundos y que se mantenga lo que ya programamos en el nivel inicial. Los tres regímenes quedan así:
- Aireador: 20 segundos encendido y 40 segundos apagado.
- Bomba: 5 segundos encendida y 55 segundos apagada.
- Dosificador: 1 segundo encendido y 59 segundos apagado.
Acá se ve la ventaja de haber resuelto el código sin bloqueos en el nivel inicial: como el programa decide el estado de cada actuador mirando el mismo cronómetro, sumar el dosificador es agregar una sola línea (¿en qué momento del ciclo tiene que estar encendido?), sin tocar la lógica del aireador ni de la bomba.
Ver el código completo · acuaponico-dosificador.ino
// Sistema acuapónico automatizado — nivel intermedio (dosificador de
// alimento). Se suma al aireador y la bomba un tercer actuador: un motor
// DC con reducción que hace girar un dosificador impreso en 3D para
// alimentar a los peces. Todo dentro del mismo ciclo de 60 s, resuelto con
// el mismo CRONÓMETRO no bloqueante del nivel inicial:
// - Aireador de la pecera : 20 s encendido / 40 s apagado.
// - Bomba de recirculación: 5 s encendida / 55 s apagada.
// - Dosificador (motor) : 1 s encendido / 59 s apagado.
//
// COMPONENTE NUEVO — ULN2003: el motor del dosificador NO puede conectarse
// directo a un pin del Arduino, porque un motor pide más corriente de la
// que un pin puede entregar. El ULN2003 es el "amplificador" intermedio
// (un arreglo de transistores Darlington): recibe la señal débil del pin
// y con ella deja pasar la corriente que el motor necesita desde una
// fuente aparte. Acá lo usamos como un simple INTERRUPTOR de motor
// UNIDIRECCIONAL (encendido/apagado): mientras el pin está en HIGH, el
// motor gira en un sentido y dosifica; en LOW, se detiene. Se cablea la
// entrada IN1 del ULN2003 al pin del Arduino, la salida OUT1 a un borne
// del motor, el otro borne del motor a la fuente, y la masa (GND) común.
//
// SEGURIDAD (220 V + agua): el aireador y la bomba son cargas de 220 V
// conmutadas por relé. En el aula se trabaja con BAJA TENSIÓN; la conexión
// real a 220 V queda reservada al docente o a una instalación supervisada,
// NUNCA sobre la protoboard, y con las conexiones eléctricas fuera y por
// encima del nivel del agua. La BOMBA NO DEBE FUNCIONAR EN SECO: se quema.
// (El motor del dosificador es de baja tensión y no maneja 220 V.)
//
// Plataforma: Arduino UNO.
// Conexión (contrato de la reedición): relé del aireador → pin 2, relé de
// la bomba → pin 3, entrada IN1 del ULN2003 (motor del dosificador) → pin 4.
//
// Basado en: Fragmento de código 3 (Nivel Intermedio) — Sistema Acuapónico
// Automatizado, Saberes Digitales (INET/EDUCAR 2019).
// Modernización: C++ idiomático con constantes nombradas en vez de mBlock3;
// aritmética de unsigned long en ms (el original llevaba la cuenta con un
// double de millis()/1000.0, con riesgo de desborde en la resta).
// Relés de las dos cargas de 220 V (ver advertencia de SEGURIDAD arriba).
const int PIN_RELE_AIREADOR = 2;
const int PIN_RELE_BOMBA = 3;
// Entrada de control del ULN2003 que mueve el motor del dosificador.
const int PIN_DOSIFICADOR = 4;
// Módulos relé activo-alto (HIGH = carga encendida). El ULN2003 también
// activa el motor con HIGH en su entrada, así que compartimos convención.
const int ENCENDIDO = HIGH;
const int APAGADO = LOW;
// Umbrales de encendido dentro del ciclo (los del ejemplo original). Los
// tres actuadores arrancan encendidos al comenzar el ciclo y se apagan al
// cruzar su umbral; a los 60 s el ciclo se reinicia.
const unsigned long AIREADOR_ON_MS = 20000UL; // aireador ON los primeros 20 s
const unsigned long BOMBA_ON_MS = 5000UL; // bomba ON los primeros 5 s
const unsigned long DOSIFICADOR_ON_MS = 1000UL; // dosificador ON el primer 1 s
const unsigned long CICLO_TOTAL_MS = 60000UL; // el ciclo dura 60 s
// Marca de tiempo (ms desde el arranque) en la que empezó el ciclo actual.
// Es nuestro "cronómetro": el tiempo transcurrido es millis() - inicioCiclo.
unsigned long inicioCiclo = 0;
void setup() {
pinMode(PIN_RELE_AIREADOR, OUTPUT);
pinMode(PIN_RELE_BOMBA, OUTPUT);
pinMode(PIN_DOSIFICADOR, OUTPUT);
// Estado inicial seguro: todo apagado hasta la primera vuelta del loop.
digitalWrite(PIN_RELE_AIREADOR, APAGADO);
digitalWrite(PIN_RELE_BOMBA, APAGADO);
digitalWrite(PIN_DOSIFICADOR, APAGADO);
inicioCiclo = millis();
}
void loop() {
// Tiempo transcurrido desde el inicio del ciclo. Con unsigned long, la
// resta funciona bien aun cuando millis() desborda (~cada 50 días).
unsigned long transcurrido = millis() - inicioCiclo;
// Cada actuador decide su estado según el cronómetro. Nada de delay():
// esta función entra y sale al instante, así que los tres se atienden
// "a la vez" (y queda tiempo de procesador para el IoT del ESP32).
digitalWrite(PIN_RELE_AIREADOR,
transcurrido < AIREADOR_ON_MS ? ENCENDIDO : APAGADO);
digitalWrite(PIN_RELE_BOMBA,
transcurrido < BOMBA_ON_MS ? ENCENDIDO : APAGADO);
digitalWrite(PIN_DOSIFICADOR,
transcurrido < DOSIFICADOR_ON_MS ? ENCENDIDO : APAGADO);
// Cumplidos los 60 s, reiniciamos el cronómetro y el ciclo vuelve a cero.
if (transcurrido >= CICLO_TOTAL_MS) {
inicioCiclo = millis();
}
} // Sistema acuapónico automatizado — nivel intermedio (dosificador de
// alimento). Se suma al aireador y la bomba un tercer actuador: un motor
// DC con reducción que mueve un dosificador impreso en 3D para alimentar
// a los peces. Todo dentro del mismo ciclo de 60 s, resuelto con el mismo
// CRONÓMETRO no bloqueante del nivel inicial:
// - Aireador de la pecera : 20 s encendido / 40 s apagado.
// - Bomba de recirculación: 5 s encendida / 55 s apagada.
// - Dosificador (motor) : 1 s encendido / 59 s apagado.
//
// COMPONENTE NUEVO — ULN2003: el motor del dosificador NO puede conectarse
// directo a un pin del ESP32, porque un motor pide más corriente de la que
// un pin puede entregar. El ULN2003 es el "amplificador" intermedio (un
// arreglo de transistores Darlington): recibe la señal débil del pin y con
// ella deja pasar la corriente que el motor necesita desde una fuente
// aparte. Acá lo usamos como interruptor de motor UNIDIRECCIONAL
// (encendido/apagado): con el pin en HIGH el motor gira y dosifica, en LOW
// se detiene. Cableado: pin del ESP32 → IN1 del ULN2003, OUT1 → un borne
// del motor, el otro borne del motor → fuente, y GND común.
//
// SEGURIDAD (220 V + agua): aireador y bomba son cargas de 220 V por relé.
// En el aula, BAJA TENSIÓN; los 220 V solo el docente / instalación
// supervisada, nunca sobre la protoboard, conexiones fuera y por encima
// del agua. La BOMBA NO DEBE FUNCIONAR EN SECO: se quema. (El motor del
// dosificador es de baja tensión.)
//
// Plataforma: ESP32 (DevKit v1).
// Conexión (contrato de la reedición): relé del aireador → GPIO 25, relé
// de la bomba → GPIO 26, entrada IN1 del ULN2003 (dosificador) → GPIO 27.
// NOTA ELÉCTRICA: los módulos relé se alimentan con 5 V (VCC al 5V/VIN),
// GND común, y la señal la toman del GPIO de 3,3 V. Para 220 V, usar
// módulos con optoacoplador.
//
// Basado en: Fragmento de código 3 (Nivel Intermedio) — Sistema Acuapónico
// Automatizado, Saberes Digitales (INET/EDUCAR 2019).
// Modernización: C++ idiomático en vez de mBlock3; portado del UNO
// (pines 2/3/4) al ESP32 (GPIO 25/26/27); aritmética de unsigned long en ms.
// Relés de las dos cargas de 220 V (ver advertencia de SEGURIDAD arriba).
const int PIN_RELE_AIREADOR = 25;
const int PIN_RELE_BOMBA = 26;
// Entrada de control del ULN2003 que mueve el motor del dosificador.
const int PIN_DOSIFICADOR = 27;
// Módulos relé activo-alto (HIGH = carga encendida). El ULN2003 también
// activa el motor con HIGH en su entrada, así que compartimos convención.
const int ENCENDIDO = HIGH;
const int APAGADO = LOW;
// Umbrales de encendido dentro del ciclo (los del ejemplo original). Los
// tres actuadores arrancan encendidos al comenzar el ciclo y se apagan al
// cruzar su umbral; a los 60 s el ciclo se reinicia.
const unsigned long AIREADOR_ON_MS = 20000UL; // aireador ON los primeros 20 s
const unsigned long BOMBA_ON_MS = 5000UL; // bomba ON los primeros 5 s
const unsigned long DOSIFICADOR_ON_MS = 1000UL; // dosificador ON el primer 1 s
const unsigned long CICLO_TOTAL_MS = 60000UL; // el ciclo dura 60 s
// Marca de tiempo (ms desde el arranque) en la que empezó el ciclo actual.
// Es nuestro "cronómetro": el tiempo transcurrido es millis() - inicioCiclo.
unsigned long inicioCiclo = 0;
void setup() {
pinMode(PIN_RELE_AIREADOR, OUTPUT);
pinMode(PIN_RELE_BOMBA, OUTPUT);
pinMode(PIN_DOSIFICADOR, OUTPUT);
// Estado inicial seguro: todo apagado hasta la primera vuelta del loop.
digitalWrite(PIN_RELE_AIREADOR, APAGADO);
digitalWrite(PIN_RELE_BOMBA, APAGADO);
digitalWrite(PIN_DOSIFICADOR, APAGADO);
inicioCiclo = millis();
}
void loop() {
// Tiempo transcurrido desde el inicio del ciclo. Con unsigned long, la
// resta funciona bien aun cuando millis() desborda (~cada 50 días).
unsigned long transcurrido = millis() - inicioCiclo;
// Cada actuador decide su estado según el cronómetro. Nada de delay():
// esta función entra y sale al instante, así que los tres se atienden
// "a la vez" (y queda tiempo de procesador para el IoT del ESP32).
digitalWrite(PIN_RELE_AIREADOR,
transcurrido < AIREADOR_ON_MS ? ENCENDIDO : APAGADO);
digitalWrite(PIN_RELE_BOMBA,
transcurrido < BOMBA_ON_MS ? ENCENDIDO : APAGADO);
digitalWrite(PIN_DOSIFICADOR,
transcurrido < DOSIFICADOR_ON_MS ? ENCENDIDO : APAGADO);
// Cumplidos los 60 s, reiniciamos el cronómetro y el ciclo vuelve a cero.
if (transcurrido >= CICLO_TOTAL_MS) {
inicioCiclo = millis();
}
} Podés ver el sistema completo funcionando —el aireador, la bomba y el dosificador en sus tiempos dentro del ciclo de 60 segundos— en el 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.
¿Cuánto alimento por día?
El dosificador tira una porción cada vez que gira, 1 vez por minuto. Calculen en el grupo: ¿cuántas porciones da en un día? Si eso es demasiado para sus peces, ¿qué conviene cambiar, el tiempo de encendido (1 s) o el tamaño del ciclo (60 s)? Prueben modificar la constante correspondiente y contrasten con lo que recomienda la ficha de alimentación de su especie (ese dato viene de Biología).
Para el aula
Buen momento para conectar con Biología: el régimen del dosificador (cuánto y cada cuánto) depende de la especie y la cantidad de peces, un dato que el proyecto electrónico recibe, no inventa. También conviene revisar que el mecanismo no se atore con el alimento húmedo: si el motor gira pero no cae comida, el problema es mecánico (la pieza), no del código.
Verificá
Con el programa cargado, observá el arranque del ciclo: el motor del dosificador gira apenas 1 segundo y se detiene, mientras el aireador y la bomba siguen sus tiempos de siempre. Si el motor no arranca, revisá la alimentación de su fuente y la masa común con la placa; si gira pero no dosifica, es cosa del mecanismo.
Cierre del nivel
Al terminar este nivel, el sistema ya se cuida solo también en la comida: además de recircular el agua y airear la pecera, un dosificador impreso en 3D y movido por un motor libera una porción de alimento una vez por minuto. En el camino apareció un componente clave —el ULN2003, que le da al motor la corriente que un pin no puede— y quedó claro por qué el código no bloqueante del nivel inicial se paga solo: sumar un tercer actuador fue trivial. En el nivel avanzado vamos a llevar todo esto a Internet: monitorear a distancia, desde un celular, si el aireador, la bomba y el dosificador están funcionando.
Evidencia de cierre
Al terminar este nivel, esto tiene que estar funcionando:
- Imprimiste en 3D las piezas del dosificador y armaste el mecanismo con el motor DC.
- El motor del dosificador está conectado a la placa a través del módulo ULN2003 (entrada IN1 al pin 4 en el UNO), con su fuente aparte y la masa en común.
- La placa suma el dosificador al ciclo de 60 s: se enciende 1 segundo y se apaga 59, sin alterar los tiempos del aireador y la bomba.
- Podés explicar por qué el motor no se conecta directo a un pin y qué hace el ULN2003 en el medio.