# Changelog All notable changes to AR-Autopilot will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). --- ## [Unreleased] ## [0.1.0-sprint1] — Sprint 1 — Firmware ESP32 base — 2026-05-18 > Sprint 1 was executed autonomously overnight after the user gave explicit > blanket authorisation (no per-decision approval) to push through subsequent > sprints. The four technical decisions in `docs/sprint-1-plan.md` §2 were > taken with the **recommended** option (Arduino-only framework -- pragmatic > shift from the dual-framework plan, see Architecture note below). ### Added #### Firmware (`firmware/ar_autopilot_v1/`) - **`platformio.ini`** — Build configuration for ESP32-DOWD on the AR-NMEA-IO v1.0 board. Three envs: - `esp32-dev` — release build (-Os, default). - `esp32-debug` — debug build (-O0, verbose logs). - `native` — host Unity tests (no hardware required, host C++ compiler needed). - `check` — cppcheck static analysis. - **Sprint 1 dependencies** pinned: `NMEA2000-library` v4.22+, `NMEA2000_esp32` v1.0+, `eModbus` v1.7.4. - **`src/main.cpp`** — boot, FreeRTOS task spawn, returns to scheduler. - **`src/system/`** — `ar_log.h` logging facade, `task_config.h` central table of stack sizes / priorities / core pinning, `heartbeat.cpp` (1 Hz LED + uptime log on Core 0). - **`src/modes/`** — STANDBY-only mode state machine. Non-STANDBY mode requests rejected with a warning. - **`src/hal/`** — `di_do.{h,cpp}` (5 DI + 10 DO with software debouncing and last-state cache); `rudder_sensor.{h,cpp}` (100 Hz ADC + 5-sample median filter, Core 1); `rudder_actuator.{h,cpp}` (DO1/DO2/DO3 driver with three layered safety interlocks: power-off, STANDBY, limit switch). - **`src/safety/`** — `watchdog.{h,cpp}` (TWDT @ 2 s, panic on expire); `safety_monitor.{h,cpp}` (50 Hz DI polling on Core 1, DI1 disengage button enforced, DI4 external alarm, both-limit-switch interlock). - **`src/protocols/modbus_slave.{h,cpp}`** — eModbus RTU server on UART2 @ 38400 8N1, slave ID 1. 17 input registers, 19 discrete inputs, 5 holding registers, 4 coils. Reads pull from live telemetry (mode, rudder, NMEA 2000 snapshot, heap). Writes validate range and route to the corresponding handler. - **`src/protocols/nmea2000_consumer.{h,cpp}`** — NMEA 2000 stack open with CAN TX=GPIO3 RX=GPIO1, subscribed to PGN 127250 (Heading) and PGN 127251 (Rate of Turn). Snapshot exposed via Modbus input registers 24-26 (heading_deg_x100, rot_dps_x100, heading_age_ms). 5 s staleness flag built in for Sprint 6 alarm wiring. - **`src/filters/median.h`** — Templated `MedianFilter` (host testable). - **`modbus_registers.yaml`** — Single source of truth for the Modbus register map. 45 entries total. - **`test/test_median_filter/test_median.cpp`** — 8 Unity tests of the median filter (host-side, no Arduino dependency). - **`tools/modbus_client_test.py`** — manual Modbus client for poking the slave from a PC with a USB-RS485 dongle. #### Cross-cutting - **`tools/gen_modbus_registers.py`** — YAML -> C++ header + Python module code generator with `--check` mode for CI/drift detection. - **`arautopilot/shared/modbus_register_map.py`** — generated Python mirror of the firmware register contract (`Reg` dataclass per entry, grouped into `DISCRETES`, `COILS`, `INPUTS`, `HOLDINGS`). - **`arautopilot/tests/test_modbus_register_map.py`** — 30 tests: schema sanity, address uniqueness within group, range bounds, spot-checks for critical registers, and **drift detection** that fails if anyone edits the YAML without regenerating. - **`docs/firmware.md`** — firmware operator + integrator guide (toolchain, build, flash, expected boot log, troubleshooting, Sprint 1 capability matrix). ### Architecture decisions taken - **Framework**: Arduino-on-ESP32 only (NOT the dual Arduino-as-ESP-IDF-component proposed in the Sprint 1 plan). Rationale: Arduino-on-ESP32 already provides full FreeRTOS access (`xTaskCreatePinnedToCore`, priorities, TWDT, log levels), the dual framework is notoriously fragile in PlatformIO, and we hit no ESP-IDF-only feature in Sprint 1 scope. OTA-with-rollback and secure boot become a real ask in Sprint 8 — at that point we either migrate to ESP-IDF or wire the equivalent via Arduino + EspOTA. - **FreeRTOS core split** as proposed: PID + safety + rudder sensor on Core 1 (real-time); NMEA 2000 RX + Modbus + heartbeat on Core 0. - **Logging**: ESP_LOG via UART0 only, no SD card. ### Verification - `pio run -e esp32-dev` -> SUCCESS (RAM 6.7 %, Flash 26.5 %, 347 KB). - `pio run -e esp32-debug` -> SUCCESS. - `pytest` -> **110 passed** in 0.22 s (80 from Sprint 0 + 30 new). - `ruff check arautopilot/` -> All checks passed. - `mypy arautopilot/core library shared` -> Success, 0 issues. - `pio test -e native` -> deferred: needs host C++ compiler (mingw / msvc / clang) on this Windows machine. The Unity test sources compile on any standard host once a toolchain is installed. ### Not in Sprint 1 (intentional, per brief §12) - PID loops (inner/outer). - True Course / Track Keeping modes. - Alarm catalogue beyond DI1/DI4 forced disengage. - Knob driver. - Studio GUI. - Dedicated display Flutter app. ## [0.1.0] — Sprint 0 — Foundations — 2026-05-17 ## [0.1.0] — Sprint 0 — Foundations — 2026-05-17 ### Added - Repository structure following the layout defined in the project brief (section 11) - Python package skeleton `arautopilot` with submodules: - `core/` — data model (Pydantic v2): modes, alarms, actuator config, PID config, vessel config, knob state, project config, IDs - `library/` — curated seed: 2 actuator profiles (hydraulic reversible, electric DC reversible) and 2 default tunings (yacht motor planeo 30 m, 40 m) - `studio/` — empty stubs for Sprint 4 - `tests/` — pytest suite covering the core data model - Firmware skeleton: `firmware/ar_autopilot_v1/src/hal/pinout.h` only — 21 I/O assignment for the AR-NMEA-IO v1.0 board, no functional code yet - Build configuration: - `pyproject.toml` with Pydantic v2, PyYAML, python-dateutil - Dev dependencies: pytest, pytest-cov, ruff, mypy - Ruff + mypy strict configuration - `examples/sprint0_demo.py` — end-to-end project creation, save, and reload - Documentation moved/created: - `docs/AR_Autopilot_brief.md` — full project brief - `docs/architecture.md` — one-page architecture overview - `LICENSE.txt` — Proprietary, all rights reserved - `.gitignore` covering Python, Flutter, PlatformIO, IDEs, Windows artifacts ### Notes - **No functional firmware**, Studio GUI, or display in this sprint — those start in Sprint 1, 4, and 4 respectively. - The seed PID tunings are **conservative starting values** drawn from classical marine control literature (Fossen, Perez). They are explicitly **not** the integrator's affinated production values, which remain IP. - Python ≥3.11 required.