Saltar al contenido
Nivel intermedio

Un dosificador de alimento impreso en 3D

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 .stl: es el formato que abre el software de impresión (el laminador o slicer) para, desde ahí, generar el código G que la impresora ejecuta capa por capa.

Render 3D de una de las piezas del dosificador: una caja rectangular alargada, con un orificio circular en la cara superior (por donde entra el alimento) y una abertura circular grande en un extremo (donde va el motor), con perforaciones para los tornillos de sujeción.
Una de las piezas del dosificador para imprimir en 3D: el cuerpo que aloja el alimento y el motor (modelo original del proyecto).

Armar el mecanismo

Con las piezas listas, armamos el mecanismo del dosificador. La idea es que el motor DC con reducción 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 ULN2003, 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.

Esquema de conexión completo: una placa Arduino UNO conectada a dos módulos relé (rotulados aireador y bomba, cada uno con su carga y un enchufe de 220 V) y a un módulo ULN2003 que maneja un motor DC. Las señales de los relés y del ULN2003 van a pines digitales de la placa; el motor se conecta a las salidas del ULN2003.
Sistema completo del nivel intermedio (figura original del proyecto): los relés del aireador y la bomba más el ULN2003 que mueve el motor del dosificador. La señal del ULN2003 va al pin 4 del Arduino.

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.

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
acuaponico-dosificador.ino Arduino UNO
// 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();
  }
}
acuaponico-dosificador.ino ESP32
// 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();
  }
}
El sistema con dosificador: el mismo control no bloqueante del nivel inicial suma el motor (vía ULN2003), encendido 1 s por ciclo.

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.

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.