"""Unified CLI for motor-only system identification. Usage: python scripts/motor_sysid.py capture --duration 20 python scripts/motor_sysid.py optimize --recording assets/motor/recordings/.npz python scripts/motor_sysid.py visualize --recording assets/motor/recordings/.npz python scripts/motor_sysid.py export --result assets/motor/motor_sysid_result.json """ from __future__ import annotations import sys from pathlib import Path # Ensure project root is on sys.path _PROJECT_ROOT = str(Path(__file__).resolve().parent.parent) if _PROJECT_ROOT not in sys.path: sys.path.insert(0, _PROJECT_ROOT) def main() -> None: if len(sys.argv) < 2 or sys.argv[1] in ("-h", "--help"): print( "Motor System Identification\n" "===========================\n" "Usage: python scripts/motor_sysid.py [options]\n" "\n" "Commands:\n" " capture Record motor trajectory under PRBS excitation\n" " optimize Run CMA-ES to fit motor parameters\n" " visualize Plot real vs simulated motor response\n" " export Write tuned MJCF + robot.yaml files\n" "\n" "Workflow:\n" " 1. Flash sysid firmware to ESP32 (motor-only, no limits)\n" " 2. python scripts/motor_sysid.py capture --duration 20\n" " 3. python scripts/motor_sysid.py optimize --recording .npz\n" " 4. python scripts/motor_sysid.py visualize --recording .npz\n" "\n" "Run ' --help' for command-specific options." ) sys.exit(0) command = sys.argv[1] sys.argv = [f"motor_sysid {command}"] + sys.argv[2:] if command == "capture": from src.sysid.motor.capture import main as cmd_main elif command == "optimize": from src.sysid.motor.optimize import main as cmd_main elif command == "visualize": from src.sysid.motor.visualize import main as cmd_main elif command == "export": from src.sysid.motor.export import main as cmd_main else: print(f"Unknown command: {command}") print("Available commands: capture, optimize, visualize, export") sys.exit(1) cmd_main() if __name__ == "__main__": main()