修复运动控制问题:ExecuteToggleEnable 在 PLC 写入失败或异常时回滚 IsJoystickEnabled 状态;OnPlcConnectionChanged 中改为 new List<>(dict.Keys) 遍历副本,避免潜在的集合修改问题;SendSourceDetectorZMoveCommand 新增 sourcePropertyName 参数,根据用户编辑的是 SourceZ 还是 DetectorZ 来决定 delta 计算方向;SavePositionsCommand 增加 () => IsPlcConnected 条件,PLC 未连接时禁止保存。
补充射线源和PLC类库所需配置和信号地址定义文件。
This commit is contained in:
@@ -1,449 +0,0 @@
|
||||
# AxisControlView PLC 通信机制 | AxisControlView PLC Communication
|
||||
|
||||
## 概述 | Overview
|
||||
|
||||
AxisControlView 是运动控制模块的核心用户控件,通过 AxisControlViewModel 与 PLC 进行双向通信。本文档详细说明摇杆 Jog 操作、轴位置输入框操作以及射线源/探测器Z轴联动状态下的 PLC 信号下发机制。
|
||||
|
||||
## 通信架构 | Communication Architecture
|
||||
|
||||
```
|
||||
AxisControlView (XAML)
|
||||
↓ (数据绑定)
|
||||
AxisControlViewModel (C#)
|
||||
↓ (调用)
|
||||
IMotionControlService
|
||||
↓ (调用)
|
||||
ISignalDataService
|
||||
↓ (写入队列)
|
||||
PLC (DB31, WriteCommon 组)
|
||||
```
|
||||
|
||||
## 1. 摇杆 Jog 操作 | Joystick Jog Operation
|
||||
|
||||
### 1.1 双轴摇杆(圆形)| Dual Axis Joystick (Circular)
|
||||
|
||||
**左键拖拽(默认模式)**:
|
||||
- X 轴输出 → StageX Jog(正向/反向)
|
||||
- Y 轴输出 → StageY Jog(正向/反向)
|
||||
|
||||
**右键拖拽(默认模式)**:
|
||||
- X 轴输出 → DetectorSwing Jog(正向/反向)
|
||||
- Y 轴输出 → StageRotation/FixtureRotation Jog(正向/反向)
|
||||
|
||||
**信号下发流程**:
|
||||
|
||||
```csharp
|
||||
// 1. 摇杆输出变化触发 HandleDualJoystickOutput()
|
||||
private void HandleDualJoystickOutput()
|
||||
{
|
||||
switch (DualJoystickActiveButton)
|
||||
{
|
||||
case MouseButtonType.Left:
|
||||
UpdateLinearJog(AxisId.StageX, DualJoystickOutputX);
|
||||
UpdateLinearJog(AxisId.StageY, DualJoystickOutputY);
|
||||
break;
|
||||
case MouseButtonType.Right:
|
||||
UpdateRotaryJog(RotaryAxisId.DetectorSwing, DualJoystickOutputX);
|
||||
var rotationAxisId = GetEnabledRotationAxisId();
|
||||
if (rotationAxisId.HasValue)
|
||||
UpdateRotaryJog(rotationAxisId.Value, DualJoystickOutputY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. UpdateLinearJog/UpdateRotaryJog 处理 Jog 启动/速度更新/停止
|
||||
private void UpdateLinearJog(AxisId axisId, double output)
|
||||
{
|
||||
if (output != 0)
|
||||
{
|
||||
var speedPercent = Math.Abs(output) * 100;
|
||||
var positive = output > 0;
|
||||
|
||||
if (!_linearJogActive[axisId])
|
||||
{
|
||||
// 首次非零:设置速度并启动 Jog
|
||||
_motionControlService.SetJogSpeed(axisId, speedPercent);
|
||||
_motionControlService.JogStart(axisId, positive);
|
||||
_linearJogActive[axisId] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 已在 Jog:仅更新速度
|
||||
_motionControlService.SetJogSpeed(axisId, speedPercent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 松开鼠标:停止 Jog
|
||||
if (_linearJogActive[axisId])
|
||||
{
|
||||
_motionControlService.JogStop(axisId);
|
||||
_linearJogActive[axisId] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. IMotionControlService 调用 ISignalDataService.EnqueueWrite 写入 PLC
|
||||
public MotionResult JogStart(AxisId axisId, bool positive)
|
||||
{
|
||||
var signalName = positive ? MotionSignalNames.SourceZ_JogPos : MotionSignalNames.SourceZ_JogNeg;
|
||||
var result = _signalService.EnqueueWrite(signalName, true);
|
||||
return result ? MotionResult.Ok() : MotionResult.Fail("Jog 启动写入失败");
|
||||
}
|
||||
```
|
||||
|
||||
**PLC 信号地址**:
|
||||
|
||||
| 轴 | 信号名 | 地址 | 说明 |
|
||||
|----|--------|------|------|
|
||||
| StageX | `MC_StageX_JogPos` | 42 | 正向 Jog(0:缺省, 1:点动) |
|
||||
| StageX | `MC_StageX_JogNeg` | 43 | 反向 Jog(0:缺省, 1:点动) |
|
||||
| StageY | `MC_StageY_JogPos` | 54 | 正向 Jog(0:缺省, 1:点动) |
|
||||
| StageY | `MC_StageY_JogNeg` | 55 | 反向 Jog(0:缺省, 1:点动) |
|
||||
| DetectorSwing | `MC_DetSwing_JogPos` | 66 | 正向 Jog(0:缺省, 1:点动) |
|
||||
| DetectorSwing | `MC_DetSwing_JogNeg` | 67 | 反向 Jog(0:缺省, 1:点动) |
|
||||
| StageRotation | `MC_StageRot_JogPos` | 78 | 正向 Jog(0:缺省, 1:点动) |
|
||||
| StageRotation | `MC_StageRot_JogNeg` | 79 | 反向 Jog(0:缺省, 1:点动) |
|
||||
| FixtureRotation | `MC_FixRot_JogPos` | 90 | 正向 Jog(0:缺省, 1:点动) |
|
||||
| FixtureRotation | `MC_FixRot_JogNeg` | 91 | 反向 Jog(0:缺省, 1:点动) |
|
||||
|
||||
### 1.2 单轴摇杆(腰圆)| Single Axis Joystick (Oval)
|
||||
|
||||
**左键拖拽(默认模式)**:
|
||||
- Y 轴输出 → SourceZ Jog(正向/反向)
|
||||
- 若 SZDZLock=true,同时 → DetectorZ Jog(正向/反向)
|
||||
|
||||
**右键拖拽(默认模式)**:
|
||||
- Y 轴输出 → DetectorZ Jog(正向/反向)
|
||||
- 若 SZDZLock=true,同时 → SourceZ Jog(正向/反向)
|
||||
|
||||
**信号下发流程**:
|
||||
|
||||
```csharp
|
||||
private void HandleSingleJoystickOutput()
|
||||
{
|
||||
switch (SingleJoystickActiveButton)
|
||||
{
|
||||
case MouseButtonType.Left:
|
||||
UpdateLinearJog(AxisId.SourceZ, SingleJoystickOutputY);
|
||||
if (_szdzLock)
|
||||
UpdateLinearJog(AxisId.DetectorZ, SingleJoystickOutputY);
|
||||
break;
|
||||
case MouseButtonType.Right:
|
||||
UpdateLinearJog(AxisId.DetectorZ, SingleJoystickOutputY);
|
||||
if (_szdzLock)
|
||||
UpdateLinearJog(AxisId.SourceZ, SingleJoystickOutputY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**PLC 信号地址**:
|
||||
|
||||
| 轴 | 信号名 | 地址 | 说明 |
|
||||
|----|--------|------|------|
|
||||
| SourceZ | `MC_SourceZ_JogPos` | 18 | 正向 Jog(0:缺省, 1:点动) |
|
||||
| SourceZ | `MC_SourceZ_JogNeg` | 19 | 反向 Jog(0:缺省, 1:点动) |
|
||||
| DetectorZ | `MC_DetZ_JogPos` | 30 | 正向 Jog(0:缺省, 1:点动) |
|
||||
| DetectorZ | `MC_DetZ_JogNeg` | 31 | 反向 Jog(0:缺省, 1:点动) |
|
||||
|
||||
### 1.3 Jog 速度控制 | Jog Speed Control
|
||||
|
||||
摇杆输出值(-1.0 ~ 1.0)映射为速度百分比(0% ~ 100%):
|
||||
|
||||
```csharp
|
||||
var speedPercent = Math.Abs(output) * 100; // 0% ~ 100%
|
||||
```
|
||||
|
||||
**速度计算流程**:
|
||||
|
||||
1. **MotionControlService.SetJogSpeed** 计算实际速度:
|
||||
```csharp
|
||||
var actualSpeed = _config.DefaultVelocity * speedPercent / 100.0;
|
||||
// 例如:DefaultVelocity=100, speedPercent=50 → actualSpeed=50 mm/s
|
||||
```
|
||||
|
||||
2. **PlcLinearAxis.SetJogSpeed** 将实际速度写入 PLC:
|
||||
```csharp
|
||||
_signalService.EnqueueWrite(_speedSignal, (float)speedPercent);
|
||||
// 注意:参数名 speedPercent 实际接收的是 actualSpeed(已计算的实际速度值)
|
||||
```
|
||||
|
||||
**PLC 信号地址**:
|
||||
|
||||
| 轴 | 信号名 | 地址 | 说明 |
|
||||
|----|--------|------|------|
|
||||
| SourceZ | `MC_SourceZ_Speed` | 14 | 速度值(mm/s,由 DefaultVelocity * speedPercent / 100 计算) |
|
||||
| DetectorZ | `MC_DetZ_Speed` | 26 | 速度值(mm/s,由 DefaultVelocity * speedPercent / 100 计算) |
|
||||
| StageX | `MC_StageX_Speed` | 38 | 速度值(mm/s,由 DefaultVelocity * speedPercent / 100 计算) |
|
||||
| StageY | `MC_StageY_Speed` | 50 | 速度值(mm/s,由 DefaultVelocity * speedPercent / 100 计算) |
|
||||
| DetectorSwing | `MC_DetSwing_Speed` | 62 | 速度值(度/s,由 DefaultVelocity * speedPercent / 100 计算) |
|
||||
| StageRotation | `MC_StageRot_Speed` | 74 | 速度值(度/s,由 DefaultVelocity * speedPercent / 100 计算) |
|
||||
| FixtureRotation | `MC_FixRot_Speed` | 86 | 速度值(度/s,由 DefaultVelocity * speedPercent / 100 计算) |
|
||||
|
||||
**示例**:
|
||||
- `DefaultVelocity = 100` mm/s
|
||||
- 摇杆输出 30% → PLC 接收速度 = 100 * 30% = 30 mm/s
|
||||
- 摇杆输出 100% → PLC 接收速度 = 100 * 100% = 100 mm/s
|
||||
|
||||
## 2. 轴位置输入框操作 | Axis Position Input Box Operation
|
||||
|
||||
### 2.1 编辑状态管理 | Editing State Management
|
||||
|
||||
- **GotFocus**:`SetEditing(propertyName, true)` → 冻结实时更新
|
||||
- **LostFocus/Escape**:`CancelEditing(propertyName)` → 恢复实时更新,显示实际值
|
||||
- **Enter**:`ConfirmPosition(propertyName)` → 发送目标位置移动命令
|
||||
|
||||
### 2.2 移动命令下发流程 | Move Command Flow
|
||||
|
||||
```csharp
|
||||
public void ConfirmPosition(string propertyName)
|
||||
{
|
||||
var value = GetPropertyValue(propertyName);
|
||||
SafeRun(() =>
|
||||
{
|
||||
MotionResult result;
|
||||
// 如果射线源与探测器Z轴联动,且操作的是SourceZ或DetectorZ,则同时发送两个轴
|
||||
if (SZDZLock && (propertyName == nameof(SourceZPosition) || propertyName == nameof(DetectorZPosition)))
|
||||
{
|
||||
result = SendSourceDetectorZMoveCommand(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = SendMoveCommand(propertyName, value);
|
||||
}
|
||||
if (result.Success)
|
||||
_logger.Info("目标位置已发送:{Property}={Value}", propertyName, value);
|
||||
else
|
||||
_logger.Warn("目标位置发送失败:{Property}={Value},原因={Reason}", propertyName, value, result.ErrorMessage);
|
||||
});
|
||||
_editingFlags[propertyName] = false;
|
||||
}
|
||||
|
||||
private MotionResult SendMoveCommand(string propertyName, double value)
|
||||
{
|
||||
switch (propertyName)
|
||||
{
|
||||
case nameof(StageXPosition):
|
||||
return _motionControlService.MoveToTarget(AxisId.StageX, value);
|
||||
case nameof(SourceZPosition):
|
||||
return _motionControlService.MoveToTarget(AxisId.SourceZ, value);
|
||||
// ... 其他轴
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 单轴移动 | Single Axis Move
|
||||
|
||||
```csharp
|
||||
public MotionResult MoveToTarget(AxisId axisId, double targetPosition, int? speed = null)
|
||||
{
|
||||
var axis = _motionSystem.GetLinearAxis(axisId);
|
||||
var actualSpeed = speed ?? _config.DefaultVelocity;
|
||||
|
||||
// 边界检查(使用配置中的 Min/Max)
|
||||
if (targetPosition < config.Min || targetPosition > config.Max)
|
||||
return MotionResult.Fail("目标位置超出范围");
|
||||
|
||||
// 写入目标位置和速度
|
||||
var targetResult = _signalService.EnqueueWrite(signalName, targetPosition);
|
||||
var speedResult = _signalService.EnqueueWrite(speedSignalName, actualSpeed);
|
||||
|
||||
// 启动移动(写入目标位置会自动触发移动)
|
||||
return targetResult && speedResult ? MotionResult.Ok() : MotionResult.Fail("移动命令写入失败");
|
||||
}
|
||||
```
|
||||
|
||||
**PLC 信号地址**:
|
||||
|
||||
| 轴 | 目标位置信号 | 地址 | 速度信号 | 地址 |
|
||||
|----|-------------|------|---------|------|
|
||||
| SourceZ | `MC_SourceZ_Target` | 10 | `MC_SourceZ_Speed` | 14 |
|
||||
| DetectorZ | `MC_DetZ_Target` | 22 | `MC_DetZ_Speed` | 26 |
|
||||
| StageX | `MC_StageX_Target` | 34 | `MC_StageX_Speed` | 38 |
|
||||
| StageY | `MC_StageY_Target` | 46 | `MC_StageY_Speed` | 50 |
|
||||
| DetectorSwing | `MC_DetSwing_Target` | 58 | `MC_DetSwing_Speed` | 62 |
|
||||
| StageRotation | `MC_StageRot_Target` | 70 | `MC_StageRot_Speed` | 74 |
|
||||
| FixtureRotation | `MC_FixRot_Target` | 82 | `MC_FixRot_Speed` | 86 |
|
||||
|
||||
### 2.4 步进移动 | Step Move
|
||||
|
||||
上下箭头键触发 `StepPosition(propertyName, delta)`:
|
||||
|
||||
```csharp
|
||||
public void StepPosition(string propertyName, double delta)
|
||||
{
|
||||
var currentValue = GetPropertyValue(propertyName);
|
||||
var newValue = currentValue + delta;
|
||||
SetPropertyValue(propertyName, newValue);
|
||||
|
||||
// 直接发送移动命令,不进入编辑冻结
|
||||
if (SZDZLock && (propertyName == nameof(SourceZPosition) || propertyName == nameof(DetectorZPosition)))
|
||||
{
|
||||
result = SendSourceDetectorZMoveCommand(newValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = SendMoveCommand(propertyName, newValue);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 射线源/探测器Z轴联动 | Source-Detector Z-axis Linkage
|
||||
|
||||
### 3.1 联动使能 | Linkage Enable
|
||||
|
||||
点击"SZDZLock"按钮切换联动状态:
|
||||
|
||||
```csharp
|
||||
private void ExecuteSZDZLock()
|
||||
{
|
||||
SZDZLock = !SZDZLock;
|
||||
var result = _motionControlService.SetSourceDetectorZLinkage(SZDZLock);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
// 设置失败,恢复状态
|
||||
SZDZLock = !SZDZLock;
|
||||
MessageBox.Show(result.ErrorMessage);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**PLC 信号**:
|
||||
|
||||
| 信号名 | 地址 | 类型 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| `MC_SourceDetZ_Linkage_Enable` | 101 | bool | 联动使能(true=启用, false=禁用) |
|
||||
|
||||
### 3.2 联动移动 | Linkage Move
|
||||
|
||||
当 SZDZLock=true 时,移动 SourceZ 或 DetectorZ 会同时移动两个轴,保持位移量相同:
|
||||
|
||||
```csharp
|
||||
private MotionResult SendSourceDetectorZMoveCommand(double targetValue)
|
||||
{
|
||||
// 1. 检查联动是否在配置中启用
|
||||
if (!_config.SourceDetectorZLinkage.Enabled)
|
||||
return MotionResult.Fail("射线源与探测器Z轴联动未启用");
|
||||
|
||||
// 2. 检查两个轴是否都在空闲状态
|
||||
var sourceZAxis = _motionSystem.GetLinearAxis(AxisId.SourceZ);
|
||||
var detectorZAxis = _motionSystem.GetLinearAxis(AxisId.DetectorZ);
|
||||
|
||||
if (sourceZAxis.Status == AxisStatus.Moving)
|
||||
return MotionResult.Fail("射线源Z轴正在运动中,无法联动移动");
|
||||
|
||||
if (detectorZAxis.Status == AxisStatus.Moving)
|
||||
return MotionResult.Fail("探测器Z轴正在运动中,无法联动移动");
|
||||
|
||||
// 3. 计算位移量和目标位置
|
||||
var currentSourceZ = sourceZAxis.ActualPosition;
|
||||
var currentDetectorZ = detectorZAxis.ActualPosition;
|
||||
var sourceDelta = targetValue - currentSourceZ;
|
||||
var targetDetectorZ = currentDetectorZ + sourceDelta;
|
||||
|
||||
// 4. 边界检查(使用配置中的 Min/Max)
|
||||
if (targetValue < sourceConfig.Min || targetValue > sourceConfig.Max)
|
||||
return MotionResult.Fail("射线源Z轴目标位置超出范围");
|
||||
|
||||
if (targetDetectorZ < detectorConfig.Min || targetDetectorZ > detectorConfig.Max)
|
||||
return MotionResult.Fail("探测器Z轴目标位置超出范围");
|
||||
|
||||
// 5. 同时发送两个轴的移动命令
|
||||
var sourceResult = sourceZAxis.MoveToTarget(targetValue, _config.DefaultVelocity);
|
||||
var detectorResult = detectorZAxis.MoveToTarget(targetDetectorZ, _config.DefaultVelocity);
|
||||
|
||||
return sourceResult.Success && detectorResult.Success
|
||||
? MotionResult.Ok()
|
||||
: (sourceResult.Success ? detectorResult : sourceResult);
|
||||
}
|
||||
```
|
||||
|
||||
**PLC 信号下发**:
|
||||
|
||||
1. **SourceZ 移动**:
|
||||
- `MC_SourceZ_Target` = targetValue(地址 10)
|
||||
- `MC_SourceZ_Speed` = DefaultVelocity(地址 14)
|
||||
|
||||
2. **DetectorZ 移动**:
|
||||
- `MC_DetZ_Target` = currentDetectorZ + (targetValue - currentSourceZ)(地址 22)
|
||||
- `MC_DetZ_Speed` = DefaultVelocity(地址 26)
|
||||
|
||||
### 3.3 联动 Jog | Linkage Jog
|
||||
|
||||
当 SZDZLock=true 时,单轴摇杆的左右键会同时控制两个轴:
|
||||
|
||||
```csharp
|
||||
private void HandleSingleJoystickOutput()
|
||||
{
|
||||
switch (SingleJoystickActiveButton)
|
||||
{
|
||||
case MouseButtonType.Left:
|
||||
UpdateLinearJog(AxisId.SourceZ, SingleJoystickOutputY);
|
||||
if (_szdzLock)
|
||||
UpdateLinearJog(AxisId.DetectorZ, SingleJoystickOutputY);
|
||||
break;
|
||||
case MouseButtonType.Right:
|
||||
UpdateLinearJog(AxisId.DetectorZ, SingleJoystickOutputY);
|
||||
if (_szdzLock)
|
||||
UpdateLinearJog(AxisId.SourceZ, SingleJoystickOutputY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**PLC 信号下发**:
|
||||
|
||||
- **SourceZ Jog**:
|
||||
- `MC_SourceZ_JogPos`/`MC_SourceZ_JogNeg` = true(地址 18/19)
|
||||
- `MC_SourceZ_Speed` = speedPercent(地址 14)
|
||||
|
||||
- **DetectorZ Jog**:
|
||||
- `MC_DetZ_JogPos`/`MC_DetZ_JogNeg` = true(地址 30/31)
|
||||
- `MC_DetZ_Speed` = speedPercent(地址 26)
|
||||
|
||||
## 4. 虚拟摇杆使能 | Virtual Joystick Enable
|
||||
|
||||
点击"使能开关"按钮切换虚拟摇杆使能状态:
|
||||
|
||||
```csharp
|
||||
private void ExecuteToggleEnable()
|
||||
{
|
||||
IsJoystickEnabled = !IsJoystickEnabled;
|
||||
_motionControlService.SetVirtualJoystickEnable(IsJoystickEnabled);
|
||||
}
|
||||
```
|
||||
|
||||
**PLC 信号**:
|
||||
|
||||
| 信号名 | 地址 | 类型 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| `MC_VirtualJoystick_Enable` | 111 | bool | 虚拟摇杆使能(true=启用, false=禁用) |
|
||||
|
||||
## 5. 信号写入队列机制 | Signal Write Queue Mechanism
|
||||
|
||||
所有 PLC 写入操作通过 `ISignalDataService.EnqueueWrite()` 进入写入队列:
|
||||
|
||||
```csharp
|
||||
public interface ISignalDataService
|
||||
{
|
||||
bool EnqueueWrite(string signalName, object value);
|
||||
bool EnqueueWriteBatch(Dictionary<string, object> writes);
|
||||
}
|
||||
```
|
||||
|
||||
**队列处理流程**:
|
||||
|
||||
1. ViewModel 调用 `EnqueueWrite(signalName, value)`
|
||||
2. 信号数据服务将写入请求加入队列
|
||||
3. PLC 服务在轮询周期(默认 100ms)中批量写入
|
||||
4. 写入成功后从队列移除
|
||||
|
||||
**优势**:
|
||||
|
||||
- 批量写入减少 PLC 通讯次数
|
||||
- 避免频繁写入导致的通讯拥塞
|
||||
- 统一的错误处理和重试机制
|
||||
|
||||
---
|
||||
@@ -0,0 +1,803 @@
|
||||
# AxisControlView PLC 通信机制 | AxisControlView PLC Communication
|
||||
|
||||
## 概述 | Overview
|
||||
|
||||
AxisControlView 是运动控制模块的核心用户控件,通过 AxisControlViewModel 与 PLC 进行双向通信。本文档详细说明摇杆 Jog 操作、轴位置输入框操作、射线源/探测器Z轴联动、安全机制以及辅助功能的 PLC 信号下发机制。
|
||||
|
||||
## 通信架构 | Communication Architecture
|
||||
|
||||
```
|
||||
AxisControlView (XAML)
|
||||
↓ (数据绑定)
|
||||
AxisControlViewModel (C#)
|
||||
↓ (调用)
|
||||
IMotionControlService
|
||||
↓ (调用)
|
||||
IMotionSystem → PlcLinearAxis / PlcRotaryAxis
|
||||
↓ (调用)
|
||||
ISignalDataService.EnqueueWrite()
|
||||
↓ (写入队列)
|
||||
PLC (DB31, WriteCommon 组)
|
||||
```
|
||||
|
||||
**关键分层说明**:
|
||||
- `AxisControlViewModel` 调用 `IMotionControlService` 的业务方法
|
||||
- `IMotionControlService` 委托给 `IMotionSystem` 获取轴实例(`PlcLinearAxis` / `PlcRotaryAxis`)
|
||||
- 轴实例内部通过 `ISignalDataService.EnqueueWrite()` 写入 PLC 信号
|
||||
- ViewModel 不直接操作信号,所有信号写入由轴实现层完成
|
||||
|
||||
## 1. 摇杆 Jog 操作 | Joystick Jog Operation
|
||||
|
||||
### 1.1 双轴摇杆(圆形)| Dual Axis Joystick (Circular)
|
||||
|
||||
**左键拖拽(默认模式)**:
|
||||
- X 轴输出 → StageX Jog(正向/反向)
|
||||
- Y 轴输出 → StageY Jog(正向/反向)
|
||||
|
||||
**右键拖拽(默认模式)**:
|
||||
- X 轴输出 → DetectorSwing Jog(正向/反向)
|
||||
- Y 轴输出 → StageRotation/FixtureRotation Jog(正向/反向)
|
||||
|
||||
> 注:当 `SwapMouseButtons=true` 时,左右键功能互换。
|
||||
|
||||
**信号下发流程**:
|
||||
|
||||
```csharp
|
||||
// 1. 摇杆输出变化触发 HandleDualJoystickOutput()
|
||||
private void HandleDualJoystickOutput()
|
||||
{
|
||||
switch (DualJoystickActiveButton)
|
||||
{
|
||||
case MouseButtonType.Left:
|
||||
UpdateLinearJog(AxisId.StageX, DualJoystickOutputX);
|
||||
UpdateLinearJog(AxisId.StageY, DualJoystickOutputY);
|
||||
break;
|
||||
case MouseButtonType.Right:
|
||||
UpdateRotaryJog(RotaryAxisId.DetectorSwing, DualJoystickOutputX);
|
||||
var rotationAxisId = GetEnabledRotationAxisId();
|
||||
if (rotationAxisId.HasValue)
|
||||
UpdateRotaryJog(rotationAxisId.Value, DualJoystickOutputY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. UpdateLinearJog 处理 Jog 启动/速度更新/停止
|
||||
private void UpdateLinearJog(AxisId axisId, double output)
|
||||
{
|
||||
if (output != 0)
|
||||
{
|
||||
var speedPercent = Math.Abs(output) * 100;
|
||||
var positive = output > 0;
|
||||
|
||||
if (!_linearJogActive[axisId])
|
||||
{
|
||||
// 从零变为非零:先设速度再启动 Jog
|
||||
_motionControlService.SetJogSpeed(axisId, speedPercent);
|
||||
_motionControlService.JogStart(axisId, positive);
|
||||
_linearJogActive[axisId] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 已在 Jog 中:仅更新速度
|
||||
_motionControlService.SetJogSpeed(axisId, speedPercent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 从非零变为零:停止 Jog
|
||||
if (_linearJogActive[axisId])
|
||||
{
|
||||
_motionControlService.JogStop(axisId);
|
||||
_linearJogActive[axisId] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. MotionControlService.JogStart 委托给轴实现
|
||||
public MotionResult JogStart(AxisId axisId, bool positive)
|
||||
{
|
||||
var axis = _motionSystem.GetLinearAxis(axisId);
|
||||
// Homing 状态检查
|
||||
if (axis.Status == AxisStatus.Homing)
|
||||
return MotionResult.Fail("轴正在回零,拒绝 Jog 命令");
|
||||
return axis.JogStart(positive);
|
||||
}
|
||||
|
||||
// 4. PlcLinearAxis.JogStart 写入 PLC 信号
|
||||
public override MotionResult JogStart(bool positive)
|
||||
{
|
||||
if (Status == AxisStatus.Homing)
|
||||
return MotionResult.Fail("轴正在回零,拒绝 Jog 命令");
|
||||
var signal = positive ? _jogPosSignal : _jogNegSignal;
|
||||
_signalService.EnqueueWrite(signal, true);
|
||||
return MotionResult.Ok();
|
||||
}
|
||||
```
|
||||
|
||||
**旋转轴 Jog 流程类似**(`UpdateRotaryJog` → `SetJogRotarySpeed` → `JogRotaryStart`),额外包含禁用轴检查。
|
||||
|
||||
|
||||
**PLC 信号地址(直线轴 Jog)**:
|
||||
|
||||
| 轴 | 信号名 | 地址 | 说明 |
|
||||
|----|--------|------|------|
|
||||
| SourceZ | `MC_SourceZ_JogPos` | 18 | 正向 Jog(0:缺省, 1:点动) |
|
||||
| SourceZ | `MC_SourceZ_JogNeg` | 19 | 反向 Jog(0:缺省, 1:点动) |
|
||||
| DetectorZ | `MC_DetZ_JogPos` | 30 | 正向 Jog(0:缺省, 1:点动) |
|
||||
| DetectorZ | `MC_DetZ_JogNeg` | 31 | 反向 Jog(0:缺省, 1:点动) |
|
||||
| StageX | `MC_StageX_JogPos` | 42 | 正向 Jog(0:缺省, 1:点动) |
|
||||
| StageX | `MC_StageX_JogNeg` | 43 | 反向 Jog(0:缺省, 1:点动) |
|
||||
| StageY | `MC_StageY_JogPos` | 54 | 正向 Jog(0:缺省, 1:点动) |
|
||||
| StageY | `MC_StageY_JogNeg` | 55 | 反向 Jog(0:缺省, 1:点动) |
|
||||
|
||||
**PLC 信号地址(旋转轴 Jog)**:
|
||||
|
||||
| 轴 | 信号名 | 地址 | 说明 |
|
||||
|----|--------|------|------|
|
||||
| DetectorSwing | `MC_DetSwing_JogPos` | 66 | 正向 Jog(0:缺省, 1:点动) |
|
||||
| DetectorSwing | `MC_DetSwing_JogNeg` | 67 | 反向 Jog(0:缺省, 1:点动) |
|
||||
| StageRotation | `MC_StageRot_JogPos` | 78 | 正向 Jog(0:缺省, 1:点动) |
|
||||
| StageRotation | `MC_StageRot_JogNeg` | 79 | 反向 Jog(0:缺省, 1:点动) |
|
||||
| FixtureRotation | `MC_FixRot_JogPos` | 90 | 正向 Jog(0:缺省, 1:点动) |
|
||||
| FixtureRotation | `MC_FixRot_JogNeg` | 91 | 反向 Jog(0:缺省, 1:点动) |
|
||||
|
||||
### 1.2 单轴摇杆(腰圆)| Single Axis Joystick (Oval)
|
||||
|
||||
**左键拖拽(默认模式)**:
|
||||
- Y 轴输出 → SourceZ Jog(正向/反向)
|
||||
- 若 SZDZLock=true,同时 → DetectorZ Jog(正向/反向)
|
||||
|
||||
**右键拖拽(默认模式)**:
|
||||
- Y 轴输出 → DetectorZ Jog(正向/反向)
|
||||
- 若 SZDZLock=true,同时 → SourceZ Jog(正向/反向)
|
||||
|
||||
**信号下发流程**:
|
||||
|
||||
```csharp
|
||||
private void HandleSingleJoystickOutput()
|
||||
{
|
||||
switch (SingleJoystickActiveButton)
|
||||
{
|
||||
case MouseButtonType.Left:
|
||||
UpdateLinearJog(AxisId.SourceZ, SingleJoystickOutputY);
|
||||
if (_szdzLock)
|
||||
UpdateLinearJog(AxisId.DetectorZ, SingleJoystickOutputY);
|
||||
break;
|
||||
case MouseButtonType.Right:
|
||||
UpdateLinearJog(AxisId.DetectorZ, SingleJoystickOutputY);
|
||||
if (_szdzLock)
|
||||
UpdateLinearJog(AxisId.SourceZ, SingleJoystickOutputY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 1.3 按键释放自动停止 | Button Release Auto-Stop
|
||||
|
||||
当摇杆按键从非 None 变为 None 时,自动停止所有关联轴的 Jog:
|
||||
|
||||
```csharp
|
||||
// DualJoystickActiveButton setter 中
|
||||
if (value == MouseButtonType.None && oldValue != MouseButtonType.None)
|
||||
StopDualJoystickAxes();
|
||||
|
||||
// StopDualJoystickAxes 停止所有双轴摇杆关联轴
|
||||
private void StopDualJoystickAxes()
|
||||
{
|
||||
UpdateLinearJog(AxisId.StageX, 0);
|
||||
UpdateLinearJog(AxisId.StageY, 0);
|
||||
UpdateRotaryJog(RotaryAxisId.DetectorSwing, 0);
|
||||
var rotationAxisId = GetEnabledRotationAxisId();
|
||||
if (rotationAxisId.HasValue)
|
||||
UpdateRotaryJog(rotationAxisId.Value, 0);
|
||||
}
|
||||
```
|
||||
|
||||
单轴摇杆同理(`StopSingleJoystickAxes` 停止 SourceZ 和 DetectorZ)。
|
||||
|
||||
### 1.4 Jog 速度控制 | Jog Speed Control
|
||||
|
||||
摇杆输出值(-1.0 ~ 1.0)映射为速度百分比(0% ~ 100%):
|
||||
|
||||
```csharp
|
||||
var speedPercent = Math.Abs(output) * 100; // 0% ~ 100%
|
||||
```
|
||||
|
||||
**速度计算流程**:
|
||||
|
||||
1. **MotionControlService.SetJogSpeed** 计算实际速度:
|
||||
```csharp
|
||||
public MotionResult SetJogSpeed(AxisId axisId, double speedPercent)
|
||||
{
|
||||
var axis = _motionSystem.GetLinearAxis(axisId);
|
||||
var actualSpeed = _config.DefaultVelocity * speedPercent / 100.0;
|
||||
return axis.SetJogSpeed(actualSpeed);
|
||||
}
|
||||
```
|
||||
|
||||
2. **PlcLinearAxis.SetJogSpeed** 将实际速度写入 PLC:
|
||||
```csharp
|
||||
public override MotionResult SetJogSpeed(double speedPercent)
|
||||
{
|
||||
// 注意:参数名为 speedPercent,但实际接收的是已计算的速度值(mm/s 或 度/s)
|
||||
_signalService.EnqueueWrite(_speedSignal, (float)speedPercent);
|
||||
return MotionResult.Ok();
|
||||
}
|
||||
```
|
||||
|
||||
**PLC 速度信号地址**:
|
||||
|
||||
| 轴 | 信号名 | 地址 | 说明 |
|
||||
|----|--------|------|------|
|
||||
| SourceZ | `MC_SourceZ_Speed` | 14 | 速度值(mm/s,由 DefaultVelocity × speedPercent / 100 计算) |
|
||||
| DetectorZ | `MC_DetZ_Speed` | 26 | 速度值(mm/s,由 DefaultVelocity × speedPercent / 100 计算) |
|
||||
| StageX | `MC_StageX_Speed` | 38 | 速度值(mm/s,由 DefaultVelocity × speedPercent / 100 计算) |
|
||||
| StageY | `MC_StageY_Speed` | 50 | 速度值(mm/s,由 DefaultVelocity × speedPercent / 100 计算) |
|
||||
| DetectorSwing | `MC_DetSwing_Speed` | 62 | 速度值(度/s,由 DefaultVelocity × speedPercent / 100 计算) |
|
||||
| StageRotation | `MC_StageRot_Speed` | 74 | 速度值(度/s,由 DefaultVelocity × speedPercent / 100 计算) |
|
||||
| FixtureRotation | `MC_FixRot_Speed` | 86 | 速度值(度/s,由 DefaultVelocity × speedPercent / 100 计算) |
|
||||
|
||||
**示例**:
|
||||
- `DefaultVelocity = 100` mm/s
|
||||
- 摇杆输出 30% → PLC 接收速度 = 100 × 30 / 100 = 30 mm/s
|
||||
- 摇杆输出 100% → PLC 接收速度 = 100 × 100 / 100 = 100 mm/s
|
||||
|
||||
## 2. 轴位置输入框操作 | Axis Position Input Box Operation
|
||||
|
||||
### 2.1 编辑状态管理 | Editing State Management
|
||||
|
||||
- **GotFocus**:`SetEditing(propertyName, true)` → 冻结实时更新
|
||||
- **LostFocus/Escape**:`CancelEditing(propertyName)` → 恢复实时更新,显示实际值
|
||||
- **Enter**:`ConfirmPosition(propertyName)` → 发送目标位置移动命令
|
||||
|
||||
### 2.2 移动命令下发流程 | Move Command Flow
|
||||
|
||||
```csharp
|
||||
public void ConfirmPosition(string propertyName)
|
||||
{
|
||||
var value = GetPropertyValue(propertyName);
|
||||
SafeRun(() =>
|
||||
{
|
||||
MotionResult result;
|
||||
// 如果射线源与探测器Z轴联动,且操作的是SourceZ或DetectorZ,则同时发送两个轴
|
||||
if (SZDZLock && (propertyName == nameof(SourceZPosition) || propertyName == nameof(DetectorZPosition)))
|
||||
{
|
||||
result = SendSourceDetectorZMoveCommand(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = SendMoveCommand(propertyName, value);
|
||||
}
|
||||
if (result.Success)
|
||||
_logger.Info("目标位置已发送:{Property}={Value}", propertyName, value);
|
||||
else
|
||||
_logger.Warn("目标位置发送失败:{Property}={Value},原因={Reason}", propertyName, value, result.ErrorMessage);
|
||||
});
|
||||
_editingFlags[propertyName] = false;
|
||||
}
|
||||
|
||||
private MotionResult SendMoveCommand(string propertyName, double value)
|
||||
{
|
||||
switch (propertyName)
|
||||
{
|
||||
case nameof(StageXPosition):
|
||||
return _motionControlService.MoveToTarget(AxisId.StageX, value);
|
||||
case nameof(StageYPosition):
|
||||
return _motionControlService.MoveToTarget(AxisId.StageY, value);
|
||||
case nameof(SourceZPosition):
|
||||
return _motionControlService.MoveToTarget(AxisId.SourceZ, value);
|
||||
case nameof(DetectorZPosition):
|
||||
return _motionControlService.MoveToTarget(AxisId.DetectorZ, value);
|
||||
case nameof(DetectorSwingAngle):
|
||||
return _motionControlService.MoveRotaryToTarget(RotaryAxisId.DetectorSwing, value);
|
||||
case nameof(StageRotationAngle):
|
||||
return _motionControlService.MoveRotaryToTarget(RotaryAxisId.StageRotation, value);
|
||||
case nameof(FixtureRotationAngle):
|
||||
return _motionControlService.MoveRotaryToTarget(RotaryAxisId.FixtureRotation, value);
|
||||
default:
|
||||
return MotionResult.Fail($"未知的属性名称:{propertyName}");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 单轴移动 | Single Axis Move
|
||||
|
||||
```csharp
|
||||
// MotionControlService.MoveToTarget — 业务层
|
||||
public MotionResult MoveToTarget(AxisId axisId, double target, double? speed = null)
|
||||
{
|
||||
var axis = _motionSystem.GetLinearAxis(axisId);
|
||||
|
||||
// 运动中防重入检查
|
||||
if (axis.Status == AxisStatus.Moving)
|
||||
return MotionResult.Fail("轴正在运动中,拒绝重复命令");
|
||||
|
||||
// 委托给轴实现(轴内部包含边界检查)
|
||||
return axis.MoveToTarget(target, speed ?? _config.DefaultVelocity);
|
||||
}
|
||||
|
||||
// PlcLinearAxis.MoveToTarget — 轴实现层
|
||||
public override MotionResult MoveToTarget(double target, double? speed = null)
|
||||
{
|
||||
if (!ValidateTarget(target))
|
||||
return MotionResult.Fail($"目标位置 {target} 超出范围 [{_min}, {_max}]");
|
||||
if (Status == AxisStatus.Moving)
|
||||
return MotionResult.Fail("轴正在运动中,拒绝重复命令");
|
||||
|
||||
if (speed.HasValue)
|
||||
_signalService.EnqueueWrite(_speedSignal, (float)speed.Value);
|
||||
_signalService.EnqueueWrite(_writeSignal, (float)target);
|
||||
Status = AxisStatus.Moving;
|
||||
return MotionResult.Ok();
|
||||
}
|
||||
```
|
||||
|
||||
**PLC 信号地址**:
|
||||
|
||||
| 轴 | 目标位置信号 | 地址 | 速度信号 | 地址 |
|
||||
|----|-------------|------|---------|------|
|
||||
| SourceZ | `MC_SourceZ_Target` | 10 | `MC_SourceZ_Speed` | 14 |
|
||||
| DetectorZ | `MC_DetZ_Target` | 22 | `MC_DetZ_Speed` | 26 |
|
||||
| StageX | `MC_StageX_Target` | 34 | `MC_StageX_Speed` | 38 |
|
||||
| StageY | `MC_StageY_Target` | 46 | `MC_StageY_Speed` | 50 |
|
||||
| DetectorSwing | `MC_DetSwing_Target` | 58 | `MC_DetSwing_Speed` | 62 |
|
||||
| StageRotation | `MC_StageRot_Target` | 70 | `MC_StageRot_Speed` | 74 |
|
||||
| FixtureRotation | `MC_FixRot_Target` | 82 | `MC_FixRot_Speed` | 86 |
|
||||
|
||||
### 2.4 步进移动 | Step Move
|
||||
|
||||
上下箭头键触发 `StepPosition(propertyName, delta)`:
|
||||
|
||||
```csharp
|
||||
public void StepPosition(string propertyName, double delta)
|
||||
{
|
||||
var currentValue = GetPropertyValue(propertyName);
|
||||
var newValue = currentValue + delta;
|
||||
SetPropertyValue(propertyName, newValue);
|
||||
SafeRun(() =>
|
||||
{
|
||||
MotionResult result;
|
||||
if (SZDZLock && (propertyName == nameof(SourceZPosition) || propertyName == nameof(DetectorZPosition)))
|
||||
{
|
||||
result = SendSourceDetectorZMoveCommand(newValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = SendMoveCommand(propertyName, newValue);
|
||||
}
|
||||
if (!result.Success)
|
||||
_logger.Warn("步进移动失败:{Property},原因={Reason}", propertyName, result.ErrorMessage);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 射线源/探测器Z轴联动 | Source-Detector Z-axis Linkage
|
||||
|
||||
### 3.1 联动使能 | Linkage Enable
|
||||
|
||||
点击"SZDZLock"按钮切换联动状态:
|
||||
|
||||
```csharp
|
||||
private void ExecuteSZDZLock()
|
||||
{
|
||||
// 切换联动状态
|
||||
SZDZLock = !SZDZLock;
|
||||
|
||||
// 调用服务设置联动
|
||||
var result = _motionControlService.SetSourceDetectorZLinkage(SZDZLock);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
// 如果设置失败,恢复状态
|
||||
SZDZLock = !SZDZLock;
|
||||
MessageBox.Show(result.ErrorMessage, ...);
|
||||
}
|
||||
}
|
||||
|
||||
// MotionControlService.SetSourceDetectorZLinkage
|
||||
public MotionResult SetSourceDetectorZLinkage(bool enabled)
|
||||
{
|
||||
var config = _config.SourceDetectorZLinkage;
|
||||
if (!config.Enabled)
|
||||
return MotionResult.Fail("射线源与探测器Z轴联动未启用");
|
||||
|
||||
var result = _signalService.EnqueueWrite(MotionSignalNames.SourceDetZ_Linkage_Enable, (bool)enabled);
|
||||
return result ? MotionResult.Ok() : MotionResult.Fail("联动使能写入失败");
|
||||
}
|
||||
```
|
||||
|
||||
另外提供公开方法 `SetSZDZLinkageToPlc()` 供外部直接同步当前联动状态到 PLC:
|
||||
|
||||
```csharp
|
||||
public MotionResult SetSZDZLinkageToPlc()
|
||||
{
|
||||
return _motionControlService.SetSourceDetectorZLinkage(SZDZLock);
|
||||
}
|
||||
```
|
||||
|
||||
**PLC 信号**:
|
||||
|
||||
| 信号名 | 地址 | 类型 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| `MC_SourceDetZ_Linkage_Enable` | 101 | bool | 联动使能(true=启用, false=禁用) |
|
||||
|
||||
### 3.2 联动移动 | Linkage Move
|
||||
|
||||
当 SZDZLock=true 时,移动 SourceZ 或 DetectorZ 会同时移动两个轴,保持位移量相同:
|
||||
|
||||
```csharp
|
||||
private MotionResult SendSourceDetectorZMoveCommand(double targetValue)
|
||||
{
|
||||
// 1. 检查联动是否在配置中启用
|
||||
if (!_config.SourceDetectorZLinkage.Enabled)
|
||||
return MotionResult.Fail("射线源与探测器Z轴联动未启用");
|
||||
|
||||
// 2. 获取两个轴并检查是否都在空闲状态
|
||||
var sourceZAxis = _motionSystem.GetLinearAxis(AxisId.SourceZ);
|
||||
var detectorZAxis = _motionSystem.GetLinearAxis(AxisId.DetectorZ);
|
||||
|
||||
if (sourceZAxis.Status == AxisStatus.Moving)
|
||||
return MotionResult.Fail("射线源Z轴正在运动中,无法联动移动");
|
||||
if (detectorZAxis.Status == AxisStatus.Moving)
|
||||
return MotionResult.Fail("探测器Z轴正在运动中,无法联动移动");
|
||||
|
||||
// 3. 计算位移量和目标位置
|
||||
var currentSourceZ = sourceZAxis.ActualPosition;
|
||||
var currentDetectorZ = detectorZAxis.ActualPosition;
|
||||
var sourceDelta = targetValue - currentSourceZ;
|
||||
var targetDetectorZ = currentDetectorZ + sourceDelta;
|
||||
|
||||
// 4. 边界检查(使用配置中的 Min/Max,收集所有错误后统一返回)
|
||||
if (_config.LinearAxes.TryGetValue(AxisId.SourceZ, out var sourceConfig) &&
|
||||
_config.LinearAxes.TryGetValue(AxisId.DetectorZ, out var detectorConfig))
|
||||
{
|
||||
var errors = new List<string>();
|
||||
if (targetValue < sourceConfig.Min || targetValue > sourceConfig.Max)
|
||||
errors.Add("射线源Z轴目标位置超出范围");
|
||||
if (targetDetectorZ < detectorConfig.Min || targetDetectorZ > detectorConfig.Max)
|
||||
errors.Add("探测器Z轴目标位置超出范围");
|
||||
if (errors.Count > 0)
|
||||
return MotionResult.Fail(string.Join("; ", errors));
|
||||
}
|
||||
|
||||
// 5. 同时发送两个轴的移动命令(通过轴实现层写入 PLC)
|
||||
var sourceResult = sourceZAxis.MoveToTarget(targetValue, _config.DefaultVelocity);
|
||||
var detectorResult = detectorZAxis.MoveToTarget(targetDetectorZ, _config.DefaultVelocity);
|
||||
|
||||
if (!sourceResult.Success) return sourceResult;
|
||||
if (!detectorResult.Success) return detectorResult;
|
||||
return MotionResult.Ok();
|
||||
}
|
||||
```
|
||||
|
||||
**PLC 信号下发**:
|
||||
|
||||
1. **SourceZ 移动**:
|
||||
- `MC_SourceZ_Speed` = DefaultVelocity(地址 14)
|
||||
- `MC_SourceZ_Target` = targetValue(地址 10)
|
||||
|
||||
2. **DetectorZ 移动**:
|
||||
- `MC_DetZ_Speed` = DefaultVelocity(地址 26)
|
||||
- `MC_DetZ_Target` = currentDetectorZ + (targetValue - currentSourceZ)(地址 22)
|
||||
|
||||
### 3.3 联动 Jog | Linkage Jog
|
||||
|
||||
当 SZDZLock=true 时,单轴摇杆的左右键会同时控制两个轴:
|
||||
|
||||
```csharp
|
||||
private void HandleSingleJoystickOutput()
|
||||
{
|
||||
switch (SingleJoystickActiveButton)
|
||||
{
|
||||
case MouseButtonType.Left:
|
||||
UpdateLinearJog(AxisId.SourceZ, SingleJoystickOutputY);
|
||||
if (_szdzLock)
|
||||
UpdateLinearJog(AxisId.DetectorZ, SingleJoystickOutputY);
|
||||
break;
|
||||
case MouseButtonType.Right:
|
||||
UpdateLinearJog(AxisId.DetectorZ, SingleJoystickOutputY);
|
||||
if (_szdzLock)
|
||||
UpdateLinearJog(AxisId.SourceZ, SingleJoystickOutputY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**PLC 信号下发**:
|
||||
|
||||
- **SourceZ Jog**:
|
||||
- `MC_SourceZ_Speed` = actualSpeed(地址 14)
|
||||
- `MC_SourceZ_JogPos`/`MC_SourceZ_JogNeg` = true(地址 18/19)
|
||||
|
||||
- **DetectorZ Jog**:
|
||||
- `MC_DetZ_Speed` = actualSpeed(地址 26)
|
||||
- `MC_DetZ_JogPos`/`MC_DetZ_JogNeg` = true(地址 30/31)
|
||||
|
||||
|
||||
## 4. 虚拟摇杆使能 | Virtual Joystick Enable
|
||||
|
||||
点击"使能开关"按钮切换虚拟摇杆使能状态:
|
||||
|
||||
```csharp
|
||||
private void ExecuteToggleEnable()
|
||||
{
|
||||
IsJoystickEnabled = !IsJoystickEnabled;
|
||||
|
||||
var result = _motionControlService.SetVirtualJoystickEnable(IsJoystickEnabled);
|
||||
if (!result.Success)
|
||||
{
|
||||
MessageBox.Show(result.ErrorMessage, ...);
|
||||
}
|
||||
}
|
||||
|
||||
// MotionControlService.SetVirtualJoystickEnable
|
||||
public MotionResult SetVirtualJoystickEnable(bool enabled)
|
||||
{
|
||||
var result = _signalService.EnqueueWrite(MotionSignalNames.VirtualJoystick_Enable, (bool)enabled);
|
||||
return result ? MotionResult.Ok() : MotionResult.Fail("虚拟摇杆使能写入失败");
|
||||
}
|
||||
```
|
||||
|
||||
**PLC 信号**:
|
||||
|
||||
| 信号名 | 地址 | 类型 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| `MC_VirtualJoystick_Enable` | 111 | bool | 虚拟摇杆使能(true=启用, false=禁用) |
|
||||
|
||||
## 5. 鼠标按键交换 | Mouse Button Swap
|
||||
|
||||
点击"交换按键"按钮切换摇杆左右键功能映射:
|
||||
|
||||
```csharp
|
||||
private void ExecuteToggleSwapMouseButtons()
|
||||
{
|
||||
SwapMouseButtons = !SwapMouseButtons;
|
||||
}
|
||||
```
|
||||
|
||||
此功能为纯 UI 层逻辑,不涉及 PLC 信号写入。当 `SwapMouseButtons=true` 时,摇杆控件内部交换左右键的功能映射。
|
||||
|
||||
## 6. 保存/恢复轴位置 | Save/Restore Axis Positions
|
||||
|
||||
### 6.1 保存当前位置 | Save Current Positions
|
||||
|
||||
```csharp
|
||||
private void ExecuteSavePositions()
|
||||
{
|
||||
_savedPositions = new SavedPositions
|
||||
{
|
||||
StageX = StageXPosition,
|
||||
StageY = StageYPosition,
|
||||
SourceZ = SourceZPosition,
|
||||
DetectorZ = DetectorZPosition,
|
||||
DetectorSwing = DetectorSwingAngle,
|
||||
StageRotation = StageRotationAngle,
|
||||
FixtureRotation = FixtureRotationAngle
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 恢复保存的位置 | Restore Saved Positions
|
||||
|
||||
恢复时会同时向所有轴发送移动命令:
|
||||
|
||||
```csharp
|
||||
private void ExecuteRestorePositions()
|
||||
{
|
||||
if (_savedPositions == null) return;
|
||||
|
||||
// 恢复到输入框
|
||||
StageXPosition = _savedPositions.StageX;
|
||||
StageYPosition = _savedPositions.StageY;
|
||||
SourceZPosition = _savedPositions.SourceZ;
|
||||
DetectorZPosition = _savedPositions.DetectorZ;
|
||||
DetectorSwingAngle = _savedPositions.DetectorSwing;
|
||||
StageRotationAngle = _savedPositions.StageRotation;
|
||||
FixtureRotationAngle = _savedPositions.FixtureRotation;
|
||||
|
||||
// 发送移动命令(通过 MotionControlService → PlcLinearAxis/PlcRotaryAxis → PLC)
|
||||
_motionControlService.MoveToTarget(AxisId.StageX, _savedPositions.StageX);
|
||||
_motionControlService.MoveToTarget(AxisId.StageY, _savedPositions.StageY);
|
||||
_motionControlService.MoveToTarget(AxisId.SourceZ, _savedPositions.SourceZ);
|
||||
_motionControlService.MoveToTarget(AxisId.DetectorZ, _savedPositions.DetectorZ);
|
||||
_motionControlService.MoveRotaryToTarget(RotaryAxisId.DetectorSwing, _savedPositions.DetectorSwing);
|
||||
_motionControlService.MoveRotaryToTarget(RotaryAxisId.StageRotation, _savedPositions.StageRotation);
|
||||
_motionControlService.MoveRotaryToTarget(RotaryAxisId.FixtureRotation, _savedPositions.FixtureRotation);
|
||||
}
|
||||
```
|
||||
|
||||
**PLC 信号下发**:恢复时向所有 7 个轴写入目标位置和速度信号(参见第 2.3 节信号地址表)。
|
||||
|
||||
## 7. 安全参数 | Safety Parameters
|
||||
|
||||
ViewModel 提供以下安全参数属性:
|
||||
|
||||
| 属性 | 说明 |
|
||||
|------|------|
|
||||
| `SafetyHeight` | 探测器安全高度限定值 |
|
||||
| `CalibrationValue` | 校准自动计算值 |
|
||||
|
||||
```csharp
|
||||
public void ConfirmSafetyHeight()
|
||||
{
|
||||
_logger.Info("探测器安全高度限定值已保存:{Value}", SafetyHeight);
|
||||
}
|
||||
|
||||
public void ConfirmCalibrationValue()
|
||||
{
|
||||
_logger.Info("校准自动计算值已保存:{Value}", CalibrationValue);
|
||||
}
|
||||
```
|
||||
|
||||
> 注:当前实现仅记录日志,未写入 PLC 信号。后续可能扩展为写入 PLC 安全参数区域。
|
||||
|
||||
## 8. PLC 断连安全处理 | PLC Disconnection Safety
|
||||
|
||||
当 PLC 连接断开时,ViewModel 自动执行以下安全操作:
|
||||
|
||||
```csharp
|
||||
private void OnPlcConnectionChanged()
|
||||
{
|
||||
IsPlcConnected = _plcService.IsConnected;
|
||||
|
||||
if (!_plcService.IsConnected)
|
||||
{
|
||||
// 1. 停止所有活跃的 Jog 操作(标记为停止)
|
||||
foreach (var axisId in _linearJogActive.Keys)
|
||||
if (_linearJogActive[axisId])
|
||||
_linearJogActive[axisId] = false;
|
||||
foreach (var axisId in _rotaryJogActive.Keys)
|
||||
if (_rotaryJogActive[axisId])
|
||||
_rotaryJogActive[axisId] = false;
|
||||
|
||||
// 2. 禁用摇杆
|
||||
IsJoystickEnabled = false;
|
||||
|
||||
// 3. 显示连接断开提示
|
||||
ErrorMessage = LocalizationHelper.Get("MC_PlcNotConnected");
|
||||
}
|
||||
else
|
||||
{
|
||||
// PLC 重连:清除错误信息(不自动启用摇杆,需用户手动开启)
|
||||
ErrorMessage = null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**安全策略**:
|
||||
- PLC 断连时立即标记所有 Jog 为停止状态
|
||||
- 禁用虚拟摇杆,防止用户误操作
|
||||
- PLC 重连后不自动恢复使能,需用户手动确认后开启
|
||||
|
||||
## 9. 实体摇杆状态 | Physical Joystick Status
|
||||
|
||||
通过 `JoystickActiveEvent` 事件订阅实体摇杆的激活状态:
|
||||
|
||||
```csharp
|
||||
_eventAggregator.GetEvent<JoystickActiveEvent>().Subscribe(OnJoystickActiveChanged, ThreadOption.UIThread);
|
||||
|
||||
private void OnJoystickActiveChanged(bool isActive)
|
||||
{
|
||||
IsJoystickActive = isActive;
|
||||
}
|
||||
```
|
||||
|
||||
**PLC 信号(读取)**:
|
||||
|
||||
| 信号名 | 说明 |
|
||||
|--------|------|
|
||||
| `MC_Joystick_Active` | 实体摇杆输入激活状态(由 PLC 轮询读取) |
|
||||
|
||||
## 10. 旋转轴可见性控制 | Rotary Axis Visibility Control
|
||||
|
||||
根据配置动态控制旋转轴输入框的可见性:
|
||||
|
||||
```csharp
|
||||
DetectorSwingVisibility = _config.RotaryAxes.ContainsKey(RotaryAxisId.DetectorSwing)
|
||||
&& _config.RotaryAxes[RotaryAxisId.DetectorSwing].Enabled
|
||||
? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
StageRotationVisibility = _config.RotaryAxes.ContainsKey(RotaryAxisId.StageRotation)
|
||||
&& _config.RotaryAxes[RotaryAxisId.StageRotation].Enabled
|
||||
? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
FixtureRotationVisibility = _config.RotaryAxes.ContainsKey(RotaryAxisId.FixtureRotation)
|
||||
&& _config.RotaryAxes[RotaryAxisId.FixtureRotation].Enabled
|
||||
? Visibility.Visible : Visibility.Collapsed;
|
||||
```
|
||||
|
||||
此功能为纯 UI 层逻辑,不涉及 PLC 信号。
|
||||
|
||||
## 11. 信号写入队列机制 | Signal Write Queue Mechanism
|
||||
|
||||
所有 PLC 写入操作通过 `ISignalDataService.EnqueueWrite()` 进入写入队列:
|
||||
|
||||
```csharp
|
||||
public interface ISignalDataService
|
||||
{
|
||||
bool EnqueueWrite(string signalName, object value);
|
||||
bool EnqueueWriteBatch(Dictionary<string, object> writes);
|
||||
T GetValueByName<T>(string signalName);
|
||||
}
|
||||
```
|
||||
|
||||
**队列处理流程**:
|
||||
|
||||
1. 轴实现层(`PlcLinearAxis`/`PlcRotaryAxis`)调用 `EnqueueWrite(signalName, value)`
|
||||
2. 信号数据服务将写入请求加入队列
|
||||
3. PLC 服务在轮询周期(默认 100ms)中批量写入
|
||||
4. 写入成功后从队列移除
|
||||
|
||||
**优势**:
|
||||
|
||||
- 批量写入减少 PLC 通讯次数
|
||||
- 避免频繁写入导致的通讯拥塞
|
||||
- 统一的错误处理和重试机制
|
||||
|
||||
## 12. 完整 PLC 信号名称常量 | Complete PLC Signal Name Constants
|
||||
|
||||
定义在 `MotionSignalNames.cs` 中:
|
||||
|
||||
| 分类 | 常量名 | 信号名 | 方向 |
|
||||
|------|--------|--------|------|
|
||||
| 联动 | `SourceDetZ_Linkage_Enable` | `MC_SourceDetZ_Linkage_Enable` | 写入 |
|
||||
| 使能 | `VirtualJoystick_Enable` | `MC_VirtualJoystick_Enable` | 写入 |
|
||||
| 状态 | `Joystick_Active` | `MC_Joystick_Active` | 读取 |
|
||||
| SourceZ | `SourceZ_Pos` | `MC_SourceZ_Pos` | 读取 |
|
||||
| SourceZ | `SourceZ_Target` | `MC_SourceZ_Target` | 写入 |
|
||||
| SourceZ | `SourceZ_Speed` | `MC_SourceZ_Speed` | 写入 |
|
||||
| SourceZ | `SourceZ_JogPos` | `MC_SourceZ_JogPos` | 写入 |
|
||||
| SourceZ | `SourceZ_JogNeg` | `MC_SourceZ_JogNeg` | 写入 |
|
||||
| SourceZ | `SourceZ_Home` | `MC_SourceZ_Home` | 写入 |
|
||||
| SourceZ | `SourceZ_Stop` | `MC_SourceZ_Stop` | 写入 |
|
||||
| DetectorZ | `DetZ_Pos` | `MC_DetZ_Pos` | 读取 |
|
||||
| DetectorZ | `DetZ_Target` | `MC_DetZ_Target` | 写入 |
|
||||
| DetectorZ | `DetZ_Speed` | `MC_DetZ_Speed` | 写入 |
|
||||
| DetectorZ | `DetZ_JogPos` | `MC_DetZ_JogPos` | 写入 |
|
||||
| DetectorZ | `DetZ_JogNeg` | `MC_DetZ_JogNeg` | 写入 |
|
||||
| DetectorZ | `DetZ_Home` | `MC_DetZ_Home` | 写入 |
|
||||
| DetectorZ | `DetZ_Stop` | `MC_DetZ_Stop` | 写入 |
|
||||
| StageX | `StageX_Pos` | `MC_StageX_Pos` | 读取 |
|
||||
| StageX | `StageX_Target` | `MC_StageX_Target` | 写入 |
|
||||
| StageX | `StageX_Speed` | `MC_StageX_Speed` | 写入 |
|
||||
| StageX | `StageX_JogPos` | `MC_StageX_JogPos` | 写入 |
|
||||
| StageX | `StageX_JogNeg` | `MC_StageX_JogNeg` | 写入 |
|
||||
| StageX | `StageX_Home` | `MC_StageX_Home` | 写入 |
|
||||
| StageX | `StageX_Stop` | `MC_StageX_Stop` | 写入 |
|
||||
| StageY | `StageY_Pos` | `MC_StageY_Pos` | 读取 |
|
||||
| StageY | `StageY_Target` | `MC_StageY_Target` | 写入 |
|
||||
| StageY | `StageY_Speed` | `MC_StageY_Speed` | 写入 |
|
||||
| StageY | `StageY_JogPos` | `MC_StageY_JogPos` | 写入 |
|
||||
| StageY | `StageY_JogNeg` | `MC_StageY_JogNeg` | 写入 |
|
||||
| StageY | `StageY_Home` | `MC_StageY_Home` | 写入 |
|
||||
| StageY | `StageY_Stop` | `MC_StageY_Stop` | 写入 |
|
||||
| DetSwing | `DetSwing_Angle` | `MC_DetSwing_Angle` | 读取 |
|
||||
| DetSwing | `DetSwing_Target` | `MC_DetSwing_Target` | 写入 |
|
||||
| DetSwing | `DetSwing_Speed` | `MC_DetSwing_Speed` | 写入 |
|
||||
| DetSwing | `DetSwing_JogPos` | `MC_DetSwing_JogPos` | 写入 |
|
||||
| DetSwing | `DetSwing_JogNeg` | `MC_DetSwing_JogNeg` | 写入 |
|
||||
| DetSwing | `DetSwing_Home` | `MC_DetSwing_Home` | 写入 |
|
||||
| DetSwing | `DetSwing_Stop` | `MC_DetSwing_Stop` | 写入 |
|
||||
| StageRot | `StageRot_Angle` | `MC_StageRot_Angle` | 读取 |
|
||||
| StageRot | `StageRot_Target` | `MC_StageRot_Target` | 写入 |
|
||||
| StageRot | `StageRot_Speed` | `MC_StageRot_Speed` | 写入 |
|
||||
| StageRot | `StageRot_JogPos` | `MC_StageRot_JogPos` | 写入 |
|
||||
| StageRot | `StageRot_JogNeg` | `MC_StageRot_JogNeg` | 写入 |
|
||||
| StageRot | `StageRot_Home` | `MC_StageRot_Home` | 写入 |
|
||||
| StageRot | `StageRot_Stop` | `MC_StageRot_Stop` | 写入 |
|
||||
| FixRot | `FixRot_Angle` | `MC_FixRot_Angle` | 读取 |
|
||||
| FixRot | `FixRot_Target` | `MC_FixRot_Target` | 写入 |
|
||||
| FixRot | `FixRot_Speed` | `MC_FixRot_Speed` | 写入 |
|
||||
| FixRot | `FixRot_JogPos` | `MC_FixRot_JogPos` | 写入 |
|
||||
| FixRot | `FixRot_JogNeg` | `MC_FixRot_JogNeg` | 写入 |
|
||||
| FixRot | `FixRot_Home` | `MC_FixRot_Home` | 写入 |
|
||||
| FixRot | `FixRot_Stop` | `MC_FixRot_Stop` | 写入 |
|
||||
| 安全门 | `Door_Open` | `MC_Door_Open` | 写入 |
|
||||
| 安全门 | `Door_Close` | `MC_Door_Close` | 写入 |
|
||||
| 安全门 | `Door_Stop` | `MC_Door_Stop` | 写入 |
|
||||
| 安全门 | `Door_Status` | `MC_Door_Status` | 读取 |
|
||||
| 安全门 | `Door_Interlock` | `MC_Door_Interlock` | 读取 |
|
||||
| 轴复位 | `Axis_Reset` | `MC_Axis_Reset` | 写入 |
|
||||
| 轴复位 | `Axis_ResetDone` | `MC_Axis_ResetDone` | 读取 |
|
||||
|
||||
---
|
||||
@@ -83,7 +83,7 @@ namespace XP.Hardware.MotionControl.ViewModels
|
||||
// 初始化命令 | Initialize commands
|
||||
ToggleEnableCommand = new DelegateCommand(ExecuteToggleEnable, () => IsPlcConnected);
|
||||
ToggleSwapMouseButtonsCommand = new DelegateCommand(ExecuteToggleSwapMouseButtons);
|
||||
SavePositionsCommand = new DelegateCommand(ExecuteSavePositions);
|
||||
SavePositionsCommand = new DelegateCommand(ExecuteSavePositions, () => IsPlcConnected);
|
||||
RestorePositionsCommand = new DelegateCommand(ExecuteRestorePositions, () => _savedPositions != null && IsPlcConnected);
|
||||
// 射线源与探测器Z轴联动命令 | Source-Detector Z-axis linkage command
|
||||
SZDZLockCommand = new DelegateCommand(() => SafeRun(ExecuteSZDZLock), () => IsPlcConnected);
|
||||
@@ -125,11 +125,7 @@ namespace XP.Hardware.MotionControl.ViewModels
|
||||
public double DualJoystickOutputX
|
||||
{
|
||||
get => _dualJoystickOutputX;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _dualJoystickOutputX, value))
|
||||
HandleDualJoystickOutput();
|
||||
}
|
||||
set => SetProperty(ref _dualJoystickOutputX, value);
|
||||
}
|
||||
|
||||
private double _dualJoystickOutputY;
|
||||
@@ -430,7 +426,7 @@ namespace XP.Hardware.MotionControl.ViewModels
|
||||
if (!_plcService.IsConnected)
|
||||
{
|
||||
// PLC 断开:停止所有活跃的 Jog 操作 | PLC disconnected: stop all active jog operations
|
||||
foreach (var axisId in _linearJogActive.Keys)
|
||||
foreach (var axisId in new List<AxisId>(_linearJogActive.Keys))
|
||||
{
|
||||
if (_linearJogActive[axisId])
|
||||
{
|
||||
@@ -438,7 +434,7 @@ namespace XP.Hardware.MotionControl.ViewModels
|
||||
_logger.Debug("PLC 断开,直线轴 Jog 已标记停止:{AxisId} | PLC disconnected, linear axis jog marked stopped: {AxisId}", axisId);
|
||||
}
|
||||
}
|
||||
foreach (var axisId in _rotaryJogActive.Keys)
|
||||
foreach (var axisId in new List<RotaryAxisId>(_rotaryJogActive.Keys))
|
||||
{
|
||||
if (_rotaryJogActive[axisId])
|
||||
{
|
||||
@@ -484,12 +480,16 @@ namespace XP.Hardware.MotionControl.ViewModels
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
// 写入失败,回滚状态 | Write failed, rollback state
|
||||
IsJoystickEnabled = !IsJoystickEnabled;
|
||||
MessageBox.Show(result.ErrorMessage, XP.Common.Localization.LocalizationHelper.Get("MC_Error"),
|
||||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 异常时回滚状态 | Rollback state on exception
|
||||
IsJoystickEnabled = !IsJoystickEnabled;
|
||||
MessageBox.Show(ex.Message, XP.Common.Localization.LocalizationHelper.Get("MC_Error"),
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
@@ -831,7 +831,7 @@ namespace XP.Hardware.MotionControl.ViewModels
|
||||
// 如果射线源与探测器Z轴联动,且操作的是SourceZ或DetectorZ,则同时发送两个轴
|
||||
if (SZDZLock && (propertyName == nameof(SourceZPosition) || propertyName == nameof(DetectorZPosition)))
|
||||
{
|
||||
result = SendSourceDetectorZMoveCommand(value);
|
||||
result = SendSourceDetectorZMoveCommand(value, propertyName);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -873,7 +873,7 @@ namespace XP.Hardware.MotionControl.ViewModels
|
||||
// 如果射线源与探测器Z轴联动,且操作的是SourceZ或DetectorZ,则同时步进两个轴
|
||||
if (SZDZLock && (propertyName == nameof(SourceZPosition) || propertyName == nameof(DetectorZPosition)))
|
||||
{
|
||||
result = SendSourceDetectorZMoveCommand(newValue);
|
||||
result = SendSourceDetectorZMoveCommand(newValue, propertyName);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -920,7 +920,7 @@ namespace XP.Hardware.MotionControl.ViewModels
|
||||
/// </summary>
|
||||
/// <param name="targetValue">目标位置 | Target position</param>
|
||||
/// <returns>操作结果 | Operation result</returns>
|
||||
private MotionResult SendSourceDetectorZMoveCommand(double targetValue)
|
||||
private MotionResult SendSourceDetectorZMoveCommand(double targetValue, string sourcePropertyName = null)
|
||||
{
|
||||
// 1. 检查联动是否在配置中启用 | Check if linkage is enabled in config
|
||||
if (!_config.SourceDetectorZLinkage.Enabled)
|
||||
@@ -945,11 +945,27 @@ namespace XP.Hardware.MotionControl.ViewModels
|
||||
return MotionResult.Fail("探测器Z轴正在运动中,无法联动移动 | Detector Z-axis is moving, linkage move rejected");
|
||||
}
|
||||
|
||||
// 3. 计算位移量和目标位置 | Calculate displacement and target positions
|
||||
// 3. 根据编辑来源计算位移量和目标位置 | Calculate displacement and targets based on edit source
|
||||
var currentSourceZ = sourceZAxis.ActualPosition;
|
||||
var currentDetectorZ = detectorZAxis.ActualPosition;
|
||||
var sourceDelta = targetValue - currentSourceZ;
|
||||
var targetDetectorZ = currentDetectorZ + sourceDelta;
|
||||
|
||||
double targetSourceZ;
|
||||
double targetDetectorZ;
|
||||
|
||||
if (sourcePropertyName == nameof(DetectorZPosition))
|
||||
{
|
||||
// 用户编辑的是探测器Z:以探测器Z为基准计算位移 | User edited DetectorZ: calculate delta from DetectorZ
|
||||
var delta = targetValue - currentDetectorZ;
|
||||
targetDetectorZ = targetValue;
|
||||
targetSourceZ = currentSourceZ + delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 用户编辑的是射线源Z(默认):以射线源Z为基准计算位移 | User edited SourceZ (default): calculate delta from SourceZ
|
||||
var delta = targetValue - currentSourceZ;
|
||||
targetSourceZ = targetValue;
|
||||
targetDetectorZ = currentDetectorZ + delta;
|
||||
}
|
||||
|
||||
// 4. 边界检查(使用配置中的 Min/Max)| Boundary check (use Min/Max from config)
|
||||
if (_config.LinearAxes.TryGetValue(AxisId.SourceZ, out var sourceConfig) &&
|
||||
@@ -957,10 +973,10 @@ namespace XP.Hardware.MotionControl.ViewModels
|
||||
{
|
||||
var errors = new List<string>();
|
||||
|
||||
if (targetValue < sourceConfig.Min || targetValue > sourceConfig.Max)
|
||||
if (targetSourceZ < sourceConfig.Min || targetSourceZ > sourceConfig.Max)
|
||||
{
|
||||
errors.Add($"射线源Z轴目标位置 {targetValue} 超出范围 [{sourceConfig.Min}, {sourceConfig.Max}] | " +
|
||||
$"Source Z-axis target {targetValue} out of range [{sourceConfig.Min}, {sourceConfig.Max}]");
|
||||
errors.Add($"射线源Z轴目标位置 {targetSourceZ} 超出范围 [{sourceConfig.Min}, {sourceConfig.Max}] | " +
|
||||
$"Source Z-axis target {targetSourceZ} out of range [{sourceConfig.Min}, {sourceConfig.Max}]");
|
||||
}
|
||||
|
||||
if (targetDetectorZ < detectorConfig.Min || targetDetectorZ > detectorConfig.Max)
|
||||
@@ -983,7 +999,7 @@ namespace XP.Hardware.MotionControl.ViewModels
|
||||
}
|
||||
|
||||
// 5. 所有检查通过,同时发送两个轴的移动命令 | All checks passed, send move commands to both axes simultaneously
|
||||
var sourceResult = sourceZAxis.MoveToTarget(targetValue, _config.DefaultVelocity);
|
||||
var sourceResult = sourceZAxis.MoveToTarget(targetSourceZ, _config.DefaultVelocity);
|
||||
var detectorResult = detectorZAxis.MoveToTarget(targetDetectorZ, _config.DefaultVelocity);
|
||||
|
||||
// 6. 返回结果(任一失败都记录日志)| Return result (log if any fails)
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<Config>
|
||||
<Group ID="WriteCommon" DBNumber="31">
|
||||
<Signal Name="SoftLive" Type="byte" StartAddr="0" IndexOrLength="" Remark="软件心跳,01周期变化表示PLC存活" />
|
||||
<Signal Name="MC_SourceZ_Target" Type="single" StartAddr="10" IndexOrLength="" Remark="射线源Z目标位置" />
|
||||
<Signal Name="MC_SourceZ_Speed" Type="single" StartAddr="14" IndexOrLength="" Remark="射线源Z运动速度" />
|
||||
<Signal Name="MC_SourceZ_JogPos" Type="byte" StartAddr="18" IndexOrLength="" Remark="射线源Z正向Jog,0:缺省,1:正向点动" />
|
||||
<Signal Name="MC_SourceZ_JogNeg" Type="byte" StartAddr="19" IndexOrLength="" Remark="射线源Z反向Jog,0:缺省,1:反向点动" />
|
||||
<Signal Name="MC_SourceZ_Home" Type="byte" StartAddr="20" IndexOrLength="" Remark="射线源Z回零,0:缺省,1:触发回零" />
|
||||
<Signal Name="MC_SourceZ_Stop" Type="byte" StartAddr="21" IndexOrLength="" Remark="射线源Z停止,0:缺省,1:触发停止" />
|
||||
<Signal Name="MC_DetZ_Target" Type="single" StartAddr="22" IndexOrLength="" Remark="探测器Z目标位置" />
|
||||
<Signal Name="MC_DetZ_Speed" Type="single" StartAddr="26" IndexOrLength="" Remark="探测器Z运动速度" />
|
||||
<Signal Name="MC_DetZ_JogPos" Type="byte" StartAddr="30" IndexOrLength="" Remark="探测器Z正向Jog,0:缺省,1:正向点动" />
|
||||
<Signal Name="MC_DetZ_JogNeg" Type="byte" StartAddr="31" IndexOrLength="" Remark="探测器Z反向Jog,0:缺省,1:反向点动" />
|
||||
<Signal Name="MC_DetZ_Home" Type="byte" StartAddr="32" IndexOrLength="" Remark="探测器Z回零,0:缺省,1:触发回零" />
|
||||
<Signal Name="MC_DetZ_Stop" Type="byte" StartAddr="33" IndexOrLength="" Remark="探测器Z停止,0:缺省,1:触发停止" />
|
||||
<Signal Name="MC_StageX_Target" Type="single" StartAddr="34" IndexOrLength="" Remark="载物台X目标位置" />
|
||||
<Signal Name="MC_StageX_Speed" Type="single" StartAddr="38" IndexOrLength="" Remark="载物台X运动速度" />
|
||||
<Signal Name="MC_StageX_JogPos" Type="byte" StartAddr="42" IndexOrLength="" Remark="载物台X正向Jog,0:缺省,1:正向点动" />
|
||||
<Signal Name="MC_StageX_JogNeg" Type="byte" StartAddr="43" IndexOrLength="" Remark="载物台X反向Jog,0:缺省,1:反向点动" />
|
||||
<Signal Name="MC_StageX_Home" Type="byte" StartAddr="44" IndexOrLength="" Remark="载物台X回零,0:缺省,1:触发回零" />
|
||||
<Signal Name="MC_StageX_Stop" Type="byte" StartAddr="45" IndexOrLength="" Remark="载物台X停止,0:缺省,1:触发停止" />
|
||||
<Signal Name="MC_StageY_Target" Type="single" StartAddr="46" IndexOrLength="" Remark="载物台Y目标位置" />
|
||||
<Signal Name="MC_StageY_Speed" Type="single" StartAddr="50" IndexOrLength="" Remark="载物台Y运动速度" />
|
||||
<Signal Name="MC_StageY_JogPos" Type="byte" StartAddr="54" IndexOrLength="" Remark="载物台Y正向Jog,0:缺省,1:正向点动" />
|
||||
<Signal Name="MC_StageY_JogNeg" Type="byte" StartAddr="55" IndexOrLength="" Remark="载物台Y反向Jog,0:缺省,1:反向点动" />
|
||||
<Signal Name="MC_StageY_Home" Type="byte" StartAddr="56" IndexOrLength="" Remark="载物台Y回零,0:缺省,1:触发回零" />
|
||||
<Signal Name="MC_StageY_Stop" Type="byte" StartAddr="57" IndexOrLength="" Remark="载物台Y停止,0:缺省,1:触发停止" />
|
||||
<Signal Name="MC_DetSwing_Target" Type="single" StartAddr="58" IndexOrLength="" Remark="探测器摆动目标角度" />
|
||||
<Signal Name="MC_DetSwing_Speed" Type="single" StartAddr="62" IndexOrLength="" Remark="探测器摆动运动速度" />
|
||||
<Signal Name="MC_DetSwing_JogPos" Type="byte" StartAddr="66" IndexOrLength="" Remark="探测器摆动正向Jog,0:缺省,1:正向点动" />
|
||||
<Signal Name="MC_DetSwing_JogNeg" Type="byte" StartAddr="67" IndexOrLength="" Remark="探测器摆动反向Jog,0:缺省,1:反向点动" />
|
||||
<Signal Name="MC_DetSwing_Home" Type="byte" StartAddr="68" IndexOrLength="" Remark="探测器摆动回零,0:缺省,1:触发回零" />
|
||||
<Signal Name="MC_DetSwing_Stop" Type="byte" StartAddr="69" IndexOrLength="" Remark="探测器摆动停止,0:缺省,1:触发停止" />
|
||||
<Signal Name="MC_StageRot_Target" Type="single" StartAddr="70" IndexOrLength="" Remark="载物台旋转目标角度" />
|
||||
<Signal Name="MC_StageRot_Speed" Type="single" StartAddr="74" IndexOrLength="" Remark="载物台旋转运动速度" />
|
||||
<Signal Name="MC_StageRot_JogPos" Type="byte" StartAddr="78" IndexOrLength="" Remark="载物台旋转正向Jog,0:缺省,1:正向点动" />
|
||||
<Signal Name="MC_StageRot_JogNeg" Type="byte" StartAddr="79" IndexOrLength="" Remark="载物台旋转反向Jog,0:缺省,1:反向点动" />
|
||||
<Signal Name="MC_StageRot_Home" Type="byte" StartAddr="80" IndexOrLength="" Remark="载物台旋转回零,0:缺省,1:触发回零" />
|
||||
<Signal Name="MC_StageRot_Stop" Type="byte" StartAddr="81" IndexOrLength="" Remark="载物台旋转停止,0:缺省,1:触发停止" />
|
||||
<Signal Name="MC_FixRot_Target" Type="single" StartAddr="82" IndexOrLength="" Remark="夹具旋转目标角度" />
|
||||
<Signal Name="MC_FixRot_Speed" Type="single" StartAddr="86" IndexOrLength="" Remark="夹具旋转运动速度" />
|
||||
<Signal Name="MC_FixRot_JogPos" Type="byte" StartAddr="90" IndexOrLength="" Remark="夹具旋转正向Jog,0:缺省,1:正向点动" />
|
||||
<Signal Name="MC_FixRot_JogNeg" Type="byte" StartAddr="91" IndexOrLength="" Remark="夹具旋转反向Jog,0:缺省,1:反向点动" />
|
||||
<Signal Name="MC_FixRot_Home" Type="byte" StartAddr="92" IndexOrLength="" Remark="夹具旋转回零,0:缺省,1:触发回零" />
|
||||
<Signal Name="MC_FixRot_Stop" Type="byte" StartAddr="93" IndexOrLength="" Remark="夹具旋转停止,0:缺省,1:触发停止" />
|
||||
<Signal Name="MC_Door_Open" Type="byte" StartAddr="94" IndexOrLength="" Remark="安全门开门,0:缺省,1:触发开门" />
|
||||
<Signal Name="MC_Door_Close" Type="byte" StartAddr="95" IndexOrLength="" Remark="安全门关门,0:缺省,1:触发关门" />
|
||||
<Signal Name="MC_Door_Stop" Type="byte" StartAddr="96" IndexOrLength="" Remark="安全门停止,0:缺省,1:触发停止" />
|
||||
<Signal Name="MC_VirtualJoystick_Enable" Type="bool" StartAddr="111" IndexOrLength="" Remark="虚拟摇杆使能"/>
|
||||
<Signal Name="MC_SourceDetZ_Linkage_Enable" Type="bool" StartAddr="101" IndexOrLength="" Remark="联动使能"/>
|
||||
</Group>
|
||||
<Group ID="ReadCommon" DBNumber="31">
|
||||
<Signal Name="PlcLive" Type="byte" StartAddr="200" IndexOrLength="" Remark="PLC心跳,01周期变化表示PLC存活" />
|
||||
<Signal Name="PlcAlarm" Type="byte" StartAddr="201" IndexOrLength="" Remark="系统报警,0:缺省,10:有报警" />
|
||||
<Signal Name="MC_SourceZ_Pos" Type="single" StartAddr="100" IndexOrLength="" Remark="射线源Z实际位置" />
|
||||
<Signal Name="MC_DetZ_Pos" Type="single" StartAddr="104" IndexOrLength="" Remark="探测器Z实际位置" />
|
||||
<Signal Name="MC_StageX_Pos" Type="single" StartAddr="108" IndexOrLength="" Remark="载物台X实际位置" />
|
||||
<Signal Name="MC_StageY_Pos" Type="single" StartAddr="112" IndexOrLength="" Remark="载物台Y实际位置" />
|
||||
<Signal Name="MC_DetSwing_Angle" Type="single" StartAddr="116" IndexOrLength="" Remark="探测器摆动实际角度" />
|
||||
<Signal Name="MC_StageRot_Angle" Type="single" StartAddr="120" IndexOrLength="" Remark="载物台旋转实际角度" />
|
||||
<Signal Name="MC_FixRot_Angle" Type="single" StartAddr="124" IndexOrLength="" Remark="夹具旋转实际角度" />
|
||||
<Signal Name="MC_Door_Status" Type="byte" StartAddr="128" IndexOrLength="" Remark="安全门状态,0:未知,1:正在开门,2:已开,3:正在关门,4:已关,5:已锁定,6:故障" />
|
||||
<Signal Name="MC_Door_Interlock" Type="byte" StartAddr="130" IndexOrLength="" Remark="安全门联锁信号,0:缺省(无联锁),10:联锁有效(禁止开门)" />
|
||||
<Signal Name="MC_Joystick_Active" Type="bool" StartAddr="110" IndexOrLength="" Remark="实体摇杆输入"/>
|
||||
</Group>
|
||||
<Group ID="Status" DBNumber="4100">
|
||||
<Signal Name="ScanMode" Type="byte" StartAddr="201" IndexOrLength="" Remark="扫描模式,0:缺省(空闲),具体值由PLC定义" />
|
||||
</Group>
|
||||
</Config>
|
||||
@@ -0,0 +1,90 @@
|
||||
[sys1____]
|
||||
"SerialNumber"
|
||||
[geo_dm__#Cougar]
|
||||
"Name9"
|
||||
"Value9"
|
||||
"Name10"
|
||||
"Value10"
|
||||
"Name19"
|
||||
"Value19"
|
||||
"Name21"
|
||||
"Value21"
|
||||
"Name24"
|
||||
"Value24"
|
||||
"Name29"
|
||||
"Value29"
|
||||
"Name30"
|
||||
"Value30"
|
||||
"Name48"
|
||||
"Value48"
|
||||
[geo_dm__#Cheetah]
|
||||
"Name9"
|
||||
"Value9"
|
||||
"Name10"
|
||||
"Value10"
|
||||
"Name12"
|
||||
"Value12"
|
||||
"Name13"
|
||||
"Value13"
|
||||
"Name22"
|
||||
"Value22"
|
||||
"Name24"
|
||||
"Value24"
|
||||
"Name27"
|
||||
"Value27"
|
||||
"Name48"
|
||||
"Value48"
|
||||
[joyspeed]
|
||||
"Speed0"
|
||||
"Speed1"
|
||||
"Speed2"
|
||||
"Speed3"
|
||||
"Speed4"
|
||||
"Speed5"
|
||||
"Speed6"
|
||||
"Speed7"
|
||||
"Speed8"
|
||||
"Speed9"
|
||||
[loadpos_]
|
||||
"SafePos[3]"
|
||||
[para_1__]
|
||||
"PosSW_End"
|
||||
"NegSW_End"
|
||||
"RefPosition"
|
||||
[para_2__]
|
||||
"PosSW_End"
|
||||
"NegSW_End"
|
||||
"RefPosition"
|
||||
[para_3__]
|
||||
"PosSW_End"
|
||||
"NegSW_End"
|
||||
"RefPosition"
|
||||
[para_4__]
|
||||
"PosSW_End"
|
||||
"NegSW_End"
|
||||
"RefPosition"
|
||||
"RefPositionEnd"
|
||||
[para_5__]
|
||||
"PosSW_End"
|
||||
"NegSW_End"
|
||||
"RefPosition"
|
||||
[para_6__]
|
||||
"PosSW_End"
|
||||
"NegSW_End"
|
||||
"RefPosition"
|
||||
"DistPerTurn"
|
||||
[para_7__]
|
||||
"PosSW_End"
|
||||
"NegSW_End"
|
||||
"RefPosition"
|
||||
[para_8__]
|
||||
"PosSW_End"
|
||||
"NegSW_End"
|
||||
"RefPosition"
|
||||
[para_9__]
|
||||
"PosSW_End"
|
||||
"NegSW_End"
|
||||
"RefPosition"
|
||||
[dm_door_]
|
||||
"DoorOpenSwitchAvail#410"
|
||||
EOF
|
||||
@@ -0,0 +1,93 @@
|
||||
[MODEDM#all]
|
||||
"everything"
|
||||
"beginExceptions"
|
||||
"Version"
|
||||
"endExceptions"
|
||||
!*************************************************************
|
||||
[TARGETDM#all]
|
||||
"everything"
|
||||
"beginExceptions"
|
||||
"Version"
|
||||
"endExceptions"
|
||||
!*************************************************************
|
||||
[TUBEDM#all]
|
||||
"everything"
|
||||
"beginExceptions"
|
||||
"Version"
|
||||
"endExceptions"
|
||||
!*************************************************************
|
||||
[HSGDM#all]
|
||||
"everything"
|
||||
"beginExceptions"
|
||||
"Version"
|
||||
"endExceptions"
|
||||
!*************************************************************
|
||||
[SYSDM#all]
|
||||
"everything"
|
||||
"beginExceptions"
|
||||
"Version"
|
||||
"SoftwareVersionPLC"
|
||||
"SysConfig"
|
||||
"SoftwareVersion"
|
||||
"endExceptions"
|
||||
!*************************************************************
|
||||
[AMPDM#all]
|
||||
"everything"
|
||||
"beginExceptions"
|
||||
"Version"
|
||||
"endExceptions"
|
||||
!*************************************************************
|
||||
[VACDM#all]
|
||||
"everything"
|
||||
"beginExceptions"
|
||||
"Version_vacuum_system"
|
||||
"endExceptions"
|
||||
!*************************************************************
|
||||
[CENTDM#all]
|
||||
"everything"
|
||||
"beginExceptions"
|
||||
"Version"
|
||||
"endExceptions"
|
||||
!*************************************************************
|
||||
[FOCUSDM#all]
|
||||
"everything"
|
||||
"beginExceptions"
|
||||
"Version"
|
||||
"endExceptions"
|
||||
!*************************************************************
|
||||
[CONSDM#all]
|
||||
"everything"
|
||||
"beginExceptions"
|
||||
"Version"
|
||||
"endExceptions"
|
||||
!*************************************************************
|
||||
[TREGDM#all]
|
||||
"everything"
|
||||
"beginExceptions"
|
||||
"Version"
|
||||
"endExceptions"
|
||||
!*************************************************************
|
||||
[CONDDM#all]
|
||||
"everything"
|
||||
"beginExceptions"
|
||||
"Version"
|
||||
"endExceptions"
|
||||
!*************************************************************
|
||||
[FILDM#all]
|
||||
"everything"
|
||||
"beginExceptions"
|
||||
"Version"
|
||||
"endExceptions"
|
||||
!*************************************************************
|
||||
[TUBEHEADDM#all]
|
||||
"everything"
|
||||
"beginExceptions"
|
||||
"version"
|
||||
"endExceptions"
|
||||
!*************************************************************
|
||||
[INITDM#all]
|
||||
"everything"
|
||||
"beginExceptions"
|
||||
"version"
|
||||
"endExceptions"
|
||||
EOF
|
||||
@@ -0,0 +1,6 @@
|
||||
// Flag, ob die Trace-Meldungen asynchron zu protokolliern sind: 1 für asynchron, 0 für synchron.
|
||||
1
|
||||
// Kategorie Konfigurationen: <Kategorie-Name> <Enabled[0/1]>
|
||||
FXDriver 0
|
||||
FXDriverPviXCreateResponse 0
|
||||
FXDriverUpgradeCP1483ToCP1583 0
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,294 @@
|
||||
[XRaySystemErrors]
|
||||
ErrorNumber0=101
|
||||
ErrorString0="Data module init error"
|
||||
ErrorNumber1=102
|
||||
ErrorString1="Data module sys error"
|
||||
ErrorNumber2=103
|
||||
ErrorString2="Data module amp error"
|
||||
ErrorNumber3=301
|
||||
ErrorString3="Timeout during filament adjusting"
|
||||
ErrorNumber4=302
|
||||
ErrorString4="Timeout during warmup"
|
||||
ErrorNumber5=303
|
||||
ErrorString5="Error door control"
|
||||
ErrorNumber6=401
|
||||
ErrorString6="Defective warn lamp 1"
|
||||
ErrorNumber7=402
|
||||
ErrorString7="Defective warn lamp 2"
|
||||
ErrorNumber8=403
|
||||
ErrorString8="Defective warn lamp 3"
|
||||
ErrorNumber9=404
|
||||
ErrorString9="Cooling defect"
|
||||
ErrorNumber10=405
|
||||
ErrorString10="Error COM2"
|
||||
ErrorNumber11=406
|
||||
ErrorString12="Error COM2"
|
||||
ErrorNumber13=407
|
||||
ErrorString13="Error COM2"
|
||||
ErrorNumber14=408
|
||||
ErrorString14="Error COM2"
|
||||
ErrorNumber15=601
|
||||
ErrorString15="Defective warn lamp 1"
|
||||
ErrorNumber16=602
|
||||
ErrorString16="Defective warn lamp 2"
|
||||
ErrorNumber17=603
|
||||
ErrorString17="Defective warn lamp 3"
|
||||
ErrorNumber18=604
|
||||
ErrorString18="Cooling defect"
|
||||
ErrorNumber19=605
|
||||
ErrorString19="Error COM2"
|
||||
|
||||
[HSGErrors]
|
||||
ErrorNumber0=101
|
||||
ErrorString0="Data module error"
|
||||
ErrorNumber1=201
|
||||
ErrorString1="Underflow of actual accelerating voltage"
|
||||
ErrorNumber2=202
|
||||
ErrorString2="Overflow of actual accelerating voltage"
|
||||
ErrorNumber3=203
|
||||
ErrorString3="Underflow of actual tube current"
|
||||
ErrorNumber4=204
|
||||
ErrorString4="Overflow of actual tube current"
|
||||
ErrorNumber5=205
|
||||
ErrorString5="Underflow of actual filament current"
|
||||
ErrorNumber6=206
|
||||
ErrorString6="Overflow of actual filament current"
|
||||
ErrorNumber7=301
|
||||
ErrorString7="Timeout acceleration voltage"
|
||||
ErrorNumber8=302
|
||||
ErrorString8="Timeout tube current"
|
||||
ErrorNumber9=303
|
||||
ErrorString9="Timeout filament adjust"
|
||||
ErrorNumber10=402
|
||||
ErrorString10="High voltage generator overload"
|
||||
ErrorNumber11=403
|
||||
ErrorString11="No filament current"
|
||||
ErrorNumber12=501
|
||||
ErrorString12="Overvlow of nominal filament current"
|
||||
ErrorNumber13=502
|
||||
ErrorString13="Overflow or underflow of nominal accelerating voltage"
|
||||
ErrorNumber14=503
|
||||
ErrorString14="Overflow of nominal tube current"
|
||||
ErrorNumber15=510
|
||||
ErrorString15="Error during filament adjust step 30"
|
||||
ErrorNumber16=520
|
||||
ErrorString16="Nominal filament current smaller than filament offset"
|
||||
ErrorNumber17=524
|
||||
ErrorString17="Filament working current exceeds limit during filament adjust"
|
||||
ErrorNumber18=525
|
||||
ErrorString18="Filament working current exceeds limit during filament adjust"
|
||||
ErrorNumber19=526
|
||||
ErrorString19="Nominal filament current smaller than filament offset during filament adjust"
|
||||
ErrorNumber19=527
|
||||
ErrorString19="Nominal filament current smaller than filament offset during filament adjust"
|
||||
|
||||
[TubeErrors]
|
||||
ErrorNumber0=101
|
||||
ErrorString0="Data module error"
|
||||
ErrorNumber1=102
|
||||
ErrorString1="Data module focus table created"
|
||||
ErrorNumber2=103
|
||||
ErrorString2="Focus data module write error"
|
||||
ErrorNumber3=104
|
||||
ErrorString3="Focus data module error"
|
||||
ErrorNumber4=105
|
||||
ErrorString4="Focus table data module info error"
|
||||
ErrorNumber5=106
|
||||
ErrorString5="Focus table data module read error"
|
||||
ErrorNumber6=107
|
||||
ErrorString6="Condensor data module error"
|
||||
ErrorNumber7=108
|
||||
ErrorString7="Data module condensor table created"
|
||||
ErrorNumber8=109
|
||||
ErrorString8="Condensor table data module info error"
|
||||
ErrorNumber9=110
|
||||
ErrorString9="Condensor table data module read error"
|
||||
ErrorNumber10=111
|
||||
ErrorString10="Centering 1 / Centering 2 / Centering 3 data module error"
|
||||
ErrorNumber11=114
|
||||
ErrorString11="Centering table 1 data module error"
|
||||
ErrorNumber12=115
|
||||
ErrorString12="Centering table 2 data module error"
|
||||
ErrorNumber13=116
|
||||
ErrorString13="Centering table 3 data module error"
|
||||
ErrorNumber14=117
|
||||
ErrorString14="Conditioning data module error"
|
||||
ErrorNumber15=118
|
||||
ErrorString15="Read focus data module error"
|
||||
ErrorNumber16=119
|
||||
ErrorString16="Write focus data module error"
|
||||
ErrorNumber17=120
|
||||
ErrorString17="Read default focus data module error"
|
||||
ErrorNumber18=121
|
||||
ErrorString18="Write default focus data module error"
|
||||
ErrorNumber19=122
|
||||
ErrorString19="Read condensor data module error"
|
||||
ErrorNumber20=123
|
||||
ErrorString20="Write condensor data module error"
|
||||
ErrorNumber21=124
|
||||
ErrorString21="Read default condensor data module error"
|
||||
ErrorNumber22=125
|
||||
ErrorString22="Write default condensor data module error"
|
||||
ErrorNumber23=126
|
||||
ErrorString23="Read centering 1 data module error"
|
||||
ErrorNumber24=127
|
||||
ErrorString24="Read centering 2 data module error"
|
||||
ErrorNumber25=128
|
||||
ErrorString25="Read centering 3 data module error"
|
||||
ErrorNumber26=129
|
||||
ErrorString26="Write centering 1 data module error"
|
||||
ErrorNumber27=130
|
||||
ErrorString27="Write centering 2 data module error"
|
||||
ErrorNumber28=131
|
||||
ErrorString28="Write centering 3 data module error"
|
||||
ErrorNumber29=132
|
||||
ErrorString29="Read default centering 1 data module error"
|
||||
ErrorNumber30=133
|
||||
ErrorString30="Read default centering 2 data module error"
|
||||
ErrorNumber31=134
|
||||
ErrorString31="Read default centering 3 data module error"
|
||||
ErrorNumber32=135
|
||||
ErrorString32="Write default centering 1 data module error"
|
||||
ErrorNumber33=136
|
||||
ErrorString33="Write default centering 2 data module error"
|
||||
ErrorNumber34=137
|
||||
ErrorString34="Write default centering 3 data module error"
|
||||
ErrorNumber35=140
|
||||
ErrorString35="Shutter data module error"
|
||||
ErrorNumber36=141
|
||||
ErrorString36="Data module shutter created"
|
||||
ErrorNumber37=142
|
||||
ErrorString37="Shutter table data module info error"
|
||||
ErrorNumber38=143
|
||||
ErrorString38="Shutter table data module read error"
|
||||
ErrorNumber39=144
|
||||
ErrorString39="Scan data module error"
|
||||
ErrorNumber40=145
|
||||
ErrorString40="Scan table data module error"
|
||||
ErrorNumber41=146
|
||||
ErrorString41="Ti_Reg data module error"
|
||||
ErrorNumber42=147
|
||||
ErrorString42="dm_ken (focus) data module error"
|
||||
ErrorNumber43=148
|
||||
ErrorString43="dm_ken (condensor) data module error"
|
||||
ErrorNumber44=149
|
||||
ErrorString44="Mode_x data module error"
|
||||
ErrorNumber45=150
|
||||
ErrorString45="burn data module error"
|
||||
ErrorNumber46=151
|
||||
ErrorString46="tube_cur data module error"
|
||||
ErrorNumber47=152
|
||||
ErrorString47="Tubehead data module error"
|
||||
ErrorNumber48=153
|
||||
ErrorString48="Target data module error"
|
||||
ErrorNumber49=154
|
||||
ErrorString49="read_def_tube_cur data module error"
|
||||
ErrorNumber50=155
|
||||
ErrorString50="write_def_tube_cur data module error"
|
||||
ErrorNumber51=156
|
||||
ErrorString51="Filament data module error"
|
||||
ErrorNumber52=201
|
||||
ErrorString52="Underflow of actual target (amp1) current"
|
||||
ErrorNumber53=202
|
||||
ErrorString53="Overflow of actual target (amp1) current"
|
||||
ErrorNumber54=203
|
||||
ErrorString54="Underflow of actual target (amp2) current"
|
||||
ErrorNumber55=204
|
||||
ErrorString55="Overflow of actual target (amp2) current"
|
||||
ErrorNumber56=205
|
||||
ErrorString56="Underflow of actual amp3 current"
|
||||
ErrorNumber57=206
|
||||
ErrorString57="Overflow of actual amp3 current"
|
||||
ErrorNumber58=301
|
||||
ErrorString58="Time limit for centering current overflow exeeded, x-ray switched off"
|
||||
ErrorNumber59=302
|
||||
ErrorString59="Time limit for shutter exceeded, xray switched off"
|
||||
ErrorNumber60=401
|
||||
ErrorString60="Overflow of target power"
|
||||
ErrorNumber61=402
|
||||
ErrorString61="Missing amplifier"
|
||||
ErrorNumber62=403
|
||||
ErrorString62="Scanning coil temperature overflow"
|
||||
ErrorNumber63=501
|
||||
ErrorString63="Overflow of nominal focus current"
|
||||
ErrorNumber64=502
|
||||
ErrorString64="Overflow of nominal centering current x"
|
||||
ErrorNumber65=503
|
||||
ErrorString65="Overflow of nominal centering current y"
|
||||
ErrorNumber66=504
|
||||
ErrorString66="Overflow of nominal centering current"
|
||||
ErrorNumber67=505
|
||||
ErrorString67="Overflow of nominal shutter current"
|
||||
ErrorNumber68=506
|
||||
ErrorString68="Overflow of actual focus current"
|
||||
ErrorNumber69=507
|
||||
ErrorString69="Negative focus current"
|
||||
ErrorNumber70=611
|
||||
ErrorString70="Error during autocentering (plane 1)"
|
||||
ErrorNumber71=612
|
||||
ErrorString71="Error during autocentering (plane 1)"
|
||||
ErrorNumber72=613
|
||||
ErrorString72="Error during autocentering (plane 1)"
|
||||
ErrorNumber73=614
|
||||
ErrorString73="Error during autocentering (plane 1)"
|
||||
ErrorNumber74=615
|
||||
ErrorString74="Error during autocentering (plane 1)"
|
||||
ErrorNumber75=616
|
||||
ErrorString75="Error during autocentering (plane 1)"
|
||||
ErrorNumber76=617
|
||||
ErrorString76="Max. number of runs for autocentering exceeded (plane 1)"
|
||||
ErrorNumber77=618
|
||||
ErrorString77="Centering current exceeded (plane 1)"
|
||||
ErrorNumber78=621
|
||||
ErrorString78="Error during autocentering (plane 2)"
|
||||
ErrorNumber79=622
|
||||
ErrorString79="Error during autocentering (plane 2)"
|
||||
ErrorNumber80=623
|
||||
ErrorString80="Error during autocentering (plane 2)"
|
||||
ErrorNumber81=624
|
||||
ErrorString81="Error during autocentering (plane 2)"
|
||||
ErrorNumber82=625
|
||||
ErrorString82="Error during autocentering (plane 2)"
|
||||
ErrorNumber83=626
|
||||
ErrorString83="Error during autocentering (plane 2)"
|
||||
ErrorNumber84=627
|
||||
ErrorString84="Max. number of runs for autocentering exceeded (plane 2)"
|
||||
ErrorNumber85=628
|
||||
ErrorString85="Centering current exceeded (plane 2)"
|
||||
ErrorNumber86=631
|
||||
ErrorString86="Error during autocentering (plane 3)"
|
||||
ErrorNumber87=632
|
||||
ErrorString87="Error during autocentering (plane 3)"
|
||||
ErrorNumber88=633
|
||||
ErrorString88="Error during autocentering (plane 3)"
|
||||
ErrorNumber89=634
|
||||
ErrorString89="Error during autocentering (plane 3)"
|
||||
ErrorNumber90=635
|
||||
ErrorString90="Error during autocentering (plane 3)"
|
||||
ErrorNumber91=636
|
||||
ErrorString91="Error during autocentering (plane 3)"
|
||||
ErrorNumber92=637
|
||||
ErrorString92="Max. number of runs for autocentering exceeded (plane 3)"
|
||||
ErrorNumber93=638
|
||||
ErrorString93="Centering current exceeded (plane 3)"
|
||||
|
||||
|
||||
[VacuumErrors]
|
||||
ErrorNumber1=101
|
||||
ErrorString1="Data module error"
|
||||
ErrorNumber2=201
|
||||
ErrorString2="Underflow of actual vacuum value"
|
||||
ErrorNumber3=202
|
||||
ErrorString3="Overflow of actual vacuum value"
|
||||
ErrorNumber4=301
|
||||
ErrorString4="Timeout vacuum"
|
||||
ErrorNumber5=301
|
||||
ErrorString5="Timeout vacuum breakdown"
|
||||
ErrorNumber6=401
|
||||
ErrorString6="Bad vacuum during X-ray on"
|
||||
|
||||
[AxisErrors]
|
||||
ErrorNumber0=1002
|
||||
ErrorString0="general EL_Critical"
|
||||
|
||||
[ManiErrors]
|
||||
Binary file not shown.
Reference in New Issue
Block a user