Pluviómetro de Cucharilla Basculante Avanzado con Integración Arduino
Componentes y Suministros
| Componente | Cantidad | Notas |
|---|---|---|
| Arduino Nano R3 | 1 | Unidad de control principal |
| Tiny RTC I2C DS1307 | 1 | Reloj tiempo real con batería |
| Módulo Tarjeta SD - LC Studios | 1 | Registro de datos en tarjeta SD |
| Fuente 7-12 VDC (o adaptador pared) | 1 | Alimentación unidad interior |
| LCD Estándar Adafruit 16x2 Blanco/Azul | 1 | Pantalla unidad interior |
| Registro Desplazamiento TI SN74HC595N | 1 | Control LCD 3 hilos (serie-paralelo) |
| Resistencia 1k Ω | 2 | Pull-up interruptores |
| Resistencia 330 Ω | 2 | Limitación corriente LED backlight |
| Condensador 100 nF | 1 | Desacoplo |
| Potenciómetro Mono-vuelta 10k Ω | 1 | Contraste LCD |
| Pulsador PCB Momentáneo | 1 | Selección menú |
| Interruptor Reed SPST-NO | 1 | Detección basculamiento cucharilla |
| Imán (7mm OD x 7mm largo) | 1 | Activa reed al bascular |
| Placa Prototipo 5x10 cm (una cara) | 1 | Montaje circuito unidad interior |
Herramientas y Máquinas Necesarias
- Impresora 3D (genérica)
- Soldador (genérico)
Sobre el Proyecto
Este es un pluviómetro de cucharilla basculante, basado en los usados por meteorólogos profesionales. Funciona embudando agua de lluvia sobre una cucharilla que parece un balancín: cada extremo tiene un cubeto que contiene ~2 ml de agua. Cuando uno se llena, la cucharilla bascula y el agua empieza a llenar el cubeto opuesto. Cada basculamiento cierra momentáneamente un interruptor reed, enviando señal a interrupción hardware del Arduino. El Arduino cuenta cada "basculamiento" y lo convierte a cantidad de lluvia (pulgadas), basándose en volumen del cubeto y área de captación del embudo (16,605 pulg²).
La unidad interior tiene menú para mostrar: 'hora actual', 'hora anterior', 'día actual', 'día anterior'.
Por cada basculamiento, se escribe un evento con fecha/hora en archivo en tarjeta SD. Este archivo puede importarse a Excel para análisis y gráficas.
Aunque no hay video del basculamiento real, este video muestra el registro de evento de lluvia real.
Paso 1: Imprimir Componentes
Imprimir todos los componentes listados. Usé PETG para todo: material adecuado para exposición UV y temperatura en exterior. Para el filtro superior, desactivar capas horizontales (arriba/abajo) para crear detalle poroso.

Paso 2: Preparar Placa Circuito Panel Frontal
Insertar LCD en placa PY-5*10CM (sin soldar) con pin 1 del LCD en agujero C-1. Taladrar placa en ubicaciones de 4 agujeros de montaje LCD. Retirar LCD para montaje posterior.
Paso 3: Montar Circuito Panel Frontal
Colocar 74HC595N, interruptores y resistencias como se muestra. Rutar cables necesarios (ver diagrama cableado) a puntos de conexión LCD y 6" extra para conectar a segunda placa.

Paso 4: Montar LCD en Panel Frontal
Montar LCD en placa panel frontal, usando separadores impresos para elevar LCD sobre el IC. Fijar con tornillos M3x15mm y tuercas. (Tornillos disponibles en Fastenal/McMaster Carr)

Paso 5: Montar Placa Principal
Insertar Arduino con Pin D12 en agujero R27. Añadir condensador y resistencias, cablear todo antes de insertar módulos SD y RTC. Referencia esquema para detalles.

Paso 6: Montar Lector SD y TinyRTC
Lector SD en agujeros A-3 a B-10. TinyRTC en C-24 a I-24. Soldar todas las conexiones.

Paso 7: Cableado Caja Control Interior
En caja control interior, taladrar agujeros para dos cables a unidad exterior y cables de alimentación externa. Pasar cables, soldar en ubicaciones correspondientes. Deslizar placa principal en caja y fijar con dos tornillos M3x6mm. Insertar pulsador por tapa frontal y atornillar placa circuito frontal con tornillos M3x6mm. Nota: usé pieza de latón torneado para botón en lugar de pieza impresa, mejor tacto.

Paso 8: Fijar Tapa Frontal
Atornillar tapa frontal con tornillo plano M3-0.5 x 10mm.
Paso 9: Pruebas Iniciales
Conectar USB a PC y subir programa RTC para poner hora. Tras ajustar reloj, subir programa principal. Insertar tarjeta SD. Probar cortocircuitando cables que van a reed switch exterior. Totales lluvia deben incrementar por cada cierre de contacto. Verificar SD leyendo con Notepad/WordPad: debe haber archivo "Text.txt" con marca temporal por cada evento "basculamiento".
Paso 10: Montaje Unidad Exterior
Fijar interruptor reed a Sub-Base con bridas. Montar imán en cucharilla, montar cucharilla con tubo latón 1/8" diámetro (~2" largo). Antes de montar, pasar broca 1/8" por agujeros cucharilla para limpiar. Debe bascular sin fricción. Usar lima redonda si needed. Añadir arandela 1/8" en lado exterior para ajustar holgura. Decidir montaje unidad exterior: usé ángulo aluminio 1". Fijar base a ángulo con tornillos hex 1/4-20 desde dentro hacia fuera. Fijar sub-base a fondo unidad exterior con tornillos M3-0.5x10mm.

Paso 11: Embudo y Filtro
Insertar embudo en tapa superior. Cortar ~24 piezas alambre galvanizado 18 gauge de 2". Con alicates, calentar con soplete/encendedor y presionar cuidadosamente en plástico superior. Estos alambres disuaden pájaros de posarse. Queremos medir lluvia, no excrementos. Fijar tapa a caja principal con (4) tornillos M3-0.5x6mm. Instalar filtro en embudo: evita hojas y atascos. Revisar y limpiar periódicamente.

Paso 12: Instalación Final
Montar unidad exterior y tender cables a unidad interior. ¡Asegurar que tapa unidad exterior está nivelada en ambas direcciones!
Paso 13: Puesta en Marcha
Alimentar unidad y añadir agua a unidad exterior para verificar funcionamiento.
Paso 14 (Opcional): Verificación Precisión
Añadir MUY LENTAMENTE una taza de agua (1 taza = 14,44 pulg³). Área captación = 16,605 pulg² → Lluvia = 14,44/16,605 = 0,87". Unidad debe medir ~0,87". Ajustar factor corrección en programa principal si difiere.
¡Felicidades! Disfruta registrando tu pluviometría.
Código
Código Arduino para Poner Hora en RTC
Cargar primero para ajustar hora en RTC. Editar código con fecha/hora real antes de subir.
#include "Wire.h"
#define DS1307_I2C_ADDRESS 0x68
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
byte decToBcd(byte val) { return (val/10*16) + (val%10); }
byte bcdToDec(byte val) { return (val/16*10) + (val%16); }
void setDateDs1307() {
second = 0; minute = 11; hour = 12;
dayOfWeek = 5; dayOfMonth = 24; month = 7; year = 20;
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(decToBcd(0));
Wire.write(decToBcd(second));
Wire.write(decToBcd(minute));
Wire.write(decToBcd(hour));
Wire.write(decToBcd(dayOfWeek));
Wire.write(decToBcd(dayOfMonth));
Wire.write(decToBcd(month));
Wire.write(decToBcd(year));
Wire.endTransmission();
}
void getDateDs1307() {
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(decToBcd(0));
Wire.endTransmission();
Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
second = bcdToDec(Wire.read() & 0x7f);
minute = bcdToDec(Wire.read());
hour = bcdToDec(Wire.read() & 0x3f);
dayOfWeek = bcdToDec(Wire.read());
dayOfMonth = bcdToDec(Wire.read());
month = bcdToDec(Wire.read());
year = bcdToDec(Wire.read());
Serial.print(hour); Serial.print(":"); Serial.print(minute); Serial.print(":"); Serial.print(second);
Serial.print(" "); Serial.print(month); Serial.print("/"); Serial.print(dayOfMonth); Serial.print("/"); Serial.print(year);
Serial.println();
}
void setup() { Wire.begin(); Serial.begin(19200); setDateDs1307(); }
void loop() { delay(2000); getDateDs1307(); }
Programa Principal Arduino para Pluviómetro
Programa principal. Instalar librerías asociadas antes de compilar. Referencia para actualizar librería LiquidCrystal: RoboIndia.
/* Pluviómetro Cucharilla Basculante - Escrito por Bob Torrence */
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include "RTClib.h"
#include <LiquidCrystal_SR.h> // Versión especial para LCD 3 hilos
LiquidCrystal_SR lcd(6, 5, 9); // Pin 6=Data/SER, 5=Clock/SCL, 9=SCK
RTC_DS3231 rtc;
int backlight = 7; // Pin LED backlight (D7)
const byte interruptPin_bucket = 3;
const byte interruptPin_menu = 2;
volatile int Bucket_Tip_Occurence = 0;
volatile int Menu_Select = 0;
float Bucket_tip_hour_total = 0;
float Bucket_tip_current_hour_total = 0;
float Bucket_tip_previous_hour_total = 0;
float Bucket_tip_current_day_total = 0;
float Bucket_tip_previous_day_total = 0;
int current_minute, loop_minute, current_hour, loop_hour, current_day, loop_day;
int tip_counter = 0;
float conversion_factor = .00854; // pulgadas lluvia por basculamiento (volumen cubeto / área captación 16.605 sq.in.)
volatile unsigned long backlightOfftime;
volatile unsigned long backlightOnDuration = 30000; // ms backlight encendido tras pulsar menú
String print_time(DateTime timestamp) {
char message[120];
sprintf(message, "%02d:%02d:%02d %02d/%02d", timestamp.hour(), timestamp.minute(), timestamp.second(), timestamp.month(), timestamp.day());
return message;
}
File myFile;
void setup() {
lcd.begin(16,2);
lcd.home();
rtc.begin();
pinMode(10, OUTPUT);
pinMode(backlight, OUTPUT);
digitalWrite(backlight, HIGH);
backlightOfftime = millis() + backlightOnDuration;
if (!SD.begin(4)) { lcd.print("insert SD Card"); return; }
pinMode(interruptPin_bucket, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin_bucket), count, FALLING);
pinMode(interruptPin_menu, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin_menu), menu, RISING);
myFile = SD.open("test.txt", FILE_WRITE);
if (myFile) { myFile.println("Pluviómetro listo - unidad encendida"); myFile.close(); }
DateTime now = rtc.now();
current_minute = loop_minute = now.minute();
current_hour = loop_hour = now.hour();
lcd.setCursor(0,0); lcd.print(print_time(now));
lcd.setCursor(1,1); lcd.print("Pluviómetro");
}
void loop() {
DateTime now = rtc.now();
current_minute = loop_minute = now.minute();
current_hour = loop_hour = now.hour();
current_day = loop_day = now.day();
// Bucle día actual
while (loop_day - current_day == 0) {
// Bucle hora actual
while (loop_hour - current_hour == 0) {
if (millis() > backlightOfftime) digitalWrite(backlight, LOW);
if (Bucket_Tip_Occurence == 1) {
Bucket_Tip_Occurence = 0;
tip_counter++;
DateTime now = rtc.now();
myFile = SD.open("test.txt", FILE_WRITE);
myFile.print("Evento ");
myFile.print(now.year()); myFile.print('/'); myFile.print(now.month()); myFile.print('/'); myFile.print(now.day());
myFile.print(" "); myFile.print(now.hour()); myFile.print(':'); myFile.print(now.minute()); myFile.print(':'); myFile.print(now.second());
myFile.print(" "); myFile.print(conversion_factor,5); myFile.println();
myFile.close();
delay(200);
} else {
DateTime now = rtc.now(); loop_hour = now.hour();
}
switch (Menu_Select) {
case 1: lcd.clear(); lcd.setCursor(0,0); lcd.print("Hora Actual"); lcd.setCursor(0,1); lcd.print(tip_counter * conversion_factor); delay(500); break;
case 2: lcd.clear(); lcd.setCursor(0,0); lcd.print("Hora Anterior"); lcd.setCursor(0,1); lcd.print(Bucket_tip_previous_hour_total); delay(500); break;
case 3: lcd.clear(); lcd.setCursor(0,0); lcd.print("Dia Actual"); lcd.setCursor(0,1); lcd.print(Bucket_tip_current_day_total + tip_counter * conversion_factor); delay(500); break;
case 4: lcd.clear(); lcd.setCursor(0,0); lcd.print("Dia Anterior"); lcd.setCursor(0,1); lcd.print(Bucket_tip_previous_day_total); delay(500); break;
}
}
// Fin hora: totalizar
DateTime now = rtc.now();
current_hour = now.hour(); loop_day = now.day(); loop_hour = now.hour();
Bucket_tip_previous_hour_total = tip_counter * conversion_factor;
Bucket_tip_current_day_total += Bucket_tip_previous_hour_total;
tip_counter = 0;
}
// Fin día: totalizar
Bucket_tip_previous_day_total = Bucket_tip_current_day_total;
Bucket_tip_current_day_total = 0;
Bucket_tip_current_hour_total = 0;
tip_counter = 0;
}
// Interrupción basculamiento cucharilla (reed switch)
void count() {
static unsigned long last_interrupt_time_bucket = 0;
unsigned long interrupt_time_bucket = millis();
if (interrupt_time_bucket - last_interrupt_time_bucket > 300) { // anti-rebote 300ms
Bucket_Tip_Occurence = 1;
}
last_interrupt_time_bucket = interrupt_time_bucket;
}
// Interrupción botón menú
void menu() {
static unsigned long last_interrupt_time_menu = 0;
unsigned long interrupt_time_menu = millis();
if (interrupt_time_menu - last_interrupt_time_menu > 300) {
if (digitalRead(backlight) == LOW) digitalWrite(backlight, HIGH);
else { Menu_Select++; if (Menu_Select > 4) Menu_Select = 1; }
backlightOfftime = millis() + backlightOnDuration;
}
last_interrupt_time_menu = interrupt_time_menu;
}
Piezas Personalizadas y Carcasas (STL para Impresión 3D)
- Base unidad exterior (PETG, 30% relleno)
- Tapa unidad exterior (PETG, 30% relleno)
- Embudo unidad exterior (PETG, 30% relleno)
- Filtro embudo (PETG, 20% relleno, SIN capas horizontales → poroso)
- Sub-base pivote cucharilla (PETG, 30% relleno)
- Cucharilla basculante (PETG, 30% relleno)
- Carcasa unidad interior (PETG, 30% relleno)
- Tapa frontal unidad interior (PETG, 30% relleno)
- Separadores LCD sobre IC (PETG, 30% relleno)
- Modelo Fusion 360 unidad exterior (
.f3d) - STEP unidad exterior (
.step) - STEP unidad interior (
.step) - Fusion 360 unidad interior (
.f3z) - Botón pulsador interruptor
Esquemáticos
Esquema de cableado del proyecto (rain_gauge_NtjqXF6QEw.fzz)
Proceso de manufactura
- Manómetros de Precisión para Aplicaciones Industriales y de Seguridad
- Persianas Inteligentes: Control Automático de Luz con Arduino y Energía Solar
- Reloj de Palabras en Italiano con Arduino Nano, NeoPixel, LCD y RTC
- Medidor kWh Sigfox Fiable con Arduino MKR Fox 1200
- Medidores de Altura Digitales: Soluciones Precisas de Medición y Control de Calidad
- Micrómetro de Tornillo: Definición, Historia, Partes, Funcionamiento y Uso Práctico
- Manómetros: tipos, funcionamiento y beneficios
- Extensómetros (Strain Gauges): Principio, Tipos, Aplicaciones y Selección
- El manómetro Pirani: principios de funcionamiento, aplicaciones y ventajas
- Manómetros de diafragma: precisión y fiabilidad en medición de presión
- Manómetros de tubo de Bourdon: diseño, funcionamiento y aplicaciones