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