Control de Incubadora con LabVIEW y ESP32

Objetivos de la Práctica

  • Controlar temperatura y humedad en una incubadora

  • Monitorear condiciones en tiempo real con LabVIEW

  • Implementar sistema de volteo automático de huevos

  • Crear sistema de alertas y registro de datos

  • Desarrollar interfaz HMI profesional en LabVIEW


Materiales Requeridos

Hardware:

  • ESP32 Dev Board

  • Sensor DHT22 (Temperatura y Humedad)

  • Sensor DS18B20 (Temperatura adicional)

  • Módulo Relé 4 canales

  • Calentador (resistencia 100W o bombilla incandescente)

  • Humidificador (nebulizador ultrasónico)

  • 2 Servomotores MG996R (volteo de huevos)

  • Ventilador DC 5V

  • Display LCD 16×2 (opcional)

  • Fuente de alimentación 12V/5A

  • Protoboard y cables

  • Caja aislante para incubadora

Software:

  • LabVIEW

  • Arduino IDE

  • VI Package Manager

  • LIFA Toolkit


Parte 1: Esquema de Conexiones

Diagrama de Conexiones ESP32:

cpp
// Sensores
DHT22      → GPIO 4
DS18B20    → GPIO 5
// Actuadores
RELE_CALENTADOR    → GPIO 12
RELE_HUMIDIFICADOR → GPIO 13
RELE_VENTILADOR    → GPIO 14
SERVO_1            → GPIO 18
SERVO_2            → GPIO 19
// Comunicación
LCD I2C            → GPIO 21 (SDA), GPIO 22 (SCL)

Esquema Eléctrico:

text
Fuente 12V ────┐
              │
       ┌──────┴──────┐
       │  RELÉS 4CH  │
       └──────┬──────┘
              │
    ┌─────────┼─────────┐
    │         │         │
Calentador Humidificador Ventilador
   (AC 110V)   (DC 12V)  (DC 12V)

Parte 2: Programación del ESP32

Código Principal (Incubadora_ESP32.ino):

cpp
#include <DHT.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Servo.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Definición de pines
#define DHT_PIN 4
#define ONE_WIRE_PIN 5
#define RELAY_HEATER 12
#define RELAY_HUMIDIFIER 13
#define RELAY_FAN 14
#define SERVO1_PIN 18
#define SERVO2_PIN 19

// Tipos de sensores
#define DHT_TYPE DHT22

// Instancias
DHT dht(DHT_PIN, DHT_TYPE);
OneWire oneWire(ONE_WIRE_PIN);
DallasTemperature sensors(&oneWire);
Servo servo1, servo2;
LiquidCrystal_I2C lcd(0x27, 16, 2);

// Variables de control
float targetTemp = 37.5;      // Temperatura objetivo
float targetHumidity = 60.0;  // Humedad objetivo
float tempTolerance = 0.5;    // Tolerancia temperatura
float humTolerance = 5.0;     // Tolerancia humedad
int flipInterval = 3600;      // Intervalo volteo (segundos)
bool autoMode = true;         // Modo automático

// Variables de estado
float currentTemp = 0;
float currentHumidity = 0;
float currentTemp2 = 0;
bool heaterState = false;
bool humidifierState = false;
bool fanState = false;
unsigned long lastFlipTime = 0;
int flipCount = 0;
String incubadoraStatus = "INICIANDO";

void setup() {
  // Inicializar comunicación
  Serial.begin(115200);
  
  // Inicializar sensores
  dht.begin();
  sensors.begin();
  
  // Configurar pines
  pinMode(RELAY_HEATER, OUTPUT);
  pinMode(RELAY_HUMIDIFIER, OUTPUT);
  pinMode(RELAY_FAN, OUTPUT);
  
  // Configurar servos
  servo1.attach(SERVO1_PIN);
  servo2.attach(SERVO2_PIN);
  resetServos();
  
  // Configurar LCD
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("INCUBADORA  AVICOLA");
  
  // Inicialmente apagar todos los relays
  digitalWrite(RELAY_HEATER, HIGH);     // HIGH = Apagado
  digitalWrite(RELAY_HUMIDIFIER, HIGH);
  digitalWrite(RELAY_FAN, HIGH);
  
  Serial.println("INCUBADORA_READY");
}

void loop() {
  // Leer sensores cada 2 segundos
  static unsigned long lastSensorRead = 0;
  if (millis() - lastSensorRead >= 2000) {
    readSensors();
    lastSensorRead = millis();
  }
  
  // Control automático
  if (autoMode) {
    controlTemperature();
    controlHumidity();
    controlVentilation();
    controlEggFlip();
  }
  
  // Actualizar LCD cada 5 segundos
  static unsigned long lastLCDUpdate = 0;
  if (millis() - lastLCDUpdate >= 5000) {
    updateLCD();
    lastLCDUpdate = millis();
  }
  
  // Enviar datos a LabVIEW cada 3 segundos
  static unsigned long lastDataSend = 0;
  if (millis() - lastDataSend >= 3000) {
    sendDataToLabVIEW();
    lastDataSend = millis();
  }
  
  // Procesar comandos seriales
  processSerialCommands();
  
  delay(100);
}

void readSensors() {
  // Leer DHT22
  currentTemp = dht.readTemperature();
  currentHumidity = dht.readHumidity();
  
  // Leer DS18B20
  sensors.requestTemperatures();
  currentTemp2 = sensors.getTempCByIndex(0);
  
  // Verificar errores de sensor
  if (isnan(currentTemp) || isnan(currentHumidity)) {
    incubadoraStatus = "ERROR_SENSOR";
    return;
  }
  
  // Promedio de temperaturas
  float avgTemp = (currentTemp + currentTemp2) / 2.0;
  currentTemp = avgTemp;
}

void controlTemperature() {
  if (currentTemp < (targetTemp - tempTolerance)) {
    digitalWrite(RELAY_HEATER, LOW);  // Encender calentador
    heaterState = true;
  } else if (currentTemp > (targetTemp + tempTolerance)) {
    digitalWrite(RELAY_HEATER, HIGH); // Apagar calentador
    heaterState = false;
    // Encender ventilador si temperatura muy alta
    if (currentTemp > (targetTemp + 1.0)) {
      digitalWrite(RELAY_FAN, LOW);
      fanState = true;
    }
  } else {
    digitalWrite(RELAY_FAN, HIGH);
    fanState = false;
  }
}

void controlHumidity() {
  if (currentHumidity < (targetHumidity - humTolerance)) {
    digitalWrite(RELAY_HUMIDIFIER, LOW);  // Encender humidificador
    humidifierState = true;
  } else if (currentHumidity > (targetHumidity + humTolerance)) {
    digitalWrite(RELAY_HUMIDIFIER, HIGH); // Apagar humidificador
    humidifierState = false;
  }
}

void controlVentilation() {
  // Ventilación periódica cada 30 minutos
  static unsigned long lastVentilation = 0;
  if (millis() - lastVentilation >= 1800000) { // 30 minutos
    digitalWrite(RELAY_FAN, LOW);
    delay(60000); // Ventilar por 1 minuto
    digitalWrite(RELAY_FAN, HIGH);
    lastVentilation = millis();
  }
}

void controlEggFlip() {
  if (millis() - lastFlipTime >= (flipInterval * 1000)) {
    flipEggs();
    lastFlipTime = millis();
    flipCount++;
  }
}

void flipEggs() {
  // Volteo a 45 grados
  servo1.write(45);
  servo2.write(45);
  delay(2000);
  
  // Regresar a posición inicial
  servo1.write(0);
  servo2.write(0);
  
  incubadoraStatus = "VOLTEO_COMPLETADO";
}

void resetServos() {
  servo1.write(0);
  servo2.write(0);
}

void updateLCD() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("T:");
  lcd.print(currentTemp, 1);
  lcd.print("C H:");
  lcd.print(currentHumidity, 0);
  lcd.print("%");
  
  lcd.setCursor(0, 1);
  lcd.print("E:");
  lcd.print(heaterState ? "ON " : "OFF");
  lcd.print(" V:");
  lcd.print(flipCount);
}

void sendDataToLabVIEW() {
  Serial.print("DATA:");
  Serial.print(currentTemp);
  Serial.print(",");
  Serial.print(currentHumidity);
  Serial.print(",");
  Serial.print(currentTemp2);
  Serial.print(",");
  Serial.print(heaterState ? "1" : "0");
  Serial.print(",");
  Serial.print(humidifierState ? "1" : "0");
  Serial.print(",");
  Serial.print(fanState ? "1" : "0");
  Serial.print(",");
  Serial.print(flipCount);
  Serial.print(",");
  Serial.println(incubadoraStatus);
}

void processSerialCommands() {
  if (Serial.available()) {
    String command = Serial.readStringUntil('\n');
    command.trim();
    
    if (command == "STATUS") {
      sendDetailedStatus();
    }
    else if (command.startsWith("SET_TEMP:")) {
      targetTemp = command.substring(9).toFloat();
      Serial.println("TEMP_SET:" + String(targetTemp));
    }
    else if (command.startsWith("SET_HUM:")) {
      targetHumidity = command.substring(8).toFloat();
      Serial.println("HUM_SET:" + String(targetHumidity));
    }
    else if (command.startsWith("SET_FLIP_INT:")) {
      flipInterval = command.substring(13).toInt();
      Serial.println("FLIP_INT_SET:" + String(flipInterval));
    }
    else if (command == "FLIP_NOW") {
      flipEggs();
      Serial.println("FLIP_EXECUTED");
    }
    else if (command == "AUTO_ON") {
      autoMode = true;
      Serial.println("AUTO_MODE_ON");
    }
    else if (command == "AUTO_OFF") {
      autoMode = false;
      Serial.println("AUTO_MODE_OFF");
    }
    else if (command == "HEATER_ON") {
      digitalWrite(RELAY_HEATER, LOW);
      heaterState = true;
      Serial.println("HEATER_ON");
    }
    else if (command == "HEATER_OFF") {
      digitalWrite(RELAY_HEATER, HIGH);
      heaterState = false;
      Serial.println("HEATER_OFF");
    }
  }
}

void sendDetailedStatus() {
  Serial.println("=== INCUBADORA STATUS ===");
  Serial.print("Temperature: "); Serial.println(currentTemp);
  Serial.print("Humidity: "); Serial.println(currentHumidity);
  Serial.print("Temp2: "); Serial.println(currentTemp2);
  Serial.print("Heater: "); Serial.println(heaterState ? "ON" : "OFF");
  Serial.print("Humidifier: "); Serial.println(humidifierState ? "ON" : "OFF");
  Serial.print("Fan: "); Serial.println(fanState ? "ON" : "OFF");
  Serial.print("Flip Count: "); Serial.println(flipCount);
  Serial.print("Auto Mode: "); Serial.println(autoMode ? "ON" : "OFF");
  Serial.print("Status: "); Serial.println(incubadoraStatus);
  Serial.println("========================");
}

Parte 3: Programación en LabVIEW

VI Principal: Control_Incubadora.vi

Front Panel Design:

labview
// PESTAÑA: MONITOREO PRINCIPAL
- Grupo: Indicadores de Temperatura
  * Termómetro: Temperatura Actual (0-50°C)
  * Numérico: Temperatura Objetivo
  * LED: Alarma Temperatura Alta
  * LED: Alarma Temperatura Baja

- Grupo: Indicadores de Humedad
  * Medidor: Humedad Actual (0-100%)
  * Numérico: Humedad Objetivo
  * LED: Alarma Humedad Alta
  * LED: Alarma Humedad Baja

- Grupo: Estado del Sistema
  * LED: Calentador Estado
  * LED: Humidificador Estado
  * LED: Ventilador Estado
  * LED: Modo Automático
  * Numérico: Contador de Volteos

- Grupo: Gráficos
  * Waveform Chart: Temperatura vs Tiempo
  * Waveform Chart: Humedad vs Tiempo
  * Waveform Chart: Estados Actuadores

// PESTAÑA: CONFIGURACIÓN
- Grupo: Parámetros de Control
  * Numérico: Temperatura Objetivo (35-39°C)
  * Numérico: Humedad Objetivo (40-80%)
  * Numérico: Tolerancia Temperatura (0.1-1.0)
  * Numérico: Tolerancia Humedad (1-10%)
  * Numérico: Intervalo Volteo (minutos)

- Grupo: Control Manual
  * Botón: Encender/Apagar Calentador
  * Botón: Encender/Apagar Humidificador
  * Botón: Volteo Manual
  * Botón: Activar/Desactivar Automático

// PESTAÑA: REGISTRO Y ALERTAS
- Grupo: Registro de Datos
  * Tabla: Histórico de Eventos
  * Botón: Exportar a Excel
  * Botón: Limpiar Registro

- Grupo: Sistema de Alertas
  * Lista: Log de Alertas
  * Numérico: Umbral Alerta Temperatura
  * Numérico: Umbral Alerta Humedad
  * Botón: Test Sonido Alerta

Diagrama de Bloques Principal:

labview
// ESTRUCTURA PRINCIPAL
While Loop con [Stop] button

// INICIALIZACIÓN
Case Structure: First Call?
  - VISA Configure Serial Port
  - Inicializar variables globales
  - Configurar gráficos

// COMUNICACIÓN SERIAL
Event Structure dentro del While Loop:
  - Timeout: 1000ms → Leer datos seriales
  - Value Change: Botones de control → Enviar comandos

// PROCESAMIENTO DE DATOS
VISA Bytes at Serial Port → If bytes > 0
  → VISA Read → Parsear datos → Actualizar indicadores

// SUBVIs ESPECIALIZADOS
- SubVI: "Parsear Datos Serial.vi"
- SubVI: "Controlar Actuadores.vi"
- SubVI: "Gestión Alertas.vi"
- SubVI: "Registro Datos.vi"

SubVI: Parsear Datos Serial.vi

labview
// Input: String de datos seriales
// Output: Cluster con todos los datos

// Ejemplo de datos: "DATA:37.5,65.2,37.6,1,0,1,15,VOLTEO_COMPLETADO"

// Algoritmo:
1. Buscar "DATA:" en string
2. Separar por comas → Array de strings
3. Convertir elementos a números/booleanos
4. Crear cluster de salida:
   - Temperatura (DBL)
   - Humedad (DBL)
   - Temperatura2 (DBL)
   - Estado Calentador (BOOL)
   - Estado Humidificador (BOOL)
   - Estado Ventilador (BOOL)
   - Contador Volteos (I32)
   - Estado Sistema (String)

SubVI: Gestión Alertas.vi

labview
// Inputs: Temperatura, Humedad, Umbrales
// Output: String de Alerta, LED Alerta

Case Structure:
  - Si Temp > Umbral Alto: "ALERTA: Temperatura ALTA"
  - Si Temp < Umbral Bajo: "ALERTA: Temperatura BAJA"
  - Si Hum > Umbral Alto: "ALERTA: Humedad ALTA"
  - Si Hum < Umbral Bajo: "ALERTA: Humedad BAJA"
  - Si sensor error: "ALERTA: Error de sensor"

// Acciones:
- Activar LED correspondiente
- Agregar a log de alertas
- Reproducer sonido (si configurado)
- Guardar en archivo de registro

Parte 4: Configuración Paso a Paso

Paso 1: Montaje Físico

  1. Construcción de la Incubadora:

    • Usar caja de espuma de poliestireno

    • Instalar ventana de observación

    • Colocar rejilla para huevos

    • Posicionar sensores a 5cm sobre huevos

  2. Instalación Eléctrica:

    • Conectar relés según diagrama

    • Aislar cables de alta potencia

    • Instalar fusibles de protección

    • Verificar puesta a tierra

Paso 2: Configuración ESP32

  1. Cargar código en Arduino IDE

  2. Verificar comunicación serial

  3. Calibrar sensores

  4. Probar actuadores individualmente

Paso 3: Programación LabVIEW

  1. Crear proyecto nuevo:

    text
    File → New Project
    Add VI: Control_Incubadora.vi
    Add SubVIs: Parsear, Alertas, Registro
  2. Configurar comunicación:

    • Puerto COM correcto

    • Baud rate 115200

    • Timeout 10 segundos

  3. Pruebas iniciales:

    • Comando «STATUS»

    • Control manual de actuadores

    • Registro de datos


Parte 5: Protocolo de Operación

Procedimiento de Inicio:

  1. Encender sistema de control

  2. Establecer parámetros iniciales:

    • Temperatura: 37.5°C

    • Humedad: 60%

    • Volteo cada 4 horas

  3. Verificar estabilidad por 2 horas

  4. Colocar huevos fértiles

Monitoreo Continuo:

  • Revisar gráficas cada 4 horas

  • Verificar contador de volteos

  • Registrar eventos importantes

  • Exportar datos diariamente

Mantenimiento:

  • Limpieza semanal

  • Calibración mensual de sensores

  • Verificación de actuadores

  • Backup de datos


Parte 6: Sistema de Seguridad

Protecciones Implementadas:

En ESP32:

cpp
// Watchdog timer
#include <esp_task_wdt.h>
void setup() {
  esp_task_wdt_init(10, true); // 10 segundos
}

// Verificación de sensores
bool checkSensors() {
  if (currentTemp > 45.0 || currentTemp < 20.0) {
    emergencyShutdown();
    return false;
  }
  return true;
}

void emergencyShutdown() {
  digitalWrite(RELAY_HEATER, HIGH);
  digitalWrite(RELAY_HUMIDIFIER, HIGH);
  digitalWrite(RELAY_FAN, HIGH);
  incubadoraStatus = "EMERGENCY_SHUTDOWN";
}

En LabVIEW:

labview
// Monitoreo de timeout
- Timer para verificar recepción de datos
- Si no hay datos en 30 segundos → Alerta
- Reintento automático de conexión

// Validación de datos
- Rango válido temperatura: 20-45°C
- Rango válido humedad: 0-100%
- Checksum de datos (opcional)

Parte 7: Análisis de Datos

Indicadores de Rendimiento:

  • Estabilidad Térmica: ±0.3°C

  • Estabilidad Humedad: ±5%

  • Eficiencia Energética: kWh por ciclo

  • Tasa de Éxito: Huevos eclosionados

Gráficos de Análisis:

labview
// Trend Analysis.vi
- Temperatura promedio por día
- Histograma de fluctuaciones
- Correlación temperatura-humedad
- Eficiencia de actuadores

Parte 8: Evaluación de la Práctica

Criterios de Evaluación:

  • ✅ Comunicación estable ESP32-LabVIEW

  • ✅ Control preciso de temperatura (±0.5°C)

  • ✅ Control preciso de humedad (±5%)

  • ✅ Sistema de volteo automático funcional

  • ✅ Interfaz intuitiva y completa

  • ✅ Sistema de alertas efectivo

  • ✅ Registro de datos confiable

Entregables:

  1. Código completo ESP32

  2. VIs de LabVIEW funcionando

  3. Diagramas de conexión

  4. Manual de operación

  5. Reporte de pruebas (24 horas)

  6. Análisis de datos de incubación

Pruebas de Validación:

  1. Prueba de Estabilidad: 24 horas sin huevos

  2. Prueba de Respuesta: Cambios bruscos de setpoint

  3. Prueba de Fallos: Desconexión de sensores

  4. Prueba de Seguridad: Límites de temperatura

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *