public class AxisInfo : INamed<string>
{
private const int DriveTypeBlockNumber = 0;
private const int FirmwareBlockNumber = 6;
private readonly int axisNumber;
private ComponentType? axisType;
private int? servoRate;
private float? maximumAmperage;
private float? maximumVoltage;
private CommandOutputType? commandOutputType;
private readonly Controller controller;
private MotionDriveInformation containingDrive;
private Version firmwareVersion;
private int fpgaVersion;
private FlashConfigStatus flashConfigStatus;
public int Number => axisNumber;
public ComponentType AxisType
{
get
{
if (!axisType.HasValue)
{
int pdwOne_ = 0;
int pdwTwo_ = 0;
int pdwThree_ = 0;
int pdwFour_ = 0;
ExceptionResolver.ResolveThrow(controller, Wrapper.AerStatusGetDriveInfoBlockEx(controller.Handle.Value, 0, axisNumber, ref pdwOne_, ref pdwTwo_, ref pdwThree_, ref pdwFour_));
if (!Global.CoreDriveIdMappings.TryGetValue((Drive)pdwFour_, out var value))
{
value = ComponentType.Unknown;
}
axisType = value;
}
return axisType.Value;
}
}
public int ServoRate
{
get
{
if (!servoRate.HasValue)
{
int pdwServoRate_ = 0;
ExceptionResolver.ResolveThrow(controller, Wrapper.AerStatusGetAxisServoRate(controller.Handle.Value, axisNumber, ref pdwServoRate_));
servoRate = pdwServoRate_;
}
return servoRate.Value;
}
}
public float MaximumAmperage
{
get
{
if (!maximumAmperage.HasValue)
{
float pdwPeakRating_ = 0f;
ExceptionResolver.ResolveThrow(controller, Wrapper.AerStatusGetAmpPeakRating(controller.Handle.Value, axisNumber, ref pdwPeakRating_));
maximumAmperage = pdwPeakRating_;
}
return maximumAmperage.Value;
}
}
public float MaximumVoltage
{
get
{
if (!maximumVoltage.HasValue)
{
maximumVoltage = (float)(double)controller.Commands.Execute($"DRIVEINFO(@{axisNumber}, DATAITEM_MaximumVoltage)");
}
return maximumVoltage.Value;
}
}
public CommandOutputType CommandOutputType
{
get
{
if (!commandOutputType.HasValue)
{
commandOutputType = (CommandOutputType)(double)controller.Commands.Execute($"DRIVEINFO(@{axisNumber}, DATAITEM_CommandOutputType)");
}
return commandOutputType.Value;
}
}
public string Name => controller.Parameters.Axes[axisNumber].AxisNameParameter.CachedValue;
internal Controller Controller => controller;
public MotionDriveInformation Drive
{
get
{
return containingDrive;
}
internal set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
containingDrive = value;
}
}
public Version FirmwareVersion
{
get
{
if (firmwareVersion == null)
{
int pdwOne_ = 0;
int pdwTwo_ = 0;
int pdwThree_ = 0;
int pdwFour_ = 0;
ExceptionResolver.ResolveThrow(controller, Wrapper.AerStatusGetDriveInfoBlockEx(controller.Handle.Value, 6, axisNumber, ref pdwOne_, ref pdwTwo_, ref pdwThree_, ref pdwFour_));
firmwareVersion = new Version(pdwOne_, pdwTwo_, pdwThree_, pdwFour_);
}
return firmwareVersion;
}
}
public int FPGAVersion => fpgaVersion;
public FlashConfigStatus FlashConfigStatus
{
get
{
if (flashConfigStatus == null)
{
int flashConfigstatus_ = 0;
ExceptionResolver.ResolveThrow(controller, Wrapper.AerGetFlashConfigStatus(controller.Handle.Value, axisNumber, ref flashConfigstatus_));
flashConfigStatus = new FlashConfigStatus(flashConfigstatus_);
}
return flashConfigStatus;
}
}
internal AxisInfo(Controller controller, int axisNumber, int fpgaVersion)
{
this.controller = controller;
this.axisNumber = axisNumber;
this.fpgaVersion = fpgaVersion;
}
internal void invalidateData()
{
axisType = null;
servoRate = null;
maximumAmperage = null;
firmwareVersion = null;
maximumVoltage = null;
commandOutputType = null;
}
}
AxisInfo
是一个表示轴信息的类,实现了 INamed<string>
接口,主要用于运动控制系统中轴(axis)相关信息的封装和管理。
类结构概述
核心字段
-
axisNumber
: 轴编号 -
多个可空字段用于缓存信息:
axisType
,servoRate
,maximumAmperage
等 -
controller
: 关联的控制器对象 -
containingDrive
: 所属的驱动信息
主要属性
-
基本信息:
-
Number
: 轴编号 -
Name
: 轴名称(来自控制器参数) -
Controller
: 关联的控制器
-
-
技术规格:
-
AxisType
: 轴类型 -
ServoRate
: 伺服速率 -
MaximumAmperage
: 最大电流 -
MaximumVoltage
: 最大电压
-
-
版本信息:
-
FirmwareVersion
: 固件版本 -
FPGAVersion
: FPGA版本 -
FlashConfigStatus
: 闪存配置状态
-
-
驱动信息:
-
Drive
: 所属驱动信息 -
CommandOutputType
: 命令输出类型
-
关键设计特点
1. 延迟加载模式
大多数属性采用延迟加载设计,首次访问时才从控制器获取数据:
public ComponentType AxisType
{
get
{
if (!axisType.HasValue)
{
// 从控制器获取数据
int pdwOne_ = 0;
// ...调用Wrapper方法获取数据...
axisType = value;
}
return axisType.Value;
}
}
这种设计:
-
减少不必要的控制器调用
-
提高性能(只在需要时获取数据)
-
通过字段缓存已获取的数据
2. 异常处理机制
使用ExceptionResolver.ResolveThrow
统一处理底层调用异常:
ExceptionResolver.ResolveThrow(controller,
Wrapper.AerStatusGetDriveInfoBlockEx(...));
3. 数据失效机制
提供invalidateData()
方法清空缓存,强制下次访问时重新获取:
internal void invalidateData()
{
axisType = null;
servoRate = null;
// ...其他字段置空...
}
4. 控制器集成
通过Controller
对象执行命令和获取参数:
maximumVoltage = (float)(double)controller.Commands.Execute(
$"DRIVEINFO(@{axisNumber}, DATAITEM_MaximumVoltage)");
典型使用场景
1. 获取轴信息
var axis = new AxisInfo(controller, axisNumber, fpgaVersion);
Console.WriteLine($"Axis {axis.Number}: {axis.Name}");
Console.WriteLine($"Type: {axis.AxisType}, Servo Rate: {axis.ServoRate}Hz");
2. 监控轴状态
if (axis.MaximumAmperage > threshold)
{
// 处理过流情况
}
3. 固件升级检查
if (axis.FirmwareVersion < requiredVersion)
{
// 提示需要升级固件
}
设计模式分析
-
代理模式:
-
作为控制器和轴信息之间的代理
-
隐藏底层复杂的调用细节
-
-
缓存模式:
-
属性值首次获取后缓存
-
通过
invalidateData
可清除缓存
-
-
延迟初始化:
-
数据只在首次访问时加载
-
潜在改进建议
-
线程安全:
-
当前实现不是线程安全的
-
可添加锁机制保护字段访问
-
-
属性变更通知:
-
可考虑实现
INotifyPropertyChanged
-
便于UI绑定和数据监控
-
-
更细粒度的失效控制:
-
当前
invalidateData
重置所有数据 -
可改为按属性失效
-
-
异步支持:
-
添加异步方法获取数据
-
避免阻塞UI线程
-
与INamed<string>的关系
实现INamed<string>
接口使得该类可以:
-
用于基于名称的集合(如
NamedConstantCollection
) -
提供标准化的名称访问方式
-
与其他命名对象保持一致的接口
public string Name => controller.Parameters.Axes[axisNumber].AxisNameParameter.CachedValue;
总结
AxisInfo
类是一个设计精良的运动控制轴信息封装类,具有以下优点:
-
良好的封装性,隐藏底层实现细节
-
高效的延迟加载机制
-
灵活的数据失效管理
-
与控制器深度集成
-
清晰的命名和职责划分
这种设计非常适合工业控制系统中对设备信息的建模和管理。