为基础示例接入按设备 ID 选择的力标定

让使用者从本地目录选标定并看见实际单位。短片回放及相关测试通过。
This commit is contained in:
ykcheungab
2026-10-05 14:02:40 +08:00
parent 8c147f03aa
commit ceb06f5702
8 changed files with 51 additions and 9 deletions
+1
View File
@@ -31,6 +31,7 @@ __pycache__/
/data/*
!/data/sample/
!/data/sample/**
!/data/calibrations/
# Generated docs / tooling outputs
/docs/.quarto/
+8 -2
View File
@@ -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:
`<calibration_dir>/<product>/<device_id>.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
+4
View File
@@ -0,0 +1,4 @@
*
!*/
!.gitignore
!.gitkeep
+1
View File
@@ -0,0 +1 @@
+1
View File
@@ -0,0 +1 @@
+1
View File
@@ -0,0 +1 @@
+27 -5
View File
@@ -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 <product>/<device-id>.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
+6
View File
@@ -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",