martes, 7 de abril de 2026

Sistema: Control Automático de Luz (LED + LDR)

 

/*

 * =========================================================

 * COLEGIO GIMNASIO BILINGÜE MARIE CURIE

 * Proyecto de Tecnología y Automatización

 * Sistema: Control Automático de Luz (LED + LDR)

 * Desarrollado por: Centro Prisma

 * Versión: 1.0 (Control proporcional con Kp + unidades físicas)

 * Fecha: 19 de Febrero de 2026

 * =========================================================

*/

 

#include <Arduino.h>

 

/*

=========================================================

CONTROL AUTOMÁTICO DE LUZ CON LAZO CERRADO (LED + LDR)

=========================================================

 

¿QUÉ HACE ESTE PROYECTO?

 

Este sistema usa:

- 1 sensor de luz (LDR)  -> mide la luz como un número (ADC)

- 1 LED (actuador)       -> cambia su brillo con PWM

- Control proporcional (Kp)

 

El sistema hace esto todo el tiempo:

 

1) Mide la luz (ENTRADA).

2) La compara con una meta llamada SETPOINT.

3) Calcula la diferencia (ERROR).

4) Decide el brillo del LED con una regla proporcional: PWM = Kp × ERROR.

5) Enciende el LED con ese brillo (SALIDA).

6) Vuelve a medir y repite.

 

Eso es un sistema de LAZO CERRADO:

mide → piensa → actúa → vuelve a medir.

 

=========================================================

*/

 

 

// ================= SENSOR DE LUZ (LDR) =================

//

// El LDR cambia su resistencia según la luz.

// El ESP32 convierte esa señal en un número digital con su ADC.

//

// ADC del ESP32 (típico): 12 bits

// Esto significa que puede leer:

//

// 0    -> 0.0V (voltaje mínimo)

// 4095 -> 3.3V (voltaje máximo)

//

// OJO: Este número NO son lúmenes reales.

// Es una lectura digital del sensor.

//

// IMPORTANTE EN ESTE MONTAJE:

//

// Más luz sobre el LDR    -> el número BAJA

// Menos luz (si lo tapas)-> el número SUBE

const int PIN_LDR = 34;

 

 

// ================= SALIDA (LED) =================

//

// Este LED será el “músculo” del sistema.

// Su brillo se controla con PWM (0 a 255).

const int PIN_LED = 12;

 

 

// ================= CONFIGURACIÓN DEL PWM =================

//

// PWM = Modulación por Ancho de Pulso

//

// El ESP32 no cambia el voltaje del LED.

// En cambio, prende y apaga el pin muy rápido.

//

// FRECUENCIA_PWM = 5000 Hz

// Esto significa que la señal se repite

// 5000 veces por segundo.

//

// RESOLUCION_PWM = 8 bits

// Esto significa 256 niveles de potencia:

//

// 0   -> 0%   (apagado)

// 255 -> 100% (máximo brillo)

const int CANAL_PWM = 0;

const int FRECUENCIA_PWM = 5000;

const int RESOLUCION_PWM = 8;

 

 

// ================= AJUSTES DEL SISTEMA (CONTROL) =================

//

// SETPOINT es la meta de luz que queremos mantener.

// Es un número del ADC (0 a 4095), no lúmenes reales.

const int SETPOINT = 2000;

 

// Kp es la “fuerza” del control proporcional.

// Entre más grande sea Kp, más fuerte reacciona el LED.

const float KP = 0.12;

 

 

// ================= TIEMPO ENTRE CICLOS =================

//

// delay(100) = 100 milisegundos = 0.1 segundos

// Eso significa que el sistema repite el lazo:

// 10 veces por segundo (aprox.)

const int TIEMPO_ENTRE_CICLOS_MS = 300;

 

 

// ================= VARIABLES (DATOS QUE CAMBIAN) =================

//

// Estas variables guardan lo que el sistema mide y calcula

// en cada vuelta del lazo cerrado.

int luzActual = 0;     // Lectura ADC (0 a 4095)

int errorLuz = 0;      // Diferencia entre lectura y meta

int pwmCalculado = 0;  // Salida PWM (0 a 255)

 

 

// =================================================

// FUNCIONES DEL SISTEMA

// =================================================

 

 

// -------------------------------------------------

// Función: medirLuz()

// -------------------------------------------------

// Lee el valor del LDR con analogRead().

//

// Resultado:

// - Guarda el valor en "luzActual"

//

// Unidad real:

// - Es un número ADC (0 a 4095)

// - 0 equivale a 0.0V y 4095 equivale a 3.3V (aprox.)

// -------------------------------------------------

void medirLuz() {

  luzActual = analogRead(PIN_LDR);

}

 

 

// -------------------------------------------------

// Función: calcularError()

// -------------------------------------------------

// Calcula qué tan lejos estamos de la meta.

//

// Fórmula:

// ERROR = Luz actual - SETPOINT

//

// Ejemplos:

//

// Si ERROR = 0

// -> estamos exactamente en la meta.

//

// Si ERROR es grande

// -> estamos lejos de la meta.

//

// Si ERROR es negativo

// -> significa que ya hay suficiente luz.

// -> lo convertimos en 0 porque el LED no puede

//    tener “potencia negativa”.

// -------------------------------------------------

void calcularError() {

 

  errorLuz = luzActual - SETPOINT;

 

  if (errorLuz < 0) {

    errorLuz = 0;

  }

}

 

 

// -------------------------------------------------

// Función: calcularBrillo()

// -------------------------------------------------

// Decide qué brillo debe tener el LED.

//

// Regla proporcional:

// PWM = Kp × ERROR

//

// - ERROR pequeño -> PWM pequeño -> LED suave.

// - ERROR grande  -> PWM grande  -> LED fuerte.

//

// Regla de seguridad:

// PWM máximo con 8 bits = 255.

// Si el cálculo supera 255, lo dejamos en 255.

// -------------------------------------------------

void calcularBrillo() {

 

  pwmCalculado = (int)(KP * errorLuz);

 

  if (pwmCalculado > 255) {

    pwmCalculado = 255;

  }

}

 

 

// -------------------------------------------------

// Función: aplicarSalida()

// -------------------------------------------------

// Envía el PWM al LED.

//

// Unidad real:

// - PWM 0   -> 0%   de potencia (apagado)

// - PWM 255 -> 100% de potencia (máximo brillo)

// -------------------------------------------------

void aplicarSalida() {

  ledcWrite(CANAL_PWM, pwmCalculado);

}

 

 

// -------------------------------------------------

// Función: mostrarDatos()

// -------------------------------------------------

// Muestra lo que está pasando en el lazo cerrado.

//

// Mostramos unidades físicas y rangos:

//

// - ADC (0 a 4095) y su voltaje aproximado (0.0V a 3.3V)

// - PWM (0 a 255) y su porcentaje aproximado (0% a 100%)

// - Tiempo del ciclo en milisegundos (ms)

// -------------------------------------------------

void mostrarDatos() {

 

  // Convertimos la lectura ADC a voltaje aproximado (0.0V a 3.3V)

  // Fórmula: voltaje = (ADC / 4095) * 3.3

  float voltajeAprox = ( (float)luzActual / 4095.0 ) * 3.3;

 

  // Convertimos PWM a porcentaje aproximado

  // Fórmula: porcentaje = (PWM / 255) * 100

  float porcentajePWM = ( (float)pwmCalculado / 255.0 ) * 100.0;

 

  Serial.println("=================================");

  Serial.println("   LAZO CERRADO DE LUZ (LED+LDR)  ");

  Serial.println("=================================");

 

  Serial.print("Luz medida (ADC 0-4095) Lumenes: ");

  Serial.print(4095 - luzActual);

 

 

  Serial.print("Meta (SETPOINT) (ADC):   ");

  Serial.println(SETPOINT);

 

  Serial.print("Error (ADC):             ");

  Serial.println(errorLuz);

 

  Serial.print("Salida LED (PWM 0-255):  ");

  Serial.print(pwmCalculado);

 

}

 

 

// =================================================

// INICIO DEL PROGRAMA

// =================================================

void setup() {

 

  // Comunicación con el computador para ver mensajes.

  Serial.begin(115200);

 

  // Configuramos el PWM:

  ledcSetup(CANAL_PWM, FRECUENCIA_PWM, RESOLUCION_PWM);

 

  // Conectamos el canal PWM al pin del LED.

  ledcAttachPin(PIN_LED, CANAL_PWM);

 

  // Iniciamos el LED apagado.

  ledcWrite(CANAL_PWM, 0);

 

  Serial.println("CONTROL DE LUZ INICIADO");

}

 

 

// =================================================

// CICLO PRINCIPAL (LAZO CERRADO)

// =================================================

void loop() {

 

  /*

  ==========================================================

  ================== CICLO DE LAZO CERRADO =================

  ==========================================================

 

  1) MEDIR        -> medirLuz()

  2) COMPARAR     -> calcularError()

  3) DECIDIR      -> calcularBrillo()   (PWM = Kp × ERROR)

  4) ACTUAR       -> aplicarSalida()

  5) OBSERVAR     -> mostrarDatos()

  6) ESPERAR      -> delay(ms)

  7) REPETIR      -> vuelve al paso 1 automáticamente

 

  Este ciclo se repite muchas veces.

  Eso es el LAZO CERRADO.

  ==========================================================

  */

 

  // 1️⃣ MEDIR (ENTRADA)

  medirLuz();

 

  // 2️⃣ COMPARAR (ERROR)

  calcularError();

 

  // 3️⃣ DECIDIR (CONTROL PROPORCIONAL)

  calcularBrillo();

 

  // 4️⃣ ACTUAR (SALIDA)

  aplicarSalida();

 

  // 5️⃣ OBSERVAR (RETROALIMENTACIÓN)

  mostrarDatos();

 

  // 6️⃣ ESPERAR Y REPETIR

  delay(TIEMPO_ENTRE_CICLOS_MS);

}

 

 

No hay comentarios:

Publicar un comentario