20 min. El DS18B20 tarda ~750 ms en convertir. Si el loop() lo espera, el GPS pierde tramas y el heartbeat se muere. Ese es todo el problema.

Por qué un RTOS y no millis()

Con 2–3 tareas, millis() sin bloquear alcanza. Con 8 sensores a frecuencias distintas (suspensión a 100 Hz, GPS a 5 Hz, temperatura a 1 Hz, LoRa a 5 Hz), el código se vuelve una máquina de estados imposible de mantener. FreeRTOS le da a cada sensor su propio flujo con su periodo y su prioridad.

Conceptos mínimos

Concepto Qué resuelve Trampa
Tarea un flujo por sensor, con su periodo una tarea que nunca cede el CPU mata a las de menor prioridad
Prioridad quién corre cuando dos están listas poner todo en prioridad alta equivale a no tener prioridades
Cola (queue) pasar datos entre tareas sin variables compartidas cola llena = datos perdidos en silencio si no se revisa el retorno
Mutex proteger un recurso único (bus I²C, SD) tomar dos mutex en distinto orden = deadlock
Core pinning separar radio/Wi-Fi de la adquisición fijar todo a un core desperdicia la mitad del chip
<code>vTaskDelayUntil</code> periodo constante, sin deriva acumulada <code>vTaskDelay</code> mide desde que termina, no desde que empezó

Jitter: lo que arruina el análisis posterior

Jitter = variación en el intervalo real entre muestras. Un sensor que dice muestrear a 100 Hz pero en realidad entrega a 100 ± 15 Hz produce datos con eje de tiempo mentiroso, y en la Sesión 6 eso rompe cualquier filtro o derivada.

Regla operativa: medir el jitter con timestamps reales y reportarlo, no asumirlo. Si el jitter pasa del ~5 % del periodo, la tarea tiene prioridad mal puesta o algo la bloquea.

delay() es el enemigo

delay() de Arduino bloquea la tarea sin cederle el CPU limpiamente al planificador en todos los casos, y sobre todo bloquea la lógica de esa tarea. Dentro de FreeRTOS: vTaskDelay() o vTaskDelayUntil(), siempre.

Bibliografía