"""Sprint 0 acceptance demo. Runs end-to-end the workflow the brief calls out in section 12: 1. Build a ``ProjectConfig`` programmatically using the seed library. 2. Save it to disk (YAML and JSON). 3. Reload it from disk. 4. Verify the reloaded object matches the original. 5. Print a human-readable summary. Usage:: python examples/sprint0_demo.py """ from __future__ import annotations from pathlib import Path from arautopilot.core import ( ProjectConfig, VesselConfig, VesselType, interpolate_gains, ) from arautopilot.library.loader import ( list_actuator_profiles, list_default_tunings, load_actuator_profile, load_default_tuning, ) from arautopilot.version import __version__ OUTPUT_DIR = Path(__file__).parent / "output" def main() -> int: print("=" * 78) print(f" AR-Autopilot v{__version__} -- Sprint 0 acceptance demo") print("=" * 78) # ---- 1. Inspect what the seed library carries --------------------------- print("\n[1] Seed library contents:") for profile in list_actuator_profiles(): print(f" - actuator profile : {profile}") for tuning in list_default_tunings(): print(f" - default tuning : {tuning}") # ---- 2. Compose a project from seed assets ------------------------------ print("\n[2] Building project from seed library...") actuator = load_actuator_profile("hydraulic_reversible") pid = load_default_tuning("yacht_motor_planeo_30m") vessel = VesselConfig( name="M/Y Sprint Zero", type=VesselType.YACHT_MOTOR_PLANEO, length_m=30.0, displacement_t=125.0, max_speed_kn=28.0, actuator=actuator, pid=pid, ) project = ProjectConfig( client_name="Demo Shipyard S.L.", project_name="Sprint 0 demonstrator", notes=( "Created by examples/sprint0_demo.py. Seed-library actuator + tuning " "for a 30 m planing motor yacht. Conservative literature gains; not " "the integrator's production tuning." ), vessel=vessel, ) # ---- 3. Save it to disk ------------------------------------------------- OUTPUT_DIR.mkdir(parents=True, exist_ok=True) yaml_out = project.save_yaml(OUTPUT_DIR / "demo_project.yaml") json_out = project.save_json(OUTPUT_DIR / "demo_project.json") print(f"\n[3] Saved to:") print(f" - YAML : {yaml_out}") print(f" - JSON : {json_out}") # ---- 4. Reload and verify integrity ------------------------------------- print("\n[4] Reloading from disk and verifying integrity...") rebuilt_yaml = ProjectConfig.load(yaml_out) rebuilt_json = ProjectConfig.load(json_out) assert rebuilt_yaml == project, "YAML round-trip mismatch" assert rebuilt_json == project, "JSON round-trip mismatch" print(" OK -- both YAML and JSON reload to identical objects.") # ---- 5. Show a human-readable summary ----------------------------------- print("\n[5] Project summary:") print(f" project_id : {project.project_id}") print(f" client : {project.client_name}") print(f" project name : {project.project_name}") print(f" vessel : {project.vessel.name}") print(f" vessel type : {project.vessel.type.value}") print(f" length / Vmax : {project.vessel.length_m:.1f} m / {project.vessel.max_speed_kn:.1f} kn") print(f" actuator type : {project.vessel.actuator.type.value}") print(f" rudder limit : +/-{project.vessel.actuator.max_rudder_angle_deg:.1f} deg" f" at max {project.vessel.actuator.max_rate_dps:.1f} deg/s") print(f" inner PID Kp/Ki/Kd: " f"{project.vessel.pid.inner_loop_base.kp} / " f"{project.vessel.pid.inner_loop_base.ki} / " f"{project.vessel.pid.inner_loop_base.kd}") print(f" outer PID Kp/Ki/Kd: " f"{project.vessel.pid.outer_loop_base.kp} / " f"{project.vessel.pid.outer_loop_base.ki} / " f"{project.vessel.pid.outer_loop_base.kd}") print(f" ROT feed-forward : {project.vessel.pid.rot_feedforward_gain}") print(f" gain schedule pts : {len(project.vessel.pid.gain_schedule)}") # Show interpolation working print("\n Interpolated outer-loop gains by SOG:") for sog in (3.0, 5.0, 10.0, 15.0, 20.0, 28.0, 35.0): gains = interpolate_gains(project.vessel.pid.gain_schedule, sog) print( f" SOG = {sog:5.1f} kn -> " f"Kp={gains.kp:.3f} Ki={gains.ki:.4f} Kd={gains.kd:.3f}" ) print("\nDemo complete.") return 0 if __name__ == "__main__": raise SystemExit(main())