Arquitectura Software
IRTimer tiene dos firmwares independientes que se cargan en la misma PCB según el modo de funcionamiento deseado. Ambos usan el framework Arduino sobre ESP32-C3 con PlatformIO.
| Aspecto | Modo Main | Modo Aux |
|---|---|---|
| Directorio | source_code/main_module/ |
source_code/aux_module/ |
| Disciplina | LineFollower | Micromouse |
| Rol | Host central + cronómetro | Sensor de pared |
| Display | ST7789, 6 pantallas con navegación | No |
| WiFi | STA+AP, servidor web + SSE | STA, solo escaneo de canal |
| ESP-NOW | Recibe comandos (27/42) | Envía comandos (27/42) |
| RC5 IR | Decodifica (control remoto) | No |
| Botones | 2 (navegación + reset) | No |
| Cronómetro | Local: su propio sensor IR | Remoto: notifica al Main |
| LED NeoPixel | Power + Connection | Power + Identificación |
Modo Main — Host y Cronómetro de LineFollower
Firmware más complejo de los dos. Actúa como centro del sistema: cronometra, muestra resultados, sirve el overlay web, recibe ESP-NOW y comandos RC5.
Bucle Principal
flowchart TD
Setup[setup] --> Config[config_setup]
Setup --> CtrlInit[control_init]
Config --> Serial[Serial 115200]
Config --> Pins[GPIO + IR ISR]
Config --> TFT[Pantalla ST7789]
CtrlInit --> Splash[Pantalla SPLASH]
Loop[loop] --> ManageScreen[control_manage_screen]
Loop --> ManageBatt[control_manage_battery]
Loop --> ManageEvent[control_manage_pending_event]
ManageScreen --> Screen{current_screen}
Screen -->|SPLASH| SplashWait[Esperar 2s → MENU]
Screen -->|MENU| MenuNav[Navegar opciones]
Screen -->|WIFI_INIT| WifiSetup[web_setup → WIFI_INFO/FAIL]
Screen -->|WIFI_INFO| WifiShow[Mostrar IP/MAC]
Screen -->|WIFI_FAIL| WifiErr[Mostrar error]
Screen -->|TIMER| TimerRun[Cronómetro activo]
setup() inicializa el hardware y loop() itera sobre tres funciones
principales:
| Función | Responsabilidad |
|---|---|
control_manage_screen() |
Navegación entre pantallas, lectura de botones |
control_manage_battery() |
Monitorización del LED de batería (parpadeo si baja) |
control_manage_pending_event() |
Procesar eventos RC5 pendientes (RESET/STOP) |
La detección del sensor IR (stopwatch_check()) se llama solo dentro de
control_manage_screen() bajo el estado SCREEN_TIMER. En cualquier otra
pantalla el cronómetro no avanza.
Máquina de Estados de Pantallas
stateDiagram-v2
[*] --> SPLASH
SPLASH --> MENU: 2s timeout
MENU --> WIFI_INIT: Botón sup. (opción 0)
MENU --> TIMER: Botón inf. (opción 1)
WIFI_INIT --> WIFI_INFO: web_setup() OK
WIFI_INIT --> WIFI_FAIL: web_setup() falla
WIFI_INFO --> MENU: Botón inf.
WIFI_FAIL --> MENU: Botón inf.
TIMER --> MENU: Botón inf.
TIMER --> TIMER: Botón sup. (reset)
| Estado | Pantalla | Acción |
|---|---|---|
SCREEN_SPLASH |
Logo OPRobots | Muestra 2s, transición automática |
SCREEN_MENU |
Menú principal | 2 opciones: Iniciar WiFi / Cronómetro |
SCREEN_WIFI_INIT |
Conectando... | web_setup(), bloquea hasta connect/timeout |
SCREEN_WIFI_INFO |
Info WiFi | Muestra IP, MAC, canal |
SCREEN_WIFI_FAIL |
Error WiFi | Muestra mensaje de error |
SCREEN_TIMER |
Cronómetro | Tiempo actual, última vuelta, mejor vuelta, historial (5) |
ISR del Receptor RC5
flowchart TD
Edge[Flanco en pin 7] --> ISR[rc5_isr]
ISR --> Register[rc5_register]
Register --> Decode[rc5_decode_pulse]
Decode --> State{Estado RC5}
State -->|START1/MID1/MID0/START0| Transition[Transición de estado]
Transition -->|14 bits completos| Command[rc5_manage_command]
Command -->|RESET| Pending[control_set_pending_event EVENT_RESET]
Command -->|STOP| Pending2[control_set_pending_event EVENT_STOP]
La ISR se dispara en cada flanco (CHANGE) del receptor TSSP77038TR. El decodificador RC5 implementa la máquina de estados del algoritmo Clearwater:
- 4 estados:
STATE_START1,STATE_MID1,STATE_MID0,STATE_START0 - 14 bits por trama: 2 start + 1 toggle + 5 address + 6 command
- Ventanas de timing: short 444–1333 µs, long 1334–2222 µs
- Comandos: dirección
0x0B(Program) → RESET, dirección0x07(Computer) → STOP
⚠️ Advertencia: La ISR contiene
delayMicroseconds(100)y escribe al pin 8 (TFT_MOSI). Ver HW-01 y HW-02.
Recepción ESP-NOW
flowchart TD
ESP_NOW[ESP-NOW packet] --> Callback[data_receive callback]
Callback --> Check{"data[0]?"}
Check -->|27| CmdStart[START/lap]
Check -->|42| CmdStop[STOP]
CmdStart --> DisableSensor[stopwatch_disable_sensor_check]
CmdStart --> Lap[stopwatch_lap + web_start/web_lap]
CmdStop --> DisableSensor2[stopwatch_disable_sensor_check]
CmdStop --> LapStop[stopwatch_lap + stopwatch_stop]
CmdStop --> WebStop[web_stop]
Al recibir un comando ESP-NOW desde una pared Aux, el sensor IR del Main se deshabilita permanentemente (hasta reinicio). Esto evita dobles detecciones cuando la pared ya ha enviado la señal.
Cronómetro
El cronómetro (stopwatch.cpp) mantiene el siguiente estado:
| Variable | Tipo | Descripción |
|---|---|---|
is_running |
bool |
Cronómetro activo |
start_ms |
long |
Timestamp de inicio (millis) |
lap_number |
int |
Número de vuelta actual |
last_lap_ms |
long |
Tiempo de la última vuelta |
best_lap_ms |
long |
Mejor tiempo de vuelta |
last_laps[5] |
long[] |
Historial circular de 5 vueltas |
last_laps_delta[5] |
long[] |
Delta respecto a mejor vuelta |
Debounce entre vueltas: 200 ms mínimo entre detecciones consecutivas.
Modo Aux — Paredes de Micromouse
Firmware minimalista. Su única función es detectar al robot con el sensor IR y notificar al Main por ESP-NOW.
Bucle Principal
flowchart TD
Setup[setup] --> Config[config_setup]
Config --> Identify{MAC address?}
Identify -->|START_MAC| Start[LED verde — pared START]
Identify -->|FINISH_MAC| Finish[LED roja — pared FINISH]
Loop[loop] --> SensorCheck[stopwatch_check]
Loop --> BattManage[manage_battery]
SensorCheck --> Sensor{!digitalRead SENSOR_PIN?}
Sensor -->|Sí| Debounce{debounce 500ms?}
Debounce -->|OK| WallType{Tipo pared?}
WallType -->|START| CheckInhibit{can_start?}
CheckInhibit -->|Sí| SendStart[client_start → cmd 27]
CheckInhibit -->|No| ReEnable[Esperar 1s → can_start=true]
WallType -->|FINISH| SendStop[client_finish → cmd 42]
Identificación por MAC
Cada placa en modo Aux se identifica al arrancar por su dirección MAC
(hardcodeada en config.cpp),
lo que determina si actúa como pared de START o de FINISH:
| MAC | Rol | LED Connection |
|---|---|---|
64:E8:33:87:CB:AC |
Pared START (inicio del laberinto) | Verde |
34:B7:DA:F8:C9:9C |
Pared FINISH (meta del laberinto) | Roja |
⚠️ Advertencia: Las MAC están hardcodeadas. Ver HW-03.
Lógica de Inhibición (pared START)
Para evitar que el robot re-dispare el cronómetro al volver a la casilla de salida durante la fase de reconocimiento:
- La pared START envía el comando y pone
can_start = false - Mientras el sensor siga detectando (robot presente):
- Si pasan > 1s con detección continua →
can_start = true(permite rearranque manual) - Al liberarse el sensor,
can_startse mantienefalsehasta la próxima detección que supere el debounce de 500 ms
Envío ESP-NOW
El cliente (client.cpp) escanea el canal WiFi del Main y envía comandos:
| Función | Comando | Comportamiento |
|---|---|---|
client_start() |
27 |
Reintenta si falla (bucle infinito) |
client_finish() |
42 |
Intento único, sin reintento |
⚠️ Advertencia:
client_start()tiene un bucle de reintento sin timeout. Ver CM-01.
Compilación Condicional
| Macro | Función |
|---|---|
PIO_FRAMEWORK_ARDUINO_ENABLE_CDC |
Habilita CDC Serial sobre USB |
IRTIMER_WIFI_SSID |
SSID WiFi (variable de entorno) |
IRTIMER_WIFI_PASS |
Contraseña WiFi (variable de entorno) |
Estructura de Archivos
source_code/
├── main_module/ # Firmware para Modo Main
│ ├── include/
│ │ ├── config.h # Pines, constantes
│ │ ├── control.h # Máquina de estados de pantalla
│ │ ├── icon_wifi.h # Bitmap icono WiFi (PROGMEM)
│ │ ├── menu_screen.h # Bitmap pantalla menú (PROGMEM)
│ │ ├── rc5.h # Decodificador RC5
│ │ ├── screen.h # Driver ST7789
│ │ ├── splash_screen.h # Bitmap pantalla splash (PROGMEM)
│ │ ├── stopwatch.h # Lógica de cronometraje
│ │ ├── utils.h # LEDs, batería, formateo
│ │ └── web.h # Servidor web + SSE
│ ├── platformio.ini
│ ├── src/ # Implementaciones (.cpp)
│ └── web/
│ └── index.html # Overlay web (empaquetado en PROGMEM)
└── aux_module/ # Firmware para Modo Aux
├── include/
│ ├── client.h # Cliente ESP-NOW
│ ├── config.h # Pines, identificación MAC
│ ├── stopwatch.h # Lógica del sensor
│ └── utils.h # LEDs, batería
├── platformio.ini
└── src/ # Implementaciones (.cpp)
Documento generado el 2026-06-29. Ver también Hardware, Comunicaciones, Menú.