♻️

Clasificador de Residuos Solidos

Manual de uso del sistema de clasificacion automatica con ESP32-S3, inteligencia artificial y servidor en la nube

v2.0 · Mayo 2026

CONTENIDO

  1. Arquitectura del sistema - Como funciona todo junto
  2. Modelos de inteligencia artificial - Groq, Mistral, Edge Impulse y DeepSeek
  3. Configurar el ESP32-S3 - Firmware y conexion WiFi
  4. Usar el dashboard - Interfaz web, panel de conexion
  5. Categorias de residuos - Aprovechable, No aprovechable, Organico
  6. Referencia de la API - Endpoints del servidor
  7. Solucion de problemas - Errores frecuentes

01 Arquitectura del sistema

El sistema usa una arquitectura PUSH: el ESP32 toma una foto y la envia al servidor en la nube, que clasifica el residuo y muestra el resultado en el dashboard. Esto permite que el ESP32 este en cualquier red con internet (como la red del colegio) sin necesidad de que el servidor pueda alcanzarlo directamente.

📷
ESP32-S3
Captura foto
🌐
Internet
HTTPS POST
🖥️
Servidor
Nube · Flask
🤖
3 modelos IA
Groq + Mistral + EI
⚖️
DeepSeek
Arbitro final
📊
Dashboard
Resultado
El ESP32 no necesita estar en la misma red que el servidor. Solo necesita acceso a internet. El servidor ya esta corriendo en la nube en clasificador.207.180.252.88.nip.io.

Flujo de una clasificacion

El ESP32 captura una foto JPEG

La camara OV3660 toma la foto automaticamente cada X segundos (configurable en el firmware).

El ESP32 envia la foto al servidor

Hace un POST HTTPS a /api/push con la imagen como cuerpo de la peticion y la API key en el header.

El servidor procesa la imagen con 3 modelos en paralelo

Groq (Llama Vision), Mistral (Pixtral) y Edge Impulse (TFLite local) analizan la imagen simultaneamente.

DeepSeek arbitra el resultado final

Recibe los 3 resultados, detecta consenso o conflicto, y emite el veredicto definitivo con razon explicada.

El dashboard muestra el resultado

El panel se actualiza automaticamente cada 2 segundos con la categoria, objeto detectado y resultados por modelo.

02 Modelos de inteligencia artificial

El sistema usa 4 modelos de IA con roles distintos para maximizar la precision:

Groq Llama 4 Scout Vision

Modelo de vision de Meta que analiza la imagen y clasifica el residuo. Accede via API de Groq (gratuita). Responde en menos de 2 segundos.

Mistral Pixtral 12B

Modelo de vision de Mistral AI, especializado en comprension visual. Segundo opinion independiente de Groq. API gratuita con registro.

Edge Impulse TFLite local

Modelo TensorFlow Lite entrenado con datos reales de residuos. Corre directamente en el servidor sin llamadas externas. Clasifica en categorias: Reciclaje, Organica, No reciclable.

DeepSeek Arbitro de coherencia

No analiza la imagen directamente. Recibe los 3 resultados anteriores y determina el veredicto final segun reglas: si coinciden 2 de 3, aplica mayoria. Si todos difieren, razona segun el objeto detectado.

Reglas del arbitro (DeepSeek)

SITUACIONDECISIONCONFIANZA
Los 3 modelos coincidenConfirma la categoriaALTA
2 de 3 coincidenAplica la mayoriaALTA
Todos difierenAnaliza segun objeto detectadoMEDIA
Algunos fallaronUsa los resultados validosMEDIA
Todos fallaronDESCONOCIDOBAJA

03 Configurar el ESP32-S3

El ESP32 actua en modo PUSH: toma fotos y las envia al servidor. No necesita que el servidor le haga peticiones. Funciona desde cualquier red WiFi con internet.

Requisitos de hardware

COMPONENTEDETALLE
PlacaESP32-S3 con camara OV3660 y PSRAM
CableUSB-C al puerto USB-UART (para programar)
RedWiFi 2.4GHz con acceso a internet

Configurar Arduino IDE

Instalar Arduino IDE 2.x

Descargar de arduino.cc/en/software e instalar normalmente.

Agregar soporte para ESP32

Archivo → Preferencias → campo "URLs adicionales de placas", agregar:

URL de placas
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
Instalar placa ESP32

Herramientas → Placa → Gestor de Placas → buscar "esp32" → instalar "esp32 by Espressif Systems" v3.x

Configurar la placa

Herramientas → Placa → ESP32S3 Dev Module. Configurar PSRAM: OPI PSRAM, Partition Scheme: Huge APP.

Si el ESP32 no aparece en los puertos COM, instala el driver CH340 o CP210x segun tu placa. Algunos cables USB son solo de carga — usa uno con datos.

Firmware (copiar en Arduino IDE)

Este es el codigo completo para el modo PUSH. Solo cambia las 3 lineas marcadas:

CameraStream.ino — Modo PUSH al servidor
/* ESP32-S3 - Clasificador de Residuos - Modo PUSH Envia fotos al servidor en la nube via HTTPS Placa: ESP32-S3 con OV3660 + PSRAM */ #include "esp_camera.h" #include <WiFi.h> #include <HTTPClient.h> #include <WiFiClientSecure.h> // =========== CONFIGURAR AQUI =========== const char* WIFI_SSID = "NombreDeWifi"; // ← CAMBIAR const char* WIFI_PASS = "ClaveDeWifi"; // ← CAMBIAR const char* SERVER_URL = "https://clasificador.207.180.252.88.nip.io/api/push"; const char* API_KEY = "esp32clasif2025"; const int INTERVALO = 5000; // ms entre fotos (5s) // ======================================= // Pines camara OV3660 (ESP32-S3) #define PWDN_GPIO_NUM -1 #define RESET_GPIO_NUM -1 #define XCLK_GPIO_NUM 15 #define SIOD_GPIO_NUM 4 #define SIOC_GPIO_NUM 5 #define Y9_GPIO_NUM 16 #define Y8_GPIO_NUM 17 #define Y7_GPIO_NUM 18 #define Y6_GPIO_NUM 12 #define Y5_GPIO_NUM 10 #define Y4_GPIO_NUM 8 #define Y3_GPIO_NUM 9 #define Y2_GPIO_NUM 11 #define VSYNC_GPIO_NUM 6 #define HREF_GPIO_NUM 7 #define PCLK_GPIO_NUM 13 bool iniciarCamara() { camera_config_t config; config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; config.pin_d0 = Y2_GPIO_NUM; config.pin_d1 = Y3_GPIO_NUM; config.pin_d2 = Y4_GPIO_NUM; config.pin_d3 = Y5_GPIO_NUM; config.pin_d4 = Y6_GPIO_NUM; config.pin_d5 = Y7_GPIO_NUM; config.pin_d6 = Y8_GPIO_NUM; config.pin_d7 = Y9_GPIO_NUM; config.pin_xclk = XCLK_GPIO_NUM; config.pin_pclk = PCLK_GPIO_NUM; config.pin_vsync = VSYNC_GPIO_NUM; config.pin_href = HREF_GPIO_NUM; config.pin_sccb_sda = SIOD_GPIO_NUM; config.pin_sccb_scl = SIOC_GPIO_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; config.xclk_freq_hz = 20000000; config.pixel_format = PIXFORMAT_JPEG; config.frame_size = FRAMESIZE_VGA; // 640x480 config.jpeg_quality = 12; config.fb_count = 2; config.fb_location = CAMERA_FB_IN_PSRAM; config.grab_mode = CAMERA_GRAB_LATEST; if (esp_camera_init(&config) != ESP_OK) { Serial.println("Error iniciando camara"); return false; } sensor_t *s = esp_camera_sensor_get(); s->set_brightness(s, 1); s->set_saturation(s, 0); return true; } void enviarFoto() { camera_fb_t* fb = esp_camera_fb_get(); if (!fb) { Serial.println("Error capturando foto"); return; } Serial.printf("Foto: %d bytes → enviando...\n", fb->len); WiFiClientSecure client; client.setInsecure(); // acepta certificado del servidor HTTPClient http; http.begin(client, SERVER_URL); http.addHeader("Content-Type", "image/jpeg"); http.addHeader("X-API-Key", API_KEY); http.setTimeout(20000); int code = http.POST(fb->buf, fb->len); esp_camera_fb_return(fb); if (code == 200) { String resp = http.getString(); Serial.println("OK: " + resp); } else { Serial.printf("Error HTTP %d\n", code); } http.end(); } void setup() { Serial.begin(115200); Serial.println("\n=== Clasificador de Residuos - PUSH Mode ==="); if (!iniciarCamara()) { while(1) delay(1000); } Serial.println("Camara OK"); WiFi.begin(WIFI_SSID, WIFI_PASS); WiFi.setSleep(false); Serial.print("Conectando WiFi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nWiFi OK - IP: " + WiFi.localIP().toString()); Serial.println("Enviando a: " + String(SERVER_URL)); } void loop() { if (WiFi.status() != WL_CONNECTED) { Serial.println("WiFi perdido, reconectando..."); WiFi.reconnect(); delay(5000); return; } enviarFoto(); delay(INTERVALO); }
Conectar el ESP32 al PC por USB-UART

Usar el puerto marcado como USB-UART (no el USB-OTG). Si no aparece el puerto, instalar el driver CH340.

Pegar el codigo y cambiar WiFi

Archivo → Nuevo Sketch, pegar el codigo completo. Cambiar NombreDeWifi y ClaveDeWifi por los datos reales de la red.

Poner en modo bootloader si no sube

Mantener BOOT presionado, presionar RESET, soltar BOOT. Luego clic en Subir en Arduino IDE.

Abrir Serial Monitor (115200 baud)

Debe mostrar "Camara OK", "WiFi OK" y luego "OK: {ok: true, ...}" en cada foto enviada.

Cuando el Serial Monitor muestre OK: {"ok":true,...} el ESP32 esta correctamente conectado al servidor y el dashboard mostrara el chip ESP32 en verde: PUSH · ONLINE.

04 Usar el dashboard

El dashboard esta disponible en:

🌐 https://clasificador.207.180.252.88.nip.io

Panel de camara (izquierda)

Cuando el ESP32 no esta conectado, el panel muestra el area de carga en modo demo. Permite subir fotos desde el celular, galeria o webcam para clasificar manualmente.

Cuando el ESP32 envia su primera foto, el panel cambia automaticamente a mostrar la ultima imagen recibida.

Panel de resultados (derecha)

Muestra la categoria detectada (APROVECHABLE / NO APROVECHABLE / ORGANICO), el objeto identificado, el nivel de confianza y los resultados individuales de los 4 modelos en bloques de terminal.

Panel "CONECTAR ESP32" (abajo)

Expandible con clic. Contiene:

ELEMENTODESCRIPCION
EndpointURL del servidor para configurar en el firmware del ESP32
API KeyClave de autenticacion que debe ir en el header X-API-Key
Ultimo frameTiempo transcurrido desde la ultima foto recibida
EstadoBadge que cambia de DESCONECTADO a CONECTADO (verde) automaticamente
Codigo ArduinoCodigo completo listo para copiar al IDE con boton COPIAR TODO

Modos de captura (modo demo)

BOTONFUNCION
TOMAR FOTOAbre la camara del dispositivo directamente (ideal en celular)
GALERIASeleccionar una imagen guardada en el dispositivo
CAMARA EN VIVOActiva la webcam del computador para capturar con el boton CAPTURAR

Indicadores en la barra superior

CHIPVERDEAMARILLO / ROJO
ESP32PUSH · ONLINE — recibiendo fotosDEMO — sin ESP32
GROQOK — clasifico correctamentePENDIENTE — sin resultado
MISTRALOK — clasifico correctamentePENDIENTE — sin resultado
EDGE IMPULSEOK — modelo TFLite funcionoTFLite — pendiente
DEEPSEEKOK — arbitro emitio veredictoARBITRO — pendiente

05 Categorias de residuos

El sistema clasifica en 3 categorias segun la normativa colombiana de separacion de residuos:

♻️ APROVECHABLE

Residuos que pueden reciclarse y reintroducirse en la cadena productiva.

Ejemplos: botellas de plastico, latas de aluminio, vidrio, carton, papel blanco, cajas de cereal, revistas, botellas de vidrio.

🚫 NO APROVECHABLE

Residuos que no pueden reciclarse ni aprovecharse. Van al relleno sanitario.

Ejemplos: papel higienico, servilletas usadas, icopor (poliestireno), empaques contaminados con grasa, pañales, papel carbon, pitillos.

🍂 ORGANICO

Residuos de origen biologico que se pueden compostar o aprovechar como abono.

Ejemplos: cascaras de fruta, restos de comida, verduras, huesos, hojas, pasto, cafe usado, residuos de jardin.

Coloca el objeto centrado frente a la camara con buena iluminacion y sin objetos de fondo que confundan al modelo. La confianza es mayor cuando el objeto ocupa la mayor parte del encuadre.

06 Referencia de la API

El servidor expone los siguientes endpoints:

METODOENDPOINTDESCRIPCION
GET/Dashboard principal (interfaz web)
GET/manualEste manual
GET/api/classifyEstado actual de clasificacion (JSON)
POST/api/uploadSubir imagen desde el navegador (multipart/form-data)
POST/api/pushRecibir frame del ESP32 (image/jpeg raw) · requiere X-API-Key
GET/api/snapshotUltimo frame recibido como imagen JPEG
GET/api/classify_nowFuerza clasificacion inmediata (solo modo ESP32_IP)

Ejemplo: enviar imagen con curl

Terminal
# Enviar una imagen JPEG al endpoint push curl -X POST https://clasificador.207.180.252.88.nip.io/api/push \ -H "Content-Type: image/jpeg" \ -H "X-API-Key: esp32clasif2025" \ --data-binary @foto.jpg # Respuesta esperada: {"ok": true, "category": "APROVECHABLE", "confidence": "ALTA"}

07 Solucion de problemas

El ESP32 muestra "Error HTTP -1" o no conecta
  • Verificar que el WiFi tiene acceso a internet (no solo a la red local)
  • Algunos colegios bloquean HTTPS saliente — pedir al administrador que permita el puerto 443
  • Revisar que WIFI_SSID y WIFI_PASS esten correctos (mayusculas/minusculas)
  • El ESP32 solo soporta WiFi 2.4GHz — no funciona en redes 5GHz
Error HTTP 401 (Unauthorized)

La API key es incorrecta. Verificar que el header X-API-Key tenga exactamente el valor esp32clasif2025 (sin espacios ni comillas extra).

Error "Camera init failed"

Los pines de la camara pueden variar segun el modelo de placa ESP32-S3. Busca el pinout exacto de tu placa y ajusta las definiciones #define Y2_GPIO_NUM etc. al inicio del codigo.

La placa no aparece en los puertos COM
  • Instalar driver CH340 (buscar "CH340 driver Windows" o "macOS")
  • Probar con otro cable USB — muchos cables son solo de carga
  • Usar el puerto USB-UART de la placa, no el USB-OTG
El dashboard muestra "DESCONECTADO" aunque el ESP32 envia fotos
  • Verificar en el Serial Monitor que el HTTP code sea 200 (no -1 ni 401)
  • Refrescar el navegador y esperar 2-3 segundos
  • Revisar el log del servidor: tail -f /tmp/clasificador.log
La clasificacion es incorrecta o dice "SIN OBJETO"
  • Asegurar que el objeto este bien iluminado y centrado en el encuadre
  • Evitar fondos muy cargados o similares al objeto
  • Acercar el objeto a la camara para que ocupe mas del encuadre
  • El nivel de confianza BAJA o MEDIA indica que los modelos no coincidieron — repetir la clasificacion
El servidor no responde o da error 502

El proceso Flask puede haberse caido. Contactar al administrador del servidor para reiniciarlo, o ejecutar en el servidor: tail -20 /tmp/clasificador.log para ver el error.