Dispositivo IoT Inteligente DIY: Construcción con ATmega32U4, ESP8266 y Sensores
Componentes y Suministros
| Microchip Technology ATmega32U4 | × | 1 |
| Espressif ESP8266 ESP-12E | × | 1 |
| Cristal 16 MHz | × | 1 |
| MOSFET Canal N de Potencia | × | 4 |
| Módulo Regulador de Voltaje Digilent | × | 1 |
| Sensor Temperatura y Humedad DHT11 (4 pines) | × | 1 |
| Termómetro Digital DS18B20 Maxim Integrated | × | 1 |
| MikroE Water Detect Click | × | 1 |
| Pantalla LCD Arduino | × | 1 |
| Fotorresistencia (LDR) | × | 1 |
Herramientas y Máquinas Necesarias
- Impresora 3D (genérica)
- Cortadora láser (genérica)
Aplicaciones y Servicios Online
- Autodesk Fusion 360
- Arduino IDE
Sobre el Proyecto
Introducción
Me inspiré mucho tras ver la charla TED sobre Agricultura Digital, impartida por el director de la Iniciativa de Agricultura Abierta del MIT, Caleb Harper, titulada: Esta Computadora Cultivará tu Comida en el Futuro. La pregunta más importante que me inspiró fue: ¿Y si pudiéramos cultivar alimentos deliciosos y ricos en nutrientes, en interiores, en cualquier parte del mundo? ¡Y aquí nació la idea!
Lo que intento hacer es una especie de caja o incubadora, capaz de crear condiciones climáticas ideales para el crecimiento, proporcionando exactamente la cantidad de luz y nutrientes que una planta necesita. Quiero construir un emulador de luz solar, sistema de riego y controlador climático todo en un diseño elegante y moderno.

Planeo lograr los resultados implementando la siguiente tecnología:
- Luz LED de cultivo: la clorofila responde principalmente a dos longitudes de onda: 450 nm y 650 nm. El sistema LED que planeo usar combinará luces rojas y azules para proporcionar la mezcla perfecta para crecimiento vegetativo y floración.
- Atomizador Ultrasónico (generador de niebla): quiero usar un nuevo método de riego, aeroponía (FogPonics), que riega las plantas mediante niebla con fertilizante.
- Dosificación Automática de Nutrientes: sistema que dosifica nutrientes exactamente cuando las plantas los necesitan.
- Sistema de Sensado de Agua: sensores pH y TDS (Sólidos Disueltos Totales) para mantener pH equilibrado en el depósito y saber cuándo dosificar nutrientes.
- Sistema de Cambio de Agua: conexión para cambios automáticos de agua, fácil y controlado con un botón.
- Sistema de Control de Aire: control preciso de temperatura y humedad dentro del sistema, hasta un grado. Usa sensor DHT22/DHT11 para recibir datos y ventilador con bobina para regular.
- App Móvil: quiero construir una app por primera vez. Debe incluir info en tiempo real sobre pH, temperatura, humedad, nutrientes, ppm, etc. y gráficos temporales para seguir estadísticas y compartir progreso en redes sociales. Alertas inteligentes cuando el sistema necesite intervención. No solo recibir datos, sino también configurar condiciones climáticas desde el móvil.
Desafortunadamente, no soy el primero con esta idea, pero la mejor forma de tener una idea creativa es mejorar las existentes.
Hay varios proyectos similares en el mercado; a pesar de ventajas individuales, tienen desventajas: demasiado espacio, demasiado pequeños, muy caros, cultivan solo un cultivo a la vez. Investigué mucho, analicé fortalezas y debilidades, y considerando la respuesta del mercado, quiero crear un nuevo sistema open source avanzado que reduzca desventajas e implemente solo las mejores características.
Muy ambicioso, ¿verdad? Pero intentémoslo.
Experimentos
¡Tratar con plantas consume mucho tiempo! Suelen requerir semanas o meses para crecer, y debo estar preparado.
Como ya sé qué quiero construir para mi proyecto final, debo ocuparme de ello con antelación y no dejar todo para el final. Por eso empezaré a testar y experimentar cuanto antes.
Lo primero que quiero averiguar es si cultivar plantas con niebla rica en nutrientes y luces LED de cultivo es mejor que sistema convencional en suelo y luz solar natural. En teoría debería ser así, pero no creo nada hasta probarlo.
Decidí iniciar mi propio experimento, que requiere tiempo, dividiendo plantas en varios grupos:
- (Suelo + Luz Solar): condiciones naturales, plantadas en suelo, en alféizar.
- (Niebla + Luz Solar): en contenedor con niebla rica en nutrientes, mismo alféizar.
- (Suelo + LED Cultivo): en suelo, pero con luz LED artificial en vez de solar.
- (Niebla + LED Cultivo): grupo HÉROE. Mi sistema futuro implementará estas dos características; espero que esta combinación dé mejores resultados.
En el supermercado alemán Kaufland, sección plantas, compré semillas de hierbas mixtas. Serán mis bebés de prueba :p


Primera vez que planto algo :D no me juzguen si hice algo mal.
Revisé varios tutoriales y aprendí que primero hay que germinar las semillas. Usé un contenedor plástico, puse semillas y las cubrí con papel de cocina. En esta etapa necesitan casi 100% humedad, así que rocié agua sobre el papel y cubrí el contenedor con bolsa plástica para que no se evapore.

Dejé las semillas 1,5 semanas y al abrir el contenedor ¡me sorprendí!

¡Casi todas germinaron! Fui feliz como un niño.
Luego seleccioné las mejores plantitas: las de tallo más grueso y que se veían más grandes y sanas.

En el tutorial que seguía (YouTuber), recomendaban plantar en cualquier medio hasta que dieran "segundas hojas". En Amazon pedí pellets de fibra de coco. Son orgánicos, propiedades similares al suelo, y al regarlos se expanden 6 veces.
También compré una caja con separadores para plantar. Costó 2 euros y organizó todo. Puse pellets en separadores, los hidraté, planté las plantitas en el centro y cubrí la caja con plástico transparente que venía en el kit.

Cerré la caja y la dejé una semana. Al abrirla, ¡sorpresa! ¡Realmente crecieron! Nunca imaginé que podría cultivar plantas, apenas me cuido yo :D

Tras una semana, la diferencia es notable. Al ver primeras raíces, las pasé a suelo y bolas de arcilla, y empecé a experimentar con niebla.


Durante la semana de Diseño Asistido por Computadora, diseñé los vasos de red para colocar las plantas.

Compré en tienda local un contenedor plástico con dimensiones aproximadas y marqué los agujeros a taladrar.

Aquí mi sistema de prueba montado, con plantas en pellets de coco, bolas de arcilla y suelo.

Para ser honesto, los resultados podrían ser mejores :D Solo unas pocas plantas sobrevivieron en mi sistema de niebla. Mi teoría: el medio de cultivo. La niebla no es lo suficientemente fuerte para mantener húmedas las bolas de arcilla ni el suelo.
Vacaciones de Pascua
Durante Pascua no hice nada y como el labo estaba cerrado, todo el sistema estuvo apagado. Mis plantas murieron.
Con mente fresca, decidí hacer otro sistema, pero esta vez con otro medio de cultivo basado en observaciones previas.
El medio elegido: Lana de Roca (Rock Wool). Lo compré en IKEA local. También compré semillas de su sección.

Puse las nuevas semillas en lana de roca para germinar una semana.

Tras una semana revisé mi caja: un tipo de semillas tuvo éxito, otro falló. Por falta de tiempo, continué con las que germinaron.

Mientras, monté otro sistema de niebla e intenté aumentar su tiempo de funcionamiento para ver si puedo germinar semillas usando SOLO NIEBLA.
Seguiré experimentando con distintos parámetros y ajustes, ¡a ver hasta dónde llego!
Diseño y Producción Electrónica
Antes de diseñar la placa final, me senté a dibujar en papel todas las características y requisitos que la placa debe implementar y cumplir. También conté cuántos pines se usarían para estimar mejor y decidir el microprocesador final.
Boceto de lo que debe llevar la placa:

La elección final fue entre satshakit de Daniele Ingrassia y FABLEO de Jonathan Grinham.
satshakit es una placa 100% compatible con Arduino IDE y librerías, fabricable y open source, versión mejorada de Fabkit.
Principales Mejoras y Características sobre Fabkit
- 16 MHz en vez de 8 MHz
- Cristal en vez de resonador
- Cuesta menos (7-9€ vs 13€)
- 100% compatible con Arduino IDE por defecto (satshakit se reconoce como Arduino UNO)
- ADC6/7 conectados en vez de no conectados
- Más espacio para soldar fácilmente
Por otro lado, FabLeo tiene características muy similares, ¡más USB hardware! Como ya usé ATmega328p antes, quise probar algo nuevo y usé el diseño FabLeo como punto de partida.
Mi biblia y guía #1 fue el pinout del ATmega32u4.

Para diseñar la placa usé EAGLE (Easily Applicable Graphical Layout Editor): captura esquemática, diseño PCB, autorrouter y CAM. Popular entre aficionados por licencia freeware y librerías de componentes disponibles online.
Eagle usa dos ventanas simultáneas:
- Esquemático (.sch): componentes lógicos
- Diseño Placa (.brd): placa real que fresamos
Tras instalar EAGLE, lo primero: Crear Nuevo Esquemático. Un esquemático en electrónica es un dibujo que representa un circuito. Usa símbolos para componentes reales. El símbolo más básico es un conductor (trazas), mostrado como línea. Si los cables se conectan en el diagrama, se muestra un punto en la intersección.
Para colocar componentes en el esquemático, hay que descargar y usar Librerías especiales. Eagle tiene muchas librerías integradas. La red fab también mantiene una librería actualizada: fab.lbr.
Para instalar la librería, en EAGLE ve a barra superior Library > use y abre el archivo .lbr descargado.
Ahora puedo ir a Add component y seleccionando la librería, elijo el componente a colocar.
Cuando todos los componentes están en el esquemático, hay que conectar cada uno a los pines del microprocesador. En menú izquierdo de EAGLE, pulso Net, que permite dibujar líneas verdes y conectar pines. Importante: iniciar la conexión desde la rayita en el pin (marcada en la imagen).

Para evitar múltiples conexiones, uso Etiquetas (Labels). En menú izquierdo, pulso Add Label y la añado al final de mi línea de conexión. Si hago clic derecho y elijo name, puedo atribuir a la etiqueta el mismo nombre que usé para el pin del microprocesador, ¡conectándolos así!
Si hice todo bien, aparece mensaje: ¿Seguro que quieres conectar tu etiqueta (N$10) con GND?

En esta etapa, lo importante en el esquemático es la Lógica de conexiones, no la estética. Tras colocar todos los componentes y conectarlos lógicamente, así se ve:

Añadí los pinheaders AVRISP en orden para el conector. Estos pines se usan para programar la placa.

Esquemático del circuito USB junto con el cristal:

También añadí circuito Regulador de Voltaje que alimenta toda la placa transformando 12V entrada a 5V.

Una característica importante son los circuitos MOSFET, añadí 4: 3 conectados directamente a entrada (12V) y uno a regulador step-up. El último alimenta la niebla que trabaja a 24V.

Tras revisar todas las conexiones, paso a Diseño de Placa (Board Layout). En menú superior, pulso Generate/Switch to Board.
Primero aumento resolución de Cuadrícula (Grid). Voy a View > Grid y cambio valores a 0.01. Esto me permite ser más preciso trazando rutas.

Sorprendentemente, el ruteo de la placa más compleja que he hecho fue también el más rápido. Me enorgullece. La experiencia haciendo placas mejoró la velocidad. Tras terminar el ruteo, así se ve la bestia:

Para esta placa uso el truco que aprendí antes: dibujo un polígono alrededor de mis componentes, y con clic derecho en la línea del polígono, cambio el nombre a GND. Esto rellena toda el área interna del polígono y la convierte en GND.
Ahorra mucho tiempo, espacio y esfuerzo.
Tras revisar todo, Exporto mi archivo como imagen .png.
En la ventana emergente, aumento resolución a 1500 dpi, marco monochrome y modo window.

Para editar la imagen .png uso GIMP. Abro imagen, uso herramienta rectangular select, selecciono dejando margen en todos los lados. File > Copy área seleccionada. Para continuar, File > Create from Clipboard.
Esto es lo que obtengo tras ediciones:

Esta imagen está lista para imprimir, la llamo Inside_Cut.
Preparo proceso para Outside Cut:

Como mi placa es doble cara, debo fresar dos piezas y pegarlas. Lo único a tener en cuenta: la parte inferior debe ser espejada horizontalmente.

Parte inferior Inside_Cut:

Parte inferior Outside_Cut:
Ahora paso a la fresadora CNC. Uso FabModules para convertir archivos .png a Gcodes para máquina Roland.
Al introducir la IP en el navegador, aparece primera interfaz:

Tras pulsar botón gris input format, aparece menú para cargar imagen .png. Subo primera imagen (grabado interior). Tras ello, aparece previsualización y otros parámetros.
En lado derecho, muchos parámetros de entrada. Para mover máquina, hay que introducir:

mod_lp.py /dev/usb/lp0en campo send commandhostname_of_your_machineen campo server (solo dirección sin http ni /)
Para mover máquina introduzco coordenadas x, y, z en campos respectivos. Antes de mover, asegurar que parámetro zjog siempre esté a 0, aunque cambie automáticamente. Pulso botón move to xyz0.
* Pequeño truco de vida: usar multímetro y comprobar si hay conexión entre herramienta y superficie. Como herramienta para grabar PCB se sugiere diámetro 0.2 mm o menos; para cortar, 1 mm.

Mis ajustes finales:

Para corte exterior, ajustes iguales excepto valor eje Z, al cambiar herramienta 0.2mm por 1mm:

Repito mismo proceso para Parte Inferior fresando Inside y Outside:


Resultado final parte Superior:

Parte Inferior:

¡Ahora Soldemos esto!
Para asegurar que soldé todo correctamente, tras cada componente soldado usé multímetro para comprobar conductividad entre componente y trazas.
Animación corta del proceso:

Al enchufar la PCB para comprobar, noté un error. Por experiencia, sé que era un cortocircuito, porque el ordenador desconectaba el Arduino cada vez que conectaba VCC y GND. Mi suposición: en algún punto VCC y GND están conectados; con multímetro confirmé que tenía razón.
Era tarde y me cabreé mucho; me tomó una hora bajo microscopio encontrar el error. Aquí está:


Lo arreglé rascando con cuchilla y aumentando el aislamiento.
Otra cosa: colocar el Regulador Step-Up en la cara posterior de mi placa.


Medí dimensiones de antemano y diseñé agujeros pre-taladrados para fijarlo con pinheaders. Pero antes de soldarlo en la cara posterior, debo calibrarlo.
La idea: al alimentar la placa con 12V, el step-up debe dar 24V necesarios para el Atomizador Ultrasónico, conectado al circuito MOSFET.
Usé fuente de banco con 12V fijos para medir voltaje salida con multímetro.

Tras ajustar salida a 24V (mi caso), puedo soldarlo en la cara posterior.
También en la cara posterior coloqué la placa WiFi que hice durante la semana de Redes y Comunicaciones.
¡Aquí está LA BESTIA:


Foto HÉROE para quienes piensen que fue fácil y todo fue suave :D

Descargar Archivos
- Esquemático GIY (.sch)
- Layout GIY (.brd)
- Placa#1 Corte Interno (.png)
- Placa#1 Corte Externo (.png)
- Placa#2 Corte Interno (.png)
- Placa#2 Corte Externo (.png)
Cableado y Programación Embebida (Dispositivos I/O)
Para programar mi placa usé Arduino IDE. Conecto Arduino al hub USB, en menú tools selecciono placa correcta (Arduino Leonardo) y puerto, voy a File > examples y abro sketch Arduino as ISP. Subo código.

Tras ver done uploading, desconecto Arduino del PC. Siguiente paso: conectar mi placa PCB a Arduino con cables. Esquema de conexión:
- SCLK: Reloj Serie (salida master) → Arduino Pin 13
- MOSI: Master Output Slave Input → Arduino Pin 11
- MISO: Master Input Slave Output → Arduino Pin 12
- VCC: Voltaje positivo → Arduino VCC
- GND: Tierra → Arduino GND
- RST: → Arduino Pin 10

Conecto Arduino al USB. En Tools selecciono placa correcta, Arduino as ISP programmer, verifico parámetros y pulso Burn Bootloader.
¡Veo Done Uploading! Buena señal.
Para testar la placa, subo ejemplo básico Blink:
¡Me encanta ese BLINK :D! Ahora vayamos a sensores.
Primer sensor: DHT11 - Sensor Temperatura y Humedad

Estos sensores son básicos y lentos, pero geniales para aficionados que quieren registrar datos básicos. Están formados por sensor capacitivo de humedad y termistor. Un chip básico interno hace conversión analógico-digital y emite señal digital con temperatura y humedad. La señal digital es fácil de leer con cualquier microcontrolador.
Características:
- Ultra bajo coste
- 3-5V alimentación y I/O
- 2.5mA máx. durante conversión
- Buenos para 20-80% humedad con 5% precisión
- Buenos para 0-50°C temperatura ±2°C precisión
- Máx. 1 Hz tasa muestreo (una vez por segundo)
- Tamaño 15.5mm x 12mm x 5.5mm
- 4 pines con espaciado 0.1"
Cableado fácil: VCC, GND y cualquier Pin Digital. En mi caso diseñé la conexión de antemano.
Para testear, subo sketch simple. Incluye librería DHT.h
// Ejemplo Sensores Temperatura y Humedad DHT11
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
dht.begin();
}
void loop() {
float h = dht.readHumidity();
float t = dht.readTemperature();
Serial.print("Temperature = ");
Serial.println(t, 2);
Serial.print("Humidity = ");
Serial.println(h, 2);
delay(2000);
}
Al abrir Monitor Serie, obtengo esto:

Otro sensor: DS18B20 - Sensor Temperatura Digital One Wire

DS18B20 es sensor digital 1-Wire de Maxim IC. Reporta grados Celsius con precisión 9-12 bits, de -55 a 125°C (±0.5). Cada sensor tiene número de serie único de 64 bits, permitiendo gran cantidad de sensores en un bus de datos.
Es uno de los sensores digitales más simples de conectar. Aparte de alimentación y tierra, tiene un solo pin de señal digital que conectaré al pin digital que diseñé de antemano. Requiere resistencia pull-up 4.7k entre pin señal y alimentación, que olvidé poner en mi PCB. Por eso la soldaré manualmente directo a cables del sensor.
Antes de empezar, descargo librerías: OneWire.h y DallasTemperature.h
// Incluir librerías
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 3
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void setup(void) {
Serial.begin(9600);
sensors.begin();
}
void loop(void) {
sensors.requestTemperatures();
Serial.print("Temperature is: ");
Serial.print(sensors.getTempCByIndex(0));
delay(1000);
}
Lo gracioso: tras programar exitosamente el sensor, ¡dejó de funcionar mientras integraba todos los sensores! Perdí mucho tiempo averiguando por qué, pero por tiempo limitado decidí usar otro DS18B20 del stock del FabLab e impermeabilizarlo yo mismo.

Tomé el sensor, usé datasheet para soldar cables correctamente y aislarlos con termorretráctil.

Supongo que tienes idea de cómo voy a impermeabilizarlo :D ¡Mamá, soy ingeniero!
¡Dicho y HECHO!

Sé cómo se ve :D pero os aseguro, es solo un sensor impermeabilizado a mano. Lo importante: funciona y no gotea sumergido en agua.
Siguiente: LDR = Resistencia Dependiente de Luz

LDR es componente pasivo, básicamente una resistencia cuyo valor varía según intensidad lumínica. Resistencia muy alta en oscuridad (~1MΩ), pero con luz cae a pocos KΩ (10-20kΩ @ 10 lux, 2-4kΩ @ 100 lux) según modelo.
El LDR entrega voltaje analógico cuando se conecta a Vcc (5V), que varía en magnitud proporcionalmente a la intensidad lumínica. Mayor intensidad = mayor voltaje. Al dar voltaje analógico, se conecta a pin analógico Arduino. El ADC integrado convierte voltaje (0-5V) en valor digital (0-1023). Con luz suficiente, valores leídos estarán en rango 800-1023.
Código para testear sensor:
int sensorPin = A0;
int sensorValue = 0;
void setup(void) {
Serial.begin(9600);
}
void loop(void) {
sensorValue = analogRead(sensorPin);
Serial.print("LDR Value = ");
Serial.print(sensorValue);
if (sensorValue < 100) Serial.println(" (Dark)");
else if (sensorValue < 200) Serial.println(" (Dim)");
else if (sensorValue < 500) Serial.println(" (Light)");
else if (sensorValue < 800) Serial.println(" (Bright)");
else Serial.println(" (Very bright)");
delay(3000);
}
Siguiente: Sensor Nivel de Agua
Quería un sensor de nivel de agua para recibir alarma cuando el contenedor esté vacío y sea hora de añadir agua. Como no lo pensé antes y no teníamos en stock, decidí hacer mi propio sensor de agua.

Decidí usar materiales disponibles: Sensor Humedad Suelo. El principio básico del sensor de nivel de agua es medir conductividad eléctrica, igual que sensor humedad suelo. Pensé que si puedo calibrarlo para cumplir mis requisitos, puedo usar sensor humedad como sensor nivel de agua. En principio es sensor analógico, datos 0-1024, el resto es matemáticas.
Pero la realidad es distinta. Cuando sensor no toca agua, valor analógico es 0; al sumergir solo la punta, sube a 800. Usé este sketch para leer valores:
void setup() { Serial.begin(9600); }
void loop() { Serial.println(analogRead(A4)); delay(100); }
Tras leer valores, calibré sensor para dar tres respuestas: VACÍO (valor 0), BAJO (valores ~800), LLENO (valores >900).
Pantalla LCD Gráfica

Como los displays LCD suelen usar muchos pines, busqué forma de conectar pantalla 128×64 de otra manera, ¡Y LA ENCONTRÉ! Esta forma permite usar solo 3 Pines Digitales en la placa, genial porque puedo necesitar el resto para otras cosas y no crea lío de cables. Pre-organicé los pines para el LCD en mi PCB, así conecté todo:

Tras conectar LCD, ¡a programarlo!
Primero, descargar librería U8glib. Otro punto importante: pines declarados en código. Los que usé: U8GLIB_ST7920_128X64 u8g(4, 12, 6, U8G_PIN_NONE)
Usando ejemplo "HELLO WORLD" de la librería, creé este código de prueba:
#include "U8glib.h"
U8GLIB_ST7920_128X64 u8g(4, 12, 6, U8G_PIN_NONE);
void draw(void) {
u8g.setFont(u8g_font_unifont);
u8g.setPrintPos(0, 20);
u8g.print("GIY Project v1.0!");
}
void setup(void) {
// u8g.setRot180(); // voltear pantalla si requerido
}
void loop(void) {
u8g.firstPage();
do { draw(); } while( u8g.nextPage() );
delay(500);
}
Resultado:

Una idea genial: mostrar el logo FabLab unos segundos cada vez que se enciende el display. Me llevó tiempo, pero lo logré. Para mostrarlo en LCD gráfico, necesité imagen en formato (.bmp) y mostrarla como bitmap.
Primero descargué logo FabLab de internet como (.png), reduje tamaño significativamente para que quepa en mi pequeño LCD. Usé servicio online: ENLACE.
Configuraciones usadas:

Paso siguiente: convertir mi imagen pequeña a formato (.bmp). Usé servicio online: ENLACE.
Ahora, con mi archivo (.bmp), para meterlo en código debo convertirlo a array HEX. Usé herramienta LCD Assistant. Para cargar imagen: File > Load Image. Previsualización debe abrirse, asegurar tamaño correcto: 128 píxeles ancho, 64 píxeles alto. También orientación Byte: Horizontal y endianness: Little.

File > Save output para generar archivo texto temporal. Abro ese archivo para ver mi nuevo array.

Sensor pH

Admito que este es el sensor más tramposo de todos. Es difícil encontrar info sobre el sensor que uso (logo ph sensor v1.1), así que haré descripción detallada.
La sonda es como una (pequeña) pila al colocarse en líquido. Según pH emite voltaje positivo o negativo de unos milivoltios. Este valor es demasiado pequeño y otras características como impedancia lo hacen inutilizable directamente con Arduino, por eso necesitas un "op amp". La placa op amp convierte los milivoltios de la sonda a algo aceptable para Arduino (positivo entre 0 y 5V).
Hay 3 soluciones tampón comunes para medición pH: pH 4.01, pH 6.86 y pH 9.18 (existen 7.0 y 10.0). Sugiero polvo en vez de líquido: más barato, caduca más tarde y no se contamina (vs frasco). Lee instrucciones pero normalmente: contenido de bolsa en 250ml agua y remueves. Puedes usar cualquier agua con pH medio (6-8) porque el polvo satura el agua al pH correcto. Yo uso agua grifo (pH 7.4) y no vi diferencia con agua destilada/desmineralizada. Los tampones no son estables en el tiempo: no puedes guardar la solución semanas o meses.
Hablemos del sensor que uso:
- Pin To: Debería ser temperatura pero no logro que funcione
- Pin Po: Señal analógica de entrada
- Pin Do: Límite ajustable High/Low 3.3V
- Pin G/GND: Tierra de la sonda. Útil cuando tierra no es la misma que Arduino. En algunas circunstancias el voltaje de tierra del líquido a medir puede ser diferente.
- Pin G/GND: Tierra de alimentación (directo de la placa).
- Pin V+/VCC: Alimentación entrada 5V DC (directo de la placa).
- Potenciómetro azul (cerca de BNC): offset pH.
- Potenciómetro azul (cerca de pines): ajuste límite.
Calibremos el sensor. Hay 2 parámetros: valor "offset" y valor "step".
El offset es el desplazamiento de todos los valores pH a un rango de voltaje específico. Si pH 7 da 2.2V y pH 8 da 2.1V, un desplazamiento de +0.3V mueve pH 7 a 2.5V y pH 8 a 2.4V. Puede hacerse en la placa o via software, pero es más fácil en la placa porque es independiente de la sonda y requiere menos programación.
Conecta GND (ambos) y Vcc a Arduino GND y 5V. Quita la sonda y haz cortocircuito entre el agujero BNC pequeño y la parte externa del BNC. Pon voltímetro (o Arduino) para medir voltaje entre GND y Po. Ajusta potenciómetro (cerca BNC) hasta que salida sea 2.5V. Ahora pH 7 tiene valor exacto 2.5V (511 con analogRead) porque la sonda emitirá 0 milivoltios.

Para calibrar steps necesito una o más soluciones tampón según rango y precisión requeridos. Idealmente saber rango de medida del sistema. Uso agua entre pH 5 y 7, elijo tampón 4.01 (y 6.86 para verificar). Si sueles medir entre pH 8 y 10 elige 9.18 (eventualmente 6.86 también).
Conecto sonda (limpia) y la pongo en tampón, dejo estabilizar 1 minuto. Sé que es estable cuando sube y baja (3.04, 3.05, 3.03, 3.04). Anoto valor voltímetro (o Arduino), en mi ejemplo 3.05V.
¡Eso es todo! Ahora puedo usarlo con el código abajo.
int ph_pin = A7; // Pin conectado a Po
void setup() { Serial.begin(9600); }
void loop() {
int measure = analogRead(ph_pin);
Serial.print("Measure: "); Serial.print(measure);
double voltage = 5 / 1024.0 * measure;
Serial.print("\tVoltage: "); Serial.print(voltage, 3);
// PH_step = (voltage@PH7 - voltage@PH4) / (PH7 - PH4)
// PH_probe = PH7 - ((voltage@PH7 - voltage@probe) / PH_step)
float Po = 7 + ((2.5 - voltage) / 0.18);
Serial.print("\tPH: "); Serial.print(Po, 3);
Serial.println("");
delay(2000);
}
El cálculo PH_step es simple. Diferencia entre dos voltajes conocidos: en mi ejemplo 2.5V@pH7 y 3.05V@pH4.01 = -0.55V. Es el rango de voltaje equivalente al rango pH 7 a 4.01 = 2.99 unidades pH. Pequeña división voltaje/unidades pH da voltios por pH (0.1839... en mi caso).
PH_probe se calcula tomando voltaje conocido pH 7 (2.5V) y añadiendo PH_step para igualar voltaje de la sonda. Significa que pH 8 tiene valor 2.5V + 0.1839; pH 9 = 2.5V + 0.1839 + 0.1839 = 2.87V.
Sin magia, SOLO MATEMÁTICAS :D
Salida MOSFET:
Conecté tira LED RGB y Atomizador Ultrasónico a salidas de circuitos MOSFET, controlados por pines digitales. Para luces LED, en setup puse digitalWrite(LED, HIGH); así el LED se enciende siempre que el sistema está alimentado. Para generador de niebla, hice función If según valor nivel agua. Si hay agua, niebla ON; si no, VACÍO, niebla OFF.
Ahora ¡Juntemos todo!
Aquí mi código final:
#include "dht.h"
#include "U8glib.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#define DHT11_PIN 2
#define ONE_WIRE_BUS 3
#define WATER_LEVEL A4
#define LDR_PIN A3
#define PH_PIN A5
#define GROW_LIGHT 10
#define FOG_PUMP 13
int waterLevel;
int LightLevel;
int pH;
dht DHT;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature waterTemp(&oneWire);
U8GLIB_ST7920_128X64 u8g(4, 12, 6, U8G_PIN_NONE);
const unsigned char logo [] PROGMEM = {
0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFE, 0x00, 0x03, 0xC0, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xF8, 0x00, 0x07, 0xE0, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xF0, 0x00, 0x1F, 0xF8, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xE0, 0x00, 0x3F, 0xFE, 0x00, 0x07, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xC0, 0x00, 0x18, 0x1F, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x80, 0x00, 0x00, 0x03, 0xC0, 0x01, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFE, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFC, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFC, 0x03, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF8, 0x07, 0xE0, 0x00, 0x00, 0x1F, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFC, 0x1F, 0xF0, 0x00, 0x00, 0x1F, 0xF0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0x3F, 0xF0, 0x00, 0x00, 0x1F, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE0, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE0, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xFF, 0xFF, 0xC0, 0x07, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xFE, 0x1F, 0xFF, 0xFF, 0xF0, 0x3C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xF8, 0x03, 0xFF, 0xFF, 0xC0, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xF0, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xF0, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xE0, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xE0, 0x00, 0x3F, 0xFC, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xE0, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xE0, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xE0, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xE0, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xE0, 0x00, 0x0F, 0xF0, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xE0, 0x00, 0x07, 0xF0, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0xF0, 0x00, 0x07, 0xF0, 0x00, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0xF0, 0x00, 0x07, 0xF0, 0x00, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0xF8, 0x00, 0x07, 0xF0, 0x00, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0xF8, 0x00, 0x07, 0xF0, 0x00, 0x1F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE0, 0xFC, 0x00, 0x07, 0xF0, 0x00, 0x1F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE0, 0xFE, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0x3E, 0x00, 0x0F, 0xF0, 0x00, 0x7C, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0x1E, 0x00, 0x1F, 0xF8, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF8, 0x06, 0x00, 0x1F, 0xFC, 0x01, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFC, 0x00, 0x00, 0x7F, 0xFF, 0x0F, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x80, 0x00, 0x7F, 0xFF, 0xC0, 0x01, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0x80, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xE0, 0x00, 0x7F, 0xFE, 0x00, 0x07, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xF0, 0x00, 0x1F, 0xF8, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xF8, 0x00, 0x0F, 0xF0, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFC, 0x00, 0x03, 0xC0, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFD, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
bool first;
float hum = 0.0;
double T = 0.0;
void dht_test(float * humPerc);
void setup(void) {
waterTemp.begin();
pinMode(GROW_LIGHT, OUTPUT);
pinMode(FOG_PUMP, OUTPUT);
digitalWrite(GROW_LIGHT, HIGH);
first = true;
if (u8g.getMode() == U8G_MODE_R3G3B2) u8g.setColorIndex(255);
else if (u8g.getMode() == U8G_MODE_GRAY2BIT) u8g.setColorIndex(3);
else if (u8g.getMode() == U8G_MODE_BW) u8g.setColorIndex(1);
else if (u8g.getMode() == U8G_MODE_HICOLOR) u8g.setHiColorByRGB(255,255,255);
u8g.firstPage();
do { u8g.drawBitmapP(32, 0, 16, 64, logo); } while(u8g.nextPage());
dht_test(&hum);
}
void RefreshDisplay(float * humPerc, double *T, int *WL, int *LL, int *pH_value) {
u8g.setFont(u8g_font_fub11);
u8g.setFontRefHeightExtendedText();
u8g.setDefaultForegroundColor();
u8g.setFontPosTop();
u8g.drawStr(4, 0, "Hum%");
u8g.setPrintPos(68, 0);
u8g.print(*humPerc);
u8g.drawStr(4, 15, "Temp");
u8g.setPrintPos(68, 15);
u8g.print(*T);
u8g.drawStr(4, 30, "Wlvl");
if (*WL == 0) {
u8g.drawStr(68, 30, "EMPTY!");
digitalWrite(FOG_PUMP, LOW);
} else {
if (*WL < 800) u8g.drawStr(68, 30, "LOW");
else {
digitalWrite(FOG_PUMP, HIGH);
u8g.drawStr(68, 30, "HIGH");
}
}
if (*LL < 100) u8g.drawStr(68, 45, "Dark");
else if (*LL < 200) u8g.drawStr(68, 45, "Dim");
else if (*LL < 500) u8g.drawStr(68, 45, "Light");
else if (*LL < 800) u8g.drawStr(68, 45, "Bright");
else u8g.drawStr(68, 45, "2Bright");
double voltage = 5.0 / 1024.0 * (*pH_value);
float Po = 7 + ((2.5 - voltage) / 0.18);
u8g.drawStr(4, 45, "pH");
u8g.setPrintPos(28, 45);
u8g.print(Po);
}
void loop(void) {
waterTemp.requestTemperatures();
T = waterTemp.getTempCByIndex(0);
waterLevel = analogRead(WATER_LEVEL);
LightLevel = analogRead(LDR_PIN);
pH = analogRead(PH_PIN);
char status;
int chk = DHT.read11(DHT11_PIN);
hum = DHT.humidity;
dht_test(&hum);
if(first) { first = false; }
else {
u8g.firstPage();
do { RefreshDisplay(&hum, &T, &waterLevel, &LightLevel, &pH); } while(u8g.nextPage());
}
}
void dht_test(float * humPerc) {
delay(1000);
}
Descargar Archivos
- Código Final GIY (.ino)
Diseño 3D e Impresión 3D
Para mi sistema final usé mucho diseño 3D e impresión 3D. Usé dos impresoras distintas y jugué con ajustes hasta conseguir resultado deseado.
Para diseño 3D usé Fusion 360, mi CAD favorito. No entraré en detalles de cómo crear formas simples y extruir objetos; todo esto está en mi semana de Diseño Asistido por Computadora y semana de Escaneo e Impresión 3D.

La tarea principal: diseñar la apariencia física de mi sistema. El reto: ¡quería que se viera SEXY!
La estética era criterio muy importante, igual que funcionalidad. El sistema debe ser ensamblable, lo que lo hace más desafiante. También quise integrar habilidades aprendidas: impresión 3D, fresado CNC, corte láser, etc.
Antes de diseñar en digital, hice boceto simple en papel:




Diseño 3D final:

Mi sexy sistema :D
Primero diseñé el contenedor de agua:

Incorpora varias características. Hay espacio suficiente para que crezcan las plantas, y en el medio hice un agujero para colocar el Atomizador Ultrasónico. Lo hice porque quería nivelar el generador de niebla con el contenedor. El nivel de agua debe estar 2cm por encima del generador, así que toda el agua a nivel del generador no se usa (desperdicio). Si coloco el generador por debajo del nivel del contenedor, tengo nivel cero de agua exactamente donde debe estar: cero para el contenedor = 2cm sobre el generador. Así se usa toda el agua.
También consideré la altura del contenedor. Todas las dimensiones se midieron durante la etapa experimental.
Como ves, hice un agujero en la pared para pasar cables de sensores en el agua hacia la sección electrónica. En el frontal, hice ranura para acoplar display gráfico. También diseñé asas para quitar fácilmente el contenedor cuando sea necesario.

Desde esta perspectiva ves la sección electrónica. Ahora está abierta, pero también diseñé tapa para cerrarla. Dentro, diseñé agujero para acceder a alimentación y programar la placa.

En la parte inferior diseñé deslizadores que se acoplan al resto del sistema, facilitando quitar el contenedor y fijándolo en su sitio.
¡Ahora ¡A Imprimir!

Orgullosamente anuncio que la impresora que usaré es BigRep 3D Printer, solo disponible en nuestro FabLab Kamp-Lintfort. Capacidad de un metro cúbico, mayor volumen FFF para uso profesional e industrial.
Software de laminado: Simplify3D, uno de los más avanzados, con muchas configuraciones y opciones.

No creo que haya forma correcta o incorrecta de imprimir; solo hay que jugar con ajustes hasta encontrar mejores opciones para el objeto específico.
Como la impresora es nueva, no hay muchos test previos. Tuve que experimentar con ajustes, probar, probar y volver a probar.
Muestro ajustes para mi impresión del contenedor de agua, algunos son intuitivos.

Elijo Tool1 porque BigRep tiene dos boquillas con dos filamentos distintos; debo especificar cuál usar, diámetro de boquilla y resto de ajustes.
Capa (Layer):

Adiciones (Additions):

Relleno (Infill):

Soportes (Support):

Temperatura:

Enfriamiento (Cooling):

Otros (Other):

Avanzado (Advanced):

Estos son los cambios que hice; el resto dejé por defecto.
Pulso Prepare to Print. El software genera las trayectorias; aquí comprobamos si todo está bien antes de enviar .gcode a la máquina.


Breve sobre ajustes de impresora: usé Temperatura Boquilla = 205°C, Temperatura Cama = 70°C. Tras posicionar ejes X, Y, Z y verificar ajustes, ¡lancé el trabajo!
Así se ve el modelo en bruto:

Al quitar soportes y limpiar, me di cuenta: ¡esto es un GRAN dolor de CULO :D
Como notarán, mis ajustes no son perfectos; el contenedor tiene agujeros grandes cerca de bordes. Ya tenía en mente impermeabilizarlo de todos modos, verán cómo en sección Moldeo y Fundición.
Siguiente pieza impresa en 3D: Maceta de Red (Net Pot). Vaso diseñado para sostener semillas en medio de cultivo. Más detalles de primera versión en mi semana de Diseño Asistido por Computadora.
Esta vez mejoro diseño basado en observaciones de etapa experimental. Principal diferencia: tamaño del espacio vacío, aumentado mucho para dar acceso más fácil a la niebla y paso a raíces.
Modifiqué diseño anterior y añadí una cosa más:

Hice un ligero redondeo (fillet) en parte superior para transición más suave. Añadí una bola en la base y usé comando Move para meterla un poco dentro, dejando 2-3mm de estructura en la base.

Tras usar substracción booleana o función Combine, consigo esta bonita curvatura en la base.

¡A imprimirlo!
Impresora 3D usada: Ultimaker 2+. Para laminar uso software muy bueno, interfaz fácil y funcional. Material: filamento PLA

Tras importar archivo .stl, estos son mis ajustes:


¡Aquí mi pequeño ejército :D

Del diseño final del sistema, decidí también imprimir en 3D la parte inferior. Es pieza grande, usaré BigRep también.

No diría que hay nada nuevo; usé mismos ajustes que para contenedor de agua, y más o menos lo mismo.
Previsualización de la impresión:

Otra cosa impresa en 3D: esquinas redondeadas en parte superior del sistema. Usé Ultimaker con estos ajustes:


El truco: lograr máxima suavidad en superficie; creo que conseguí buen resultado:

Descargar Archivos
- Diseño Sistema GIY (.f3d)
- Diseño Net Pot (.f3d)
Diseño 2D y Corte Láser
Usé corte láser para cortar piezas acrílicas que cubrirán todo el interior del sistema, dándole acabado terminado.
En realidad no diseñé las piezas de nuevo, solo exporté los bocetos ya creados en Fusion 360 como archivos .dxf. Tras exportar, edité el diseño antes de importar a la cortadora láser.

Así se ve el boceto en Fusion360:

Parece un gran lío, pero lo bueno es que todo es paramétrico. Se ve desordenado porque tuve que alinear todo en posición correcta y mantener paramétrico por si hay cambios luego.
Así se ve el boceto final en Rhino antes de cortar láser:

Decidí usar acrílico verde porque da aspecto orgánico y combina bien con plantas verdes.
Para cubierta frontal y trasera, usé color blanco. Es cuestión de gusto, así lo veo y me gusta.
Frontal y trasera son muy similares, mismas dimensiones, excepto cortes interiores. La frontal tiene agujero para display LCD:

Para la trasera, quiero agujero para acceder a alimentar y programar la placa:

Otra pieza cortada láser es la superior. Usé acrílico transparente para que pase la luz. También diseñé cortes adicionales para reducir peso y dar más espacio a la luz. Medí ancho de tiras LED RGB y las acoplaré de forma que haya espacio para luz solar y artificial.

Terminé diseño, ¡¡A Cortar Láser!

Cortadora láser en FabLab: Epilog Fusion 60W, CO2, área trabajo 1016 x 711 mm. Corta y graba madera, cartón, acrílico u otros plásticos de ingeniería.
Como usé mismo material para todas las piezas, plexiglass 5mm, usé mismos ajustes para todas.

Descargar Archivos
- Cubierta Frontal / Trasera (.dxf)
- Soporta Plantas (.dxf)
- Soporta Luz LED (.dxf)
Fresado CNC
Como quise integrar en mi sistema todas las habilidades y técnicas aprendidas, también tengo una pieza de estructura para fresar CNC. No la diseñé de nuevo, exporté archivo .dxf desde boceto Fusion360.
Para cortar mi diseño usaré el monstruo CNC grande.
Un CNC (control numérico por computadora) es máquina que usa una fresa que gira a muy alta velocidad para remover material de una pieza.
La máquina lee un archivo pre-programado indicando dónde y cómo cortar, usualmente archivo .GCode. Una fresa gira a alto RPM por motor de husillo, que mueve la fresa arriba/abajo. Este mecanismo se mueve izquierda, derecha, frente, atrás por brazo transversal. Se conoce como fresadora de tres ejes (X, Y, Z). Puede hacer recortes 2D, grabado y relieve 3D.
En FabLab Kamp-Lintfort tenemos fresadora portal CNC e(sign: Easy Worker MasterPro 2513.

Área de trabajo: 2600 x 1400 x 300mm, con mesa de vacío. Usada principalmente para fresado de madera, pero con husillo HSD (3.9KW; 24.000 RPM) también fresa metales fácilmente.
Material: Madera contrachapada 18mm
Primero coloco lámina de madera en cama CNC, la alineo y enciendo vacío. Tras exportar .dxf, edité diseño antes de importar a software CAM de la máquina.

Primero, HOME de la máquina.
Para establecer Cero X, Y, Z, hago home pulsando botón home en software (o mando).


Al principio, puedo establecer cero X e Y alineados aproximadamente a una esquina de la cama. También probamos usar láser para esto, pero siempre al simular mostraba colisiones porque el cero salía del área de trabajo.

Ahora debo encontrar eje Z, usando herramienta especial que viene con la máquina:

Importante: colocarla sobre la cama de la máquina.
Lanzo primer trabajo: grabado. Ajustes usados:

Pulso Calculate Toolpath para simular y asegurar que no hay colisiones. Tras guardar .GCode, lanzo trabajo:

Lanzo corte exterior:


Resultado tras terminar trabajo:

Otra pieza para fresar: sección Moldeo y Fundición.
Preparé molde para impermeabilizar mi contenedor de agua. Diseño:

Nada nuevo. Usé exactamente mismos ajustes. Lo único: grosor material madera 10mm, y corté 7 piezas para pegarlas después y preparar mi molde.
Descargar Archivos
- Paredes Estructura (.dxf)
- Molde (.dxf)
Moldeo y Fundición
Usé esta técnica para preparar contenedor de agua e impermeabilizar el existente. Lo veo como capa fina de material (contenedor menor) fácilmente removable.
Resultado de sección anterior Fresado CNC:

Corté 7 piezas idénticas, las alineé usando agujeros de referencia. También corté agujero grande en medio de 5 piezas inferiores para colocar bomba de aire dentro y quitar el molde fácilmente después.
Tras pegar todas las piezas y fijarlas:

Mientras secaba pegamento, preparé pequeño "cosa" plástica (no sé cómo llamarlo :D) para la bomba. Idea: poder atornillarlo a mi molde y quitarlo cuando quiera.
Molde listo:


¡LISTO PARA VACUUM CASTING!
Usé máquina de vacío en FabLab Kamp-Lintfort: Formech – Manual Vacuum Forming Machine
Intenté muchas veces y siempre no podía quitar el molde sin romper la pieza. Tras horas de pruebas, encontré solución: primero hago vacuum casting de una capa fina de material, y sin quitarla, fundo el contenedor real encima. La primera capa es resbaladiza, y si la rocio con silicona, me permite quitar el molde mucho más fácil.
Tras dejar secar silicona un poco, fundo la capa real.
¡¡AQUÍ ESTAMOS!!
Foto HÉROE para quienes piensen que fue fácil


Montaje Final
¡A montar todo! Empiezo ensamblando estructura. Pongo a mano todas las herramientas necesarias:

Animación corta del proceso:

Para montar luces, corté tiras LED RGB en 4 piezas (medí longitud de antemano) y las soldé accordingly.

Tras conectar todos los sensores y gestionar cableado, fijé la placa en sección electrónica.

¡Aquí está el sistema! Todo ensamblado, bonito sistema de cultivo GIY

Foto HÉROE durante funcionamiento:

Video Presentación Final
© 2017 Albot Dima. Todos los derechos reservados | Albot.Dumitru@hsrw.org
Esta obra está licenciada bajo Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Para más detalles sobre el proyecto, visita la fuente oficial:
https://archive.fabacademy.org/2017/fablabkamplintfort/students/396/final.html
Código
GIY Board - CÓDIGO Arduino
#include "dht.h"
#include "U8glib.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#define DHT11_PIN 2
#define ONE_WIRE_BUS 3
#define WATER_LEVEL A4
#define LDR_PIN A3
#define PH_PIN A5
#define GROW_LIGHT 10
#define FOG_PUMP 13
int waterLevel;
int LightLevel;
int pH;
dht DHT;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature waterTemp(&oneWire);
U8GLIB_ST7920_128X64 u8g(4, 12, 6, U8G_PIN_NONE);
const unsigned char logo [] PROGMEM = {
0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFE, 0x00, 0x03, 0xC0, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xF8, 0x00, 0x07, 0xE0, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xF0, 0x00, 0x1F, 0xF8, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xE0, 0x00, 0x3F, 0xFE, 0x00, 0x07, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xC0, 0x00, 0x18, 0x1F, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x80, 0x00, 0x00, 0x03, 0xC0, 0x01, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFE, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFC, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFC, 0x03, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF8, 0x07, 0xE0, 0x00, 0x00, 0x1F, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFC, 0x1F, 0xF0, 0x00, 0x00, 0x1F, 0xF0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0x3F, 0xF0, 0x00, 0x00, 0x1F, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE0, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE0, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xFF, 0xFF, 0xC0, 0x07, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xFE, 0x1F, 0xFF, 0xFF, 0xF0, 0x3C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xF8, 0x03, 0xFF, 0xFF, 0xC0, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xF0, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xF0, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xE0, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xE0, 0x00, 0x3F, 0xFC, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xE0, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xE0, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xE0, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xE0, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xE0, 0x00, 0x0F, 0xF0, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xE0, 0x00, 0x07, 0xF0, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0xF0, 0x00, 0x07, 0xF0, 0x00, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0xF0, 0x00, 0x07, 0xF0, 0x00, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0xF8, 0x00, 0x07, 0xF0, 0x00, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0xF8, 0x00, 0x07, 0xF0, 0x00, 0x1F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE0, 0xFC, 0x00, 0x07, 0xF0, 0x00, 0x1F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE0, 0xFE, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0x3E, 0x00, 0x0F, 0xF0, 0x00, 0x7C, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0x1E, 0x00, 0x1F, 0xF8, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF8, 0x06, 0x00, 0x1F, 0xFC, 0x01, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFC, 0x00, 0x00, 0x7F, 0xFF, 0x0F, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x80, 0x00, 0x7F, 0xFF, 0xC0, 0x01, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0x80, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xE0, 0x00, 0x7F, 0xFE, 0x00, 0x07, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xF0, 0x00, 0x1F, 0xF8, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xF8, 0x00, 0x0F, 0xF0, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFC, 0x00, 0x03, 0xC0, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFD, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
bool first;
float hum = 0.0;
double T = 0.0;
void dht_test(float * humPerc);
void setup(void) {
waterTemp.begin();
pinMode(GROW_LIGHT, OUTPUT);
pinMode(FOG_PUMP, OUTPUT);
digitalWrite(GROW_LIGHT, HIGH);
first = true;
if (u8g.getMode() == U8G_MODE_R3G3B2) u8g.setColorIndex(255);
else if (u8g.getMode() == U8G_MODE_GRAY2BIT) u8g.setColorIndex(3);
else if (u8g.getMode() == U8G_MODE_BW) u8g.setColorIndex(1);
else if (u8g.getMode() == U8G_MODE_HICOLOR) u8g.setHiColorByRGB(255,255,255);
u8g.firstPage();
do { u8g.drawBitmapP(32, 0, 16, 64, logo); } while(u8g.nextPage());
dht_test(&hum);
}
void RefreshDisplay(float * humPerc, double *T, int *WL, int *LL, int *pH_value) {
u8g.setFont(u8g_font_fub11);
u8g.setFontRefHeightExtendedText();
u8g.setDefaultForegroundColor();
u8g.setFontPosTop();
u8g.drawStr(4, 0, "Hum%");
u8g.setPrintPos(68, 0);
u8g.print(*humPerc);
u8g.drawStr(4, 15, "Temp");
u8g.setPrintPos(68, 15);
u8g.print(*T);
u8g.drawStr(4, 30, "Wlvl");
if (*WL == 0) {
u8g.drawStr(68, 30, "EMPTY!");
digitalWrite(FOG_PUMP, LOW);
} else {
if (*WL < 800) u8g.drawStr(68, 30, "LOW");
else {
digitalWrite(FOG_PUMP, HIGH);
u8g.drawStr(68, 30, "HIGH");
}
}
if (*LL < 100) u8g.drawStr(68, 45, "Dark");
else if (*LL < 200) u8g.drawStr(68, 45, "Dim");
else if (*LL < 500) u8g.drawStr(68, 45, "Light");
else if (*LL < 800) u8g.drawStr(68, 45, "Bright");
else u8g.drawStr(68, 45, "2Bright");
double voltage = 5.0 / 1024.0 * (*pH_value);
float Po = 7 + ((2.5 - voltage) / 0.18);
u8g.drawStr(4, 45, "pH");
u8g.setPrintPos(28, 45);
u8g.print(Po);
}
void loop(void) {
waterTemp.requestTemperatures();
T = waterTemp.getTempCByIndex(0);
waterLevel = analogRead(WATER_LEVEL);
LightLevel = analogRead(LDR_PIN);
pH = analogRead(PH_PIN);
char status;
int chk = DHT.read11(DHT11_PIN);
hum = DHT.humidity;
dht_test(&hum);
if(first) { first = false; }
else {
u8g.firstPage();
do { RefreshDisplay(&hum, &T, &waterLevel, &LightLevel, &pH); } while(u8g.nextPage());
}
}
void dht_test(float * humPerc) {
delay(1000);
}
GIY BOARD - LCD + LIGHT CODE Arduino
#include "U8glib.h"
int led = 10;
U8GLIB_ST7920_128X64 u8g(4, 12, 6, U8G_PIN_NONE);
void draw(void) {
u8g.setFont(u8g_font_unifont);
u8g.setPrintPos(0, 20);
u8g.print("GIY Project v1.0!");
}
void setup(void) {
pinMode(led, OUTPUT);
digitalWrite(led, HIGH);
}
void loop(void) {
u8g.firstPage();
do { draw(); } while(u8g.nextPage());
delay(500);
}
Esquemáticos


Proceso de manufactura
- Tarjeta de visita PCB 4×4 Tic Tac Toe personalizada – Guía de diseño, construcción y código
- Sistema de Sensor de Temperatura Multiposición para Integración en Hogar Inteligente
- Controlador DIY para soldador 862D+ — Precisión y fiabilidad
- MotionSense: Detección inteligente de intrusos con Arduino y ESP8266
- Prevención de Incendios en Impresoras 3D: Sistema de Seguridad con Sensor Inteligente
- Crear un medidor IoT web con Arduino, Yaler e IFTTT
- Levitación magnética repulsiva con Arduino: Circuito simple y guía DIY
- Robot pinza controlado remotamente para manipulación de precisión
- Registrador de Datos de Alto Rendimiento para Globo Meteorológico con Arduino
- ArduFarmBot Parte 2: Estación de Control IoT Remota para Cultivos
- CoroFence: Detector Térmico Avanzado con Sensor PIR e Integración IoT