docs(sprint-1): proposed plan + firmware libraries research
Two new documents to drive the Sprint 1 approval cycle when the user reviews in the morning. NO firmware code touched -- this is planning material only, per brief rule #1 "Antes de cada sprint, me presentas plan detallado y esperas mi OK. No improvises features." docs/sprint-1-plan.md - Sprint 1 objective (firmware boot + STANDBY + Modbus slave + NMEA 2000 consume of PGN 127250/127251 + watchdog). - 4 explicit technical decisions awaiting the user's go/no-go: 2.1 Framework: Arduino-as-ESP-IDF-component (recommended) 2.2 New libraries: NMEA2000-library, NMEA2000_esp32, eModbus (asked per brief rule #4 "No agregues dependencias sin preguntarme") 2.3 FreeRTOS core/priority mapping (PID isolated on Core 1) 2.4 Logging: ESP_LOG via UART0 - 7-phase breakdown over 3-4 weeks (mirrors brief's Sprint 1 scope). - Acceptance criteria, risks, and the inputs needed from the user before kickoff (hardware availability, schematic, NMEA 2000 bus). docs/firmware-libraries-research.md - Detailed rationale for each library choice with comparison tables. - Pinout / hardware references aligned with the existing firmware/ar_autopilot_v1/src/hal/pinout.h. - Draft platformio.ini outline (NOT yet written to the firmware directory -- needs user OK first). - All external sources cited for traceability. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
# Firmware libraries — research notes (Sprint 1 prep)
|
||||
|
||||
Investigación realizada antes de planificar el Sprint 1 para elegir las
|
||||
librerías del firmware ESP32. Documento de referencia — no normativo, solo
|
||||
para que tengamos trazabilidad de por qué se eligió cada cosa.
|
||||
|
||||
Fecha: 2026-05-18.
|
||||
|
||||
---
|
||||
|
||||
## 1. NMEA 2000 stack
|
||||
|
||||
### Decisión: `ttlappalainen/NMEA2000-library` + `ttlappalainen/NMEA2000_esp32`
|
||||
|
||||
**Por qué es el estándar de facto:**
|
||||
|
||||
- Es la stack NMEA 2000 más adoptada del ecosistema open-source para
|
||||
microcontroladores. Casi todos los proyectos NMEA 2000 de aficionados
|
||||
y muchos productos comerciales pequeños la usan.
|
||||
- Cubre tanto consumo como publicación de PGN.
|
||||
- Mantenida desde 2015, sigue activa.
|
||||
|
||||
**Componentes:**
|
||||
|
||||
| Repo | Rol |
|
||||
|---|---|
|
||||
| [`ttlappalainen/NMEA2000`](https://github.com/ttlappalainen/NMEA2000) | Stack core (parsing, PGNs, NMEA2000 class). Independiente de hardware |
|
||||
| [`ttlappalainen/NMEA2000_esp32`](https://github.com/ttlappalainen/NMEA2000_esp32) | Driver CAN específico para ESP32. Incluye su propio low-level driver — no requiere libs adicionales |
|
||||
|
||||
**Configuración por defecto:**
|
||||
|
||||
- TX pin: `GPIO 16`
|
||||
- RX pin: `GPIO 4`
|
||||
- Override: definir `ESP32_CAN_TX_PIN` y `ESP32_CAN_RX_PIN` antes de
|
||||
incluir los headers.
|
||||
|
||||
**Framework support:**
|
||||
|
||||
- ✅ Arduino framework
|
||||
- ✅ ESP-IDF (añadido oficialmente en 2022)
|
||||
- → Compatible con la decisión "Arduino-as-ESP-IDF-component"
|
||||
|
||||
**Licencia:** MIT (compatible con producto comercial propietario).
|
||||
|
||||
**Hardware externo necesario:**
|
||||
|
||||
- Transceiver CAN físico: Microchip MCP2562, NXP TJA1051T, o similar.
|
||||
Conecta los pines GPIO16/4 del ESP32 al bus diferencial CAN-H/CAN-L
|
||||
del backbone NMEA 2000. El driver de la librería NO incluye el
|
||||
hardware del transceiver — es un chip aparte en la tarjeta
|
||||
AR-NMEA-IO. (Probablemente ya lo tienes en la v1.0 que diseñaste.)
|
||||
|
||||
**PGN que vamos a consumir en Sprint 1:**
|
||||
|
||||
| PGN | Nombre | Contenido relevante |
|
||||
|---|---|---|
|
||||
| 127250 | Vessel Heading | heading (rad), deviation, variation, reference (true/magnetic) |
|
||||
| 127251 | Rate of Turn | rate (rad/s) |
|
||||
|
||||
**Snippet de referencia para Sprint 1 (no es código final):**
|
||||
|
||||
```cpp
|
||||
#include <NMEA2000_CAN.h> // selects ESP32 driver automatically
|
||||
#include <N2kMessages.h>
|
||||
|
||||
void HandleHeading(const tN2kMsg &N2kMsg) {
|
||||
unsigned char SID;
|
||||
double Heading, Deviation, Variation;
|
||||
tN2kHeadingReference HeadingReference;
|
||||
if (ParseN2kHeading(N2kMsg, SID, Heading, Deviation, Variation, HeadingReference)) {
|
||||
// Heading in radians; convert to degrees for our use
|
||||
gLastHeadingDeg = Heading * 180.0 / M_PI;
|
||||
gLastHeadingTimestamp = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
NMEA2000.SetN2kCANMsgBufSize(8);
|
||||
NMEA2000.SetMsgHandler(HandleHeading); // registers for ALL PGNs;
|
||||
// we filter inside the handler
|
||||
NMEA2000.Open();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
NMEA2000.ParseMessages(); // call frequently from a dedicated task
|
||||
}
|
||||
```
|
||||
|
||||
Esto es **orientativo**. En el sprint lo encapsulamos en una tarea
|
||||
FreeRTOS dedicada (`nmea2000_rx_task` en Core 0).
|
||||
|
||||
---
|
||||
|
||||
## 2. Modbus RTU server (slave)
|
||||
|
||||
### Decisión: `eModbus/eModbus` v1.7.4
|
||||
|
||||
**Comparación rápida:**
|
||||
|
||||
| Lib | Slave RTU | Async/Tasks FreeRTOS | Mantenimiento | Veredicto |
|
||||
|---|---|---|---|---|
|
||||
| `eModbus/eModbus` v1.7.4 (2025-06) | ✅ | ✅ tasks separados, no bloquea | Activo | **Elegida** |
|
||||
| `emelianov/modbus-esp8266` (a.k.a. `modbus-esp32`) | ✅ | Parcial | Activo | Alternativa válida |
|
||||
| `MrMoses1911/ModbusRTU_ESP32` | ✅ | No documentado | Menor adopción | Descartada |
|
||||
| `ArduinoModbus` (oficial Arduino) | ✅ | No | Mantenida pero feature-pobre | Descartada |
|
||||
| `bertmelis/esp32ModbusRTU` | ❌ solo cliente | ✅ | Activo | No aplica (cliente, no slave) |
|
||||
|
||||
**Por qué eModbus:**
|
||||
|
||||
- Único que documenta explícitamente "Modbus communication is done in
|
||||
separate tasks" y API "non blocking / asynchronous" → el lazo PID no
|
||||
se bloquea jamás por tráfico Modbus.
|
||||
- Soporta RTU, ASCII y TCP — si en el futuro queremos pasar a Modbus
|
||||
TCP por Ethernet/WiFi, es la misma librería.
|
||||
- Versión estable reciente (junio 2025).
|
||||
- Licencia MIT.
|
||||
|
||||
**Punto a verificar en Fase 1.3:**
|
||||
|
||||
⚠️ El README de eModbus no confirma explícitamente que la librería
|
||||
maneje sola la línea **DE/RE** (Driver Enable / Receiver Enable) del
|
||||
transceiver RS-485 MAX485 / MAX3485. Si no lo hace, escribimos un
|
||||
wrapper de ~30 líneas que toggle el `PIN_RS485_DE` del pinout antes
|
||||
y después de cada respuesta.
|
||||
|
||||
**Framework support:**
|
||||
|
||||
- ✅ Arduino framework (confirmado)
|
||||
- ❓ ESP-IDF nativo (no confirmado explícitamente; lo verifico al
|
||||
integrarlo)
|
||||
|
||||
Si ESP-IDF nativo no está soportado: igual funciona desde el componente
|
||||
Arduino dentro de un proyecto ESP-IDF (eso es el patrón
|
||||
Arduino-as-ESP-IDF-component).
|
||||
|
||||
**Mapa de registros propuesto** (a refinar en Sprint 1):
|
||||
|
||||
| Tipo Modbus | Rango | Contenido |
|
||||
|---|---|---|
|
||||
| Holding (40001-) | 1-50 | Setpoints: heading_deseado, modo, comandos de operador |
|
||||
| Input (30001-) | 1-50 | Estado: heading_actual, rudder_angle_actual, modo_activo, alarmas activas |
|
||||
| Discrete (10001-) | 1-32 | Bits: engaged, alarms (uno por tipo), DI raw |
|
||||
| Coils (00001-) | 1-32 | Comandos digitales: engage_request, disengage_request, alarm_ack |
|
||||
|
||||
El mapa exacto se finaliza al inicio de Fase 1.3 y se genera en
|
||||
single-source-of-truth desde un YAML.
|
||||
|
||||
---
|
||||
|
||||
## 3. Framework: ESP-IDF vs Arduino vs híbrido
|
||||
|
||||
### Decisión: Arduino-as-ESP-IDF-component
|
||||
|
||||
**Resumen de la discusión:**
|
||||
|
||||
| Aspecto | Arduino solo | ESP-IDF solo | Arduino-as-ESP-IDF-component |
|
||||
|---|---|---|---|
|
||||
| Manejo de FreeRTOS | Abstraído a single-thread | Nativo, control total | **Nativo (ESP-IDF), Arduino se compone encima** |
|
||||
| Disponibilidad de libs NMEA2000/Modbus | ✅ inmediata | ⚠️ requiere wrap | ✅ inmediata |
|
||||
| OTA con rollback automático | ❌ no | ✅ sí | ✅ sí |
|
||||
| Secure boot + flash encryption | ⚠️ limitado | ✅ sí | ✅ sí |
|
||||
| Determinismo PID real-time | ❌ unsuitable | ✅ excelente | ✅ excelente |
|
||||
| Production-grade (TWDT, panic handlers, partitions, NVS) | Limitado | Completo | Completo |
|
||||
| Complejidad inicial `platformio.ini` | Baja | Media | Media-alta (10 min de setup) |
|
||||
| Curva de aprendizaje | Cortísima | Media | Media |
|
||||
|
||||
**Por qué para AR-Autopilot:**
|
||||
|
||||
El brief es taxativo:
|
||||
|
||||
> **Regla #11:** El PID corre en firmware ESP32, no en el display. Esto
|
||||
> es no-negociable: latencia determinística, seguridad ante caída del
|
||||
> display, eficiencia.
|
||||
>
|
||||
> **Sección 6 (frecuencias):** Lazo PID interno (timón a posición): 50
|
||||
> Hz (20 ms) **Determinístico, sin jitter**.
|
||||
|
||||
"Sin jitter" en 50 Hz exige FreeRTOS real con prioridades correctas, no
|
||||
el modelo abstraído de Arduino. Y al mismo tiempo no queremos perder 2
|
||||
semanas reescribiendo NMEA2000_esp32 ni eModbus — son cientos de horas
|
||||
de trabajo de la comunidad.
|
||||
|
||||
**Solución oficial Espressif:** [Arduino as an ESP-IDF component](https://docs.espressif.com/projects/arduino-esp32/en/latest/esp-idf_component.html).
|
||||
Permite usar libs Arduino dentro de un proyecto ESP-IDF "puro". Es
|
||||
exactamente lo que necesitamos.
|
||||
|
||||
**Configuración en PlatformIO (resumen):**
|
||||
|
||||
```ini
|
||||
[env:esp32-arautopilot]
|
||||
platform = espressif32@~6.7.0
|
||||
board = esp32dev ; ajustar al chip real (ESP32-DOWD)
|
||||
framework = arduino, espidf ; ← aquí está el truco
|
||||
|
||||
; Pinneamos versión del core Arduino para reproducibilidad
|
||||
platform_packages =
|
||||
framework-arduinoespressif32@~3.20017.0
|
||||
|
||||
lib_deps =
|
||||
ttlappalainen/NMEA2000-library
|
||||
ttlappalainen/NMEA2000_esp32
|
||||
https://github.com/eModbus/eModbus.git#v1.7.4.stable
|
||||
|
||||
build_flags =
|
||||
-DCORE_DEBUG_LEVEL=3
|
||||
-DCONFIG_FREERTOS_HZ=1000
|
||||
; ... más flags al hacer el sprint
|
||||
|
||||
monitor_speed = 115200
|
||||
```
|
||||
|
||||
**Riesgo conocido:** el modo dual `framework = arduino, espidf` a veces
|
||||
se rompe entre versiones de PlatformIO. Mitigación: pinneamos versión
|
||||
exacta del `platform` y de `framework-arduinoespressif32`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Hardware externo / transceivers (referencia)
|
||||
|
||||
Pinout `firmware/ar_autopilot_v1/src/hal/pinout.h` ya declara los pines
|
||||
lógicos. Para que el sistema físicamente funcione, la tarjeta
|
||||
AR-NMEA-IO debe tener:
|
||||
|
||||
| Función | Chip típico | Pin ESP32 |
|
||||
|---|---|---|
|
||||
| Transceiver CAN (NMEA 2000) | MCP2562, TJA1051T | GPIO16 (TX), GPIO4 (RX) — overridable |
|
||||
| Transceiver RS-485 (Modbus) | MAX485, MAX3485, SP485E | GPIO21 (TX), GPIO22 (RX), GPIO23 (DE) |
|
||||
| Acondicionamiento AI1 (rudder sensor) | Op-amp + divisor / módulo 4-20 mA loop | GPIO36 (ADC1_CH0) |
|
||||
| Driver de potencia para DO1/DO2 (bomba) | Relé SSR o transistor + flyback | GPIO13, GPIO12 |
|
||||
|
||||
Asumo que tu tarjeta v1.0 ya los lleva (es la misma usada en
|
||||
VMS-Sailor). Si hay alguna diferencia, lo cuadramos al inicio de
|
||||
Fase 1.2 con tu esquemático.
|
||||
|
||||
---
|
||||
|
||||
## 5. Fuentes consultadas
|
||||
|
||||
- [NMEA2000_esp32 — GitHub](https://github.com/ttlappalainen/NMEA2000_esp32)
|
||||
- [NMEA2000 library — GitHub](https://github.com/ttlappalainen/NMEA2000)
|
||||
- [NMEA2000_esp32 — PlatformIO Registry](https://registry.platformio.org/libraries/ttlappalainen/NMEA2000_esp32)
|
||||
- [eModbus — GitHub](https://github.com/eModbus/eModbus)
|
||||
- [Arduino as ESP-IDF component — Espressif docs](https://docs.espressif.com/projects/arduino-esp32/en/latest/esp-idf_component.html)
|
||||
- [ESP-IDF vs Arduino Framework for ESP32 — Hubble Network Community](https://hubble.com/community/comparisons/esp-idf-vs-arduino-framework-for-esp32-when-to-switch-and-why/)
|
||||
- [ESP-IDF vs. Arduino for ESP32-S3: The Engineering Pivot to Production — Hoomanely Tech](https://tech.hoomanely.com/esp-idf-vs-arduino-for-esp32-s3-the-engineering-pivot-to-production/)
|
||||
- [Modbus RTU slave (RS485) for ESP32 on Arduino platform — PlatformIO Community](https://community.platformio.org/t/modbus-rtu-slave-rs485-for-esp32-on-arduino-platform/16196)
|
||||
Reference in New Issue
Block a user