Trabajo de Fin de Grado — Escuela Superior de Ingeniería y Tecnología · Universidad de La Laguna
Alumno: Oscar Navarro Mesa
Tutor: Jesús Miguel Torres Jorge
Cotutor: Aram Pérez Dios
Este TFG forma parte de la misión TEIDESAT-I, el primer CubeSat universitario canario, desarrollado por estudiantes de la Universidad de La Laguna. El satélite, de configuración 1U, tiene como objetivo la demostración experimental de comunicación óptica Tierra-Espacio mediante pulsos de luz, complementada con comunicaciones tradicionales por radiofrecuencia.
El objetivo central del trabajo es la instalación, configuración y validación de un Sistema Operativo en Tiempo Real (RTOS) en el Ordenador a Bordo (OBC) de TEIDESAT-I, estableciendo una base de software de vuelo estable que garantice el correcto funcionamiento del satélite durante su operación en órbita.
El desarrollo se realiza en dos plataformas:
| Plataforma | Rol |
|---|---|
| ESP32 DevKit | Hardware de desarrollo, simulación y pruebas en tierra |
| OBC Triskel | Hardware objetivo de vuelo (destino final del firmware) |
La capa de abstracción de hardware (HAL) aísla el núcleo del software de vuelo de ambas plataformas, permitiendo compilar el mismo código para ESP32 y para la OBC Triskel cambiando únicamente los drivers de bajo nivel.
El sistema implementa una arquitectura FDIR (Fault Detection, Isolation and Recovery) sobre FreeRTOS, con comunicaciones bidireccionales seguras con la estación terrestre mediante el protocolo CSP (CubeSat Space Protocol) sobre UDP/WiFi y serialización de datos con Protocol Buffers (nanopb).
[Sensores] ──► vTaskHealth ──► fdirQueue ──► vTaskModeManager ──► currentMode
│ │
telemetryMutex telemetryMutex
│ │
└───────────────────────────────┘
│
vTaskDownlink ──► CSP/UDP ──► Estación Terrestre
| Tarea | Prioridad | Rol |
|---|---|---|
vTaskHealth |
5 (máx.) | Lee sensores, clasifica eventos FDIR y los emite a la cola |
vTaskModeManager |
4 | Árbitro de modos: fusiona demanda FDIR + comandos de tierra |
vTaskUplink |
3 | Recibe y autentica comandos (HMAC-SHA256 + anti-replay) |
vTaskSolver |
2 | Infiere código de error para enriquecer la telemetría |
vTaskMonitor |
2 | Watchdog software + alimentación del TWDT hardware + benchmark |
vTaskDownlink |
1 | Serializa y transmite telemetría a la estación terrestre |
vTaskLedsPulsing |
1 | Payload: patrón óptico guiado por IMU (suspendido fuera de NOMINAL) |
vTaskPostDeployment |
1 | Secuencia de despliegue post-lanzamiento (one-shot) |
NOMINAL (0) ──► LOW_POWER (1) ──► COOLING (2) ──► SAFE (3)
▲ │
└──────────────── (recuperación) ─────────────────┘
La transición aplica siempre el modo más restrictivo entre lo que demanda el FDIR autónomo y lo que ordena la estación terrestre. El operador puede forzar SAFE, pero no puede rebajar un SAFE ya demandado por el FDIR.
Cada comando recibido pasa tres capas de verificación antes de ejecutarse:
- Decodificación Protobuf — formato
SecureCommand { payload, mac }. - HMAC-SHA256 — MAC calculado sobre el payload con clave precompartida (
UPLINK_PSK). - Anti-replay (nonce monótono) — el nonce debe ser estrictamente mayor que el último aceptado.
cubesat-so/
├── include/
│ ├── hal/
│ │ ├── hal_system.h # HAL: red y causa de reinicio
│ │ └── hal_radio.h # HAL: envío/recepción radio
│ ├── globals.h # Tipos, handles RTOS y estado compartido
│ ├── sat_config.h # Parámetros de configuración (umbrales, tiempos…)
│ ├── benchmark.h # Profiling no intrusivo por tarea
│ ├── csp_udp.h # Protocolo CSP v1 sobre UDP
│ ├── battery.h # Stub de simulación de sensores
│ ├── mpu6050.h # Driver IMU MPU-6050
│ └── task_*.h # Cabeceras de cada tarea RTOS
├── src/
│ ├── hal/
│ │ ├── hal_system.cpp # Implementación ESP32 (WiFi, esp_reset_reason)
│ │ └── hal_radio.cpp # Implementación ESP32 (WiFiUDP)
│ ├── main.cpp # Boot, primitivas RTOS y arranque de tareas
│ ├── globals.cpp
│ ├── benchmark.cpp
│ ├── csp_udp.cpp
│ ├── battery.cpp
│ ├── mpu6050.cpp
│ └── tasks/
│ └── task_*.cpp # Implementación de cada tarea RTOS
├── test/
│ ├── test_health/ # Tests FDIR: clasificación de temperatura y batería
│ ├── test_mode_manager/ # Tests de arbitraje de modos e invariante de seguridad
│ ├── test_uplink/ # Tests del pipeline de seguridad (HMAC, anti-replay)
│ └── test_downlink/ # Tests de serialización Protobuf de telemetría
├── ground_station/ # Firmware de la estación terrestre (ESP8266)
│ ├── include/csp_udp.h
│ └── src/
│ ├── main.cpp # AP WiFi, envío de comandos, recepción de telemetría
│ └── csp_udp.cpp
├── sat.proto # Esquema Protobuf (Command, SecureCommand, Telemetry)
└── platformio.ini
- PlatformIO (CLI o extensión VS Code)
- ESP32 DevKit (OBC de desarrollo)
- ESP8266 (estación terrestre, opcional)
# Compilar
pio run
# Flashear
pio run --target upload
# Monitor serie (115200 baud)
pio device monitor --baud 115200pio test -e test_health # Tests FDIR
pio test -e test_mode_manager # Tests Mode Manager
pio test -e test_uplink # Tests seguridad uplink
pio test -e test_downlink # Tests serializacióncd ground_station
pio run --target uploadDurante las pruebas en tierra, el firmware acepta comandos por serie para simular condiciones de vuelo sin hardware de sensores real:
| Tecla | Acción |
|---|---|
w |
Batería +5 % |
s |
Batería −5 % |
e |
Temperatura +2 °C |
d |
Temperatura −2 °C |
b |
Vuelca el informe de benchmark en el próximo ciclo del monitor |
El sistema implementa dos niveles de supervisión independientes para garantizar la recuperación automática ante fallos:
-
Software WDT (
vTaskMonitor): cada tarea crítica activa su bit en un FreeRTOS Event Group al final de cada ciclo. Si algún bit no aparece dentro del período del monitor, se registra la causa (SW_REBOOT_TASK_CRASH) en SRAM persistente y se lanza un reset controlado. -
Hardware WDT (ESP32 TWDT): solo se alimenta cuando todos los bits del software WDT están presentes. Si el propio monitor se bloquea, el TWDT dispara independientemente (configurado a 2× el período del monitor).
La causa de reinicio se diagnostica en cada arranque combinando el registro de hardware (esp_reset_reason) con la causa software almacenada en SRAM persistente de la RTC (RTC NOINIT), distinguiendo power-on, brownout, crash y reset por comando de tierra.
El módulo de benchmark (activado con ENABLE_BENCHMARK 1 en sat_config.h) mide, por tarea y por ventana de tiempo:
- Tiempo de ejecución mínimo, máximo y promedio (resolución µs).
- Porcentaje de CPU consumido.
- Stack libre (high-water mark).
- Latencia end-to-end de eventos FDIR (Health → ModeManager), objetivo < 200 ms.
Los resultados se emiten automáticamente ante anomalías (starvation, latencia FDIR > 2 ms) o bajo demanda pulsando b.
La capa HAL (include/hal/, src/hal/) aísla todo acceso a hardware de plataforma. Para portar a la OBC Triskel (STM32) basta con implementar los stubs #else existentes en cuatro puntos:
| Función / macro | Descripción |
|---|---|
HAL_Network_Init() |
Inicializar SPI/UART del transceptor de RF |
HAL_GetHwRebootReason() |
Leer RCC->CSR (flags de reset STM32) |
HAL_Radio_Send() / HAL_Radio_Recv() |
Driver de radio a nivel de byte |
SYSTEM_RESET, PERSISTENT_ATTR, HAL_WDT_* |
Macros en sat_config.h |
El núcleo de tareas RTOS, la lógica FDIR, el sistema de modos y las comunicaciones CSP/Protobuf no requieren ninguna modificación.
MIT License — ver LICENSE para más detalles.