为基础示例接入按设备 ID 选择的力标定
让使用者从本地目录选标定并看见实际单位。短片回放及相关测试通过。
This commit is contained in:
@@ -31,6 +31,7 @@ __pycache__/
|
|||||||
/data/*
|
/data/*
|
||||||
!/data/sample/
|
!/data/sample/
|
||||||
!/data/sample/**
|
!/data/sample/**
|
||||||
|
!/data/calibrations/
|
||||||
|
|
||||||
# Generated docs / tooling outputs
|
# Generated docs / tooling outputs
|
||||||
/docs/.quarto/
|
/docs/.quarto/
|
||||||
|
|||||||
@@ -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:
|
For multiple physical sensors, keep calibration files in a user-selected directory:
|
||||||
`<calibration_dir>/<product>/<device_id>.json` (for example,
|
`<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
|
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
|
curves for FN/FX/FY, and a compatible measurement pipeline. Enter the device ID
|
||||||
manually until hardware identification is available:
|
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
|
```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
|
If that ID has no file, the sensor reports raw force; it never falls back to the
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
*
|
||||||
|
!*/
|
||||||
|
!.gitignore
|
||||||
|
!.gitkeep
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -19,6 +19,7 @@ Run:
|
|||||||
python examples/basic_pipeline.py -v 0 -c mini
|
python examples/basic_pipeline.py -v 0 -c mini
|
||||||
python examples/basic_pipeline.py -v recording.mp4 -c box
|
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 --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.
|
Keys: 'q' quit, 'r' reset the tracker.
|
||||||
"""
|
"""
|
||||||
@@ -44,18 +45,39 @@ def main() -> int:
|
|||||||
help="camera index or video file path (default: 0)")
|
help="camera index or video file path (default: 0)")
|
||||||
parser.add_argument("-c", "--config", default="box",
|
parser.add_argument("-c", "--config", default="box",
|
||||||
help="product config: box, mini, finger, or a config path")
|
help="product config: box, mini, finger, or a config path")
|
||||||
parser.add_argument("--cal", default=None,
|
calibration = parser.add_mutually_exclusive_group()
|
||||||
|
calibration.add_argument("--cal", default=None,
|
||||||
help="force calibration file; omit to use the sensor bundle's own")
|
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",
|
parser.add_argument("--no-show", dest="show", action="store_false",
|
||||||
help="do not open the display windows")
|
help="do not open the display windows")
|
||||||
parser.add_argument("-verbose", action="store_true", help="SDK verbose logs")
|
parser.add_argument("-verbose", action="store_true", help="SDK verbose logs")
|
||||||
args = parser.parse_args()
|
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
|
# ------------------------------------------------------------------ create the object
|
||||||
# That is the whole setup. The source may be a camera index or a video path.
|
# 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
|
source = int(args.video) if args.video.isdigit() else args.video
|
||||||
sensor = orisys.Sensor(source, config_name=args.config, cal_path=args.cal,
|
sensor = orisys.Sensor(
|
||||||
verbose=args.verbose)
|
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;
|
# 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.
|
# 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:
|
if colour is not None:
|
||||||
cv2.imshow("depth", colour)
|
cv2.imshow("depth", colour)
|
||||||
|
|
||||||
key = cv2.waitKey(1) & 0xFF
|
key = cv2.waitKey(1) & 0xFF if args.show else -1
|
||||||
if key == ord("q"):
|
if key == ord("q"):
|
||||||
print("\nExiting.")
|
print("\nExiting.")
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -8,6 +8,12 @@
|
|||||||
{"from": "docs", "to": "docs", "include": ["get_started.md", "api.md"]},
|
{"from": "docs", "to": "docs", "include": ["get_started.md", "api.md"]},
|
||||||
{"from": "examples", "to": "examples", "exclude": ["__pycache__", "*.pyc", "*.pyo"]},
|
{"from": "examples", "to": "examples", "exclude": ["__pycache__", "*.pyc", "*.pyo"]},
|
||||||
{"from": "config", "to": "config", "include": ["box.json", "finger.json", "mini.json"]},
|
{"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": [
|
{"from": "sensors", "to": "sensors", "include": [
|
||||||
"box/sensor.json",
|
"box/sensor.json",
|
||||||
"box/force_calibration.json",
|
"box/force_calibration.json",
|
||||||
|
|||||||
Reference in New Issue
Block a user