ソースを参照

fix(calib): 修正水平定位——以EEPROM位置为中心小范围微调,废弃全行程扫描

实测16个well的EEPROM水平位置70800~205800(间距~9000),移到位即|偏移|<5%。
- 删除HCoarseLocate(从0全行程扫+命中即停→16个well坍缩到同一孔的bug根源)
- ②居中改为以eepromHPos为中心±2000(9步)微调Y,半幅远小于well间距一半
- 关键修正HMax 70000→220000(旧值会把well位置全钳死,205800>70000)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
huangjie 1 週間 前
コミット
8e6508ba2e
1 ファイル変更14 行追加66 行削除
  1. 14 66
      Calib/CalibrationEngine.cs

+ 14 - 66
Calib/CalibrationEngine.cs

@@ -43,16 +43,18 @@ namespace AutoFocusTool.Calib
         public int CenterScanExposure = 60;
 
         // ── 行程限位(所有电机移动前钳到该区间)──
-        /// <summary>水平电机行程下/上限脉冲(旧工程自检值 70000)。</summary>
-        public int HMin = 0, HMax = 70000;
+        /// <summary>水平电机行程下/上限脉冲(实测16个well EEPROM位置达205800,留余量到220000)。</summary>
+        public int HMin = 0, HMax = 220000;
         /// <summary>垂直电机行程下/上限脉冲(旧工程软上限 125000)。</summary>
         public int ZMin = 0, ZMaxPulse = 125000;
 
-        // ── 水平全行程粗扫定位 ──
-        /// <summary>水平全行程粗扫起点/终点/步距。命中完整圆即停。</summary>
-        public int HCoarseStart = 0;
-        public int HCoarseEnd = 70000;
-        public int HCoarseStep = 2000;
+        // ── 水平居中微调(以各well的EEPROM位置为中心做小范围Y居中)──
+        // 实测well间距~9000、EEPROM位置已准(移到位即|偏移|<5%),故半幅须远小于间距一半(4500),
+        // 只在小范围微调Y居中,绝不大范围扫描(否则会扫到相邻well)。
+        /// <summary>水平微调半幅(脉冲,EEPROM位置±range)。</summary>
+        public int HFineRange = 2000;
+        /// <summary>水平微调步数(±2000内9步→步距500)。</summary>
+        public int HFineSteps = 9;
 
         // ── Z 全范围粗对焦(固定中心大窗口)──
         /// <summary>Z 粗对焦固定中心(实测焦面集中区间 60000~120000 的中点)。</summary>
@@ -169,57 +171,6 @@ namespace AutoFocusTool.Calib
             return (bestHPos, best);
         }
 
-        /// <summary>
-        /// 水平全行程粗扫定位 + 局部密扫居中。不依赖 EEPROM 水平位置准确:
-        /// ① 从 HCoarseStart 到 HCoarseEnd 按 HCoarseStep 扫,命中完整圆即停,记录该位置;
-        /// ② 以命中点为中心做局部密扫(ScanForCenter)优化 Y 居中;
-        /// ③ 全程未命中完整圆则取扫描中 |Y偏移| 最小且检出的位置;仍无返回 (-1,null)。
-        /// </summary>
-        (int bestHPos, WellCircle bestCircle) HCoarseLocate(int well)
-        {
-            _cam.SetExposure(CenterScanExposure);
-
-            int hitHPos = -1; WellCircle hitCircle = null;
-            int fallbackHPos = -1; WellCircle fallbackCircle = null;
-            double fallbackScore = double.MaxValue;
-
-            // ① 全行程粗扫,命中完整圆即停
-            for (int hp = HCoarseStart; hp <= HCoarseEnd; hp += HCoarseStep)
-            {
-                int p = ClampH(hp);
-                _motor.HorizontalMoveTo(p, ScanDelayMs);
-                var b = Grab();
-                var c = WellDetector.Detect(b, W, H);
-                DebugSave?.Invoke(b, $"hcoarse_w{well}_hp{p}");
-                Log?.Invoke(c.Found
-                    ? $"  粗扫水平{p}: Y偏移={c.OffsetYPct:F1}% 完整={c.Complete}"
-                    : $"  粗扫水平{p}: 未检出圆");
-                OnStep?.Invoke($"水平粗扫 hp={p}", c, null);
-                if (c.Found)
-                {
-                    double score = Math.Abs(c.OffsetYPct) + (c.Complete ? 0 : 100);
-                    if (score < fallbackScore) { fallbackScore = score; fallbackHPos = p; fallbackCircle = c; }
-                    if (c.Complete) { hitHPos = p; hitCircle = c; break; }
-                }
-            }
-
-            // 命中完整圆 → 局部密扫;否则用检出最优的降级点
-            int center = hitHPos >= 0 ? hitHPos : fallbackHPos;
-            if (center < 0)
-            {
-                Log?.Invoke($"[well{well}] ✗ 水平全行程未检出任何圆");
-                return (-1, null);
-            }
-
-            // ② 以命中/降级点为中心局部密扫居中(范围取粗扫步距量级)
-            int fineRange = HCoarseStep;
-            var fine = ScanForCenter(well, center, fineRange, FineScanSteps, 800);
-            if (fine.bestCircle != null) return (fine.bestHPos, fine.bestCircle);
-
-            // ③ 局部密扫没检出 → 回退到粗扫命中/降级结果
-            return (center, hitCircle ?? fallbackCircle);
-        }
-
         /// <summary>
         /// 标定单个 well。eepromHPos=该well的EEPROM水平位置(扫描中心),eepromZ=Z焦准零点。
         /// 返回标定结果。
@@ -245,14 +196,11 @@ namespace AutoFocusTool.Calib
 
             // ── ② 旋转居中(此时画面清晰,圆可稳定检出;只优化Y偏移)──
             // 转动培养皿让well在画面里上下(Y)移动;X的~5%固定偏移是相机/转盘硬件偏移,旋转修不了。
-            Log?.Invoke($"[well{well}] ②水平全行程定位+居中...");
-            var located = HCoarseLocate(well);
-            if (located.bestHPos < 0)
-            {
-                Log?.Invoke($"[well{well}] ✗ 水平全行程未找到圆,跳过该well");
-                return new WellCalib { Well = well, Note = "水平全程未检出圆" };
-            }
-            int bestHPos = located.bestHPos;
+            // 实测EEPROM位置已准(移到位即|偏移|<5%),故以eepromHPos为中心做小范围微调(半幅<well间距一半),
+            // 绝不大范围扫描(否则会扫到相邻well)。
+            Log?.Invoke($"[well{well}] ②以EEPROM位置({eepromHPos})为中心微调Y居中...");
+            var located = ScanForCenter(well, ClampH(eepromHPos), HFineRange, HFineSteps, 800);
+            int bestHPos = located.bestCircle != null ? located.bestHPos : eepromHPos;
             WellCircle bestCircle = located.bestCircle;
             r.HorizontalPulse = bestHPos;
             r.CircleFound = bestCircle != null;