Commit Graph

10 Commits

Author SHA1 Message Date
alro65 ad4c4581b6 fix(spice): corregir errores LTspice en buck chain y output stage
1_buck_chain.cir:
- RL1 creaba nodo flotante V5V_AFTER_L sin retorno
- Reemplazado por parametro Rser=0.051 en L1 (soporte nativo LTspice)

2_output_stage.cir:
- Gcoll con VALUE={} no es sintaxis valida para G-source en LTspice
  → convertido a B-source: Bcoll GATE_Q1 EMITTER I={MAX(0, 1.0*I(Dled))}
- .net V(out1) VLOAD → directiva invalida en este contexto, eliminada
- .meas V(out1) → nodo inexistente, corregido a V(drain_q1)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 00:30:24 -04:00
alro65 78a58d1b53 fix: remove invalid .connect directive in output_stage.cir — use shared node name GATE_Q1 2026-05-22 23:27:21 -04:00
alro65 b82ed400bc feat: BNO085 IMU integration — SPICE + simulator yaw rate feed-forward
SPICE (6_bno085_imu.cir):
  - BNO085 power supply with 10uF + 100nF decoupling on VDD
  - Power-on reset RC circuit (R=10K, C=1uF, tau=10ms → deasserts at ~12ms)
  - I2C Fast Mode 400kHz bus: 4.7K pull-ups, 50pF bus capacitance model
  - Full I2C transaction: START + address 0x4A + R/W + BNO085 ACK + STOP
  - INT pin (open-drain, 10K pull-up, 100Hz interrupt simulation)
  - .meas directives: reset timing, SCL rise time, VDD stability

Simulator (esp32_sim.py):
  - SimSnapshot.bno085_yaw_rate_dps field added
  - _bno085_enabled / _bno085_noise_std_dps / _bno085_yaw_rate_dps state
  - enable_bno085(noise_std_dps=0.02) public method
  - disable_bno085() public method
  - _run_physics: samples gyro at 50Hz with Gaussian noise model
  - _run_outer_loop: uses BNO085 yaw rate for rot_ff_term when enabled
    (replaces NMEA-derived ROT — lower latency ~4ms vs ~100-200ms)

Usage:
  sim.enable_bno085()          # activate gyro feed-forward
  sim.enable_bno085(noise_std_dps=0.014)  # with BNO085 spec noise

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 22:46:16 -04:00
alro65 3b36f178aa fix: update analog input SPICE to reflect corrected 100K+27K resistor values
All analog ports (IN-BAT, IN-WATER, IN-OILP, IN-RPM) now use R_high=100K,
R_low=27K — unified design confirmed in schematic. Updated .param values,
voltage divider netlist, verification comments, and design notes.

Vout @ 14.4V (alternator) = 3.06V — just at the ADC limit, correct.
Vout @ 15.5V = 3.30V — absolute maximum safe input voltage.
Filter fc = 747 Hz with 100K||27K and 10nF.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 10:19:24 -04:00
alro65 210c44341f feat: LTspice RS-485 / NMEA 0183 interface simulation (SN65HVD1781)
Simulates the full RS-485 half-duplex channel on the ESP32+CAN+RS485 board:
  - SN65HVD1781 behavioral driver/receiver (3.3V native, 32 unit loads)
  - Half-duplex direction control via DE/RE GPIO4
  - 560Ω bias resistors keeping bus HIGH during idle (NMEA 0183 failsafe)
  - 120Ω termination at both ends of a 10m T-line model (Zo=120, Td=50ns)
  - Transmits ASCII 'G' (0x47) at 4800 bps — one complete NMEA character
  - Second node as passive 12kΩ unit-load receiver
  - .meas directives verify Vdiff > ±200mV (RS-485 spec) in both polarities

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 10:13:16 -04:00
alro65 fa8a65f687 feat: LTspice SPICE netlists for all hardware subcircuits
Four .cir behavioral simulations ready to open in LTspice via File→Open:
  1_buck_chain.cir      — dual MP2338 12V→5V→3.3V, verifies Rfb math + soft-start
  2_output_stage.cir    — PC817 + IRLML6344 isolated output (inverted logic confirmed)
  3_analog_input.cir    — analog input conditioning; flags ADC overvoltage on IN-BAT/WATER/OILP
  4_nmea2000_can.cir    — MCP2562T CAN transceiver, two-node NMEA2000 bus, T-line model

CRITICAL finding in 3_analog_input.cir: R_high=10K + R_low=15K gives 4.3V
at ESP32 ADC when measuring a 12V battery — exceeds 3.3V limit. Fix: use
R_high=100K (same as IN-RPM, which is correctly designed at 3.06V @ 14.4V).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 09:59:50 -04:00
alro65 c432fc3725 feat: sea-state model + 7 bad-weather / stress TCs (14/14 pass)
esp32_sim.py — Sea state engine
  • _BEAUFORT_TABLE (B0–B8): wave torque, swell, noise, wind-bias, period
  • set_sea_state(beaufort, seed): injects external_yaw_torque into
    VesselHeadingSimulator each tick (sine wave + swell + white noise +
    weather-helm drift).  B4≈±3° heading osc, B6 disengages correctly.
  • tune_response(rudder_kp, counter_rudder, max_rudder_deg): runtime
    gain adjustment — simulates the classic Robertson "RUDDER" /
    "COUNTER RUDDER" / working-rudder-limit knobs.
  • _compute_wave_torque(): composed 4-component disturbance model.

sim_protocol.py — 7 new demanding test cases
  TC-08  Beaufort 4, 5 min     max dev 10.4°, RMS 5.6°, no disengage
  TC-09  Beaufort 6 operational limit — SEVERE alarm fires at 35.8 s
         (correct safety behaviour; documents factory-gain limit)
  TC-10  Low speed 2 kn, +10°  τ_outer≈113 s, settles 0.83° < 3°
  TC-11  180° reversal          no SEVERE (tracking_settled guard), 1.18°
  TC-12  Rapid setpoint stress  5 changes in 100 s, final error 1.17°
  TC-13  Gain boost in B5       1.70× RMS improvement (12.3°→7.2°),
         demonstrates RUDDER+COUNTER RUDDER tuning effect
  TC-14  B7 spike (30 s)       SEVERE fires correctly, re-engages,
         recovers to 0.0° within 90 s of calm return

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 08:26:37 -04:00
alro65 2b574b57f6 feat: Python-native ESP32 simulator + 7-TC HIL protocol (all pass)
tools/esp32_sim.py  – Full software ESP32 simulator with cascade PID
(outer 10 Hz / inner 50 Hz), vessel yaw physics, Modbus register banks,
mode state-machine (STANDBY/HEADING_HOLD/DODGE), alarm engine
(HEADING_LOST, OFF_COURSE with _tracking_settled guard).

Sim-specific parameter tuning vs. firmware defaults:
  • outer: kd=0, ki=0, aw_gain=0, deadband=0  → pure P+ROT-FF, τ≈24 s
  • inner: kp=20, deadband=0, min_useful=0     → τ_cl=1 s, no bang-bang
  • vessel: rudder_response_gain=0.004         → 30 m yacht dynamics

tools/sim_protocol.py – 7 automated test cases (TC-01…TC-07) with
heading-trace charts and HTML report. All 7 PASS:
  TC-02 settle 49.8 s, error 0.488°   (crit <60 s, <1°)
  TC-03 settle 134 s, error 0.985°    (crit <180 s, <2°)
  TC-04 settle 56.5 s, error 0.570°   (crit <90 s, <1°)
  TC-07 dodge 1.73°, return 0.527°    (crit <2°, <1°)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 04:18:01 -04:00
alro65 65860948b4 sprint-1: firmware ESP32 base -- STANDBY + Modbus + NMEA 2000 + watchdog
End-to-end implementation of Sprint 1 per docs/sprint-1-plan.md.

Builds: pio run -e esp32-dev SUCCESS, RAM 6.7%, Flash 26.5% (347 KB).
Tests: pytest 110/110 green; pio test -e native deferred (needs host
       C++ compiler -- none on this Windows machine).

Firmware (firmware/ar_autopilot_v1/):

- platformio.ini: 4 envs (esp32-dev release, esp32-debug, native unity
  tests, check static analysis). NMEA2000-library@4.22, NMEA2000_esp32@
  1.0, eModbus@1.7.4 pinned.
- main.cpp: boot in STANDBY, FreeRTOS task spawn, returns to scheduler.
- system/: ar_log.h facade, task_config.h (priorities/stacks/cores
  central table), heartbeat (1 Hz LED + uptime).
- modes/: STANDBY-only state machine; non-STANDBY rejected.
- hal/: di_do.cpp (5 DI + 10 DO with debounce + last-state cache),
  rudder_sensor.cpp (100 Hz ADC + 5-sample median filter, Core 1),
  rudder_actuator.cpp (DO1/DO2/DO3 with three safety interlocks:
  power-off, STANDBY mode, limit switch).
- safety/: TWDT @ 2 s panic-on-expire; 50 Hz safety task on Core 1
  enforcing DI1 physical disengage button, DI4 external alarm,
  both-limit-switch interlock.
- protocols/modbus_slave.cpp: eModbus RTU server on UART2 @ 38400 8N1,
  slave ID 1. 17 inputs + 19 discretes + 5 holdings + 4 coils. Reads
  pull live telemetry; writes validate range and route to handlers.
- protocols/nmea2000_consumer.cpp: stack open with CAN TX=GPIO3
  RX=GPIO1, subscribed to PGN 127250 (Heading) + PGN 127251 (Rate of
  Turn). 5 s staleness flag built in for Sprint 6 alarm wiring.
- filters/median.h: templated MedianFilter<T,N> (host testable).

Cross-cutting:

- modbus_registers.yaml: single source of truth for the Modbus register
  map. 45 entries.
- tools/gen_modbus_registers.py: YAML -> C++ header + Python module
  generator with --check for drift detection.
- arautopilot/shared/modbus_register_map.py: generated Python mirror,
  imported by Studio + tools.
- arautopilot/tests/test_modbus_register_map.py: 30 tests covering
  schema, address uniqueness, range, spot-checks, and drift detection
  (fails if YAML edited without regenerating).
- firmware/ar_autopilot_v1/tools/modbus_client_test.py: manual Modbus
  client for poking the slave from a PC with USB-RS485 dongle.
- firmware/ar_autopilot_v1/test/test_median_filter/test_median.cpp:
  8 Unity tests of the median filter (host-side, no Arduino dependency).
- docs/firmware.md: full operator + integrator guide (toolchain, build,
  flash, expected boot log, troubleshooting, Sprint 1 capability matrix).

Architecture note: opted for Arduino-on-ESP32 only instead of the
proposed dual Arduino-as-ESP-IDF-component setup. Rationale documented
in CHANGELOG and docs/firmware.md -- Arduino-on-ESP32 already provides
the FreeRTOS primitives we need; dual framework adds fragility without
benefit at Sprint 1 scope. Reconsider in Sprint 8 (OTA + secure boot).

NOT in Sprint 1 (intentional per brief sec. 12):
  - PID loops (inner/outer)
  - True Course / Track Keeping
  - Full alarm catalogue beyond DI1/DI4
  - Knob driver
  - Studio GUI / dedicated display

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 10:45:56 -04:00
alro65 700756c16f sprint-0: foundations -- data model, seed library, tests, demo
Initial commit. Delivers what the brief calls 'Sprint 0 - Foundations'
(see docs/AR_Autopilot_brief.md section 12):

- Complete repository structure (arautopilot package + firmware, display,
  installer, tools placeholders + docs).
- Core data model (Pydantic v2): modes, alarms, actuator config, PID
  config + gain scheduling, vessel config, knob state machine, project
  config with YAML/JSON serialisation.
- Seed library: 2 actuator profiles (hydraulic & electric DC reversible)
  and 2 default tunings (yacht motor planeo 30 m and 40 m). Conservative
  literature values, NOT the integrator's production tuning IP.
- Firmware skeleton: only src/hal/pinout.h with the 21 I/O contract for
  the AR-NMEA-IO v1.0 board. No drivers, no main loop.
- Studio stubs (real PySide6 app starts in Sprint 4).
- pytest suite (80 tests, all green): modes, alarms, actuator, PID
  (incl. gain interpolation and the +/-50% adaptive bound from brief
  section 6), vessel, knob state, project config, library loader,
  end-to-end roundtrip.
- examples/sprint0_demo.py - the acceptance demo from the brief.

Acceptance criteria met:
- pytest green (80/80)
- demo creates, saves (YAML + JSON), reloads, and verifies a full
  ProjectConfig using the seed library
- repository ready for tag `sprint-0-approved`

See CHANGELOG.md for the detailed scope.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 23:57:18 -04:00