update sensor bench
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
# Sensor Bench Operator (Internal)
|
||||
|
||||
Private operator / inspection workflow UI. **Do not publish** this folder or its
|
||||
resources in customer EXEs, public docs, or release zips.
|
||||
|
||||
## What lives here
|
||||
|
||||
- Workflow UI (`sensor_bench_operator.app.MainWindow`)
|
||||
- Inspection steps (`steps/default.json`)
|
||||
- Lab component options (`config/options.json`, including Chinese lab labels)
|
||||
- Operator locale catalogs (`config/locales/`)
|
||||
|
||||
The public exhibition app lives under the repository root (`run.py`,
|
||||
`src/sensor_bench/exhibition_app.py`) and must not import this package.
|
||||
|
||||
## Run (source)
|
||||
|
||||
From the repository root:
|
||||
|
||||
```powershell
|
||||
python internal/run_operator.py
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```bat
|
||||
.\internal\run_operator.bat
|
||||
```
|
||||
|
||||
Requires the public `sensor-bench` package sources on `PYTHONPATH` (the launcher
|
||||
adds `src/` and `internal/src/` automatically) and an importable `orisys`.
|
||||
|
||||
## Build private EXE
|
||||
|
||||
Uses the same conda env as the public build (`sensor-bench-build-py310`):
|
||||
|
||||
```bat
|
||||
.\build\create_env.bat
|
||||
.\build\build_operator_exe.bat
|
||||
```
|
||||
|
||||
Output (internal only — do not ship to customers):
|
||||
|
||||
```text
|
||||
dist/SensorBenchOperator/SensorBenchOperator.exe
|
||||
```
|
||||
|
||||
The build copies public sensor configs plus operator `options.json`, locales, and
|
||||
`steps/` beside the EXE. See [`../build/README.md`](../build/README.md).
|
||||
|
||||
## Relationship to public Sensor Bench
|
||||
|
||||
```text
|
||||
orisys (public SDK)
|
||||
├── sensor-bench → dist/SensorBench/ (public exhibition EXE)
|
||||
└── internal/ → dist/SensorBenchOperator/ (private operator EXE)
|
||||
```
|
||||
@@ -0,0 +1,166 @@
|
||||
{
|
||||
"app": {
|
||||
"title": "Sensor Bench",
|
||||
"language": "Language",
|
||||
"lang_zh": "中文",
|
||||
"lang_en": "English"
|
||||
},
|
||||
"panels": {
|
||||
"instructions": "Instructions",
|
||||
"options": "Sensor Component Types",
|
||||
"camera": "Camera (Orisys SDK)",
|
||||
"recording": "Recording",
|
||||
"raw": "Raw Image (sensor.frame)",
|
||||
"processed": "Processed Image (Sensor.get_img)",
|
||||
"force": "Force Curves"
|
||||
},
|
||||
"labels": {
|
||||
"sensor_type": "Sensor type",
|
||||
"elastomer": "Elastomer",
|
||||
"cmos": "CMOS",
|
||||
"marker": "Marker",
|
||||
"indentor": "Indenter",
|
||||
"platform": "Platform",
|
||||
"camera_index": "Camera index",
|
||||
"backend": "Backend",
|
||||
"fixed_mode": "Fixed mode: {mode}",
|
||||
"fixed_mode_unset": "Fixed mode: set config path",
|
||||
"fixed_mode_invalid": "Fixed mode: invalid config ({error})",
|
||||
"requested": "Requested",
|
||||
"actual": "Actual",
|
||||
"capture_fps": "Capture FPS",
|
||||
"render_fps": "Render FPS",
|
||||
"proc_ms": "Proc ms",
|
||||
"fn": "FN",
|
||||
"fx": "FX",
|
||||
"fy": "FY",
|
||||
"no_preview": "No preview",
|
||||
"processed_placeholder": "Start Preview to show Orisys output",
|
||||
"not_recording": "Not recording",
|
||||
"force_plot": "Force",
|
||||
"config_dir_tip": "Installed configs dir: {path}\nSelected: {selected}",
|
||||
"config_dir_missing": "Installed Orisys configs directory not found. Use Config… to browse a local JSON."
|
||||
},
|
||||
"buttons": {
|
||||
"config": "Config…",
|
||||
"cal": "Cal…",
|
||||
"start_preview": "Start Preview",
|
||||
"stop_preview": "Stop Preview",
|
||||
"browse": "Browse…",
|
||||
"start_record": "Start Record",
|
||||
"stop_record": "Stop Record",
|
||||
"next": "Next",
|
||||
"revert": "Revert",
|
||||
"reset": "New Sample / Reset"
|
||||
},
|
||||
"placeholders": {
|
||||
"config": "Select an installed Orisys config, or browse a JSON file",
|
||||
"cal": "Optional calibration .npy"
|
||||
},
|
||||
"dialogs": {
|
||||
"select_config": "Select config JSON",
|
||||
"select_cal": "Select calibration",
|
||||
"select_recordings": "Select recordings folder",
|
||||
"orisys_title": "Orisys",
|
||||
"orisys_required": "orisys SDK is required for preview.\n\n{detail}",
|
||||
"config_title": "Config",
|
||||
"config_required": "Select a DDJX01 config JSON first.",
|
||||
"config_invalid": "Config could not be loaded.",
|
||||
"capture_title": "Capture",
|
||||
"recording_title": "Recording",
|
||||
"no_frame": "No frame yet."
|
||||
},
|
||||
"status": {
|
||||
"ready": "Ready — Start Preview uses Orisys DDJX01 fixed format.",
|
||||
"orisys_ok": "orisys available (version {version})",
|
||||
"orisys_missing": "orisys not importable — add orisys-sdk/src to PYTHONPATH.",
|
||||
"opening": "Opening Orisys ({mode})…",
|
||||
"preview_stopped": "Preview stopped.",
|
||||
"capture_error": "Capture error: {message}",
|
||||
"frame_info": "{raw_w}x{raw_h} raw / {proc_w}x{proc_h} processed @ {fps:.1f} FPS",
|
||||
"recording": "Recording… {name}\nOptions: sensor={sensor_type}, elastomer={elastomer}, cmos={cmos}, marker={marker}, indenter={indentor}, platform={platform}",
|
||||
"recording_frames": "Recording… {name}\nFrames: {count}",
|
||||
"saved": "Saved {count} frames → {path}",
|
||||
"workflow_done": "All steps completed. Click New Sample / Reset for the next unit."
|
||||
},
|
||||
"exhibition": {
|
||||
"title": "Sensor Bench Exhibition",
|
||||
"btn_search": "Search",
|
||||
"btn_camera": "Camera",
|
||||
"btn_config": "Config",
|
||||
"btn_start": "Start",
|
||||
"btn_starting": "Starting…",
|
||||
"btn_stop": "Pause",
|
||||
"btn_reset": "Reset",
|
||||
"btn_start_record": "Start Record",
|
||||
"btn_stop_record": "Stop Record",
|
||||
"show_log": "Show log panel",
|
||||
"view": "View",
|
||||
"view_pure_color": "Arrows on solid bg",
|
||||
"view_captured": "Arrows on captured",
|
||||
"view_processed": "Processed image",
|
||||
"view_raw": "Raw image",
|
||||
"sensor_type": "Sensor",
|
||||
"sensor_orisys": "ORY-BOX/ORY-MINI",
|
||||
"sensor_dd06": "ORY-X",
|
||||
"sensor_switched": "Switched sensor type: {sensor}",
|
||||
"placeholder_camera": "Camera index or video path",
|
||||
"dialog_video": "Select video file",
|
||||
"camera_found": "Found {count} camera(s): {names}",
|
||||
"camera_none": "No usable camera found. Click Search to rescan, or use Camera to pick a video file.",
|
||||
"plot_fn": "Normal Force FN",
|
||||
"plot_fx": "Shear Force FX",
|
||||
"plot_fy": "Shear Force FY",
|
||||
"reset_done": "Tracker reset.",
|
||||
"reset_need_start": "Start the sensor before resetting the tracker.",
|
||||
"reset_failed": "Reset failed: {message}",
|
||||
"force_fn_n": "Normal force (N)={value:.6f}",
|
||||
"recording_started": "Recording started: {name}",
|
||||
"hints": "Keys: Q quit | R reset tracker | S start record | E stop record | ESC fullscreen",
|
||||
"menu_help": "Help",
|
||||
"menu_about": "About",
|
||||
"about_title": "About Sensor Bench",
|
||||
"about_body": "Sensor Bench Exhibition\nVersion: {app_version}\nOrisys: {orisys_version}\n\nOrisys-Tech",
|
||||
"config_dir_tip": "Installed configs dir: {path}\nSelected: {selected}",
|
||||
"config_dir_missing": "Installed Orisys configs directory not found. Use Config… to browse a local JSON."
|
||||
},
|
||||
"workflow": {
|
||||
"title": "Sensor Bench Inspection Workflow",
|
||||
"current_marker": "Current",
|
||||
"done_marker": "Done",
|
||||
"steps": {
|
||||
"power_on": {
|
||||
"title": "Power on and connect",
|
||||
"body": "Connect the sensor USB cable and wait until Windows recognizes the device."
|
||||
},
|
||||
"select_camera": {
|
||||
"title": "Start Orisys preview",
|
||||
"body": "Confirm camera index (usually 0) and DDJX01 config, then click Start Preview. Format is fixed by the Orisys config (1920x1080 @ 30)."
|
||||
},
|
||||
"set_options": {
|
||||
"title": "Set sensor options",
|
||||
"body": "Choose elastomer type, CMOS type, and marker type that match the physical unit under test."
|
||||
},
|
||||
"check_preview": {
|
||||
"title": "Check raw and processed preview",
|
||||
"body": "Confirm raw frame is ~1920x1080 and processed Orisys image is ~365x365. Inspect focus, lighting, and image cleanliness."
|
||||
},
|
||||
"record": {
|
||||
"title": "Record raw data",
|
||||
"body": "Choose a storage folder, start recording, exercise the sensor, then stop recording."
|
||||
},
|
||||
"review_curves": {
|
||||
"title": "Review performance curves",
|
||||
"body": "Watch capture/render FPS and force curves for drops or unstable exposure before signing off."
|
||||
},
|
||||
"sensitivity": {
|
||||
"title": "Sensitivity test",
|
||||
"body": "Choose a small indenter and apply a 2g weight, then watch for a clear force-curve change."
|
||||
},
|
||||
"max_load": {
|
||||
"title": "Maximum load test",
|
||||
"body": "Choose a flat plate indenter and apply weights from 10g to 500g to watch for curve changes. Use 10g to 500g for MINI and 2kg for BOX."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
{
|
||||
"app": {
|
||||
"title": "传感器检测台",
|
||||
"language": "语言",
|
||||
"lang_zh": "中文",
|
||||
"lang_en": "English"
|
||||
},
|
||||
"panels": {
|
||||
"instructions": "操作步骤",
|
||||
"options": "传感器组件类型",
|
||||
"camera": "相机(Orisys SDK)",
|
||||
"recording": "录制",
|
||||
"raw": "原始图像(sensor.frame)",
|
||||
"processed": "处理后图像(Sensor.get_img)",
|
||||
"force": "力曲线"
|
||||
},
|
||||
"labels": {
|
||||
"sensor_type": "传感器类型",
|
||||
"elastomer": "弹性体",
|
||||
"cmos": "CMOS",
|
||||
"marker": "图案",
|
||||
"indentor": "压头",
|
||||
"platform": "平台",
|
||||
"camera_index": "相机索引",
|
||||
"backend": "后端",
|
||||
"fixed_mode": "固定模式:{mode}",
|
||||
"fixed_mode_unset": "固定模式:请设置配置路径",
|
||||
"fixed_mode_invalid": "固定模式:配置无效({error})",
|
||||
"requested": "请求",
|
||||
"actual": "实际",
|
||||
"capture_fps": "采集 FPS",
|
||||
"render_fps": "渲染 FPS",
|
||||
"proc_ms": "处理 ms",
|
||||
"fn": "FN",
|
||||
"fx": "FX",
|
||||
"fy": "FY",
|
||||
"no_preview": "暂无预览",
|
||||
"processed_placeholder": "点击开始预览以显示 Orisys 输出",
|
||||
"not_recording": "未在录制",
|
||||
"force_plot": "力",
|
||||
"config_dir_tip": "已安装配置目录:{path}\n当前:{selected}",
|
||||
"config_dir_missing": "未找到已安装的 Orisys 配置目录。可用“配置…”浏览本地 JSON。"
|
||||
},
|
||||
"buttons": {
|
||||
"config": "配置…",
|
||||
"cal": "标定…",
|
||||
"start_preview": "开始预览",
|
||||
"stop_preview": "停止预览",
|
||||
"browse": "浏览…",
|
||||
"start_record": "开始录制",
|
||||
"stop_record": "停止录制",
|
||||
"next": "下一步",
|
||||
"revert": "上一步",
|
||||
"reset": "新样品 / 重置"
|
||||
},
|
||||
"placeholders": {
|
||||
"config": "从已安装 Orisys 配置中选择,或浏览 JSON",
|
||||
"cal": "可选标定文件 .npy"
|
||||
},
|
||||
"dialogs": {
|
||||
"select_config": "选择配置 JSON",
|
||||
"select_cal": "选择标定文件",
|
||||
"select_recordings": "选择录制文件夹",
|
||||
"orisys_title": "Orisys",
|
||||
"orisys_required": "预览需要 Orisys SDK。\n\n{detail}",
|
||||
"config_title": "配置",
|
||||
"config_required": "请先选择 DDJX01 配置 JSON。",
|
||||
"config_invalid": "无法加载配置。",
|
||||
"capture_title": "采集",
|
||||
"recording_title": "录制",
|
||||
"no_frame": "尚无可用帧。"
|
||||
},
|
||||
"status": {
|
||||
"ready": "就绪 — 开始预览将使用 Orisys DDJX01 固定格式。",
|
||||
"orisys_ok": "orisys 可用(版本 {version})",
|
||||
"orisys_missing": "无法导入 orisys — 请将 orisys-sdk/src 加入 PYTHONPATH。",
|
||||
"opening": "正在打开 Orisys({mode})…",
|
||||
"preview_stopped": "预览已停止。",
|
||||
"capture_error": "采集错误:{message}",
|
||||
"frame_info": "{raw_w}x{raw_h} 原始 / {proc_w}x{proc_h} 处理 @ {fps:.1f} FPS",
|
||||
"recording": "正在录制… {name}\n选项:传感器={sensor_type},弹性体={elastomer},CMOS={cmos},标记={marker},压头={indentor},平台={platform}",
|
||||
"recording_frames": "正在录制… {name}\n帧数:{count}",
|
||||
"saved": "已保存 {count} 帧 → {path}",
|
||||
"workflow_done": "全部步骤已完成。可点击“新样品 / 重置”开始下一个样品。"
|
||||
},
|
||||
"exhibition": {
|
||||
"title": "Sensor Bench 展示端",
|
||||
"btn_search": "搜索",
|
||||
"btn_camera": "摄像机",
|
||||
"btn_config": "配置",
|
||||
"btn_start": "启动",
|
||||
"btn_starting": "启动中…",
|
||||
"btn_stop": "暂停",
|
||||
"btn_reset": "重置",
|
||||
"btn_start_record": "开始录像",
|
||||
"btn_stop_record": "结束录像",
|
||||
"show_log": "显示日志面板",
|
||||
"view": "画面",
|
||||
"view_pure_color": "纯色背景箭头",
|
||||
"view_captured": "采集图像箭头",
|
||||
"view_processed": "处理后图像",
|
||||
"view_raw": "原始图像",
|
||||
"sensor_type": "传感器",
|
||||
"sensor_orisys": "ORY-BOX/ORY-MINI",
|
||||
"sensor_dd06": "ORY-X",
|
||||
"sensor_switched": "已切换传感器类型:{sensor}",
|
||||
"placeholder_camera": "摄像头编号或视频路径",
|
||||
"dialog_video": "选择视频文件",
|
||||
"camera_found": "已发现 {count} 路摄像机:{names}",
|
||||
"camera_none": "未发现可用摄像机。可点击“搜索”重扫,或通过“摄像机”选择视频文件。",
|
||||
"plot_fn": "法向力 FN",
|
||||
"plot_fx": "切向力 FX",
|
||||
"plot_fy": "切向力 FY",
|
||||
"reset_done": "追踪器已重置。",
|
||||
"reset_need_start": "请先启动传感器后再重置追踪器。",
|
||||
"reset_failed": "重置失败:{message}",
|
||||
"force_fn_n": "法向力(N)={value:.6f}",
|
||||
"recording_started": "开始录像:{name}",
|
||||
"hints": "按键:Q 退出 | R 重置追踪器 | S 开始录像 | E 结束录像 | ESC 全屏",
|
||||
"menu_help": "帮助",
|
||||
"menu_about": "关于",
|
||||
"about_title": "关于 Sensor Bench",
|
||||
"about_body": "Sensor Bench 展示端\n版本:{app_version}\nOrisys:{orisys_version}\n\nOrisys-Tech",
|
||||
"config_dir_tip": "已安装配置目录:{path}\n当前:{selected}",
|
||||
"config_dir_missing": "未找到已安装的 Orisys 配置目录。可用“配置…”浏览本地 JSON。"
|
||||
},
|
||||
"workflow": {
|
||||
"title": "传感器检测流程",
|
||||
"current_marker": "当前",
|
||||
"done_marker": "已完成",
|
||||
"steps": {
|
||||
"power_on": {
|
||||
"title": "开机并连接",
|
||||
"body": "连接传感器 USB 线缆,等待 Windows 识别设备。"
|
||||
},
|
||||
"select_camera": {
|
||||
"title": "启动 Orisys 预览",
|
||||
"body": "确认相机索引(通常为 0)和 DDJX01 配置,然后点击开始预览。格式由 Orisys 配置固定(1920x1080 @ 30)。"
|
||||
},
|
||||
"set_options": {
|
||||
"title": "设置传感器选项",
|
||||
"body": "选择与当前被测实物一致的弹性体类型、CMOS 类型和标记类型。"
|
||||
},
|
||||
"check_preview": {
|
||||
"title": "检查原始与处理后预览",
|
||||
"body": "确认原始画面约为 1920x1080,处理后 Orisys 图像约为 365x365。检查对焦、光照和画面清洁度。"
|
||||
},
|
||||
"record": {
|
||||
"title": "录制原始数据",
|
||||
"body": "选择存储文件夹,开始录制,操作传感器,然后停止录制。"
|
||||
},
|
||||
"review_curves": {
|
||||
"title": "查看性能曲线",
|
||||
"body": "观察采集/渲染 FPS 与力曲线,确认无明显掉帧或曝光不稳定后再签字确认。"
|
||||
},
|
||||
"sensitivity": {
|
||||
"title": "灵敏度测试",
|
||||
"body": "选择小压头,并加载 2g 砝码,观察力曲线是否有清晰变化。"
|
||||
},
|
||||
"max_load": {
|
||||
"title": "最大载荷测试",
|
||||
"body": "选择平板压头,并加载 10g 到 500g 的砝码观察曲线变化;MINI 使用 10g 到 500g,BOX 使用 2kg。"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"sensor_types": [
|
||||
{"id": "BOX", "label": "BOX"},
|
||||
{"id": "MINI", "label": "MINI"}
|
||||
],
|
||||
"elastomer_types": [
|
||||
{"id": "shoreA20", "label": "冯总20度"},
|
||||
{"id": "shore0030", "label": "0度"},
|
||||
{"id": "solaris", "label": "铂金"}
|
||||
],
|
||||
"cmos_types": [
|
||||
{"id": "ov2710", "label": "OV2710"},
|
||||
{"id": "ov9745", "label": "OV9745"}
|
||||
],
|
||||
"marker_types": [
|
||||
{"id": "4color", "label": "4Color"}
|
||||
],
|
||||
"indentor_types": [
|
||||
{"id": "1mm_circle", "label": "1mm圆柱"},
|
||||
{"id": "1mm_ball", "label": "1mm球"}
|
||||
],
|
||||
"platoform_types": [
|
||||
{"id": "manual", "label": "手动"},
|
||||
{"id": "single_axis", "label": "单轴"},
|
||||
{"id": "six_axis", "label": "六轴"}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
cd /d "%~dp0.."
|
||||
python "%~dp0run_operator.py" %*
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Launch the private Sensor Bench operator workflow UI.
|
||||
|
||||
Usage (from the repository root or this folder):
|
||||
python internal/run_operator.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
os.environ.setdefault("OPENCV_VIDEOIO_MSMF_ENABLE_HW_TRANSFORMS", "0")
|
||||
|
||||
INTERNAL = Path(__file__).resolve().parent
|
||||
REPO = INTERNAL.parent
|
||||
PUBLIC_SRC = REPO / "src"
|
||||
OPERATOR_SRC = INTERNAL / "src"
|
||||
|
||||
for path in (OPERATOR_SRC, PUBLIC_SRC):
|
||||
if str(path) not in sys.path:
|
||||
sys.path.insert(0, str(path))
|
||||
|
||||
# Prefer sibling orisys-sdk checkout for Sensor-owned preview.
|
||||
ORISYS_SRC = REPO.parent / "orisys-sdk" / "src"
|
||||
if ORISYS_SRC.is_dir() and str(ORISYS_SRC) not in sys.path:
|
||||
sys.path.insert(0, str(ORISYS_SRC))
|
||||
|
||||
from sensor_bench_operator.__main__ import main # noqa: E402
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,5 @@
|
||||
"""Private Sensor Bench operator workflow UI (internal use only)."""
|
||||
|
||||
from .app import MainWindow
|
||||
|
||||
__all__ = ["MainWindow"]
|
||||
@@ -0,0 +1,26 @@
|
||||
"""python -m sensor_bench_operator"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
os.environ.setdefault("OPENCV_VIDEOIO_MSMF_ENABLE_HW_TRANSFORMS", "0")
|
||||
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
|
||||
from .app import MainWindow
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
args = list(sys.argv if argv is None else argv)
|
||||
qt_app = QApplication(args)
|
||||
qt_app.setApplicationName("Sensor Bench Operator")
|
||||
qt_app.setOrganizationName("Orisys-Tech")
|
||||
window = MainWindow()
|
||||
window.show()
|
||||
return qt_app.exec_()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,50 @@
|
||||
"""Resolve internal operator resource paths (steps, options, locales)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def is_frozen() -> bool:
|
||||
return bool(getattr(sys, "frozen", False))
|
||||
|
||||
|
||||
def app_root() -> Path:
|
||||
"""Editable ``internal/`` directory, or frozen executable directory."""
|
||||
if is_frozen():
|
||||
return Path(sys.executable).resolve().parent
|
||||
return Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def resource_root() -> Path:
|
||||
"""Bundled resource root for editable and PyInstaller runs."""
|
||||
if is_frozen():
|
||||
return Path(getattr(sys, "_MEIPASS", app_root())).resolve()
|
||||
return app_root()
|
||||
|
||||
|
||||
def operator_root() -> Path:
|
||||
"""Compatibility alias for ``app_root()``."""
|
||||
return app_root()
|
||||
|
||||
|
||||
def default_options_path() -> Path:
|
||||
external = app_root() / "config" / "options.json"
|
||||
if external.exists():
|
||||
return external
|
||||
return resource_root() / "config" / "options.json"
|
||||
|
||||
|
||||
def default_steps_path() -> Path:
|
||||
external = app_root() / "steps" / "default.json"
|
||||
if external.exists():
|
||||
return external
|
||||
return resource_root() / "steps" / "default.json"
|
||||
|
||||
|
||||
def default_locales_dir() -> Path:
|
||||
external = app_root() / "config" / "locales"
|
||||
if external.exists():
|
||||
return external
|
||||
return resource_root() / "config" / "locales"
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"title_key": "workflow.title",
|
||||
"steps": [
|
||||
{"id": "power_on"},
|
||||
{"id": "select_camera"},
|
||||
{"id": "set_options"},
|
||||
{"id": "check_preview"},
|
||||
{"id": "record"},
|
||||
{"id": "review_curves"},
|
||||
{"id": "sensitivity"},
|
||||
{"id": "max_load"}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
"""Smoke tests for the internal Sensor Bench operator UI."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
sys.path.insert(0, str(ROOT / "src"))
|
||||
sys.path.insert(0, str(ROOT / "internal" / "src"))
|
||||
|
||||
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
||||
|
||||
|
||||
def test_mainwindow_offscreen() -> None:
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
from sensor_bench.acquisition import FixedCameraMode
|
||||
from sensor_bench.i18n import DEFAULT_LOCALE
|
||||
from sensor_bench_operator.app import MainWindow
|
||||
|
||||
app = QApplication.instance() or QApplication([])
|
||||
win = MainWindow()
|
||||
assert win.tr.locale == DEFAULT_LOCALE == "zh_CN"
|
||||
assert "传感器" in win.windowTitle()
|
||||
assert win.btn_start.text() == "开始预览"
|
||||
assert win.camera_index.value() == 0
|
||||
assert win.config_combo is not None
|
||||
assert win.config_combo.count() >= 1
|
||||
assert win.btn_next is not None
|
||||
assert win.btn_revert is not None
|
||||
assert win.btn_reset is not None
|
||||
assert win.sensor_type_combo.count() == 2
|
||||
assert win.indentor_combo.count() == 2
|
||||
assert win.platform_combo.count() == 3
|
||||
assert win.selected_sensor_options()["sensor_type"] == "BOX"
|
||||
assert win.selected_sensor_options()["indentor"] == "1mm_circle"
|
||||
assert win.selected_sensor_options()["platform"] == "manual"
|
||||
assert not hasattr(win, "resolution_combo")
|
||||
assert not hasattr(win, "btn_search")
|
||||
assert win._current_step_index == 0
|
||||
assert not win.btn_revert.isEnabled()
|
||||
assert win.btn_next.isEnabled()
|
||||
|
||||
# Language switch refreshes labels without restart.
|
||||
win.language_combo.setCurrentIndex(1)
|
||||
assert win.tr.locale == "en_US"
|
||||
assert win.windowTitle() == "Sensor Bench"
|
||||
assert win.btn_start.text() == "Start Preview"
|
||||
|
||||
# Workflow next / revert / reset.
|
||||
total = len(win.workflow.steps)
|
||||
win._on_step_next()
|
||||
assert win._current_step_index == 1
|
||||
assert win.btn_revert.isEnabled()
|
||||
win._on_step_revert()
|
||||
assert win._current_step_index == 0
|
||||
for _ in range(total):
|
||||
win._on_step_next()
|
||||
assert win._current_step_index == total
|
||||
assert not win.btn_next.isEnabled()
|
||||
assert "completed" in win.workflow_status.text().lower() or "完成" in win.workflow_status.text()
|
||||
win._on_step_reset()
|
||||
assert win._current_step_index == 0
|
||||
assert win.btn_next.isEnabled()
|
||||
|
||||
win._fixed_mode = FixedCameraMode(
|
||||
width=1920,
|
||||
height=1080,
|
||||
fps=30.0,
|
||||
config_ref=str(ROOT / "tests" / "fixtures" / "ddjx01_min.json"),
|
||||
stitch_width=365,
|
||||
stitch_height=365,
|
||||
)
|
||||
win.mode_label.setText(win.t("labels.fixed_mode", mode=win._fixed_mode.label()))
|
||||
assert "1920x1080" in win.mode_label.text()
|
||||
win.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_mainwindow_offscreen()
|
||||
print("ok")
|
||||
Reference in New Issue
Block a user