From ceb06f5702da10c4aabd929959f655476e1b2bd1 Mon Sep 17 00:00:00 2001 From: ykcheungab Date: Mon, 5 Oct 2026 14:02:40 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BA=E5=9F=BA=E7=A1=80=E7=A4=BA=E4=BE=8B?= =?UTF-8?q?=E6=8E=A5=E5=85=A5=E6=8C=89=E8=AE=BE=E5=A4=87=20ID=20=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E7=9A=84=E5=8A=9B=E6=A0=87=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 让使用者从本地目录选标定并看见实际单位。短片回放及相关测试通过。 --- .gitignore | 3 ++- README.md | 10 +++++++-- data/calibrations/.gitignore | 4 ++++ data/calibrations/box/.gitkeep | 1 + data/calibrations/finger/.gitkeep | 1 + data/calibrations/mini/.gitkeep | 1 + examples/basic_pipeline.py | 34 ++++++++++++++++++++++++----- tools/downstream_sync_manifest.json | 6 +++++ 8 files changed, 51 insertions(+), 9 deletions(-) create mode 100644 data/calibrations/.gitignore create mode 100644 data/calibrations/box/.gitkeep create mode 100644 data/calibrations/finger/.gitkeep create mode 100644 data/calibrations/mini/.gitkeep diff --git a/.gitignore b/.gitignore index ccb4fea..e0156c3 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ __pycache__/ /data/* !/data/sample/ !/data/sample/** +!/data/calibrations/ # Generated docs / tooling outputs /docs/.quarto/ @@ -49,4 +50,4 @@ __pycache__/ /outputs/ # Agent scratch: one directory per task, see D:\orisys_ws\AGENTS.md -.scratch/ \ No newline at end of file +.scratch/ diff --git a/README.md b/README.md index 7d64062..2cc3fa9 100644 --- a/README.md +++ b/README.md @@ -94,13 +94,19 @@ cfg = orisys.export_config("box", "./config/exported_config.json") For multiple physical sensors, keep calibration files in a user-selected directory: `//.json` (for example, -`./calibrations/box/BOX-001.json`). Each file uses the existing calibration JSON +`data/calibrations/box/BOX-001.json`). Each file uses the existing calibration JSON format and must contain matching `identity.sensor_type` and `identity.sn`, Newton curves for FN/FX/FY, and a compatible measurement pipeline. Enter the device ID manually until hardware identification is available: +The source checkout provides `data/calibrations/{box,mini,finger}/` folders; device +files placed there are ignored by Git. This location is optional: pass +`--calibration-dir data/calibrations` +and `--device-id BOX-001` to `examples/basic_pipeline.py` to select a file there. +Installed wheels do not create or search this directory automatically. + ```python -sensor = orisys.Sensor(0, config_name="box", calibration_dir="./calibrations", device_id="BOX-001") +sensor = orisys.Sensor(0, config_name="box", calibration_dir="data/calibrations", device_id="BOX-001") ``` If that ID has no file, the sensor reports raw force; it never falls back to the diff --git a/data/calibrations/.gitignore b/data/calibrations/.gitignore new file mode 100644 index 0000000..5c0276a --- /dev/null +++ b/data/calibrations/.gitignore @@ -0,0 +1,4 @@ +* +!*/ +!.gitignore +!.gitkeep diff --git a/data/calibrations/box/.gitkeep b/data/calibrations/box/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/data/calibrations/box/.gitkeep @@ -0,0 +1 @@ + diff --git a/data/calibrations/finger/.gitkeep b/data/calibrations/finger/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/data/calibrations/finger/.gitkeep @@ -0,0 +1 @@ + diff --git a/data/calibrations/mini/.gitkeep b/data/calibrations/mini/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/data/calibrations/mini/.gitkeep @@ -0,0 +1 @@ + diff --git a/examples/basic_pipeline.py b/examples/basic_pipeline.py index 4f80e51..99754cf 100644 --- a/examples/basic_pipeline.py +++ b/examples/basic_pipeline.py @@ -19,6 +19,7 @@ Run: python examples/basic_pipeline.py -v 0 -c mini python examples/basic_pipeline.py -v recording.mp4 -c box python examples/basic_pipeline.py --no-show # headless: print only + python examples/basic_pipeline.py -v 0 -c box --calibration-dir data/calibrations --device-id BOX-001 Keys: 'q' quit, 'r' reset the tracker. """ @@ -44,18 +45,39 @@ def main() -> int: help="camera index or video file path (default: 0)") parser.add_argument("-c", "--config", default="box", help="product config: box, mini, finger, or a config path") - parser.add_argument("--cal", default=None, - help="force calibration file; omit to use the sensor bundle's own") + calibration = parser.add_mutually_exclusive_group() + calibration.add_argument("--cal", default=None, + help="force calibration file; omit to use the sensor bundle's own") + calibration.add_argument("--calibration-dir", default=None, + help="root containing /.json") + parser.add_argument("--device-id", default=None, + help="physical sensor ID; required with --calibration-dir") parser.add_argument("--no-show", dest="show", action="store_false", help="do not open the display windows") parser.add_argument("-verbose", action="store_true", help="SDK verbose logs") args = parser.parse_args() + if args.calibration_dir is not None and args.device_id is None: + parser.error("--calibration-dir requires --device-id") + if args.device_id is not None and args.calibration_dir is None and args.cal is None: + parser.error("--device-id requires --calibration-dir or --cal") # ------------------------------------------------------------------ create the object # That is the whole setup. The source may be a camera index or a video path. source = int(args.video) if args.video.isdigit() else args.video - sensor = orisys.Sensor(source, config_name=args.config, cal_path=args.cal, - verbose=args.verbose) + sensor = orisys.Sensor( + source, config_name=args.config, cal_path=args.cal, + calibration_dir=args.calibration_dir, device_id=args.device_id, + verbose=args.verbose, + ) + fn_unit, fx_unit, fy_unit = sensor.force_units + selected = sensor.calibration.source_path if sensor.calibration else None + print(f"Force calibration: {selected or 'none'}") + print(f"Force units: FN={fn_unit}, FX={fx_unit}, FY={fy_unit}") + if sensor.device_calibration_missing: + print( + f"Warning: no calibration for {args.device_id!r} under " + f"{args.calibration_dir}; force is raw." + ) # contact=True runs contact analysis. include=... selects which arrays each snapshot carries; # arrays that are not included are None, so you pay only for what you use. @@ -99,7 +121,7 @@ def main() -> int: if colour is not None: cv2.imshow("depth", colour) - key = cv2.waitKey(1) & 0xFF + key = cv2.waitKey(1) & 0xFF if args.show else -1 if key == ord("q"): print("\nExiting.") break @@ -117,4 +139,4 @@ def main() -> int: if __name__ == "__main__": - sys.exit(main()) \ No newline at end of file + sys.exit(main()) diff --git a/tools/downstream_sync_manifest.json b/tools/downstream_sync_manifest.json index 7ff2659..de240be 100644 --- a/tools/downstream_sync_manifest.json +++ b/tools/downstream_sync_manifest.json @@ -8,6 +8,12 @@ {"from": "docs", "to": "docs", "include": ["get_started.md", "api.md"]}, {"from": "examples", "to": "examples", "exclude": ["__pycache__", "*.pyc", "*.pyo"]}, {"from": "config", "to": "config", "include": ["box.json", "finger.json", "mini.json"]}, + {"from": "data/calibrations", "to": "data/calibrations", "include": [ + ".gitignore", + "box/.gitkeep", + "mini/.gitkeep", + "finger/.gitkeep" + ]}, {"from": "sensors", "to": "sensors", "include": [ "box/sensor.json", "box/force_calibration.json",