End-to-end implementation per docs/sprint-3-plan.md.
Closes the cascade: outer loop (heading control, 10 Hz on Core 1) drives
the inner loop (rudder position control, 50 Hz from Sprint 2). First real
mode other than STANDBY is now activable: HEADING_HOLD.
Builds: pio run -e esp32-dev SUCCESS, RAM 6.8%, Flash 27.1% (355 KB).
Tests: pytest 258/258 green (231 Sprint 2.5 + 27 Sprint 3 new).
Python (arautopilot/studio/simulator/):
- vessel_heading.py: first-order yaw model. ROT responds to
rudder*speed; damping returns ROT to zero when rudder is centred.
Defaults tuned so 5 deg rudder @ 10 kn -> ~3 dps steady-state ROT.
Includes heading_error_deg() shortest-arc helper.
- pid_outer.py: pure-Python outer heading PID. Anti-windup via back-
calculation, gain scheduling by SOG, deadband, derivative LPF,
output saturation, ROT feed-forward (brief sec. 6 -- the term that
distinguishes a premium autopilot from a basic one), rate limit on
produced rudder setpoint, shortest-arc heading wrap-around.
Firmware (firmware/ar_autopilot_v1/src/pid/):
- pid_outer.h: header-only C++17 port. Same algorithm, same variables,
same numerics. Fixed-capacity gain schedule (up to 8 points).
- pid_outer_task.{h,cpp}: 10 Hz FreeRTOS task on Core 1. Subscribes to
TWDT. Reads heading + ROT from the NMEA 2000 snapshot. Uses
operator-configurable SOG (default 15 kn until PGN 129026 wiring in
Sprint 5). Pushes rudder setpoint into the inner loop only when
current_mode == HEADING_HOLD.
Modes (firmware/ar_autopilot_v1/src/modes/standby.cpp):
- HEADING_HOLD activable via request_mode(). Pre-conditions:
* NMEA 2000 heading sensor valid (fresh PGN 127250)
* Rudder sensor valid (median filter filled)
On success, captures current heading as initial setpoint so the
operator doesn't get a sudden swing toward an old setpoint.
Modbus (regenerated from YAML):
- 7 new INPUTs (50-56): outer heading setpoint, produced rudder
setpoint, error, current SOG, live kp/ki/kd.
- 5 new HOLDINGs (24-28): writable heading setpoint, SOG override,
outer base gains. Writing any of kp/ki/kd disables the built-in
3-point gain schedule (operator override).
Tests:
- test_vessel_heading_simulator.py: 6 dynamics tests + 9 parameterised
heading_error_deg edge cases (wrap-around).
- test_pid_outer_python.py: 12 tests covering gain interpolation,
per-tick PID behaviour (deadband, sign, ROT feed-forward,
saturation, rate limit, allowed=false), and three end-to-end cascade
tests (positive step, negative step, wrap-around 360->10).
Cascade verification: outer + inner + rudder dynamics + vessel-heading
simulator settles a 30 deg step within +-2 deg in 60 s.
NOT in Sprint 3 (intentional):
- True Course / Track Keeping / Dodge -- Sprint 5
- Off-course alarms + auto-disengage on sensor loss -- Sprint 6
- COG / SOG / Position via N2K PGN 129025/9/6 -- Sprint 5
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AR-Autopilot
Professional marine autopilot for vessels in the 30-40 m range (motor yachts, motor sailboats, fishing vessels, small ferries, coastal patrol boats).
Part of the AR Suite alongside AR-ECDIS, VMS-Sailor, AR-ShipDesign, AR-ElecArrangement, and AR-StabCol. Sold standalone or bundled with AR-ECDIS.
NOT Dynamic Positioning. NOT joystick docking. This is a classic heading-and-track autopilot with intelligent drift compensation, controlling rudder actuators (hydraulic or electric).
Status
Sprint 0 — Foundations (in progress).
This sprint delivers the repository structure, core data model, seed library, and a passing test suite. No functional firmware, Studio GUI, or display yet — those start in Sprint 1.
See docs/AR_Autopilot_brief.md for the complete project brief, scope, and roadmap.
Components
| Component | Tech | Purpose |
|---|---|---|
Studio (arautopilot/studio/) |
Python 3.11 + PySide6 | Project configurator (integrator-side, not shipped to customers). Generates per-vessel .appack packages |
Firmware (firmware/ar_autopilot_v1/) |
C++ on ESP32 via PlatformIO | Real-time PID control, NMEA 2000 + Modbus, safety logic. Runs on the AR-NMEA-IO v1.0 board (shared with VMS-Sailor) |
Display (display/) |
Flutter Desktop (Win + Linux) | Dedicated bridge cockpit-feel touch display with rotary knob input |
Core models (arautopilot/core/) |
Pydantic v2 | Shared data model (vessel config, PID config, actuator config, alarms, modes, knob state) |
Library (arautopilot/library/) |
YAML + JSON | Curated seed: actuator profiles, default tunings per vessel type |
Requirements
- Python 3.11 or newer
- Git
- (Later sprints) PlatformIO, Flutter SDK, WiX Toolset
Quick start (Sprint 0)
# Create venv and install
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -U pip
pip install -e ".[dev]"
# Run tests
pytest
# Run the Sprint 0 demo (creates, saves, reloads a project config)
python examples/sprint0_demo.py
Repository layout
AR-Autopilot/
├── arautopilot/ # Python package (core models, library, studio stubs, tests)
├── firmware/ # ESP32 firmware (Sprint 1+; only pinout.h in Sprint 0)
├── display/ # Flutter dedicated display (Sprint 4+)
├── examples/ # Runnable demos
├── docs/ # Brief + per-sprint design docs
├── installer/ # WiX MSI scripts (later)
└── tools/ # Helper scripts (later)
See docs/architecture.md for a one-page architecture overview.
Sprint roadmap
| Sprint | Focus |
|---|---|
| 0 | Foundations: repo structure, core data model, seed library, tests |
| 1 | Firmware base (I/O, Modbus, NMEA 2000 read, STANDBY mode) |
| 2 | PID inner loop (rudder position control) |
| 3 | PID outer loop + Heading Hold (with ROT feed-forward & gain scheduling) |
| 4 | Studio + basic dedicated display |
| 5 | True Course + Track Keeping (smooth XTE correction) |
| 6 | Safety, alarms, NMEA 2000 publish, VMS alarm consumption |
| 7 | Knob + commissioning + offline auto-tuning |
| 8 | EKF + adaptive tuning + telemetry + VPN |
| 9 | Hardening + integrated testing |
| 10+ | Phase 2 (wind modes for sailboats) and beyond |
Full detail in the brief.
License
Proprietary. All rights reserved. See LICENSE.txt.
Commercial deployment requires a per-vessel license bound to the installation HWID. Contact alro65@gmail.com for licensing.