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

27 KiB
Raw Blame History

运动控制模块集成指南 | Motion Control Module Integration Guide

1. 模块注册 | Module Registration

App.xaml.cs 中注册模块:

using XP.Hardware.MotionControl.Module;

protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
    moduleCatalog.AddModule<MotionControlModule>();
}

模块启动时自动完成:

  • 从 App.config 加载配置(轴范围、几何原点、轮询周期)
  • 注册 IMotionSystemIMotionControlServiceGeometryCalculator 为单例
  • 注册多语言资源到 Fallback Chain
  • 启动 PLC 状态轮询(100ms 周期)

2. 界面集成 | UI Integration

AxisControlView 控件使用 | AxisControlView Usage

AxisControlView 是运动控制模块的核心用户控件,提供完整的轴控制和调试功能。

XAML 引用 | XAML Reference

<UserControl x:Class="YourView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:motion="clr-namespace:XP.Hardware.MotionControl.Views;assembly=XP.Hardware.MotionControl">
    
    <Grid>
        <!-- 基本使用 | Basic usage -->
        <motion:AxisControlView />
        
        <!-- 设置最小宽度 | Set minimum width -->
        <motion:AxisControlView MinWidth="400" />
    </Grid>
</UserControl>

自动 ViewModel 绑定 | Auto ViewModel Binding

控件使用 Prism 的 ViewModelLocator.AutoWireViewModel="True" 自动绑定 AxisControlViewModel,无需手动设置 DataContext

ViewModel 属性说明 | ViewModel Properties

属性 类型 说明
StageXPosition double 载物台 X 轴位置(mm),范围由配置决定
StageYPosition double 载物台 Y 轴位置(mm),范围由配置决定
SourceZPosition double 射线源 Z 轴位置(mm),范围由配置决定
DetectorZPosition double 探测器 Z 轴位置(mm),范围由配置决定
DetectorSwingAngle double 探测器摆动角度(度),范围 -45~45
StageRotationAngle double 载物台旋转角度(度),范围 -360~360
FixtureRotationAngle double 夹具旋转角度(度),范围 -90~90
IsJoystickEnabled bool 摇杆使能开关(默认 true
SwapMouseButtons bool 摇杆左右键功能切换(默认 false
SZDZLock bool 射线源/探测器Z轴锁定移动(默认 false)
HasSavedPositions bool 是否有已保存的位置快照

交互方式 | Interaction Modes

  1. 手动输入位置

    • 直接编辑 RadNumericUpDown 控件
    • Enter 键确认并移动轴
    • Escape 键取消修改,恢复原值
    • 上下箭头键步进移动(±0.1
  2. 单轴摇杆(SourceZ/DetectorZ

    • 左键拖拽:Y轴方向控制 SourceZ Jog(正/反向由拖拽方向决定)
    • 右键拖拽:Y轴方向控制 DetectorZ Jog(正/反向由拖拽方向决定)
    • 当 SZDZLock=true 时,左键同时控制 SourceZ + DetectorZ,右键同理
    • 松开鼠标:停止 Jog
  3. 双轴摇杆(StageX/Y + Rotation/Swing

    • 默认模式(SwapMouseButtons=false):
      • 左键拖拽:X轴→StageX JogY轴→StageY Jog
      • 右键拖拽:X轴→DetectorSwing JogY轴→StageRotation/FixtureRotation Jog
    • 切换模式(SwapMouseButtons=true):左右键功能互换
    • 松开鼠标:停止所有关联轴 Jog
  4. 快捷按钮

    • 使能开关:启用/禁用虚拟摇杆控制(同步写入 PLC 信号)
    • 摇杆模式:切换左右键功能映射
    • SZDZ锁定:锁定 SourceZ/DetectorZ 同步移动(同步写入 PLC 联动使能信号)
    • 保存位置:保存当前所有轴位置到快照(需 PLC 已连接)
    • 恢复位置:恢复到上次保存的位置快照并发送移动命令

3. 获取轴状态和位置 | Reading Axis Status and Position

通过 DI 注入 IMotionSystem

using XP.Hardware.MotionControl.Abstractions;
using XP.Hardware.MotionControl.Abstractions.Enums;

public class YourService
{
    private readonly IMotionSystem _motionSystem;

    public YourService(IMotionSystem motionSystem)
    {
        _motionSystem = motionSystem;
    }

    public void ReadStatus()
    {
        // 获取直线轴 | Get linear axis
        ILinearAxis sourceZ = _motionSystem.GetLinearAxis(AxisId.SourceZ);
        double position = sourceZ.ActualPosition;       // 实际位置(mm
        AxisStatus status = sourceZ.Status;              // Idle/Moving/Homing/Error/Alarm
        bool posLimit = sourceZ.PositiveLimitHit;        // 正限位
        bool negLimit = sourceZ.NegativeLimitHit;        // 负限位

        // 获取旋转轴 | Get rotary axis
        IRotaryAxis stageRot = _motionSystem.GetRotaryAxis(RotaryAxisId.StageRotation);
        double angle = stageRot.ActualAngle;             // 实际角度(度)
        bool enabled = stageRot.Enabled;                 // 是否启用

        // 获取安全门 | Get safety door
        ISafetyDoor door = _motionSystem.SafetyDoor;
        DoorStatus doorStatus = door.Status;             // Unknown/Opening/Open/Closing/Closed/Locked/Error
        bool interlocked = door.IsInterlocked;           // 联锁信号

        // 遍历所有轴 | Iterate all axes
        foreach (var kvp in _motionSystem.LinearAxes)
        {
            AxisId id = kvp.Key;
            ILinearAxis axis = kvp.Value;
            // ...
        }
        foreach (var kvp in _motionSystem.RotaryAxes)
        {
            RotaryAxisId id = kvp.Key;
            IRotaryAxis axis = kvp.Value;
            // ...
        }
    }
}

4. 下发运动控制命令 | Sending Motion Commands

通过 DI 注入 IMotionControlService

using XP.Hardware.MotionControl.Abstractions;
using XP.Hardware.MotionControl.Abstractions.Enums;
using XP.Hardware.MotionControl.Services;

public class YourController
{
    private readonly IMotionControlService _mc;
    private readonly IMotionSystem _motionSystem;

    public YourController(IMotionControlService motionControlService, IMotionSystem motionSystem)
    {
        _mc = motionControlService;
        _motionSystem = motionSystem;
    }

    // 单轴移动 | Single axis move
    public void MoveSingleAxis()
    {
        MotionResult result = _mc.MoveToTarget(AxisId.SourceZ, 100.0);
        if (!result.Success)
            Console.WriteLine($"移动失败: {result.ErrorMessage}");

        // 带速度参数 | With speed parameter
        _mc.MoveToTarget(AxisId.SourceZ, 100.0, speed: 50.0);

        // 旋转轴 | Rotary axis
        _mc.MoveRotaryToTarget(RotaryAxisId.DetectorSwing, 15.0);
        _mc.MoveRotaryToTarget(RotaryAxisId.DetectorSwing, 15.0, speed: 30.0);
    }

    // 多轴联动 | Multi-axis coordinated move
    public void MoveMultipleAxes()
    {
        var targets = new Dictionary<AxisId, double>
        {
            { AxisId.SourceZ, 100.0 },
            { AxisId.DetectorZ, 400.0 },
            { AxisId.StageX, 0.0 },
            { AxisId.StageY, 0.0 }
        };
        // 原子性边界检查:任意轴越界则全部拒绝
        MotionResult result = _mc.MoveAllToTarget(targets);
    }

    // 停止和回零 | Stop and Home
    public void StopAndHome()
    {
        _mc.StopAll();   // 停止所有已启用轴
        _mc.HomeAll();   // 所有已启用轴机械回零(驱动轴物理运动到机械零点,建立坐标系)
    }

    // 移动到安全点 | Move to safe position
    // 将所有轴移动到用户在 App.config 中配置的安全点位置坐标,用于设备维护、换件等场景避免碰撞。
    // 注意:与 HomeAll()(机械回零)不同,MoveToSafePosition 是移动到用户配置的坐标值。
    // Note: Different from HomeAll() (mechanical homing). MoveToSafePosition moves to user-configured safe coordinates.
    public void MoveToSafe()
    {
        MotionResult result = _mc.MoveToSafePosition();  // 所有轴移动到配置的安全点
    }

    // 坐标系补偿 | Coordinate compensation
    // 主框架坐标匹配得到像素偏移 (dX, dY) 后,一步完成"记录补偿 + 修正移动"(默认覆盖模式)
    // After coordinate matching, record compensation and perform corrective move in one step (Replace by default)
    public void ApplyCompensation(double dxPixels, double dyPixels)
    {
        // 默认覆盖模式;同一位置迭代修正残差时用 CompensationMode.Accumulate
        MotionResult result = _mc.ApplyPixelOffsetCompensation(dxPixels, dyPixels);

        // 仅记录补偿、不移动(预览/仅计算)
        _mc.RecordPixelOffsetCompensation(dxPixels, dyPixels);

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

        // 换工件/维护时清零补偿(HomeAll 回零不会清补偿)
        _mc.ResetStageCompensation();
    }

    // 定点移动并叠加补偿(仅 StageX/StageY 生效,补偿后仍过边界校验)
    // Move to target with compensation (only StageX/StageY, boundary check still applies)
    public void MoveWithCompensation()
    {
        _mc.MoveToTarget(AxisId.StageX, 100.0, applyCompensation: true);

        var targets = new Dictionary<AxisId, double>
        {
            { AxisId.StageX, 100.0 },
            { AxisId.StageY, 50.0 }
        };
        _mc.MoveAllToTarget(targets, applyCompensation: true);
    }

    // Jog 点动 | Jog
    public void JogAxis()
    {
        _mc.JogStart(AxisId.SourceZ, positive: true);   // 正向 Jog
        // ... 用户松开按钮时 ...
        _mc.JogStop(AxisId.SourceZ);                     // 停止 Jog

        // 旋转轴 Jog
        _mc.JogRotaryStart(RotaryAxisId.DetectorSwing, positive: false);
        _mc.JogRotaryStop(RotaryAxisId.DetectorSwing);
    }

    // 安全门控制 | Safety door control
    public void DoorControl()
    {
        MotionResult openResult = _mc.OpenDoor();   // 含联锁检查
        _mc.CloseDoor();
        _mc.StopDoor();
    }

    // 轴复位(清除故障)| Axis reset (clear fault)
    // 注意:Reset 与 Home 是完全不同的操作,不要混淆!
    // - Home(机械回零):驱动轴物理运动到机械零点,通过零点开关确认位置,建立坐标系。轴必须处于正常状态才能 Home。
    // - Reset(轴复位):清除故障/报警状态(Alarm/Error → Idle),不产生物理运动,轴位置不变。用于轴碰限位或驱动器报错后恢复。
    // 正确顺序:轴报警时 → 先排除物理故障 → Reset(清除报警)→ Home(建立坐标系)
    // Note: Reset and Home are completely different operations!
    // - Home: drives axis physically to mechanical zero (via home switch), establishes coordinate system. Axis must be in normal state.
    // - Reset: clears alarm/fault status (Alarm/Error → Idle), no physical movement, position unchanged. Used after limit hit or drive error.
    // Correct sequence: axis alarm → resolve physical issue → Reset (clear alarm) → Home (establish coordinate system)
    public void AxisReset()
    {
        // 通过 IMotionSystem 获取轴复位实例 | Get axis reset instance via IMotionSystem
        IAxisReset axisReset = _motionSystem.AxisReset;
        MotionResult result = axisReset.Reset();     // 发送复位命令(写入 MC_Axis_Reset = 10
        bool done = axisReset.IsResetDone;           // 读取复位完成状态
    }
}

5. 几何计算 | Geometry Calculation

public class YourGeometryUser
{
    private readonly IMotionControlService _mc;
    private readonly GeometryCalculator _calc;

    public YourGeometryUser(
        IMotionControlService mc,
        GeometryCalculator calc)
    {
        _mc = mc;
        _calc = calc;
    }

    // 正算:获取当前 FOD/FDD/放大倍率 | Forward: get current geometry
    public void GetCurrentGeometry()
    {
        var (fod, fdd, magnification) = _mc.GetCurrentGeometry();
        Console.WriteLine($"FOD={fod:F2}mm, FDD={fdd:F2}mm, M={magnification:F3}");
    }

    // 反算:由目标 FOD+FDD 移动轴 | Inverse: move axes by target FOD+FDD
    public void ApplyGeometry()
    {
        MotionResult result = _mc.ApplyGeometry(targetFOD: 200.0, targetFDD: 500.0);
    }

    // 反算:由目标 FOD+放大倍率 移动轴 | Inverse: move axes by target FOD+magnification
    public void ApplyByMagnification()
    {
        MotionResult result = _mc.ApplyGeometryByMagnification(targetFOD: 200.0, magnification: 2.5);
    }

    // 直接使用 GeometryCalculator | Use GeometryCalculator directly
    public void DirectCalculation()
    {
        double fod = _calc.CalcFOD(sourceZAbsolute: 100.0, stageRotationCenterZ: 300.0);
        double fdd = _calc.CalcFDD(sourceZAbsolute: 100.0, detectorZAbsolute: 600.0);
        double mag = _calc.CalcMagnification(fdd, fod);  // FOD < 0.001 时返回 NaN

        // 反算轴目标位置
        var (szTarget, dzTarget) = _calc.CalcAxisTargets(
            targetFOD: 200.0, targetFDD: 500.0,
            stageRotationCenterZ: 300.0,
            sourceZOrigin: 0.0, detectorZOrigin: 600.0);
    }
}

6. 事件订阅 | Event Subscription

通过 Prism IEventAggregator 被动接收状态变化:

using Prism.Events;
using XP.Hardware.MotionControl.Abstractions.Enums;
using XP.Hardware.MotionControl.Abstractions.Events;

public class YourMonitor
{
    public YourMonitor(IEventAggregator eventAggregator)
    {
        // 轴状态变化 | Axis status changed
        eventAggregator.GetEvent<AxisStatusChangedEvent>()
            .Subscribe(data =>
            {
                Console.WriteLine($"轴 {data.AxisId} 状态变为 {data.Status}");
            }, ThreadOption.UIThread);

        // 门状态变化 | Door status changed
        eventAggregator.GetEvent<DoorStatusChangedEvent>()
            .Subscribe(status =>
            {
                Console.WriteLine($"门状态: {status}");
            }, ThreadOption.UIThread);

        // 门联锁状态变化 | Door interlock status changed
        eventAggregator.GetEvent<DoorInterlockChangedEvent>()
            .Subscribe(isInterlocked =>
            {
                Console.WriteLine($"联锁状态: {(isInterlocked ? "已联锁" : "未联锁")}");
            }, ThreadOption.UIThread);

        // 几何参数更新(每轮询周期触发)| Geometry updated (every polling cycle)
        eventAggregator.GetEvent<GeometryUpdatedEvent>()
            .Subscribe(data =>
            {
                Console.WriteLine($"FOD={data.FOD:F2}, FDD={data.FDD:F2}, M={data.Magnification:F3}");
            }, ThreadOption.UIThread);

        // 运动错误(轴进入 Error/Alarm| Motion error
        eventAggregator.GetEvent<MotionErrorEvent>()
            .Subscribe(data =>
            {
                Console.WriteLine($"运动错误: 轴 {data.AxisId} - {data.ErrorMessage}");
            }, ThreadOption.UIThread);

        // 实体摇杆激活状态变化 | Physical joystick active status changed
        eventAggregator.GetEvent<JoystickActiveEvent>()
            .Subscribe(isActive =>
            {
                Console.WriteLine($"实体摇杆: {(isActive ? "激活" : "未激活")}");
            }, ThreadOption.UIThread);

        // 几何反算结果填入请求(DebugWindow → MotionControlViewModel
        // Geometry apply request (DebugWindow → MotionControlViewModel)
        eventAggregator.GetEvent<GeometryApplyRequestEvent>()
            .Subscribe(data =>
            {
                Console.WriteLine($"几何反算请求: SourceZ={data.SourceZTarget}, DetectorZ={data.DetectorZTarget}");
            }, ThreadOption.UIThread);

        // 载物台坐标系补偿变化(记录/设置/清零时触发)| Stage compensation changed
        eventAggregator.GetEvent<StageCompensationChangedEvent>()
            .Subscribe(data =>
            {
                Console.WriteLine($"补偿值: X={data.Xmm:F4}mm, Y={data.Ymm:F4}mm");
            }, ThreadOption.UIThread);
    }
}

7. PLC 信号定义 | PLC Signal Definitions

信号名称硬编码在 MotionSignalNames.cs 中,信号地址定义在 PlcAddrDfn.xml(位于 XplorePlane/bin/Debug/net8.0-windows/win-x64/)。

7.1 写入信号(WriteCommonDB31

信号名 类型 地址 说明
MC_SourceZ_Target single 10 射线源Z目标位置(mm
MC_SourceZ_Speed single 14 射线源Z运动速度
MC_SourceZ_JogPos byte 18 射线源Z正向Jog
MC_SourceZ_JogNeg byte 19 射线源Z反向Jog
MC_SourceZ_Home byte 20 射线源Z回零
MC_SourceZ_Stop byte 21 射线源Z停止
MC_DetZ_Target single 22 探测器Z目标位置(mm
MC_DetZ_Speed single 26 探测器Z运动速度
MC_DetZ_JogPos byte 30 探测器Z正向Jog
MC_DetZ_JogNeg byte 31 探测器Z反向Jog
MC_DetZ_Home byte 32 探测器Z回零
MC_DetZ_Stop byte 33 探测器Z停止
MC_StageX_Target single 34 载物台X目标位置(mm
MC_StageX_Speed single 38 载物台X运动速度
MC_StageX_JogPos byte 42 载物台X正向Jog
MC_StageX_JogNeg byte 43 载物台X反向Jog
MC_StageX_Home byte 44 载物台X回零
MC_StageX_Stop byte 45 载物台X停止
MC_StageY_Target single 46 载物台Y目标位置(mm
MC_StageY_Speed single 50 载物台Y运动速度
MC_StageY_JogPos byte 54 载物台Y正向Jog
MC_StageY_JogNeg byte 55 载物台Y反向Jog
MC_StageY_Home byte 56 载物台Y回零
MC_StageY_Stop byte 57 载物台Y停止
MC_DetSwing_Target single 58 探测器摆动目标角度(度)
MC_DetSwing_Speed single 62 探测器摆动运动速度
MC_DetSwing_JogPos byte 66 探测器摆动正向Jog
MC_DetSwing_JogNeg byte 67 探测器摆动反向Jog
MC_DetSwing_Home byte 68 探测器摆动回零
MC_DetSwing_Stop byte 69 探测器摆动停止
MC_StageRot_Target single 70 载物台旋转目标角度(度)
MC_StageRot_Speed single 74 载物台旋转运动速度
MC_StageRot_JogPos byte 78 载物台旋转正向Jog
MC_StageRot_JogNeg byte 79 载物台旋转反向Jog
MC_StageRot_Home byte 80 载物台旋转回零
MC_StageRot_Stop byte 81 载物台旋转停止
MC_FixRot_Target single 82 夹具旋转目标角度(度)
MC_FixRot_Speed single 86 夹具旋转运动速度
MC_FixRot_JogPos byte 90 夹具旋转正向Jog
MC_FixRot_JogNeg byte 91 夹具旋转反向Jog
MC_FixRot_Home byte 92 夹具旋转回零
MC_FixRot_Stop byte 93 夹具旋转停止
MC_Door_Open byte 94 安全门开门
MC_Door_Close byte 95 安全门关门
MC_Door_Stop byte 96 安全门停止
MC_SourceDetZ_Linkage_Enable bool 101 射线源与探测器Z轴联动使能
MC_Axis_Reset byte 102 轴复位命令(清除所有轴故障/报警状态,0:缺省,10:触发复位。不产生物理运动,与各轴 Home 不同)
MC_VirtualJoystick_Enable bool 111 虚拟摇杆使能

7.2 读取信号(ReadCommonDB31

信号名 类型 地址 说明
MC_SourceZ_Pos single 100 射线源Z实际位置(mm
MC_DetZ_Pos single 104 探测器Z实际位置(mm
MC_StageX_Pos single 108 载物台X实际位置(mm
MC_StageY_Pos single 112 载物台Y实际位置(mm
MC_DetSwing_Angle single 116 探测器摆动实际角度(度)
MC_StageRot_Angle single 120 载物台旋转实际角度(度)
MC_FixRot_Angle single 124 夹具旋转实际角度(度)
MC_Door_Status byte 128 安全门状态(0:未知,1:开门中,2:已开,3:关门中,4:已关,5:已锁定,6:故障)
MC_Door_Interlock byte 130 安全门联锁信号(0:无联锁,10:联锁有效)
MC_Joystick_Active bool 110 实体摇杆输入激活
MC_Axis_ResetDone bool 112 轴复位完成(Reset 操作完成后 PLC 置 true

7.3 信号类型说明 | Signal Type Notes

  • single32位浮点数(4字节)
  • byte8位无符号整数(1字节)
  • bool:布尔值(1字节,0=false, 非0=true

7.4 Home(机械回零)与 Reset(轴复位)的区别 | Difference between Home and Reset

对比项 Home(机械回零) Reset(轴复位)
PLC 信号 各轴独立信号(如 MC_SourceZ_Home 全局单一信号 MC_Axis_Reset
是否产生物理运动 ,驱动轴运动到机械零点 ,轴原地不动
目的 建立坐标系(位置寄存器归零) 清除故障/报警状态(Alarm → Idle
前提条件 轴处于正常状态(Idle/Standstill 轴处于故障/报警状态
执行结果 轴到达机械零位,位置 = 0 轴状态恢复正常,位置不变
典型场景 设备开机上电后确认轴位置 轴碰限位开关或驱动器报错后恢复
调用方式 IMotionControlService.HomeAll()ILinearAxis.Home() IAxisReset.Reset()

正确操作顺序:轴报警时 → 排除物理故障 → Reset(清除报警)→ Home(建立坐标系)


8. 安全机制 | Safety Mechanisms

机制 说明
边界检查 目标位置超出 Min/Max 范围时拒绝移动
运动中防重入 轴处于 Moving 状态时拒绝新的移动命令
联锁检查 联锁信号有效时禁止开门
禁用轴检查 Enabled=false 的旋转轴拒绝所有命令
Homing 中拒绝 Jog 回零过程中不允许 Jog 操作
多轴原子性检查 MoveAllToTarget 任意轴越界则全部拒绝
轮询异常不中断 轮询中 PLC 异常被捕获,不影响下一轮
UI 异常保护 ViewModel 命令通过 SafeRun 包裹,PLC 异常弹窗而非崩溃
PLC 断连安全 PLC 断开时自动停止所有 Jog 并禁用摇杆,重连后需用户手动恢复
使能/联动回滚 使能切换或联动设置写入 PLC 失败时自动回滚 UI 状态

9. 安全点配置 | Safe Position Configuration

每个轴可以配置一个安全点位置(SafePosition),用于设备维护、换件时将轴移动到安全位置避免碰撞。

App.config 配置示例 | App.config Configuration Example

<!-- 直线轴安全点(mm| Linear axis safe position (mm) -->
<add key="MotionControl:SourceZ:SafePosition" value="0" />
<add key="MotionControl:DetectorZ:SafePosition" value="600" />
<add key="MotionControl:StageX:SafePosition" value="0" />
<add key="MotionControl:StageY:SafePosition" value="0" />
<!-- 旋转轴安全点(度)| Rotary axis safe position (degrees) -->
<add key="MotionControl:DetectorSwing:SafePosition" value="0" />
<add key="MotionControl:StageRotation:SafePosition" value="0" />
<add key="MotionControl:FixtureRotation:SafePosition" value="0" />

调用方式 | Usage

MotionResult result = _motionControlService.MoveToSafePosition();

注意 | Note

  • 安全点坐标必须在轴的 Min/Max 范围内,否则会被边界检查拒绝
  • HomeAll()(机械回零)不同,MoveToSafePosition() 是移动到用户配置的坐标,不是机械零点
  • 禁用的旋转轴会被自动跳过

10. 轮询机制 | Polling Mechanism

MotionControlService 使用 System.Threading.Timer 以配置的 PollingInterval(默认 100ms)周期执行:

  1. 检查 PLC 连接状态(通过 IPlcService.IsConnected),未连接时跳过
  2. 缓存所有轴、门状态和联锁状态的旧值
  3. 调用 IMotionSystem.UpdateAllStatus() 从 PLC 读取最新状态
  4. 重新计算几何参数,发布 GeometryUpdatedEvent
  5. 检测状态变化,发布 AxisStatusChangedEventDoorStatusChangedEventDoorInterlockChangedEvent
  6. 轴进入 Error/Alarm 时额外发布 MotionErrorEvent
  7. 异常捕获并记录 Error 日志,不中断轮询

通过 StartPolling() / StopPolling() 控制轮询生命周期。


11. 坐标系补偿 | Coordinate Compensation

用于将主框架坐标匹配得到的图像像素偏移换算为载物台物理补偿,并让后续定点运动自动叠加补偿,保持工件对齐。

11.1 补偿模型

  • 补偿值以物理量 mm 存储(Stage 坐标系,放大比无关),初始 (0,0)
  • 仅作用于 StageX / StageY,其余轴不补偿
  • HomeAll() 回零不会清零补偿;仅 ResetStageCompensation() 显式清零

11.2 记录模式(CompensationMode

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

ApplyPixelOffsetCompensation 的移动为相对移动。覆盖模式假设"同参考位置、每位置一次";同位置迭代修正请用 Accumulate,否则物理移动会重复叠加。

11.3 接口一览

方法 说明
ApplyPixelOffsetCompensation(dx, dy, mode = Replace) 记录补偿 + 执行相对修正移动
RecordPixelOffsetCompensation(dx, dy, mode = Replace) 仅记录补偿,不移动
GetStageCompensation() 获取当前补偿值 (Xmm, Ymm)
SetStageCompensation(xMm, yMm) 直接以 mm 设置补偿值
ResetStageCompensation() 清零补偿(换工件/维护时调用)
MoveToTarget(..., applyCompensation: true) 单轴定点移动叠加补偿(仅 StageX/StageY
MoveAllToTarget(targets, applyCompensation: true) 多轴定点移动叠加补偿(仅 StageX/StageY

11.4 调用示例

// 主框架坐标匹配后:记录补偿并修正到位(默认覆盖)
_mc.ApplyPixelOffsetCompensation(dxPixels, dyPixels);

// 后续定点运动叠加补偿
_mc.MoveAllToTarget(new Dictionary<AxisId, double>
{
    { AxisId.StageX, 100 }, { AxisId.StageY, 50 }
}, applyCompensation: true);

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

补偿值变化时发布 StageCompensationChangedEvent(见第 6 节)。补偿功能复用现有几何配置(DetectorPixelSizeX/YPixelDirectionX/Y),无需新增 App.config 参数。


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