TFG · Ingeniería de Telecomunicaciones · UC3M
Registro cronológico del trabajo realizado en el desarrollo del sistema de búsqueda y rescate basado en UAV.
El proyecto tiene ya resuelta toda la base sobre la que se construirá el resto del sistema. Está cerrada la parte normativa —certificado de piloto A1/A3 y número de operador AESA— y el acceso a un espacio de vuelo seguro, gracias a la federación en el club Alas de Galapagar, cuya licencia de socio incluye el seguro obligatorio. He realizado además un primer vuelo de referencia, cuyo registro GPS me sirve para planificar misiones en simulación.
En el plano técnico, la infraestructura extremo a extremo está operativa. La adquisición de datos en el nodo edge se ha organizado por dominios independientes (ambiental, sistema, vuelo y detección), cada uno como un proceso propio con su buffer local en SQLite y publicando bajo una estructura jerárquica de topics sar/{dron_id}/{dominio}, con almacenamiento intermedio local para no perder datos ante cortes de red. El sensor ambiental BME680 sobre la Raspberry Pi 5 alimenta ya el dominio ambiental, cuyas lecturas llegan por MQTT al servidor en la nube (AWS EC2 con Mosquitto e InfluxDB). El enlace entre el nodo edge y la nube ya no depende del entorno de desarrollo: he configurado un módem USB 4G/LTE con una SIM de DIGI —con su propio perfil APN y el PIN desactivado para que arranque de forma autónoma—, de modo que el dron sale a Internet por red celular, reservando la Wi-Fi como enlace local alternativo. Sobre esa conectividad he levantado además una VPN en malla (mesh) con Tailscale que une el servidor, la Raspberry y mi equipo en una red privada Zero Trust, cifrada de extremo a extremo y sin necesidad de abrir puertos al exterior. Los servidores web están en marcha, y tanto las páginas como los servicios dinámicos (API REST e InfluxDB) se sirven ya por HTTPS con certificado propio, accediéndose a estos últimos a través de un reverse proxy en nginx que permite mantener cerrados sus puertos al exterior.
En cuanto al vuelo, he llevado el control autónomo de la simulación a la Raspberry Pi: la Pi comanda el dron simulado (Mission Planner + ArduPilot SITL) por MAVLink a través de la red. Sobre esa base he montado el control por MQTT —un publicador en el EC2 y un receptor en la Pi que traduce las órdenes a MAVLink— y una API REST con una página de botones para teleoperar el dron (armar, despegar, aterrizar, RTL, misión) desde el navegador, ya validada contra el simulador. Este panel se ha ampliado además con un selector que permite elegir a qué dron (dron-01 / dron-02) se dirige cada comando, y con nuevos botones de gestión remota del nodo edge —como apagar la Raspberry Pi o ajustar en caliente parámetros de funcionamiento (cada cuánto envía datos el dominio de sistema o el intervalo anti-spam de las alertas)—. Tanto la API como el receptor se ejecutan como servicios systemd, de modo que arrancan solos y se reinician ante cualquier interrupción.
En el apartado de visión artificial, he desarrollado el pipeline de detección de personas con YOLO y lo he validado sobre vídeo real, ejecutándolo en mi propio equipo (todavía sin el acelerador Hailo y sin desplegar en la Raspberry Pi). Cuando el sistema detecta a una persona, genera una alerta que se publica por MQTT con el mismo esquema store-and-forward que el resto de dominios, incluyendo la caja de la detección, la posición del dron y una foto del fotograma con las coordenadas y la marca temporal superpuestas. En paralelo, he empezado a construir el dataset con Roboflow y ya he capturado las primeras imágenes para el entrenamiento.
El repositorio del servidor se ha reorganizado por carpetas para separar las páginas web, el panel de control y la API, y se trabaja ahora sobre una rama develop que mantiene la rama principal con la versión estable. El fallo de la tarjeta microSD que dejó temporalmente fuera de servicio a la Raspberry Pi está resuelto: se ha sustituido y repetido la instalación de la imagen, además de rehacer el script del receptor, que no estaba subido al repositorio. He puesto en marcha también la presencia web pública del proyecto: una landing de colaboración para captar vídeos aéreos y patrocinios, y una web técnica que documenta el sistema completo (arquitectura de comunicaciones, hardware, software y cloud, IA y marco del proyecto).
Próximos pasos: ampliar el dataset de detección con muchas más imágenes aéreas para entrenar el modelo definitivo. En paralelo, ensamblar el dron definitivo e incorporar autenticación a la API y cifrado MQTT antes de conectar la cadena de mando a la aeronave real.
Filtrar por área
Julio 2026
1883 para la comunicación MQTT con el broker Mosquitto, puerto 22 para SSH y puerto 8086 para el acceso a la base de datos InfluxDB.sensor.py en la Pi y mqtt_to_influx.py en la EC2.sensor.py para que ningún dato se pierda ante una caída temporal de la conexión (cada lectura se almacena primero en una base de datos local SQLite, buffer.db).mqtt_to_influx.py actúa como cliente suscriptor; se ejecuta en la EC2 dentro de un entorno virtual propio (env) con las librerías paho-mqtt (comunicación con el broker) e influxdb-client (escritura en la base de datos).8086, de forma que se pueda acceder desde el navegador mediante la dirección pública de la EC2..gitignore (evita subir archivos sensibles o innecesarios), requirements.txt (dependencias reproducibles) y .env.example (plantilla de credenciales, que se mantienen fuera del repositorio).
gorostiditfg.com en Cloudflare 10,41 $, para acceder a los servicios mediante subdominios legibles en vez de la IP del servidor.www.gorostiditfg.com y control.gorostiditfg.com.8086 en la petición HTTP, había que indicarlo y ya no es necesario especificarlo → influxdb.gorostiditfg.com..ssh en la EC2 para permitir el acceso con mi clave pública en lugar del .pem (habilitando esta otra forma editando el .ssh).14550.8086 del grupo de seguridad de la EC2, ya innecesario: el acceso a la interfaz de InfluxDB se realiza ahora a través de nginx configurado como reverse proxy (influxdb.gorostiditfg.com), sin exponer el puerto directamente a internet.127.0.0.1, el reenvío UDP y el puerto 14550.udpin/udpout) y por qué en MAVLink la Pi escucha mientras recibe la telemetría del autopiloto.comandos.py, en el EC2) que envía las órdenes por MQTT, y de un receptor (receptor.py, en la Pi) que las traduce a MAVLink y las ejecuta sobre el dron simulado.api.py, en el EC2) para poder invocar los comandos por HTTP en lugar de por terminal, y para ello se ha abierto el puerto 5000 en el grupo de seguridad de AWS.api.py) para entender no solo qué hace, sino por qué existe y qué papel tiene dentro de la arquitectura. Se ha revisado la cadena completa de comunicación: navegador (HTTP) → api.py en el EC2, que traduce HTTP a MQTT → broker Mosquitto (puerto 1883) → receptor.py en la Raspberry Pi, que traduce MQTT a MAVLink → autopiloto → dron.
api.py y receptor.py no están conectados directamente: se comunican a través del broker, gracias al modelo publicador/suscriptor desacoplado de MQTT.comandos.py y api.py son alternativas paralelas para enviar los mismos comandos, no pasos consecutivos.5000 y Mosquitto en el 1883. receptor.py no abre ningún puerto porque actúa como cliente, no como servidor.Ctrl+C incompleto. Resuelto con pkill -f api.py.api.py y receptor.py en servicios systemd, igual que ya lo están mqtt_to_influx.py y sensor.py, para que arranquen solos y no dependan de una terminal abierta. PENDIENTE443 en el grupo de seguridad del servidor.api.gorostiditfg.com en Cloudflare en modo Proxied, configurar nginx como reverse proxy hacia localhost:5000 y actualizar la URL del fetch en el JavaScript del panel. PENDIENTEwww/web/, control/ y api-rest/) e incluyendo las páginas HTML, que hasta ahora solo existían en el servidor.sudo poweroff. Se ha intentado volver a cargar la imagen de Raspberry Pi OS en la tarjeta y no es capaz de leerla.sudo poweroff y mantener todo actualizado en GitHub, para no perder los códigos ni el trabajo hecho hasta el momento.receptor.py, único script que no estaba subido al repositorio y que se perdió con la tarjeta.api.gorostiditfg.com, configurado nginx como reverse proxy hacia localhost:5000, emitido el certificado TLS y actualizada la URL del fetch en el panel de control.receptor.py en la Raspberry Pi y para api.py en la instancia EC2, de forma que ambos arranquen automáticamente y se reinicien ante cualquier interrupción, sin depender de una sesión SSH abierta.Agosto 2026
best.pt).patience=20); la métrica de validación se estabiliza en torno a la época 40, por lo que ese número resulta suficiente para la convergencia.output.mp4. La he probado tanto con un vídeo grabado con el móvil como con uno grabado desde el dron.sar/{dron_id}/{dominio}) y client_id como {dron_id}-{dominio} para que Mosquitto no tire conexiones por IDs duplicados.dron_id desde un .env compartido.vuelo.py y deteccion.py mediante escrituras atómicas en posicion_actual.json.ambiental.py para leer los datos del sensor BME680.sistema.py para monitorizar las métricas y el estado de la Raspberry Pi.vuelo.py de forma provisional con telemetría simulada (a la espera de integrar la Pixhawk).deteccion.py integrando YOLO, afinando parámetros como flags explícitos (--mqtt y --preview), un --anti-spam por defecto a 5 s y haciendo que cada proceso infiera automáticamente su base de datos según el dominio, sin configuraciones extra.sar/#: así identifica automáticamente de qué sensor viene el dato leyendo el topic y simplifica la estructura del JSON para que la base de datos lo trague sin procesado extra.deteccion.py con YOLO sobre un vídeo real, corriéndolo en mi propia máquinasar/{dron_id}/deteccion (con buffer store-and-forward), que incluye la caja en píxeles, la posición del dron y la foto.API_BASE del index.html seguía apuntando por HTTP directamente a la IP pública de la instancia EC2. Como el navegador bloquea las llamadas HTTP inseguras, cambio la URL para que apunte a https://api.gorostiditfg.com.drone_id en el cuerpo de la petición. La API asigna por defecto dron-01, pero como el receptor está escuchando en dron-02, el comando se pierde y nunca llega a ejecutarse.dron-01 / dron-02) en el panel de control.enviar() para que capture el valor seleccionado y lo adjunte en cada petición a la API.receptor.py falla al arrancar con WinError 10013 porque Mission Planner tiene ocupado el puerto 14550. Cambio la conexión a MAVLINK_CONN = "udpin:127.0.0.1:14551".wait_heartbeat() porque el reenvío UDP de Mission Planner sigue apuntando al puerto antiguo. Entro al menú avanzado de Mission Planner (Ctrl + F) y redirijo el forward UDP a 127.0.0.1:14551.TFG ·, definición de topics y creación del README del perfil con badges.TFG ·, definición de topics y creación del README del perfil con badges.Base sobre la que arranca el proyecto. En lo normativo: certificado A1/A3 de AESA y número de operador obtenidos, e inscripción como socia en el club Alas de Galapagar para volar sin necesidad de permisos adicionales y con el seguro incluido. En lo técnico: compra de la Raspberry Pi 5 y del sensor ambiental BME680 con la conexión ya configurada, una instancia EC2 en AWS con el broker Mosquitto e IP elástica, y el primer flujo de datos de extremo a extremo (sensor.py → MQTT → mqtt_to_influx.py → InfluxDB) con arquitectura store-and-forward para no perder lecturas. Todo ello arrancando solo mediante servicios systemd, publicado en dos repositorios de GitHub, sobre el dominio propio gorostiditfg.com y con dos primeras páginas web (presentación y control) ya creadas.
Primera semana completa de desarrollo: servidores web con nginx y subdominios propios (www, control, influxdb) sobre el dominio de Cloudflare, y limpieza de la gestión de claves SSH. Primer vuelo real de un dron en el club de Galapagar, con el número de operador ya pegado en el aparato. El control autónomo del dron simulado se lleva a la Raspberry Pi por MAVLink (arquitectura edge-first), y sobre esa base se monta el control por MQTT y una API REST con panel web de botones para teleoperar el dron. Se activa HTTPS en todas las páginas —apareciendo el primer bloqueo por mixed content— y se reorganiza el repositorio del servidor en GitHub. La semana se cierra con la detección de un fallo en la tarjeta microSD de la Raspberry Pi.
Recuperación completa tras el fallo de la tarjeta microSD: nueva tarjeta grabada, repositorio clonado desde GitHub y receptor.py reescrito por ser el único script que no estaba respaldado. Comienza la redacción de la memoria del TFG (arquitectura IoT con EC2, BME680 y MQTT), y se resuelve definitivamente el problema de mixed content creando el subdominio api.gorostiditfg.com con reverse proxy en nginx y certificado TLS.
Semana centrada en la memoria del TFG: reorganización de capítulos (control de vuelo separado de la arquitectura IoT), reconstrucción del estado del arte, redacción de la normativa (Reglamento UE 2019/947, categoría A3, Remote ID, RD 517/2024) y bibliografía en formato IEEE. También primer contacto con Roboflow de cara al futuro dataset de detección de personas.
Un socio del club presta un hexacóptero de fibra de carbono para reutilizar piezas, lo que permite definir el plan de compra de componentes nuevos (Pixhawk 6C, GPS, telemetría, batería LiPo) y contactar con RC-Innovations. En paralelo, primera práctica completa con Roboflow y Ultralytics: dataset de prueba con frutas, entrenamiento de un primer modelo YOLO en local, ajuste del número de épocas, inferencia sobre vídeo y publicación del código en GitHub.
Semana de mucho avance: se recibe presupuesto y se reserva el kit de vuelo con RC-Innovations, se graban los primeros vídeos reales para el dataset de detección de personas (35 imágenes) y se diseña e implementa la arquitectura de datos definitiva del nodo edge, con un proceso independiente por dominio (ambiental, sistema, vuelo, detección) y topics MQTT jerárquicos. Se prueba con éxito la detección de personas con YOLO sobre vídeo real, y se depuran varios fallos del panel de control web (mixed content, pérdida del drone_id, conflicto de puertos con Mission Planner), añadiendo un selector para elegir el dron. La semana se cierra con la publicación de la landing page de colaboración y el arranque de la web técnica del proyecto (Guardian Eye).
Continúa y se cierra la web técnica del proyecto (Guardian Eye), con las secciones de arquitectura, inteligencia artificial y proyecto ya desarrolladas y enlazadas con la landing, GitHub y el journal. Se reorganiza la memoria separando la adquisición de datos IoT (cap. 6) de los servicios web y control remoto (cap. 7), y se despliega conectividad robusta en el nodo edge: una VPN en malla Zero Trust con Tailscale y un enlace 4G/LTE con SIM de DIGI como salida a Internet principal.