618 """Main entry point — interactive or scripted PT calibration via UDP"""
621 parser = argparse.ArgumentParser(
622 description="Autonomous PT Calibration System (UDP)",
623 formatter_class=argparse.RawDescriptionHelpFormatter,
626 # Interactive mode — prompts for reference pressures
627 python3 autonomous_pt_calibration.py --interactive
629 # Zero-cal all channels
630 python3 autonomous_pt_calibration.py --ref-all 0.0 --collect-time 10
633 python3 autonomous_pt_calibration.py --sensor 1 --pressure 14.7 --sensor 2 --pressure 100.0
640 help="UDP port to listen on (default: from config.toml)",
645 help="Filter by board source IP (default: from config.toml)",
648 "--reference-pressures",
650 help="JSON file with reference pressures {channel_id: psi}",
653 "--sensor", type=int, action="append", help="Sensor channel ID to calibrate"
659 help="Reference pressure (PSI) — paired with --sensor",
665 help="Set all channels (1-10) to this reference pressure",
671 help="Seconds to collect per reference point (default: 5)",
677 help="Status print interval in seconds (default: 10)",
683 help="Interactive mode — prompt for commands",
686 args = parser.parse_args()
689 calibrator = AutonomousPTCalibrator(udp_port=args.port, board_ip=args.board_ip)
691 # Load reference pressures from file
692 if args.reference_pressures:
693 with open(args.reference_pressures, "r") as f:
694 ref_pressures = json.load(f)
695 # Convert keys to int
696 calibrator.set_reference_pressures(
697 {int(k): float(v) for k, v in ref_pressures.items()}
701 if args.ref_all is not None:
702 calibrator.set_reference_all(args.ref_all)
704 # Set from --sensor / --pressure pairs
705 if args.sensor and args.pressure:
706 if len(args.sensor) != len(args.pressure):
707 print("❌ Error: Number of --sensor must match number of --pressure")
709 for sensor_id, pressure in zip(args.sensor, args.pressure):
710 calibrator.set_reference_pressure(sensor_id, pressure)
716 def shutdown(sig=None, frame=None):
717 print("\n🛑 Stopping...")
719 calibrator.save_calibrations()
720 calibrator.print_status()
721 print("✅ Calibrations saved")
724 signal.signal(signal.SIGINT, shutdown)
725 signal.signal(signal.SIGTERM, shutdown)
728 # ── Interactive calibration loop ────────────────────────────────
729 print(f"\n{'═' * 70}")
730 print(" INTERACTIVE PT CALIBRATION (UDP)")
731 print(f" Listening on UDP :{args.port}")
734 print(" ref <ch> <psi> — set reference for one channel")
735 print(" ref-all <psi> — set reference for all channels (1-10)")
736 print(" collect [secs] — collect calibration points")
737 print(" fit — fit polynomials now")
738 print(" save — save calibrations to JSON + CSV")
739 print(" status — show full status")
740 print(" live — show live ADC values (Ctrl+C to stop)")
741 print(" quit — save and exit")
746 cmd = input(" [PT] > ").strip()
752 verb = parts[0].lower()
754 if verb == "ref-all" and len(parts) >= 2:
755 calibrator.set_reference_all(float(parts[1]))
756 elif verb == "ref" and len(parts) >= 3:
757 calibrator.set_reference_pressure(int(parts[1]), float(parts[2]))
758 elif verb == "collect":
759 dur = float(parts[1]) if len(parts) > 1 else args.collect_time
760 calibrator.collect_samples(dur)
762 calibrator._auto_fit_calibrations()
763 calibrator.print_status()
765 calibrator._auto_fit_calibrations()
766 calibrator.save_calibrations()
767 elif verb == "status":
768 calibrator.print_status()
770 print(" (Ctrl+C to stop live view)")
774 for ch in sorted(calibrator.live_adc.keys()):
775 buf = calibrator.live_adc[ch]
778 f"CH{ch}:{int(np.mean(list(buf))):>10d}"
781 f"\r [{calibrator.stats['packets_received']:>6d} pkts] "
782 + " ".join(parts_live),
787 except KeyboardInterrupt:
789 elif verb in ("quit", "exit", "q"):
792 print(f" ⚠️ Unknown command: {cmd}")
795 # ── Non-interactive mode ────────────────────────────────────────
796 if not calibrator.reference_pressures:
797 print("⚠️ No references set — showing live ADC (Ctrl+C to stop)")
800 calibrator.print_status()
801 time.sleep(args.status_interval)
802 except KeyboardInterrupt:
805 # Collect at current references and save
806 calibrator.collect_samples(args.collect_time)
807 calibrator._auto_fit_calibrations()
808 calibrator.save_calibrations()
809 calibrator.print_status()