支持传感器独立校准文件与批量配置启动
保留逐台添加,并通过显式配置一次连接全组;失败时撤销本批新增连接。通过 35 项回归测试、真实 SDK 校准与 1–4 路验证、Ruff 和文档检查。
This commit is contained in:
+43
-2
@@ -2,6 +2,7 @@
|
||||
|
||||
import argparse
|
||||
import itertools
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from functools import partial
|
||||
@@ -16,6 +17,7 @@ def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--recording", required=True, type=Path)
|
||||
parser.add_argument("--scratch", required=True, type=Path)
|
||||
parser.add_argument("--calibration", type=Path, help="explicit calibration used for all offline test sources")
|
||||
args = parser.parse_args()
|
||||
scratch = args.scratch.resolve()
|
||||
scratch.mkdir(parents=True, exist_ok=True)
|
||||
@@ -39,6 +41,7 @@ def main():
|
||||
capture.release()
|
||||
height, width = frames[0].shape[:2]
|
||||
sources = []
|
||||
calibrations = []
|
||||
for sensor_id in range(1, 5):
|
||||
path = scratch / f"sensor-{sensor_id}.avi"
|
||||
writer = cv2.VideoWriter(str(path), cv2.VideoWriter_fourcc(*"MJPG"), 30, (width, height))
|
||||
@@ -50,6 +53,10 @@ def main():
|
||||
finally:
|
||||
writer.release()
|
||||
sources.append(str(path))
|
||||
if args.calibration:
|
||||
calibration = scratch / f"sensor-{sensor_id}-calibration.json"
|
||||
calibration.write_bytes(args.calibration.read_bytes())
|
||||
calibrations.append(str(calibration))
|
||||
|
||||
# Keep the SDK implementation intact; redirect only its generated UV cache.
|
||||
open_runtime = partial(FingerRuntime.open, map_cache=str(scratch / "uv-map.npz"))
|
||||
@@ -57,11 +64,17 @@ def main():
|
||||
for count in range(1, 5):
|
||||
bank = FingerSensorBank()
|
||||
try:
|
||||
for source in sources[:count]:
|
||||
for index, source in enumerate(sources[:count]):
|
||||
existing = dict(bank.runtimes)
|
||||
bank.add(source)
|
||||
bank.add(source, cal_path=calibrations[index] if calibrations else None)
|
||||
assert all(bank.runtimes[i] is runtime for i, runtime in existing.items())
|
||||
assert len(bank.read_all()) == len(bank.runtimes)
|
||||
if calibrations:
|
||||
for sensor_id, runtime in bank.runtimes.items():
|
||||
calibration = runtime.tactile.raw_sensor.calibration
|
||||
assert calibration is not None
|
||||
assert calibration.source_path.resolve() == Path(calibrations[sensor_id - 1])
|
||||
assert runtime.tactile.force_units == ("N", "N", "N")
|
||||
runtimes = list(bank.runtimes.values())
|
||||
for left, right in itertools.combinations(runtimes, 2):
|
||||
assert left.capture is not right.capture
|
||||
@@ -75,6 +88,34 @@ def main():
|
||||
finally:
|
||||
bank.close()
|
||||
assert all(runtime.capture is None for runtime in runtimes)
|
||||
setup = scratch / "sensors.json"
|
||||
setup.write_text(json.dumps({"sensors": [
|
||||
{"source": source, **({"calibration": calibrations[i]} if calibrations else {})}
|
||||
for i, source in enumerate(sources)
|
||||
]}), encoding="utf-8")
|
||||
bank = FingerSensorBank()
|
||||
try:
|
||||
assert bank.add_setup(setup) == (1, 2, 3, 4)
|
||||
assert len(bank.read_all()) == 4
|
||||
bad_calibration = scratch / "invalid-calibration.json"
|
||||
bad_calibration.write_text("{}", encoding="utf-8")
|
||||
finally:
|
||||
bank.close()
|
||||
bank = FingerSensorBank()
|
||||
try:
|
||||
bank.add(sources[0])
|
||||
first = bank.runtimes[1]
|
||||
try:
|
||||
bank.add(sources[1], cal_path=str(bad_calibration))
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError("invalid explicit calibration was accepted")
|
||||
assert bank.runtimes == {1: first}
|
||||
assert len(bank.read_all()) == 1
|
||||
finally:
|
||||
bank.close()
|
||||
print("PASS 4-source JSON setup; invalid calibration rejected without fallback", flush=True)
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user