选点、对准、加载与录像分散在两个面板,状态靠隐藏相位判断。现改由不依赖 Qt 的采集控制器驱动,并加入录像选项、汇总平铺副本、保持到时自动结束、会话结束回到空闲,以及无设备时的模拟采集。已运行 Autocal 非 Qt 测试并通过范围内门禁;界面测试待 Windows 复核,未做实机验收。
12 KiB
Autocal 标定采集页重构实施计划
状态:2026-10-18 计划,P0–P6 已实施并通过独立验收复核。仅软件验证:V10 实机验收未执行,需用户指定设备、运动与载荷范围及停机条件;各项检查的实际口径见文末实施结果。目标是把“选点 → 对准 → 逐档加载 → 记录”收成一条流程:一个测点队列、一个不依赖 Qt 的状态控制器、一个随步骤变化的主按钮;同时加入录像选项、打开文件夹和平铺汇总。执行分工见任务分工。本计划不改变运动安全规则、不自动加载、不写回 SDK 系数。
基线与问题
调查基线:app main、HEAD 7607653(实施时实际 HEAD 为 7b5ffa7,以 .scratch/autocal-capture-workflow/baseline.md 为准);工作树已有 motion/service.py、record_diagnostics.py 改动,实施时不得覆盖。结论来自源码、界面截图和 D:/orisys_ws/data/dd02-gl,未运行程序或硬件。
位置(相对 apps/autocal/src/orisys_autocal/) |
问题 |
|---|---|
ui/calibration_panel.py: _confirm/_sync |
“到达目标”按钮与参考力输入框按隐藏的 campaign.phase 在单点与多点之间切换 |
ui/multipoint_panel.py: _levels/_hold |
多点读取右栏载荷档位,又自带 Min/Max force,存在两套载荷设置 |
ui/calibration_panel.py 子页 |
UV 图与实时图互斥;输入源配置藏在实时图子页;开始试验会自动切页 |
ui/multipoint_panel.py: bind_finger |
求解器借用 Finger debug 的 stack;该页另有测点表、导出和执行,测点有两份 |
| 两个面板共 10 条状态文字 | 报错落点取决于代码路径,禁用按钮没有原因 |
trial.py:157、multipoint.py:1476 |
RecordConfig 默认 mp4v,实测约 27 Mbit/s;同画面 H.264 样例约 5 Mbit/s |
capture_guard.capture_verdict、summary.py:264 |
无视频必判 video_missing,多点汇总还要求帧在视频内,因此无法安全提供“不录视频” |
summary_export.publish_summary |
汇总藏在 derived/summary_<UTC>_<id>/;用户手工拼出 dd02-gl,已出现 site_id 重名 |
需先确认的决定
| 编号 | 决定 | 建议默认 | 阻塞阶段 |
|---|---|---|---|
| D1 | 新采集的单点是否改为“一个点的多点会话”(sites/ 格式) |
是;旧 trials/ 会话继续可读,ManualTrial 暂留不删 |
P3 |
| D2 | 默认视频编码及等效门槛 | 保持 mp4v 直到 P2b 证明 H.264 重放差异可接受;门槛由用户给出 |
P2 默认值 |
| D3 | Test sequence 页与测点队列的关系 | 本计划不改该页 | 无 |
| D4 | 只录保持窗口前后 | 不做:违背“每 trial 连续录像”契约 | 无 |
未确认的决定由主代理暂停相应阶段,不得自行选择。
阶段
每阶段的入口条件不满足就不开始;出口条件全部有证据才算完成。
P0 基线(主代理)
- 入口:本计划及 D1、D2 已确认。
- 内容:记录 app 与工作区根的分支、HEAD、index、工作树;建立
.scratch/autocal-capture-workflow/和.active;跑基线全量测试与panel_check.py,记录已知失败(finger 页QDoubleSpinBox高度 2 项)。 - 出口:基线命令与结果写入 scratch;之后任何失败须与基线对比后才能归因。
P1 打开文件夹与平铺汇总
- 入口:P0。
- 内容:
- 将
ui/window.py: _reveal提取为ui/reveal.py: reveal(path, select=None),Windows 用explorer /select,<文件>;菜单与采集页共用。 - 采集页会话行加“打开会话文件夹”“打开汇总”“复制路径”;无目录时禁用并写明原因。
publish_summary在原子替换summary-latest.json之后,把同一份四件文件写到会话根summary/:先写临时目录再替换。副本失败只报告,不回滚指针、不改采集结果。
- 将
- 出口:
summary/文件哈希与指针所指版本一致;副本失败时旧summary/和指针保持不变;reveal参数由测试模拟subprocess断言;两份格式文档更新目录说明。
P2 录像选项
- 入口:P0;D2 已确认。
- 内容:
- 新增
recording_options.py:video: bool、codec、lossless_frames: bool;默认值进preferences.py和config/preferences.default.json。 - 用一个工厂
make_record_config(options, fps)替换trial.py与multipoint.py两处RecordConfig(...);不改 shared 默认值(Studio 也在用)。 - 选项写入根
session.json的recording块,会话建立后锁定。 capture_verdict增加video_expected;为 False 时跳过视频相关判定。summary.py和session_review.py从recording块读取;缺该块的旧会话按video_expected=True处理。- 启动时用 cv2 向 scratch 写 3 帧探测编码器;不可用的编码在界面上禁用并说明,绝不静默回退。
- 界面显示按码率与计划时长估算的体积和磁盘剩余空间(
shutil.disk_usage),不足两倍估算时警告。
- 新增
- 出口:关视频时 trial 为 complete、汇总行 eligible、复核显示“按设置未录视频”;旧会话结果不变;编码不可用在开始前拒绝。
P2b 编码等效验证(只出报告,不改代码)
- 入口:P0。
- 内容:同一视频文件作为输入,分别用
mp4v与 H.264 录制,各自经 SDK 重放,按frame_id比较FN_raw/FX_raw/FY_raw的逐帧差和各保持窗口均值差。脚本与结果只放 scratch。 - 出口:报告给出差值相对 1 N 档阶跃响应的比例,交用户按 D2 决定是否切换默认编码。
P3 采集状态控制器
- 入口:P0;D1 已确认。
- 内容:新增
capture_controller.py,不导入 Qt 或运动服务,内部包一个Campaign。- 队列即
campaign.sites;单点就是只有一行的队列。 readiness()返回检查项:标定包、输入出帧、总线已初始化且轴映射无问题、输出目录可写、SN、最大力。primary_action()返回(key, label_key, enabled, blocked_reason);perform(key, **inputs)执行;secondary_actions()返回重测、跳过、停止;poll()推进保持与收尾。- 对准只发出请求,仍走
window._on_align_multipoint → plan_pose_move。 - 求解器由构造参数注入
PlatformStack,不再取 Finger 面板。
- 队列即
- 出口:表驱动测试覆盖完整加载阶梯、确认离开、换点、重测、复采、任意状态停止;每个禁用的主动作都有非空原因;录制中拒绝对准;直接驱动
Campaign与经由控制器写出的session.json、reference.csv结构一致;test_binding_purity.py通过。
P4 新采集页界面
- 入口:P1、P3 完成(P2 可并行合入)。
- 内容:按设计稿重排
CalibrationPanel:- 会话行和 Ready 标签行;输入源与标定包放入“更改输入/标定包…”对话框。
- 左侧 UV 图与实时图并排,下方是基于控制器模型的队列表。
- 右侧当前点卡片(步骤标签、提示、参考力或六维力输入、主按钮、次要按钮)和力曲线;底部一行消息。
- 控件只渲染控制器给出的内容,不读
campaign内部字段;中英文 locale 同步。
- 出口:
panel_check.py在 1440×900、1920×1080 下无新增失败;在模拟模式下用界面测试走完两个点;用 grep 证明ui/中没有campaign.phase判断;离屏截图存 scratch 供人工查看。
P5 合并 Finger debug
- 入口:P4。
- 内容:Finger debug 改名为“几何与安装”,保留安装偏置、工具 XY、行程限制、3D 预览和单点试选;删除其测点表,“导出测点操作表”迁到队列的导入/导出;
stackChanged触发控制器重新求解,不可达行标出;删除未使用的multipoint.import_points文案或实现它。 - 出口:修改安装偏置后队列位姿更新、不可达行禁止对准;导出的操作表字段与数据格式一致;
test_finger_panel.py更新后通过。
P6 收尾与可选的跨会话导出
- 入口:P5。
- 内容:更新数据格式、多点格式、汇总契约和 README 的操作流程。可选:Records 页“导出批次…”,把多个会话合并成一个 dd02-gl 式文件夹,每行带
session_id、trial_id,不按 site_id 合并。 - 出口:文档门禁通过;如做批次导出,用两会话同名 site_id 夹具证明不混行。
统一验证
所有命令在 D:\orisys_ws\orisys-app 下执行,$pythonExe 指 .venv-build\Scripts\python.exe,basetemp 每次新建。
| 编号 | 检查 | 何时 | 通过条件 |
|---|---|---|---|
| V1 | 各阶段新增测试 | 每个任务交付 | 先在旧行为上失败、修复后通过(可行时) |
| V2 | pytest apps/autocal/tests |
每阶段出口 | 0 失败;跳过项须解释 |
| V3 | tools/lint_gate.py |
每阶段出口 | status: clean 或仅既有抑制 |
| V4 | apps/autocal/tools/panel_check.py |
P1、P4、P5 | 与 P0 基线相比无新增失败 |
| V5 | test_binding_purity.py、test_locales_autocal.py |
P3、P4 | 通过 |
| V6 | shared 测试 | 仅当改到 shared/ |
记录器、生命周期、回放测试通过 |
| V7 | D:\orisys_ws\scripts\doc_lint.py |
改文档时 | 无新错误 |
| V8 | 离屏截图人工检查 | P4、P5 | 用户或验收代理确认 |
| V9 | P2b 编码报告 | 切换默认编码前 | 用户按 D2 接受 |
| V10 | 实机验收 | 全部完成后 | 需指定设备、运动与载荷范围、停机条件;代理不执行 |
V1–V9 是软件证据,不代表实机可用;V10 未执行前状态只能写“仅软件验证”。
实施结果(2026-10-18)
证据都在 D:\orisys_ws\orisys-app\.scratch\autocal-capture-workflow\:
| 阶段 | 结果 | 证据 |
|---|---|---|
| P0 | 基线 572 项测试通过;panel_check 2/260 既有失败 |
baseline.md |
| P1、P2 | 打开文件夹、会话根 summary/ 副本、录像选项与 recording 块 |
a/handoff-patches.zh.md、a/logs/ |
| P2b | 逐帧口径三轴均超 5% 门槛;保持窗口口径 FN、FX 基本在门槛内、FY 不在;本机 cv2 写不了 H.264 |
d/p2b-codec-equivalence.zh.md |
| P3 | 控制器:队列、六项 Ready、单一主动作带原因、重测/跳过/停止 | b/notes.md |
| P4 | 新采集页只经控制器渲染,ui/ 中 campaign.phase 零命中 |
c/verification.md、c/screens/ |
| P5 | 「几何与安装」页去掉测点表,操作表迁到队列;panel_check 由 2/260 失败变为 260 全过 |
c/verification-p5.md |
| P6 | 三份格式/契约文档、workflow.md、README |
本目录各文档 |
| 验收 | 无阻断;2 项重要 + 1 项次要,修复后复核全部 PASS | v/acceptance-report.zh.md |
当前 pytest apps/autocal/tests 668 项全过,panel_check.py 260 项全过,被改文档的 doc_lint 为 clean。
各检查的实际口径:V2、V4、V5、V7 通过;V3 只在本任务范围内 clean,全仓门禁另有并行外部会话引入的 findings;
V6 不适用(未改 shared/);V8 截图已备、待人工确认;V9 报告已交,是否切换默认编码待用户按 D2 决定。
验收后修正(2026-10-18,审查 F1、F3、F5)
- 会话结束(完成或停止)后,主按钮“结束会话”把页面带回空闲:队列可编辑、可开始新会话,已记录的文件不变。
- 保持时间到点由控制器
poll()自动结束,参考窗口为计划时长(t_end - t_start = 保持秒数),与点击或计时器迟到多久无关。 - 勾选“模拟”后不需要平台、总线、相机、标定包,也不需要先对准;没有标定包时,U、V 直接作为点的 X、Y,位姿标为
simulated。有平台时仍须先对准。 - 仅软件验证:控制器与 Campaign 的新增测试已运行;界面测试(含新增的离线模拟用例)在本机因缺 libEGL 未能运行,须在 Windows 上补跑。