blob: 1586775afbefe0d45210a015e93cab70370a7ab3 [file] [log] [blame]
Jim Ostrowski68c321d2023-11-14 21:36:28 -08001#!/usr/bin/env python3
2# This script runs the multi camera calibration code through its paces using log data
3# It uses the AprilTag output logs, rather than directly from images
4import argparse
5import os
6import subprocess
7import sys
8import time
9from typing import Sequence, Text
10
11
12# Compare two json files that may have a different timestamp
13def compare_files(gt_file: str, calc_file: str):
14 with open(gt_file, "r") as f_gt:
15 with open(calc_file, "r") as f_calc:
16 while True:
17 line_gt = f_gt.readline()
18 line_calc = f_calc.readline()
19 if not line_gt:
20 if not line_calc:
21 return True
22 else:
23 return False
24
25 # timestamp field will be different, so ignore this line
26 if "timestamp" in line_gt:
27 if "timestamp" in line_calc:
28 continue
29 else:
30 return False
31
32 # Compare line and return False if different
33 if line_gt != line_calc:
34 print("Lines don't match!")
35 print("\tGround truth file:", line_gt, end='')
36 print("\tCalculated file:", line_calc, end='')
37 return False
38 return True
39
40 return False
41
42
43# Run through the calibration routine and file checking with max_pose_error arg
44def check_calib_match(args, max_pose_error: float):
45 calibrate_result = subprocess.run(
46 [
47 args.calibrate_binary,
48 args.logfile,
49 "--target_type",
50 "apriltag",
51 "--team_number",
52 "971",
53 "--max_pose_error",
54 str(max_pose_error),
55 ],
56 stdout=subprocess.PIPE,
57 stderr=subprocess.PIPE,
58 encoding="utf-8",
59 )
60
61 calibrate_result.check_returncode()
62
63 # Check for the 3 pi's that get calibrated
64 for pi in [2, 3, 4]:
65 pi_name = "pi-971-" + str(pi)
66 # Look for calculated calibration file in /tmp dir with pi_name
67 calc_calib_dir = "/tmp/"
68 files = os.listdir(calc_calib_dir)
69 calc_file = ""
70 # Read the calculated files in reverse order, so that we pick
71 # up the most newly created file each time
72 for file in files[::-1]:
73 # check if file contains substring pi_name
74 if pi_name in file:
75 calc_file = calc_calib_dir + file
76
77 # Next find the "ground truth" file with this pi_name
James Kuszmaul98c798d2024-04-24 15:58:09 -070078 expected_dir = 'y2023/vision/test_data/'
79 files = os.listdir(expected_dir)
Jim Ostrowski68c321d2023-11-14 21:36:28 -080080 gt_file = ""
81 for file in files[::-1]:
82 if pi_name in file:
James Kuszmaul98c798d2024-04-24 15:58:09 -070083 gt_file = expected_dir + file
Jim Ostrowski68c321d2023-11-14 21:36:28 -080084
85 if calc_file != "" and gt_file != "":
86 if not compare_files(gt_file, calc_file):
87 return False
88
89 return True
90
91
92def main(argv: Sequence[Text]):
93 parser = argparse.ArgumentParser()
94 parser.add_argument("--logfile",
95 required=True,
96 default="calib1",
97 help="Path to logfile.")
98 parser.add_argument(
99 "--calibrate_binary",
100 required=False,
101 default=
102 "/home/jimostrowski/code/FRC/971-Robot-Code/bazel-bin/y2023/vision/calibrate_multi_cameras",
103 help="Path to calibrate_multi_cameras binary",
104 )
105 args = parser.parse_args(argv)
106
107 # Run once with correct max_pose_error
108 # These were the flags used to create the test file
109 # max_pose_error = 5e-5
110 # max_pose_error_ratio = 0.4
111 if not check_calib_match(args, 5e-5):
112 return -1
113
114 # And once with the incorrect value for max_pose_error to see that it fails
115 if check_calib_match(args, 1e-5):
116 return -1
117
118 return 0
119
120
121if __name__ == "__main__":
122 sys.exit(main(sys.argv[1:]))