Proyecto de Hardware · 2026

( ^   ^ )
     .
[ CALMO ]

LUMINA

Un amiguito tipo tamagotchi que mide tu pulso y reacciona a cómo te sientes.

ESP32 MAX30102 OLED 0.96" BUZZER PCB Custom
▼ scroll

01

¿Que es lumina y como funciona

Que y Por que?





Lumina mide tu ritmo cardíaco y te dice, con expresiones animadas y sonidos, si estás tranquilo o si necesitas respirar profundo.
Parte oxímetro, parte tamagotchi. :B

Lumina es una maquina de estados y es en base a tu pulso, y esta basado en Healthline.com

Lumina device front view

Fig. 01 — Vista frontal del dispositivo Lumina terminado

función principal
Mide BPM en tiempo real con el sensor MAX30102
( ^ ^ )
interfaz
Pantalla OLED con cara animada que refleja tu estado emocional
audio
Buzzer sincronizado con cada latido detectado — como un radar
u   u
STANDBY
sin dedo detectado
^   ^
CALMADO
≤ 100 BPM
O   O
AGITADO
> 100 BPM

hardware

Componentes & BOM

Todos los componentes fueron elegidos pensando en tamaño mínimo y precio razonable. El costo total del proyecto ronda los $8–10 USD.

Componente Función Cant. Precio
ESP32 Microcontrolador principal, WiFi/BT integrado, ESP32 generico 1 $9.56
OLED 0.96" SSD1306 Pantalla que muestra la cara animada de Lumina y los BPM 1 $5.36
MAX30102 (GY-MAX30102) Sensor de pulso cardíaco por luz infrarroja 1 $3.69
Buzzer Pasivo 3.8kHz Feedback sonoro — pitido con cada latido detectado 1 $3.46
Push Button Interacción del usuario ( reset) 20 $9.56
PCB Custom PCB diseñada a medida para todo el sistema 1 ~$1.00
TOTAL ESTIMADO ~$31.63
◈ BUS I2C COMPARTIDO — OLED + MAX30102 en los mismos pines SDA/SCL

El ESP32-C3 Super Mini fue elegido por su tamaño ultra compacto y porque corre el mismo código Arduino que cualquier ESP32 estándar. El bus I2C permite conectar la pantalla y el sensor en solo 2 pines de datos, dejando el resto libre.

Voltajes del Sistema

Componente Voltaje Operativo Fuente Notas
ESP32 3.3V / 5V USB-C / batería LiPo Regulador interno a 3.3V
OLED SSD1306 3.3V Pin 3V3 del ESP32 No conectar a 5V — puede dañar el panel
MAX30102 3.3V Pin 3V3 del ESP32 I2C a 3.3V, velocidad Fast (400kHz)
Buzzer Pasivo 3.3V GPIO D5 Controlado por PWM (función tone())

ensamblaje

Cableado & Pines

Todo el sistema comparte la alimentación de 3.3V del ESP32. El bus I²C (SDA/SCL) conecta en paralelo la pantalla OLED y el sensor de pulso — sin conflicto porque tienen direcciones I²C distintas (0x3C y 0x57).

▸ ESP32 ↔ MAX30102
3V3——VIN
GND——GND
GPIO 21——SCL
GPIO 22——SDA
▸ ESP32 ↔ OLED 0.96
3V3——3V3
GND——GND
GPIO 21——SCK (SCL)
GPIO 22——SDA
▸ ESP32 ↔ Buzzer Pasivo
GND——GND (–)
GPIO D5——S (señal)
Lumina wiring

Cableado y componentes del sistema

Lumina final

Dispositivo ensamblado, vista lateral

Protocolo de comunicaciónI2C
Velocidad I2C400 kHz (Fast Mode)
Dirección I2C — OLED0x3C
Dirección I2C — MAX301020x57
Pin buzzerGPIO D5 (PWM)
Frecuencia buzzer — calmo1200 Hz
Frecuencia buzzer — agitado1800 Hz (alerta)
Duración pitido40 ms (no bloqueante)

firmware

Código & Lógica

El firmware corre en Arduino (framework ESP32). El loop principal lee el sensor, aplica un filtro de plausibilidad, promedia con un búfer circular de 6 muestras y despacha el estado emocional — todo sin usar delay(), para que la pantalla nunca se congele.

librería principal
SparkFun MAX3010x Pulse and Proximity Sensor Library
display
Adafruit SSD1306 + Adafruit GFX
filtro BPM
Solo acepta 45–145 BPM. Buffer circular de 6 muestras. Promedio estable.
buzzer
Non-blocking: millis() en vez de delay(). Pitido de 40ms exactos.
DEMO EN VIVO — WOKWI SIMULATOR (escribe tu emoción en el terminal (ESTA EN ESPAÑOL " feliz, triste, enojado"))
Lumina.ino — loop principal
 Loop principal — no bloqueante
void loop() {
  long irValue = particleSensor.getIR();

   Sin dedo → modo standby
  if (irValue < 50000) {
    estadoActual = DESCONECTADO;
    beatAvg = 0;
  } else {
    if (checkForBeat(irValue) == true) {
      long delta = millis() - lastBeat;
      lastBeat = millis();
      beatsPerMinute = 60 / (delta / 1000.0);

       Filtro de plausibilidad: solo valores humanos reales
      if (beatsPerMinute >= 45 && beatsPerMinute <= 145) {
        rates[rateSpot++] = (byte)beatsPerMinute;
        rateSpot %= RATE_SIZE; // Buffer circular

        long total = 0;
        for (byte x = 0; x < RATE_SIZE; x++) total += rates[x];
        beatAvg = total / RATE_SIZE; // Promedio suavizado

         Activar buzzer — tono según estado emocional
        buzzerActivo = true;
        tiempoBuzzerEncendido = millis();
        if (beatAvg > 100) {
          tone(BUZZER_PIN, 1800); // Agudo: alerta
        } else {
          tone(BUZZER_PIN, 1200); // Normal: calmo
        }
      }
    }
    Clasificar estado emocional
    estadoActual = (beatAvg == 0) ? DESCONECTADO
                 : (beatAvg > 100) ? AGITADO : CALMO;
  }

   Apagar buzzer automáticamente a los 40ms
  if (buzzerActivo && (millis() - tiempoBuzzerEncendido > 40)) {
    noTone(BUZZER_PIN);
    buzzerActivo = false;
  }

  actualizarPantalla(); // Siempre re-dibuja
}
Lumina.ino — actualizarPantalla() (lógica de caras)
void actualizarPantalla() {
  display.clearDisplay();

  // BPM en tamaño grande (zona inferior)
  display.setTextSize(2);
  display.setCursor(0, 48);
  display.print("BPM:");

  switch (estadoActual) {
    case CALMO:
      display.println("Lumina: Calmado");
      // Ojos: ^ ^ alternando con o o cada 500ms
      if (alternarAnimacion) {
        display.print("^"); display.print("^");
      } else {
        display.print("o"); display.print("o");
      }
      break;

    case AGITADO:
      display.println("!Respira profundo!");
      // Ojos bien abiertos, boca tensa
      display.print("O"); display.print("O");
      break;

    case DESCONECTADO:
      display.println("Modo Standby");
      // Ojos dormidos: u u o guiones
      break;
  }
  display.display(); // Flush al panel físico
}

diseño PCB

PCB & CAD

La PCB fue diseñada para que todo el sistema quepa en un factor de forma de llavero. El resultado es una placa compacta y ordenada :B

PCB Layout vista superior

Layout de la PCB, vista superior

PCB 3D render

Render 3D de la PCB

PCB ensamblada

PCB lista para ensamblaje

ESQUEMA DE CONEXIONES
  ┌─────────────────────────────────────────┐
  │           ESP32-C3 SUPER MINI           │
  │                                         │
  │  3V3 ──┬── VIN[MAX30102]                │
  │        └── 3V3[OLED]                    │
  │                                         │
  │  GND ──┬── GND[MAX30102]                │
  │        ├── GND[OLED]                    │
  │        └── GND[BUZZER]                  │
  │                                         │
  │  G21 ──┬── SCL[MAX30102] ──── I2C BUS  │
  │        └── SCK[OLED]                    │
  │                                         │
  │  G22 ──┬── SDA[MAX30102] ──── I2C BUS  │
  │        └── SDA[OLED]                    │
  │                                         │
  │  D5  ──── S[BUZZER]                     │
  └─────────────────────────────────────────┘
    
Factor de formaLlavero / Keychain
Capas PCB2 capas
Software KiCad
Conector de alimentaciónUSB-C (via ESP32)
EstadoFUNCIONAL :D ✓

D: lo que salió mal

Dificultades & Aprendizajes

Por mas sencillo que sea hay dificultades aveces

fin del documento yeyyy

Lumina Funciona

De un oxímetro roto en un cajón, a un llavero con personalidad.
Lumina sabe cuándo estás bien y cuándo necesitas respirar.
— Hecho a mano, con mucho sueño y cariño.

( ^   ^ )
     .
▶ PRUEBA LA DEMO