using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using MECF.Framework.Common.Algorithm; using MECF.Framework.Common.Beckhoff.ModuleIO; using MECF.Framework.Common.CommonData.Prewet; using MECF.Framework.Common.Persistent.Prewet; using MECF.Framework.Common.TwinCat; using CyberX8_Core; using System; using System.Collections.Generic; using System.Reflection; using CyberX8_RT.Modules; using CyberX8_RT.Modules.Prewet; using CyberX8_RT.Modules.Metal; using MECF.Framework.Common.Persistent.Temperature; using MECF.Framework.Common.IOCore; namespace CyberX8_RT.Devices.Prewet { public class PrewetDevice : BaseDevice, IDevice { private enum PrewetOperation { None, PumpEnable, PumpDisable } #region 常量 private const string PUMP_VALVE = "PumpValve"; private const string PUMP_ENABLE = "PumpEnable"; private const string PUMP_SPEED = "PumpSpeed"; private const string PUMP_STAUS = "PumpStatus"; private const string PUMP_CURRENT = "PumpCurrent"; private const string PUMP_FLOW = "PumpFlow"; private const string PUMP_PRESSURE = "PumpPressure"; private const string PUMP_DATA = "PumpData"; private const string PERSISTENT_VALUE = "PersistentValue"; #endregion #region 内部变量 /// /// 数据 /// private PrewetPumpData _prewetPumpData=new PrewetPumpData(); /// /// pdi控制中的p /// private double _pumpKp; /// /// pdi控制中的i /// private double _pumpKi; /// /// pdi控制中的d /// private double _pumpKd; /// /// 操作当前状态 /// private RState _status; /// /// 当前操作 /// private PrewetOperation _currentOperation; /// /// Prewet 持久性数值对象 /// private PrewetPersistentValue _prewetPersistentValue; /// /// Pump Enable routine /// private PrewetPumpEnableRoutine _prewetPumpEnableRoutine; /// /// Pump Disable routine /// private PrewetPumpDisableRoutine _prewetPumpDisableRoutine; /// /// 上一次Pump速度 /// private short _lastPumpSpeed; /// /// 变量是否初始化字典 /// private Dictionary _variableInitializeDic = new Dictionary(); /// /// 定时器Job /// PeriodicJob _periodicJob = null; /// /// Run recipe total time /// public int _runRecipeTotalTime; #endregion #region 属性 /// /// Pump 数据 /// public PrewetPumpData PrewetPumpData { get { return _prewetPumpData; } } /// /// 操作当前状态 /// public RState Status { get { return _status; } } /// /// 所有io变量是否初始化 /// public bool IOInitialized { get { return AllIoVariableInitialized(); } } /// /// Last Pump Speed /// public short LastPumpSpeed { get { return _lastPumpSpeed; } } /// 是否启动调速 /// public bool IsStartAutoSpeed { get; set; } #endregion /// /// 构造函数 /// /// /// public PrewetDevice(string moduleName) : base(moduleName, moduleName,moduleName,moduleName) { _prewetPumpData = new PrewetPumpData(); _prewetPumpData.PumpPressureData = new MECF.Framework.Common.CommonData.CommonLimitData(); _prewetPumpData.PumpFlowData = new MECF.Framework.Common.CommonData.CommonLimitData(); _periodicJob = new PeriodicJob(100, OnTimer, $"{Module}.OnTimer", true); } /// /// 初始化 /// /// public bool Initialize() { InitializeParameter(); InitializeRoutine(); SubscribeData(); SubscribeValueAction(); InitializeOperation(); return true; } /// /// 初始化参数 /// private void InitializeParameter() { _prewetPersistentValue = PrewetPersistentManager.Instance.GetPrewetPersistentValue(Module); if (_prewetPersistentValue != null) { _lastPumpSpeed = _prewetPersistentValue.Speed; } else { LOG.WriteLog(eEvent.ERR_PREWET, Module, "Persistent Value Object is not exist"); } } /// /// 初始化Routine /// private void InitializeRoutine() { _prewetPumpEnableRoutine = new PrewetPumpEnableRoutine(Module, this, _prewetPersistentValue); _prewetPumpDisableRoutine = new PrewetPumpDisableRoutine(Module, this, _prewetPersistentValue); } /// /// 订阅数据 /// private void SubscribeData() { DATA.Subscribe($"{Module}.{PERSISTENT_VALUE}", () => _prewetPersistentValue, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.{PUMP_DATA}", () => PrewetPumpData, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.OfTotalTime", () => _runRecipeTotalTime ,SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PumpStatus", () => PrewetPumpData.PumpStatus, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PumpCurrent",()=>PrewetPumpData.PumpCurrent,SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PumpSpeed", () => _lastPumpSpeed, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PumpEnable", () => PrewetPumpData.PumpEnable, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PumpValve", () => PrewetPumpData.PumpValve, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PumpFlow", () => PrewetPumpData.PumpFlowData.Value, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PumpFlow.MinWarning", () => PrewetPumpData.PumpFlowData.MinWarning, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PumpFlow.MaxWarning", () => PrewetPumpData.PumpFlowData.MaxWarning, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PumpFlow.MinError", () => PrewetPumpData.PumpFlowData.MinError, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PumpFlow.MaxError", () => PrewetPumpData.PumpFlowData.MaxError, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PumpPressure", () => PrewetPumpData.PumpPressureData.Value, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PumpPressure.MinWarning", () => PrewetPumpData.PumpPressureData.MinWarning, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PumpPressure.MaxWarning", () => PrewetPumpData.PumpPressureData.MaxWarning, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PumpPressure.MinError", () => PrewetPumpData.PumpPressureData.MinError, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PumpPressure.MaxError", () => PrewetPumpData.PumpPressureData.MaxError, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.TargetPressure", () => PrewetPumpData.PressureTarget, SubscriptionAttribute.FLAG.IgnoreSaveDB); } /// /// 订阅变量数值发生变化 /// private void SubscribeValueAction() { BeckhoffIoSubscribeUpdateVariable( PUMP_VALVE); BeckhoffIoSubscribeUpdateVariable( PUMP_ENABLE); BeckhoffIoSubscribeUpdateVariable( PUMP_STAUS); BeckhoffIoSubscribeUpdateVariable( PUMP_CURRENT); BeckhoffIoSubscribeUpdateVariable( PUMP_PRESSURE); BeckhoffIoSubscribeUpdateVariable( PUMP_FLOW); } /// /// 订阅IO变量 /// /// private void BeckhoffIoSubscribeUpdateVariable(string variable) { _variableInitializeDic[variable] = false; IOModuleManager.Instance.SubscribeModuleVariable(Module, variable, UpdateVariableValue); } /// /// 更新变量数值 /// /// /// private void UpdateVariableValue(string variable, object value) { if (!PrewetPumpData.IsDataInitialized) { PrewetPumpData.IsDataInitialized = true; PrewetPumpData.PumpModel = "Manual"; } PropertyInfo property = PrewetPumpData.GetType().GetProperty(variable); if (property != null) { property.SetValue(PrewetPumpData, value); } if (_variableInitializeDic.ContainsKey(variable) && !_variableInitializeDic[variable]) { _variableInitializeDic[variable] = true; } switch (variable) { case PUMP_STAUS: string statusContent = PrewetPumpData.PumpStatus ? "On" : "Off"; PrewetPumpData.PumpStatusContent = $"{PrewetPumpData.PumpModel}: {statusContent}"; break; case PUMP_FLOW: if (double.TryParse(value.ToString(), out var flow)) { PrewetPumpData.PumpFlowData.Value = flow; } break; case PUMP_PRESSURE: if(double.TryParse(value.ToString(),out var pressure)) { PrewetPumpData.PumpPressureData.Value = pressure; } break; } } /// /// 是否所有IO变量初始化完成 /// /// private bool AllIoVariableInitialized() { foreach (string item in _variableInitializeDic.Keys) { if (!_variableInitializeDic[item]) { LOG.WriteLog(eEvent.ERR_PREWET, Module, $"{item} is not initialized"); return false; } } return true; } /// /// 初始化操作 /// private void InitializeOperation() { OP.Subscribe($"{Module}.PumpValveOn", PumpValveOnOperation); OP.Subscribe($"{Module}.PumpValveOff", PumpValveOffOperation); OP.Subscribe($"{Module}.PumpEnable", PumpEnableOperation); OP.Subscribe($"{Module}.PumpDisable", PumpDisableOperation); OP.Subscribe($"{Module}.PumpSpeedManual", PumpSpeedManualOperation); OP.Subscribe($"{Module}.PumpSpeedAuto", PumpSpeedAutoOperation); OP.Subscribe($"{Module}.PumpSpeedKeyDown", PumpSpeedKeyDownOperation); OP.Subscribe($"{Module}.DisabledAction", DisabledOperation); OP.Subscribe($"{Module}.ManualAction", ManualOperation); OP.Subscribe($"{Module}.AutoAction", AutoOperation); OP.Subscribe($"{Module}.EngineeringModeAction", EngineeringModeOperation); OP.Subscribe($"{Module}.ProductionModeAction", ProductionModeOperation); } /// /// 定时器 /// /// private bool OnTimer() { PrewetPumpData.PumpFlowData.MinError = SC.GetValue($"Prewet.PumpFlow.Error_Min"); PrewetPumpData.PumpFlowData.MinWarning = SC.GetValue($"Prewet.PumpFlow.Warning_Min"); PrewetPumpData.PumpFlowData.MaxError = SC.GetValue($"Prewet.PumpFlow.Error_Max"); PrewetPumpData.PumpFlowData.MaxWarning = SC.GetValue($"Prewet.PumpFlow.Warning_Max"); PrewetPumpData.PumpPressureData.MinError = SC.GetValue($"Prewet.PumpPressure.Error_Min"); PrewetPumpData.PumpPressureData.MinWarning = SC.GetValue($"Prewet.PumpPressure.Warning_Min"); PrewetPumpData.PumpPressureData.MaxError = SC.GetValue($"Prewet.PumpPressure.Error_Max"); PrewetPumpData.PumpPressureData.MaxWarning = SC.GetValue($"Prewet.PumpPressure.Warning_Max"); PrewetPumpData.PressureTarget = SC.GetValue($"Prewet.PressureTarget"); if (_status == RState.Running) { IRoutine routine = GetCurrentRoutine(); if (routine != null) { RState rsState = routine.Monitor(); if (rsState == RState.Failed || rsState == RState.Timeout) { _status = RState.Failed; _currentOperation = PrewetOperation.None; LOG.WriteLog(eEvent.ERR_LINMOT, Module.ToString(), $"{_currentOperation} error"); IsStartAutoSpeed = false; } else if (rsState == RState.End) { if (_currentOperation == PrewetOperation.PumpEnable) { IsStartAutoSpeed = true; } else { IsStartAutoSpeed = false; } _status = RState.End; _currentOperation = PrewetOperation.None; } } } if (IsStartAutoSpeed) { AdjustPumpSpeed(); } return true; } /// /// 调速 /// public void AdjustPumpSpeed() { //Speed Auto模式同时pump enbled,根据kdi调整泵速 if (PrewetPumpData.PumpSpeedAuto && PrewetPumpData.PumpEnable) { _pumpKp = SC.GetValue($"Prewet.PumpKp"); _pumpKd = SC.GetValue($"Prewet.PumpKd"); _pumpKi = SC.GetValue($"Prewet.PumpKi"); double limit = SC.GetValue("Prewet.PrewetTargetLimit"); short speed = PdiAlgorithm.Instance.CalculateSpeed(_pumpKp, _pumpKi, _pumpKd, PrewetPumpData.PressureTarget, PrewetPumpData.PumpPressureData.Value, _lastPumpSpeed,limit); if (Math.Abs(speed - _lastPumpSpeed) >= 1) { _lastPumpSpeed = speed; PumpSpeed(speed); } } else { IsStartAutoSpeed = false; } } /// /// 当前Routine; /// /// private IRoutine GetCurrentRoutine() { switch (_currentOperation) { case PrewetOperation.PumpEnable: return _prewetPumpEnableRoutine; case PrewetOperation.PumpDisable: return _prewetPumpDisableRoutine; default: return null; } } #region Operation /// /// DisabledAction /// /// /// /// private bool DisabledOperation(string cmd, object[] args) { string currentOperation = "Disabled"; PrewetEntity prewetEntity = Singleton.Instance.GetModule(Module); if (prewetEntity == null || _prewetPersistentValue == null) return false; if (_prewetPersistentValue.OperatingMode != "Disabled") prewetEntity.EnterInit(); _prewetPersistentValue.OperatingMode = currentOperation; PrewetPersistentManager.Instance.UpdatePersistentValue(Module); return true; } /// /// ManualAction /// /// /// /// private bool ManualOperation(string cmd, object[] args) { string currentOperation = "Manual"; PrewetEntity prewetEntity = Singleton.Instance.GetModule(Module); if (prewetEntity == null || _prewetPersistentValue == null) return false; if (_prewetPersistentValue.OperatingMode == "Auto" && prewetEntity.IsBusy) { LOG.WriteLog(eEvent.ERR_PREWET, Module, $"{Module} is Busy, can't change to manual mode"); return false; } if (_prewetPersistentValue.OperatingMode != "Manual") prewetEntity.EnterInit(); _prewetPersistentValue.OperatingMode = currentOperation; PrewetPersistentManager.Instance.UpdatePersistentValue(Module); return true; } /// /// AutoAction /// /// /// /// private bool AutoOperation(string cmd, object[] args) { string currentOperation = "Auto"; PrewetEntity prewetEntity = Singleton.Instance.GetModule(Module); if (prewetEntity == null || _prewetPersistentValue == null) return false; if (_prewetPersistentValue.OperatingMode != "Auto") prewetEntity.EnterInit(); _prewetPersistentValue.OperatingMode = currentOperation; PrewetPersistentManager.Instance.UpdatePersistentValue(Module); return true; } /// /// EngineeringModeAction /// /// /// /// private bool EngineeringModeOperation(string cmd, object[] args) { string currentRecipeOperation = "Engineering"; _prewetPersistentValue.RecipeOperatingMode=currentRecipeOperation; PrewetPersistentManager.Instance.UpdatePersistentValue(Module); return true; } /// /// ProductionAction /// /// /// /// private bool ProductionModeOperation(string cmd, object[] args) { string currentRecipeOperation = "Production"; _prewetPersistentValue.RecipeOperatingMode = currentRecipeOperation; PrewetPersistentManager.Instance.UpdatePersistentValue(Module); return true; } /// /// Pump Valve On /// /// /// /// public bool PumpValveOnOperation(string cmd, object[] param) { return PumpValveOpen(); } /// /// Pump Valve Off /// /// /// /// public bool PumpValveOffOperation(string cmd, object[] param) { return PumpValveClose(); } /// /// Pump Valve Open /// /// public bool PumpValveOpen() { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{PUMP_VALVE}"); return IOModuleManager.Instance.WriteIoValue(ioName, true); } /// /// Pump Valve Close /// /// public bool PumpValveClose() { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{PUMP_VALVE}"); bool result= IOModuleManager.Instance.WriteIoValue(ioName, false); if(result && PrewetPumpData.PumpEnable) { PumpDisable(); } return result; } /// /// Pump Enable操作 /// /// /// /// public bool PumpEnableOperation(string cmd, object[] param) { if (_status == RState.Running) { LOG.WriteLog(eEvent.ERR_PREWET, Module.ToString(), $"{Module} current execute {_currentOperation},cannot Pump enable"); return false; } _status = _prewetPumpEnableRoutine.Start(); _currentOperation = PrewetOperation.PumpEnable; return _status==RState.Running; } /// /// pump disable 操作 /// /// /// /// public bool PumpDisableOperation(string cmd, object[] param) { if (_status == RState.Running) { LOG.WriteLog(eEvent.ERR_PREWET, Module.ToString(), $"{Module} current execute {_currentOperation},cannot Pump disable"); return false; } _status = _prewetPumpDisableRoutine.Start(); _currentOperation = PrewetOperation.PumpDisable; return _status == RState.Running; //return PumpDisable(); } /// /// Pump enable /// /// public bool PumpEnable() { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{PUMP_ENABLE}"); return IOModuleManager.Instance.WriteIoValue(ioName, true); } /// /// Pump disable /// /// public bool PumpDisable() { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{PUMP_ENABLE}"); return IOModuleManager.Instance.WriteIoValue(ioName, false); } /// /// 写入Pump速度 /// /// /// public bool PumpSpeed(short speed=0) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{PUMP_SPEED}"); return IOModuleManager.Instance.WriteIoValue(ioName, speed==0?_lastPumpSpeed:speed); } /// /// Pump Speed手动模式 /// /// /// /// public bool PumpSpeedManualOperation(string cmd, object[] param) { PrewetPumpData.PumpSpeedAuto = false; PrewetPumpData.PumpModel = "Manual"; string statusContent = PrewetPumpData.PumpStatus ? "On" : "Off"; PrewetPumpData.PumpStatusContent = $"{PrewetPumpData.PumpModel}: {statusContent}"; return true; } /// /// Pump Speed自动模式 /// /// /// /// public bool PumpSpeedAutoOperation(string cmd, object[] param) { PrewetPumpData.PumpSpeedAuto = true; PrewetPumpData.PumpModel = "Auto"; string statusContent = PrewetPumpData.PumpStatus ? "On" : "Off"; PrewetPumpData.PumpStatusContent = $"{PrewetPumpData.PumpModel}: {statusContent}"; return true; } /// /// Pump Speed回车操作 /// /// /// /// public bool PumpSpeedKeyDownOperation(string cmd, object[] param) { if (PrewetPumpData.PumpSpeedAuto) { LOG.WriteLog(eEvent.ERR_PREWET, Module, "Pump speed is auto,cannot change speed"); return false; } short speed=(short)param[0]; bool result = PumpSpeed(speed); if(result) { _prewetPersistentValue.Speed = speed; _lastPumpSpeed = speed; PrewetPersistentManager.Instance.UpdatePersistentValue(Module); } return true; } /// /// 中止当前Routine /// public void AbortCurrentRoutine() { if (_status == RState.Running) { IRoutine routine = GetCurrentRoutine(); if (routine != null) { routine.Abort(); _currentOperation = PrewetOperation.None; } } } #endregion #region 设备接口 /// /// 监控 /// public void Monitor() { } public void Reset() { } public void Terminate() { _prewetPersistentValue.Speed = _lastPumpSpeed; PrewetPersistentManager.Instance.UpdatePersistentValue(Module); _periodicJob.Stop(false); } #endregion } }