internal class AxesDiagPacketRetriever
{
private readonly Controller controller;
private short[] itemCodes;
private short[] axisNumbers;
private int[] extraCodes;
private static readonly short[] PerAxisItemCodes;
private static readonly Dictionary<short, int> NonZeroExtraItemCodes;
static AxesDiagPacketRetriever()
{
PerAxisItemCodes = new short[27]
{
10, 11, 28, 29, 36, 37, 38, 39, 49, 48,
47, 8, 7, 15, 16, 14, 1, 0, 4, 3,
90, 107, 6, 192, 376, 377, 443
};
NonZeroExtraItemCodes = new Dictionary<short, int>();
NonZeroExtraItemCodes[90] = 0;
NonZeroExtraItemCodes[107] = 0;
}
public AxesDiagPacketRetriever(Controller controller)
{
this.controller = controller;
}
private void EnsureRequestDataInitialized()
{
if (itemCodes == null)
{
itemCodes = StatusItemRetrievalHelper.CreateItemArray(PerAxisItemCodes, 32);
}
if (axisNumbers == null)
{
axisNumbers = StatusItemRetrievalHelper.CreateIndexArray(PerAxisItemCodes, 32);
}
if (extraCodes == null)
{
extraCodes = StatusItemRetrievalHelper.CreateExtraItemCodesArray(PerAxisItemCodes, 32, NonZeroExtraItemCodes);
}
}
public KeyValuePair<DiagPacket[], double[]> GetAxesDiagnostics(UnitInformation toUnits)
{
if (toUnits == null)
{
throw new ArgumentNullException("toUnits");
}
EnsureRequestDataInitialized();
int num = PerAxisItemCodes.Length * 32;
double[] array = new double[num];
ExceptionResolver.ResolveThrow(controller, Wrapper.AerStatusGetItems(controller.Handle.Value, num, axisNumbers, itemCodes, extraCodes, array));
return ScaleAxesDiagnostics(array, new UnitInformation(DistanceUnit.Primary, TimeUnit.Seconds), toUnits);
}
public KeyValuePair<DiagPacket[], double[]> ScaleAxesDiagnostics(double[] rawData, UnitInformation fromUnits, UnitInformation toUnits)
{
EnsureRequestDataInitialized();
_ = PerAxisItemCodes.Length;
KeyValuePair<string, double>[] array = UnitUtilities.ConvertData(controller.Parameters, fromUnits, toUnits, itemCodes, axisNumbers, rawData);
double[] value = Array.ConvertAll(array, (KeyValuePair<string, double> kvp) => kvp.Value);
DiagPacket[] array2 = new DiagPacket[32];
for (int i = 0; i < 32; i++)
{
array2[i] = interpretDiagnosticData(array, i);
}
return new KeyValuePair<DiagPacket[], double[]>(array2, value);
}
private DiagPacket interpretDiagnosticData(KeyValuePair<string, double>[] statusData, int axis)
{
_ = controller.Parameters.Axes[axis].Units.CountsPerUnit.CachedValue;
KeyValuePair<string, double>[] dataForIndex = StatusItemRetrievalHelper.GetDataForIndex(statusData, PerAxisItemCodes, axis);
DiagPacket result = default(DiagPacket);
result.AnalogInput0 = dataForIndex[0].Value;
result.AnalogInput1 = dataForIndex[1].Value;
result.AnalogInput2 = dataForIndex[2].Value;
result.AnalogInput3 = dataForIndex[3].Value;
result.AnalogOutput0 = dataForIndex[4].Value;
result.AnalogOutput1 = dataForIndex[5].Value;
result.AnalogOutput2 = dataForIndex[6].Value;
result.AnalogOutput3 = dataForIndex[7].Value;
result.CurrentCommand = (float)dataForIndex[11].Value;
result.CurrentFeedback = (float)dataForIndex[12].Value;
result.DigitalInputs = InternalUtilities.DoubleAsIntOrUIntToInt(dataForIndex[13].Value);
result.DigitalOutputs = InternalUtilities.DoubleAsIntOrUIntToInt(dataForIndex[14].Value);
result.AxisFault = InternalUtilities.DoubleAsIntOrUIntToInt(dataForIndex[8].Value);
result.AxisStatus = InternalUtilities.DoubleAsIntOrUIntToInt(dataForIndex[9].Value);
result.DriveStatus = InternalUtilities.DoubleAsIntOrUIntToInt(dataForIndex[10].Value);
result.PositionFeedbackAuxiliary = dataForIndex[15].Value;
result.PositionCommand = dataForIndex[16].Value;
result.PositionUnitName = dataForIndex[16].Key;
result.PositionFeedback = dataForIndex[17].Value;
result.VelocityCommand = dataForIndex[18].Value;
result.VelocityUnitName = dataForIndex[18].Key;
result.VelocityFeedback = dataForIndex[19].Value;
result.ProgramPositionCommand = dataForIndex[20].Value;
result.ProgramPositionFeedback = dataForIndex[21].Value;
result.AccelerationCommand = dataForIndex[22].Value;
result.AccelerationUnitName = dataForIndex[22].Key;
result.AccelerationFeedback = dataForIndex[23].Value;
result.PiezoVoltageCommand = dataForIndex[24].Value;
result.PiezoVoltageFeedback = dataForIndex[25].Value;
result.STOStatus = InternalUtilities.DoubleAsIntOrUIntToInt(dataForIndex[26].Value);
return result;
}
}
以下是针对 AxesDiagPacketRetriever
类的深度解析,从架构设计到实现细节的全面分析:
1. 核心职责
作为 轴诊断数据采集器,主要功能包括:
-
多轴状态采集:同时获取32个轴的实时诊断数据
-
数据标准化处理:原始值→工程单位转换
-
高效数据重组:扁平数组→结构化对象转换
-
硬件交互抽象:封装底层
AerStatusGetItems
调用
2. 关键设计模式
(1)工厂方法模式
-
数据预加工:通过辅助类构建硬件请求所需的数据结构
(2)策略模式
private static readonly Dictionary<short, int> NonZeroExtraItemCodes;
// 特殊项的特殊处理规则
(3)缓存模式
private short[] itemCodes; // 缓存初始化后的请求参数
private void EnsureRequestDataInitialized() {
if (itemCodes == null) {
itemCodes = StatusItemRetrievalHelper.CreateItemArray(...);
}
}
3. 核心数据结构
字段 | 类型 | 用途 |
---|---|---|
PerAxisItemCodes | short[27] | 每个轴需要采集的27种数据项ID |
NonZeroExtraItemCodes | Dictionary<short,int> | 需要额外参数的项配置 |
itemCodes | short[] | 硬件API所需的项ID数组(32轴×27项) |
axisNumbers | short[] | 对应的轴编号数组 |
extraCodes | int[] | 特殊项的额外参数 |
4. 关键流程分析
(1)数据采集流程
(2)数据结构转换
// 原始扁平数组→结构化对象
double[] rawData = new double[32*27]; // 硬件返回
DiagPacket[] packets = new DiagPacket[32];
for (int i = 0; i < 32; i++) {
packets[i] = new DiagPacket {
AnalogInput0 = rawData[i*27 + 0],
AnalogInput1 = rawData[i*27 + 1],
// ...其他字段
};
}
5. 性能优化点
-
请求数据缓存
private short[] itemCodes; // 避免每次请求重新构建数组
-
批量读取
Wrapper.AerStatusGetItems(..., count: 864, ...); // 单次调用读取所有数据
并行处理(潜在优化)
Parallel.For(0, 32, i => {
packets[i] = interpretDiagnosticData(..., i);
});
6. 典型使用场景
(1)实时监控
var retriever = new AxesDiagPacketRetriever(controller);
var data = retriever.GetAxesDiagnostics(new UnitInformation(mm, sec));
// 显示X轴状态
var xAxisData = data.Key[0];
Console.WriteLine($"X轴位置: {xAxisData.PositionFeedback} mm");
(2)故障诊断
if ((data.Key[2].AxisStatus & 0x01) != 0) {
Alert("Y轴超限位!");
}
7. 异常处理增强
错误类型 | 当前处理 | 改进建议 |
---|---|---|
硬件超时 | 通过ExceptionResolver | 增加重试机制 |
单位转换错误 | 未明确处理 | 添加详细日志 |
轴号越界 | 可能数组越界 | 添加范围检查 |
总结
该类的设计优势:
-
高效批量采集:单次调用获取所有轴数据
-
类型安全输出:强类型
DiagPacket
结构 -
单位抽象:支持灵活的单位转换
-
资源优化:缓存请求参数减少GC压力
适用于:
-
多轴运动控制系统的实时监控
-
设备健康状态诊断
-
高频率数据采集场景
通过增加异步流式接口和动态配置能力,可进一步提升其在现代工业系统中的适用性。