|
|
@@ -0,0 +1,157 @@
|
|
|
+# AutoFocus 扫描范围扩大与电机限位 — 设计文档
|
|
|
+
|
|
|
+日期:2026-06-16
|
|
|
+涉及文件:`Calib/CalibrationEngine.cs`(主要)、`Serial/HouseMotor.cs`(参考,不改)
|
|
|
+
|
|
|
+## 1. 背景与问题
|
|
|
+
|
|
|
+AutoFocusTool 自动标定单 well 时,偶发"找不到圆孔"。经排查确认现象为:
|
|
|
+**水平扫描的 7 个位置从头到尾都检不出圆,且标定窗口实时画面里始终看不到完整圆孔**——
|
|
|
+即 well 没有充分转进相机画面。
|
|
|
+
|
|
|
+根因:当前水平找圆以 well 的 EEPROM 位置为中心做 `±4000` 脉冲、7 步扫描
|
|
|
+(`CalibrationEngine.cs:30-31`)。当某 well 的 EEPROM 水平位置偏差大于该窗口时,
|
|
|
+well 圆始终落在画面外,整段扫描都检不出。
|
|
|
+
|
|
|
+同理 Z 对焦:粗对焦以 EEPROM Z 零点为中心 `±1500`(`ZHalf=1500`)扫描,
|
|
|
+若真实焦面离零点超过 1500 脉冲也会扫不到峰。
|
|
|
+
|
|
|
+## 2. 目标
|
|
|
+
|
|
|
+1. 水平找圆改为**全行程粗扫定位 + 局部密扫**,不再依赖 EEPROM 位置准确。
|
|
|
+2. Z 粗对焦改为**大范围固定窗口扫描**,覆盖实测焦面分布区间。
|
|
|
+3. 所有电机移动加**行程限位钳位**,水平 [0,70000]、垂直 [0,125000]。
|
|
|
+4. 关键扫描参数做成可配置字段,便于现场调整。
|
|
|
+
|
|
|
+## 3. 关键决策(已与用户确认)
|
|
|
+
|
|
|
+| 项 | 决策值 |
|
|
|
+|---|---|
|
|
|
+| 水平方案 | 全行程粗扫定位 + 局部密扫 |
|
|
|
+| 水平行程上限 | 可配置,默认 70000(来源:旧工程自检 `HouseBin.cs:468`) |
|
|
|
+| 水平粗扫步距 | 默认 2000,**命中完整圆即停**,不必扫完全程 |
|
|
|
+| Z 粗对焦中心 | 固定 90000(所有 well 统一;用户实测焦面均落在 60000~120000) |
|
|
|
+| Z 粗对焦区间 | 60000~120000(中心 90000,±30000) |
|
|
|
+| Z 粗对焦步距 | 2000 → 约 31 层 |
|
|
|
+| Z 精对焦半幅 | 6000(围绕粗峰 ±6000) |
|
|
|
+| Z 精对焦步距 | 500 → 约 24 层(B 方案:精度优先) |
|
|
|
+| 限位 | 水平 [0,HMax]、垂直 [0,ZMax],所有移动前钳位 |
|
|
|
+
|
|
|
+## 4. 详细设计
|
|
|
+
|
|
|
+### 4.1 新增/修改参数(`CalibrationEngine` 字段)
|
|
|
+
|
|
|
+```csharp
|
|
|
+// ── 行程限位(所有电机移动前钳到该区间)──
|
|
|
+public int HMin = 0, HMax = 70000; // 水平行程上下限
|
|
|
+public int ZMin = 0, ZMaxPulse = 125000; // 垂直行程上下限(旧工程软上限)
|
|
|
+
|
|
|
+// ── 水平全行程粗扫定位 ──
|
|
|
+public int HCoarseStart = 0; // 粗扫起点
|
|
|
+public int HCoarseEnd = 70000; // 粗扫终点(= HMax)
|
|
|
+public int HCoarseStep = 2000; // 粗扫步距(够小不跨过 well)
|
|
|
+// 命中完整圆即停:扫到 Found && Complete 立即转入局部密扫
|
|
|
+
|
|
|
+// ── Z 全范围粗对焦(固定中心窗口)──
|
|
|
+public int ZCoarseCenter = 90000; // 粗对焦中心(固定,所有 well 统一)
|
|
|
+public int ZCoarseHalf = 30000; // 粗对焦半幅 → 区间 60000~120000
|
|
|
+public int ZCoarseStep = 2000; // 粗对焦步距 → 约 31 层
|
|
|
+
|
|
|
+// ── Z 精对焦(围绕粗峰)──
|
|
|
+// 复用现有精对焦逻辑,半幅与步距改为:
|
|
|
+public int FineZHalf = 6000; // 精对焦半幅(原 fineZHalf=500)
|
|
|
+public int FineZStep = 500; // 精对焦步距 → 约 24 层
|
|
|
+```
|
|
|
+
|
|
|
+保留现有 `HScanRange`/`HScanSteps`/`FineScanSteps` 用于**水平局部密扫**阶段
|
|
|
+(命中后在最佳点附近精调 Y 居中),无需删除。
|
|
|
+
|
|
|
+### 4.2 限位钳位(统一入口)
|
|
|
+
|
|
|
+新增两个私有方法,所有 `_motor.HorizontalMoveTo` / `_motor.VerticalMoveTo`
|
|
|
+调用前先过钳位,避免越界指令发给下位机:
|
|
|
+
|
|
|
+```csharp
|
|
|
+int ClampH(int p) => Math.Max(HMin, Math.Min(HMax, p));
|
|
|
+int ClampZ(int p) => Math.Max(ZMin, Math.Min(ZMaxPulse, p));
|
|
|
+```
|
|
|
+
|
|
|
+钳位发生时写一条 Log(便于发现 EEPROM 异常值或参数配置过界)。
|
|
|
+
|
|
|
+### 4.3 水平找圆:全行程粗扫定位 + 局部密扫
|
|
|
+
|
|
|
+新增方法 `HCoarseLocate`,替换 `CalibrateWell` 中"②旋转居中"
|
|
|
+对 `ScanForCenter(eepromHPos, HScanRange, ...)` 的首次调用:
|
|
|
+
|
|
|
+1. **全行程粗扫**:从 `HCoarseStart` 到 `HCoarseEnd`,步距 `HCoarseStep`,
|
|
|
+ 每个位置 `Grab` + `WellDetector.Detect`。
|
|
|
+2. **命中即停**:一旦检出 `Found && Complete`,记录该粗扫位置 `hpHit`,立即停止粗扫。
|
|
|
+3. **局部密扫**:以 `hpHit` 为中心,调用现有 `ScanForCenter(well, hpHit, fineRange, FineScanSteps)`
|
|
|
+ 做 Y 居中精调(`fineRange` 取 `HCoarseStep` 量级,约 ±2000)。
|
|
|
+4. **全程未命中**:若粗扫扫完全程仍无 `Found && Complete`,
|
|
|
+ 退化为"取扫描中 |Y偏移| 最小且 Found 的位置";仍无则记 `Note="水平全程未检出圆"`,
|
|
|
+ 该 well 标定失败(沿用现有失败返回风格)。
|
|
|
+
|
|
|
+粗扫阶段沿用 `CenterScanExposure` 固定中低曝光(well 是暗背景中灰盘)。
|
|
|
+
|
|
|
+### 4.4 Z 粗对焦:固定大窗口扫描
|
|
|
+
|
|
|
+修改 `CoarseFocus`:扫描中心由"传入的 EEPROM 零点"改为固定 `ZCoarseCenter=90000`,
|
|
|
+半幅 `ZCoarseHalf=30000`,步距 `ZCoarseStep=2000`:
|
|
|
+
|
|
|
+```
|
|
|
+for z in [ZCoarseCenter-ZCoarseHalf .. ZCoarseCenter+ZCoarseHalf] step ZCoarseStep:
|
|
|
+ move ClampZ(z); discard frame; grab; score = Sharpness(中央40% ROI)
|
|
|
+取最高分 z 作为 coarseZ
|
|
|
+```
|
|
|
+
|
|
|
+约 31 层。`CalibrateWell` 中调用处随之调整(不再传 `eepromZ` 作中心)。
|
|
|
+
|
|
|
+### 4.5 Z 精对焦:扩大半幅
|
|
|
+
|
|
|
+现有精对焦围绕 `coarseZ ± fineZHalf` 密扫。将半幅改用 `FineZHalf=6000`、
|
|
|
+步距 `FineZStep=500`(约 24 层)。半幅 6000 足以覆盖粗扫 ±2000 的峰值定位误差并留余量。
|
|
|
+保留现有 3 点平滑 + 抛物线插值峰顶逻辑不变。
|
|
|
+
|
|
|
+## 5. 数据流(单 well 标定)
|
|
|
+
|
|
|
+```
|
|
|
+读 EEPROM(水平位置仅作参考/不再作扫描中心) → 开灯
|
|
|
+ ① Z 粗对焦:固定 90000±30000 步距2000 (31层) → coarseZ
|
|
|
+ ② 水平全行程粗扫 0~70000 步距2000 命中完整圆即停 → hpHit
|
|
|
+ → 局部密扫 ScanForCenter(hpHit, ±~2000) → 最居中水平位置
|
|
|
+ ③ 曝光二分(well 内 ROI,逻辑不变)
|
|
|
+ ④ Z 精对焦:coarseZ±6000 步距500 (24层) + 平滑插值 → focusZ
|
|
|
+ 存图 + 写 calibration.json
|
|
|
+```
|
|
|
+
|
|
|
+注:相比原流程,①②顺序保持"先对焦后居中"
|
|
|
+(对焦与居中耦合,焦准画面才检得出圆),但①改为固定大窗口、②改为全行程粗扫。
|
|
|
+
|
|
|
+## 6. 性能影响(需用户知晓)
|
|
|
+
|
|
|
+- Z 粗对焦:约 31 层 × (移动+`ScanDelayMs`350ms+抓帧) ≈ 单 well 15~20 秒。
|
|
|
+- Z 精对焦:约 24 层 ≈ 单 well 10~15 秒。
|
|
|
+- 水平全行程粗扫:最坏 35 步(命中即停通常更少)。
|
|
|
+- 16 个 well 全标定预计较原方案明显变慢(分钟级增加)。精度优先,已确认接受。
|
|
|
+
|
|
|
+## 7. 错误处理
|
|
|
+
|
|
|
+- 所有移动经 `ClampH`/`ClampZ` 钳位,越界写 Log 但不崩溃。
|
|
|
+- 水平全程未检出圆 → 退化策略(4.3 第 4 点),最终失败则记 Note 并跳过该 well。
|
|
|
+- 抓帧失败沿用现有 `Grab()` 重试 3 次机制。
|
|
|
+- Z 精对焦峰过弱(`PeakRatio<1.2`)沿用现有"弱峰/可能空well"告警。
|
|
|
+
|
|
|
+## 8. 测试
|
|
|
+
|
|
|
+- 现有 `SelfTest`/`SmokeTest` 子工程验证编译与基本调用不被破坏。
|
|
|
+- 真机验证:对一批已知 EEPROM 偏差较大的 well 运行标定,确认
|
|
|
+ (a) 水平全行程能找到圆;(b) Z 粗对焦命中 60000~120000 内焦面;
|
|
|
+ (c) 越界脉冲被钳位并有 Log。
|
|
|
+- 无真机时:纯参数/钳位逻辑可加轻量单元验证(`ClampH`/`ClampZ` 边界)。
|
|
|
+
|
|
|
+## 9. 不在本次范围
|
|
|
+
|
|
|
+- 不改协议层 `Protocol.cs`、不改 `HouseMotor` 的移动接口(限位放在 CalibrationEngine)。
|
|
|
+- 不改相机分辨率/崩溃问题(`GetSourceBuffer` 段错误)——另行处理。
|
|
|
+- 不做 UI 参数配置界面(参数先以字段默认值形式存在,后续可接入设置页)。
|