Files
XplorePlane/XP.Hardware.MotionControl/Documents/CoordinateCompensation.md
T

11 KiB
Raw Blame History

载物台坐标系补偿功能 | Stage Coordinate Compensation

文档版本:v1.0 创建日期:2026-07-28 适用模块:XP.Hardware.MotionControl


1. 功能概述 | Overview

在平面 CT 检测中,工件在载物台上的实际摆放位置常与程序假定的"名义位置"存在偏差。主框架通过图像坐标匹配可计算出工件当前的像素偏移 (dX, dY)(可为负)。

坐标系补偿功能负责:

  1. 将主框架传入的像素偏移换算为载物台的物理位移(mm,记录为补偿值
  2. 执行修正移动,使工件对齐到位;
  3. 后续任意"移动到名义位置"的指令,可选择自动叠加该补偿值,使工件在整个检测流程中持续对齐。

补偿值在软件启动时初始化为 (0, 0)


2. 坐标模型 | Coordinate Model

2.1 补偿值的本质

补偿值是载物台 StageX / StageY 坐标系上的一个物理偏移向量(mm,表示"工件实际位置"与"程序名义位置"之间的差。

作用链条:

名义 home 位置 → 工件特征在图像里偏了 (dX, dY) 像素
      ↓ 按当前放大比换算
需要载物台移动 (stageDx, stageDy) mm 才能把特征移正
      ↓ 记录
补偿值 comp = (stageDx, stageDy)
      ↓ 后续
"移动到名义位置 P" → 实际目标 = P + comp,工件特征始终对齐

2.2 为什么存 mm 而非像素

像素偏移与放大比绑定,一旦放大比变化就失效;而物理 mm 偏移代表工件的真实错位,与放大比无关,在后续任何放大比下都成立。因此补偿值以 mm(Stage 坐标系)存储。

2.3 作用范围

补偿仅作用于 StageX / StageYSourceZ / DetectorZ / 旋转轴 不参与补偿。


3. 像素 → mm 换算 | Pixel-to-mm Conversion

补偿的换算逻辑与 MoveStageByPixelOffset 一致,内部统一由私有方法 TryConvertPixelToStageMm 实现:

mmPerPixelX = DetectorPixelSizeX / M
mmPerPixelY = DetectorPixelSizeY / M
dxMm = dxPixels × mmPerPixelX × PixelDirectionX
dyMm = dyPixels × mmPerPixelY × PixelDirectionY
参数 来源 说明
DetectorPixelSizeX/Y App.configMotionControl:Geometry:* 探测器单像素物理尺寸(mm),由探测器规格书获取
PixelDirectionX/Y App.config 对齐图像像素方向与载物台运动方向(+1 或 -1)
M GetCurrentGeometry() 实时计算 当前放大倍率(FDD / FOD

换算失败的情形(返回失败结果):

  • 探测器像素尺寸未配置(DetectorPixelSizeX/Y <= 0
  • 当前放大倍率无效(M 为 NaN 或 <= 0

补偿功能复用现有几何配置,不引入新的 App.config 参数。


4. 记录模式 | Compensation Mode

补偿的记录方式由 CompensationMode 枚举控制:

模式 语义 适用场景
Replace(默认) comp = 本次换算值 每次都从同一名义参考位置测量、每位置只记录一次的一次性对位
Accumulate comp += 本次换算值 在同一位置迭代修正残差的闭环逼近

4.1 如何选择

判断标准是主框架每次传入的 dX, dY 代表什么

  • 传入的是"这次还差多少"(残差/增量)→ 用 Accumulate
  • 传入的是"离名义原点一共差多少"(绝对总量)→ 用 Replace

4.2 覆盖模式的重要前提

ApplyPixelOffsetCompensation 的移动为相对移动。覆盖模式假设"每次测量都从同一名义参考位置开始、每位置只调用一次"。

若在同一位置连续多次修正而不回到参考位置,覆盖模式只保证补偿值不累积,但相对移动会重复叠加,导致物理位置与补偿值不一致。此时应改用 Accumulate

4.3 累加 vs 覆盖示例

前提:1 像素 = 0.01mm(当前放大比下)。

场景 A:闭环迭代残差(用 Accumulate) —— 每轮都在当前位置重新测残差:

轮次 测得残差 换算 mm 相对移动 Accumulate comp Replace comp
第 1 轮 +200px +2.0mm +2.0 2.0 ✓ 2.0
第 2 轮 +30px +0.3mm +0.3 2.3 ✓ 0.3 ✗
第 3 轮 +2px +0.02mm +0.02 2.32 ✓ 0.02 ✗

台子实际总共走了 2.32mm,只有累加能记成真实总偏移。

场景 B:绝对总量(用 Replace) —— 每次都相对固定名义原点给出总偏移:

时刻 测得总偏移 换算 mm Accumulate comp Replace comp
第 1 次 +200px +2.0mm 2.0 2.0 ✓
第 2 次重测 +205px +2.05mm 4.05 ✗ 2.05 ✓

第 2 次的 205px 已包含第一次的 200px,累加会重复计入。


5. 接口说明 | API Reference

全部定义在 IMotionControlService(单例)。

方法 说明
ApplyPixelOffsetCompensation(dxPixels, dyPixels, mode = Replace) 换算像素→mm,按模式记录补偿,并以相对移动方式驱动 StageX/StageY 修正到位(记录 + 移动,一步完成)
RecordPixelOffsetCompensation(dxPixels, dyPixels, mode = Replace) 仅换算并记录补偿,不移动(预览/仅计算)
GetStageCompensation() 返回当前补偿值 (Xmm, Ymm)
SetStageCompensation(xMm, yMm) 直接以物理量(mm)设置补偿值
ResetStageCompensation() 补偿值清零
MoveToTarget(axisId, target, speed = null, applyCompensation = false) 单轴定点移动;applyCompensation = true 时仅对 StageX/StageY 叠加补偿
MoveAllToTarget(targets, applyCompensation = false) 多轴联动移动;applyCompensation = true 时仅对字典中的 StageX/StageY 目标叠加补偿

5.1 补偿值生命周期

  • 补偿值随软件运行保持,存储在 MotionControlService 单例中。
  • HomeAll() / HomeAllAsync() 回零不会清零补偿,补偿的清零仅通过 ResetStageCompensation()
  • 换工件、重新装夹时应由主框架显式调用 ResetStageCompensation()(覆盖模式下也可依赖新值直接冲掉旧值,但显式清零语义更明确)。

5.2 边界校验

MoveToTarget / MoveAllToTarget 叠加补偿后,仍执行原有的 Min/Max 边界校验。若补偿把目标推出行程范围,命令会被拒绝。

5.3 线程安全

补偿值以 _compXmm / _compYmm 字段存储,读写通过 _compLock 加锁保护,以应对轮询线程与 UI/命令线程的并发访问。

5.4 事件通知

补偿值被记录、设置或清零时,发布 StageCompensationChangedEvent

public record StageCompensationData(double Xmm, double Ymm);
public class StageCompensationChangedEvent : PubSubEvent<StageCompensationData> { }

UI 可订阅该事件实时显示当前补偿量。


6. 典型调用流程 | Typical Usage

6.1 主框架:坐标匹配后记录并修正

public class CoordinateMatcher
{
    private readonly IMotionControlService _mc;

    public CoordinateMatcher(IMotionControlService mc) => _mc = mc;

    // 坐标匹配得到像素偏移后,一步完成"记录补偿 + 修正移动"(默认覆盖)
    public void OnMatchCompleted(double dxPixels, double dyPixels)
    {
        var result = _mc.ApplyPixelOffsetCompensation(dxPixels, dyPixels);
        if (!result.Success)
            _log.Warn($"补偿失败:{result.ErrorMessage}");
    }

    // 同一位置迭代修正残差时,使用累加模式
    public void OnResidualMatch(double dxPixels, double dyPixels)
    {
        _mc.ApplyPixelOffsetCompensation(dxPixels, dyPixels, CompensationMode.Accumulate);
    }
}

6.2 其他类库:定点移动叠加补偿

// 单轴:仅 StageX/StageY 生效
_mc.MoveToTarget(AxisId.StageX, 100.0, applyCompensation: true);
_mc.MoveToTarget(AxisId.StageY, 50.0,  applyCompensation: true);

// 多轴联动一次性带补偿
_mc.MoveAllToTarget(new Dictionary<AxisId, double>
{
    { AxisId.StageX, 100.0 },
    { AxisId.StageY, 50.0 }
}, applyCompensation: true);

6.3 查询、设置与清零

// 查询当前补偿值
var (compX, compY) = _mc.GetStageCompensation();

// 直接设置(如从历史记录恢复)
_mc.SetStageCompensation(1.25, -0.80);

// 换工件时清零
_mc.ResetStageCompensation();

6.4 订阅补偿变化事件

eventAggregator.GetEvent<StageCompensationChangedEvent>()
    .Subscribe(data =>
    {
        // 更新 UI 显示
        CompensationText = $"补偿: X={data.Xmm:F4}mm, Y={data.Ymm:F4}mm";
    }, ThreadOption.UIThread);

7. 点击居中 vs 坐标系补偿 | Click-to-Center vs Compensation

两者基于相同的像素→mm 换算,但用途不同:

用途 接口 是否记录补偿 说明
点击居中 MoveStageByPixelOffset(dx, dy) 用户点击图像某点,一次性把该点移到中心,不影响后续运动
坐标系补偿 ApplyPixelOffsetCompensation(dx, dy) 坐标匹配后记录补偿并修正到位,后续定点运动可叠加补偿

MoveStageByPixelOffset 保持原有行为不变,继续服务点击居中场景。


8. 边界与注意事项 | Edge Cases & Notes

情况 处理方式
探测器像素尺寸未配置 换算失败,返回 MotionResult.Fail,不记录、不移动
当前放大倍率无效(NaN 或 ≤ 0 换算失败,返回 MotionResult.Fail
补偿后目标越界 移动被 Min/Max 边界校验拒绝
SetStageCompensation 传入 NaN/Infinity 返回 MotionResult.Fail,补偿值不变
回零(HomeAll 补偿值不变,需显式 ResetStageCompensation() 清零
覆盖模式同位置连续修正 物理移动会重复叠加,应改用 Accumulate

9. 相关代码位置 | Source Locations

内容 文件
补偿模式枚举 Abstractions/Enums/CompensationMode.cs
补偿变化事件 Abstractions/Events/StageCompensationChangedEvent.cs
接口定义 Services/IMotionControlService.cs"坐标系补偿"区域)
实现(含 TryConvertPixelToStageMm_compXmm/_compYmm_compLock Services/MotionControlService.cs"坐标系补偿"区域)

文档 说明
MotionControl_Design.md 运动控制模块设计文档(第 14 节补偿设计)
GUIDENCE.md 外部集成指南(第 11 节坐标系补偿)
Calibration_README.md 像素-载物台映射子模块
GeometryWithDetectorSwing.md FOD/FDD/放大倍率几何计算模型

最后更新 | Last Updated: 2026-07-28