Browse Source

1 add platingcell run recipe entry part
2 reivse clamshell close/open

chenzk 2 weeks ago
parent
commit
c23ae5e67f

+ 6 - 1
Framework/Common/CommonData/PlatingCell/PlatingCellData.cs

@@ -15,12 +15,16 @@ namespace MECF.Framework.Common.CommonData.PlatingCell
         private double _clamShellCylinderPressure;
         private double _overFlowLevel;
         private string _overFlowStatus;
+ 
         
         private bool _clamShellClose;
         private bool _headTilt;
         private bool _isDataInitialized;
         private bool _cCREnable;
         private bool _rinseEnable;
+
+        private bool _clammShellClosed;
+        private bool _clammShellOpened;
         #endregion
 
         #region 属性
@@ -43,7 +47,8 @@ namespace MECF.Framework.Common.CommonData.PlatingCell
         
         public bool CCREnable { get { return _cCREnable; } set { _cCREnable = value; InvokePropertyChanged(nameof(CCREnable)); } }
         
-        public bool RinseEnable { get { return _rinseEnable; } set { _rinseEnable = value; InvokePropertyChanged(nameof(RinseEnable)); } }
+        public bool ClamShellClosed { get { return _clammShellClosed; } set { _clammShellClosed = value; InvokePropertyChanged(nameof(ClamShellClosed)); } }
+        public bool ClamShellOpened { get { return _clammShellOpened; } set { _clammShellOpened = value; InvokePropertyChanged(nameof(ClamShellOpened)); } }
         #endregion
 
 

+ 18 - 2
PunkHPX8_RT/Config/Station/StationPositionsCfg_Simulator.xml

@@ -54,7 +54,15 @@
 			<ToleranceDefault>0.5</ToleranceDefault>
 			<Stations>
 				<Station Name="PlatingCell1_2.Vertical.Home" Position="0" />
-				<Station Name="PlatingCell1_2.Vertical.Load" Position="10" />
+				<Station Name="PlatingCell1_2.Vertical.Maintenance" Position="1" />
+				<Station Name="PlatingCell1_2.Vertical.Load" Position="2" />
+				<Station Name="PlatingCell1_2.Vertical.Load2" Position="3" />
+				<Station Name="PlatingCell1_2.Vertical.Rinse" Position="4" />
+				<Station Name="PlatingCell1_2.Vertical.CCR" Position="5" />
+				<Station Name="PlatingCell1_2.Vertical.Reclaim" Position="6" />
+				<Station Name="PlatingCell1_2.Vertical.Entry" Position="7" />
+				<Station Name="PlatingCell1_2.Vertical.Plate" Position="8" />
+				<Station Name="PlatingCell1_2.Vertical.ACE" Position="9" />
 			</Stations>
 		</Axis>
 		<Axis Name="PlatingCell1.Rotation">
@@ -77,7 +85,15 @@
 			<ToleranceDefault>0.5</ToleranceDefault>
 			<Stations>
 				<Station Name="PlatingCell3_4.Vertical.Home" Position="0" />
-				<Station Name="PlatingCell3_4.Vertical.Load" Position="10" />
+				<Station Name="PlatingCell3_4.Vertical.Maintenance" Position="1" />
+				<Station Name="PlatingCell3_4.Vertical.Load" Position="2" />
+				<Station Name="PlatingCell3_4.Vertical.Load2" Position="3" />
+				<Station Name="PlatingCell3_4.Vertical.Rinse" Position="4" />
+				<Station Name="PlatingCell3_4.Vertical.CCR" Position="5" />
+				<Station Name="PlatingCell3_4.Vertical.Reclaim" Position="6" />
+				<Station Name="PlatingCell3_4.Vertical.Entry" Position="7" />
+				<Station Name="PlatingCell3_4.Vertical.Plate" Position="8" />
+				<Station Name="PlatingCell3_4.Vertical.ACE" Position="9" />
 			</Stations>
 		</Axis>
 		<Axis Name="PlatingCell3.Rotation">

+ 3 - 0
PunkHPX8_RT/Config/System.sccfg

@@ -344,6 +344,9 @@
 		<config default="80" name="OverflowLevelHigh" nameView="OverflowLevelHigh" description="Overflow Level High" max="100" min="0" paramter="" tag="" unit="mm" type="Integer"></config>
 		<config default="25" name="OverflowLevelLow" nameView="OverflowLevelLow" description="Overflow Level Low" max="100" min="0" paramter="" tag="" unit="mm" type="Integer"></config>
 		<config default="1000" name="RinseDripIdlePeriod" nameView="RinseDripIdlePeriod" description="Rinse Drip Idle Period" max="100000" min="0" paramter="" tag="" unit="ms" type="Integer"></config>
+		<config default="1000" name="ClamShellOpenCheckDelay" nameView="ClamShellOpenCheckDelay" description="ClamShell Open Check Delay" max="100000" min="0" paramter="" tag="" unit="ms" type="Integer"></config>
+		<config default="5" name="ClamShellCloseDistanceThreshold" nameView="ClamShellCloseDistanceThreshold" description="Clam Shell Close DistanceT hreshold" max="1000" min="0" paramter="" tag="" unit="mm" type="Integer"></config>
+		<config default="55" name="ClamShellOpenDistanceThreshold" nameView="ClamShellOpenDistanceThreshold" description="Clam Shell Open DistanceT hreshold" max="1000" min="0" paramter="" tag="" unit="mm" type="Integer"></config>
 		<configs name="CSR" nameView="CSR">
 			<config default="true" name="CSREnable" nameView="CSREnable" description="CSR Enabled" max="" min="" paramter="" tag="" unit="" type="Bool"/>
 			<config default="80" name="RinseSpeed" nameView="RinseSpeed" description="Rinse Speed" max="1000" min="0" paramter="" tag="" unit="rpm" type="Integer"></config>

+ 120 - 0
PunkHPX8_RT/Devices/PlatingCell/ClamShellCloseRoutine.cs

@@ -0,0 +1,120 @@
+using Aitex.Core.RT.Device;
+using Aitex.Core.RT.Log;
+using Aitex.Core.RT.Routine;
+using Aitex.Core.RT.SCCore;
+using MECF.Framework.Common.Beckhoff.ModuleIO;
+using MECF.Framework.Common.CommonData.PlatingCell;
+using MECF.Framework.Common.IOCore;
+using MECF.Framework.Common.Routine;
+using PunkHPX8_Core;
+using PunkHPX8_RT.Devices.SRD;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace PunkHPX8_RT.Devices.PlatingCell
+{
+    public class ClamShellCloseRoutine : RoutineBase, IRoutine
+    {
+
+        private enum ClamshellClose
+        {
+            ClamShellClose,
+            End
+        }
+        #region 常量
+        private const string CLAMSHELL_CLOSE = "ClamShellClose";
+        #endregion
+
+        #region 内部变量
+        private bool _close;
+        private PlatingCellDevice _device;
+        private int _openSensor = 55;
+        private int _closeSensor = 5;
+        private int _sensorCheckTime = 1000;
+        #endregion
+
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="module"></param>
+        public ClamShellCloseRoutine(string module):base(module) 
+        {
+
+        }
+
+        public void Abort()
+        {
+            Runner.Stop("Manual Abort");
+        }
+
+        public RState Monitor()
+        {
+            Runner.Run(ClamshellClose.ClamShellClose, ClamShellClose, CheckClamShellClose, _sensorCheckTime)
+                .End(ClamshellClose.End, NullFun, 100);
+            return Runner.Status;
+        }
+
+        private bool ClamShellClose()
+        {
+            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CLAMSHELL_CLOSE}");
+            return IOModuleManager.Instance.WriteIoValue(ioName, _close);
+        }
+
+        private bool CheckClamShellClose()
+        {
+            if (_close)
+            {
+                if (_device.PlatingCellDeviceData.ClamShellDistance <= _closeSensor)
+                {
+                    LOG.WriteLog(eEvent.INFO_PLATINGCELL, Module, $"ClamShell is Closed");
+                    _device.PlatingCellDeviceData.ClamShellClosed = true;
+                    _device.PlatingCellDeviceData.ClamShellOpened = false;
+                    return true;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                if (_device.PlatingCellDeviceData.ClamShellDistance > _openSensor)
+                {
+                    LOG.WriteLog(eEvent.INFO_PLATINGCELL, Module, $"ClamShell is Opened");
+                    _device.PlatingCellDeviceData.ClamShellClosed = false;
+                    _device.PlatingCellDeviceData.ClamShellOpened = true;
+                    return true;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+        }
+
+        public RState Start(params object[] objs)
+        {
+            _close = (bool)objs[0];
+            _device = DEVICE.GetDevice<PlatingCellDevice>($"{Module}");
+            _openSensor = SC.GetValue<int>("PlatingCell.ClamShellOpenDistanceThreshold");
+            _closeSensor = SC.GetValue<int>("PlatingCell.ClamShellCloseDistanceThreshold");
+            _sensorCheckTime = SC.GetValue<int>("PlatingCell.ClamShellOpenCheckDelay");
+            if (_close)
+            {
+                return Runner.Start(Module, "ClamShell Close");
+            }
+            else
+            {
+                return Runner.Start(Module, "ClamShell Open");
+            }
+        }
+    }
+
+
+
+}

+ 154 - 11
PunkHPX8_RT/Devices/PlatingCell/PlatingCellDevice.cs

@@ -1,7 +1,9 @@
 using Aitex.Core.RT.DataCenter;
 using Aitex.Core.RT.Device;
+using Aitex.Core.RT.Event;
 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.Beckhoff.ModuleIO;
@@ -12,11 +14,13 @@ using MECF.Framework.Common.Equipment;
 using MECF.Framework.Common.IOCore;
 using MECF.Framework.Common.Persistent.Reservoirs;
 using MECF.Framework.Common.ToolLayout;
+using MECF.Framework.RT.Core.Equipments;
 using PunkHPX8_Core;
 using PunkHPX8_RT.Devices.AXIS;
 using PunkHPX8_RT.Devices.LinMot;
 using PunkHPX8_RT.Devices.PowerSupplier;
 using PunkHPX8_RT.Devices.Reservoir;
+using PunkHPX8_RT.Devices.SRD;
 using PunkHPX8_RT.Devices.VpwMain;
 using PunkHPX8_RT.Modules;
 using PunkHPX8_RT.Modules.PlatingCell;
@@ -32,6 +36,17 @@ namespace PunkHPX8_RT.Devices.PlatingCell
 {
     public class PlatingCellDevice : BaseDevice, IDevice
     {
+        /// <summary>
+        /// Srd操作枚举
+        /// </summary>
+        private enum PlatingCellCommonOperation
+        {
+            None,
+            ClamShellClose,
+            ClamShellOpen,
+        }
+
+
         #region 常量 
         private const string PERSISTENT_VALUE = "PersistentValue";
         private const string PLATINGCELLDATA = "PlatingCellData";
@@ -55,6 +70,14 @@ namespace PunkHPX8_RT.Devices.PlatingCell
         #endregion
 
         #region 内部变量
+        /// <summary>
+        /// 当前操作
+        /// </summary>
+        private PlatingCellCommonOperation _currentOperation;
+        /// <summary>
+        /// clamshell routine操作
+        /// </summary>
+        private ClamShellCloseRoutine _closeRoutine;
         /// 变量是否初始化字典
         /// </summary>
         private Dictionary<string, bool> _variableInitializeDic = new Dictionary<string, bool>();
@@ -146,7 +169,7 @@ namespace PunkHPX8_RT.Devices.PlatingCell
 
         #endregion
 
-        #region 属性
+        #region 共享属性
         /// <summary>
         /// 设备数据
         /// </summary>
@@ -161,7 +184,7 @@ namespace PunkHPX8_RT.Devices.PlatingCell
         /// <param name="moduleName"></param>
         public PlatingCellDevice(string moduleName) : base(moduleName, moduleName, moduleName, moduleName)
         {
-            
+           
         }
         /// <summary>
         /// 初始化
@@ -173,9 +196,17 @@ namespace PunkHPX8_RT.Devices.PlatingCell
             SubscribeData();
             InitializeOperation();
             SubscribeValueAction();
+            InitializeRoutine();
             return true;
         }
         /// <summary>
+        /// 初始化Routine
+        /// </summary>
+        private void InitializeRoutine()
+        {
+            _closeRoutine = new ClamShellCloseRoutine(Module);
+        }
+        /// <summary>
         /// 定时器执行
         /// </summary>
         public bool OnTimer(int interval)
@@ -199,9 +230,67 @@ namespace PunkHPX8_RT.Devices.PlatingCell
             { 
                 _rotationAxis.OnTimer();
             }
+            
+            if (_status == RState.Running)
+            {
+                if (_currentOperation != PlatingCellCommonOperation.None)
+                {
+                    IRoutine routine = GetCurrentRoutine(_currentOperation);
+                    if (routine != null)
+                    {
+                        CheckRoutineState(routine, _currentOperation);
+                    }
+                    else
+                    {
+                        EndOperation();
+                    }
+                }
+            }
             return true;
         }
-
+        /// <summary>
+        /// 获取当前操作对应的Routine
+        /// </summary>
+        /// <param name="currentOperation"></param>
+        /// <returns></returns>
+        private IRoutine GetCurrentRoutine(PlatingCellCommonOperation currentOperation)
+        {
+            switch (currentOperation)
+            {
+                case PlatingCellCommonOperation.ClamShellOpen:
+                case PlatingCellCommonOperation.ClamShellClose:
+                    return _closeRoutine;
+                default:
+                    return null;
+            }
+        }
+        /// <summary>
+        /// 检验Routine状态
+        /// </summary>
+        /// <param name="routine"></param>
+        /// <param name="currentOperation"></param>
+        private void CheckRoutineState(IRoutine routine, PlatingCellCommonOperation currentOperation)
+        {
+            RState state = routine.Monitor();
+            if (state == RState.End)
+            {
+                EndOperation();
+            }
+            else if (state == RState.Failed || state == RState.Timeout)
+            {
+                LOG.WriteLog(eEvent.ERR_SRD, $"{Module}", $"{currentOperation} error");
+                _status = RState.Failed;
+                _currentOperation = PlatingCellCommonOperation.None;
+            }
+        }
+        /// <summary>
+        /// 结束操作
+        /// </summary>
+        private void EndOperation()
+        {
+            _status = RState.End;
+            _currentOperation = PlatingCellCommonOperation.None;
+        }
         /// <summary>
         /// 初始化参数
         /// </summary>
@@ -386,14 +475,14 @@ namespace PunkHPX8_RT.Devices.PlatingCell
         {
             return _rotationAxis.StopPositionOperation();
         }
-        public bool ClamShellClose()
-        {
-            return WriteVariableValue(CLAMSHELL_CLOSE, true);
-        }
-        public bool ClamShellOpen()
-        {
-            return WriteVariableValue(CLAMSHELL_CLOSE, false);
-        }
+        //public bool ClamShellClose()
+        //{
+        //    return WriteVariableValue(CLAMSHELL_CLOSE, true);
+        //}
+        //public bool ClamShellOpen()
+        //{
+        //    return WriteVariableValue(CLAMSHELL_CLOSE, false);
+        //}
         public bool HeadtTiltAction()
         {
             return WriteVariableValue(HEAD_TILT, true);
@@ -418,6 +507,60 @@ namespace PunkHPX8_RT.Devices.PlatingCell
         {
             return WriteVariableValue(RINSE_ENABLE, false);
         }
+        #region ClamShell Close
+        /// <summary>
+        /// ClamShell Close
+        /// </summary>
+        /// <param name="cmd"></param>
+        /// <param name="args"></param>
+        /// <returns></returns>
+        public bool ClamShellClose()
+        {
+            if (!JudgeRunningState(PlatingCellCommonOperation.ClamShellClose))
+            {
+                _currentOperation = PlatingCellCommonOperation.ClamShellClose;
+                _status = _closeRoutine.Start(true);
+                return _status == RState.Running;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        /// <summary>
+        /// ClamShell Open
+        /// </summary>
+        /// <param name="cmd"></param>
+        /// <param name="args"></param>
+        /// <returns></returns>
+        public bool ClamShellOpen()
+        {
+            if (!JudgeRunningState(PlatingCellCommonOperation.ClamShellOpen))
+            {
+                _currentOperation = PlatingCellCommonOperation.ClamShellOpen;
+                _status = _closeRoutine.Start(false);
+                return _status == RState.Running;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        /// <summary>
+        /// 判定运行状态
+        /// </summary>
+        /// <returns></returns>
+        private bool JudgeRunningState(PlatingCellCommonOperation operation)
+        {
+            if (_status == RState.Running)
+            {
+                EV.PostAlarmLog($"{Module}", eEvent.ERR_PLATINGCELL, $"{Module} current execute {_currentOperation},cannot {operation}");
+                return true;
+            }
+            return false;
+        }
+        #endregion
+        
         /// <summary>
         /// DisabledAction
         /// </summary>

+ 2 - 2
PunkHPX8_RT/Modules/ModuleMatcherManager.cs

@@ -54,11 +54,11 @@ namespace PunkHPX8_RT.Modules
         /// <param name="verticalId"></param>
         public void InitialPlatingCellVerticalID(string platingCellId,string verticalId)
         {
-            _platingCellVerticalMatcher[platingCellId] = verticalId;
+            _platingCellVerticalMatcher[platingCellId] = verticalId;  //key platingcell名字 - value vertical 名字
             List<string> list = null;
             if (_verticalMatcherListDic.ContainsKey(verticalId))
             { 
-                list= _verticalMatcherListDic[verticalId];
+                list= _verticalMatcherListDic[verticalId];    // key vertical名字,  value 所在的platingcell 列表
             }
             else
             {

+ 3 - 3
PunkHPX8_RT/Modules/PlatingCell/PlatingCellCCRRoutine.cs

@@ -137,7 +137,7 @@ namespace PunkHPX8_RT.Modules.PlatingCell
             CheckCurrentStepAndTimeRemain();
             _platingCellDevice.UpdateStatus(_currentStep);
             Runner.RunIf(CCRStep.CSRStart, _cSREnable , () => RecordCCRStepStartTime(out _cSRStartTime),  _delay_1ms)
-                .RunIf(CCRStep.CSRClamshellClose, _cSREnable , () => _platingCellDevice.ClamShellClose(), CheckClamShellClosed, _delay_1ms)
+                .RunIf(CCRStep.CSRClamshellClose, _cSREnable , () => { return _platingCellDevice.ClamShellClose(); }, CheckClamShellClosed, _delay_1ms)
                 .RunIf(CCRStep.CSROpenRinseValve, _cSREnable, OpenRinseValve, _delay_1ms)
                 .RunIf(CCRStep.CSRStartRotation, _cSREnable, () => CSRStartRotation(), _delay_1ms)
                 .WaitIf(CCRStep.CSRRinseMonitor, _cSREnable, MonitorCSRRinseRotationEndStatus)
@@ -245,7 +245,7 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         /// <returns></returns>
         private bool CheckClamShellClosed()
         {
-            return _platingCellDevice.PlatingCellDeviceData.ClamShellClose;
+            return _platingCellDevice.PlatingCellDeviceData.ClamShellClosed;
         }
         /// <summary>
         /// 检查ClamShell是否Open
@@ -253,7 +253,7 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         /// <returns></returns>
         private bool CheckClamShellOpen()
         {
-            return !_platingCellDevice.PlatingCellDeviceData.ClamShellClose;
+            return _platingCellDevice.PlatingCellDeviceData.ClamShellOpened;
         }
 
         /// <summary>

+ 2 - 2
PunkHPX8_RT/Modules/PlatingCell/PlatingCellInitializeRoutine.cs

@@ -229,7 +229,7 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         /// <returns></returns>
         private bool CheckClamShellClosed()
         {
-            return _platingCellDevice.PlatingCellDeviceData.ClamShellClose;
+            return _platingCellDevice.PlatingCellDeviceData.ClamShellClosed;
         }
         /// <summary>
         /// 检查ClamShell是否Open
@@ -237,7 +237,7 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         /// <returns></returns>
         private bool CheckClamShellOpen()
         {
-            return !_platingCellDevice.PlatingCellDeviceData.ClamShellClose;
+            return _platingCellDevice.PlatingCellDeviceData.ClamShellOpened;
         }
         /// <summary>
         /// 检查Angle是否Tilt

+ 10 - 35
PunkHPX8_RT/Modules/PlatingCell/PlatingCellInterRinseRoutine.cs

@@ -21,7 +21,7 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         {
             OpenRinseValve,
             StartRotation,
-            CheckRotationStop,
+            WaitRotation,
             CloseRinseValve,
             End
         }
@@ -48,6 +48,10 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         ///rotation Provider对象
         /// </summary>
         private BeckhoffProviderAxis _rotationProviderAxis;
+        /// <summary>
+        /// rotation运动的目的地
+        /// </summary>
+        private int _targetPosition;
 
         /// <summary>
         /// 构造函数
@@ -71,8 +75,8 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         public RState Monitor()
         {
             Runner.Run(RunRecipeStep.OpenRinseValve, _device.RinseEnableAction, _delay_1ms)
-                .Run(RunRecipeStep.StartRotation, StartRotation, _delay_1ms)
-                .WaitWithStopCondition(RunRecipeStep.CheckRotationStop, CheckRotationEndStatus, CheckRotationStopStatus)
+                .Run(RunRecipeStep.StartRotation, () => { return StartRotation(_targetPosition); }, _delay_1ms)
+                .Delay(RunRecipeStep.WaitRotation, _recipe.IntervalRinseTime*1000)
                 .Run(RunRecipeStep.CloseRinseValve, _device.RinseDisableAction, _delay_1ms)
                 .End(RunRecipeStep.End, NullFun);
             return Runner.Status;
@@ -83,14 +87,9 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         /// </summary>
         /// <param name="param"></param>
         /// <returns></returns>
-        private bool StartRotation()
+        private bool StartRotation(int targetPosition)
         {
-            //比例
-            double _scale = _rotationProviderAxis.ScaleFactor;
-            //rinse 目标位置 
-            double rinsePosition = _recipe.IntervalRinseTime * BeckhoffVelocityUtil.ConvertVelocityToDegPerSecondByRPM(_recipe.IntervalRinseSpeed);
-            int targetPosition = (int)Math.Round((rinsePosition + _recipe.IntervalRinseZoffset) * _scale, 0);
-            bool result = _rotationAxis.ProfilePosition(targetPosition, _recipe.IntervalRinseSpeed * SPEED_RATIO, 0, 0);
+            bool result = _rotationAxis.ProfilePosition(targetPosition, _recipe.IntervalRinseSpeed * SPEED_RATIO * 6, 0, 0); //rpm->deg/s
             if (!result)
             {
                 NotifyError(eEvent.ERR_PLATINGCELL, "Start Rotation is failed", 0);
@@ -98,31 +97,6 @@ namespace PunkHPX8_RT.Modules.PlatingCell
             }
             return true;
         }
-        /// <summary>
-        /// 检验Rotation是否停止
-        /// </summary>
-        /// <returns></returns>
-        private bool CheckRotationEndStatus()
-        {
-            if (!_rotationAxis.IsRun && _rotationAxis.Status == RState.End)
-            {
-                return true;
-            }
-            return false;
-        }
-        /// <summary>
-        /// 检验Rotation停止状态
-        /// </summary>
-        /// <returns></returns>
-        private bool CheckRotationStopStatus()
-        {
-            if (_rotationAxis.Status == RState.Failed || _rotationAxis.Status == RState.Timeout)
-            {
-                NotifyError(eEvent.ERR_PLATINGCELL, $"{Module}.Rotation is failed", 0);
-                return true;
-            }
-            return false;
-        }
 
         /// <summary>
         /// 启动
@@ -135,6 +109,7 @@ namespace PunkHPX8_RT.Modules.PlatingCell
             _rotationAxis = (JetAxisBase)objs[1];
             _device = (PlatingCellDevice)objs[2];
             _rotationProviderAxis = (BeckhoffProviderAxis)objs[3];
+            _targetPosition = (int)objs[4];
             return Runner.Start(Module, "start intervale rinse");
         }
     }

+ 112 - 14
PunkHPX8_RT/Modules/PlatingCell/PlatingCellRunRecipeRoutine.cs

@@ -3,6 +3,7 @@ using Aitex.Core.RT.Log;
 using Aitex.Core.RT.Routine;
 using Aitex.Core.Util;
 using MECF.Framework.Common.Beckhoff.AxisProvider;
+using MECF.Framework.Common.Beckhoff.Station;
 using MECF.Framework.Common.RecipeCenter;
 using MECF.Framework.Common.Routine;
 using MECF.Framework.Common.SubstrateTrackings;
@@ -18,6 +19,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using static Mono.Security.X509.X520;
 
 namespace PunkHPX8_RT.Modules.PlatingCell
 {
@@ -26,14 +28,26 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         private enum RunRecipeStep
         {
             Delay,
+            VerticalGotoRinse,
+            CheckVerticalGotoRinse,
             InterRinse,
             CheckInterRinse,
-            Vertical,
+            RotationStartEntry,
+            RotationChangeToEntrySpeed,
+            AngleTilt,
+            VerticalGotoEntry,
+            WaitEntryCurrentProtectedFromRinse,
+            WaitEntryCurrentProtectedFromHome,
+            EntryCurrentProtected,
             CheckVertical,
             End
         }
         #region 常量 
         private const int ALL_DAY_MILLOSECONDS = 24 * 60 * 60 * 1000;
+        /// <summary>
+        /// ROTATION电机转速比例
+        /// </summary>
+        private const int SPEED_RATIO = 1;
         #endregion
 
         #region 内部变量
@@ -76,6 +90,18 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         /// vertical axis entity
         /// </summary>
         private PlatingCellVerticalEntity _verticalEntity;
+        /// <summary>
+        /// vertical 轴的位置数据
+        /// </summary>
+        private BeckhoffStationAxis _verticalBeckhoffStation;
+        /// <summary>
+        /// recipe中是否存在电机反转
+        /// </summary>
+        private bool _isRecipeContainsRevserseRotation;
+        /// <summary>
+        /// run recipe 过程中电机会停的位置(需要根据recipe计算出来)
+        /// </summary>
+        private List<int> _targetPositionList = new List<int>(); 
         #endregion
         /// <summary>
         /// 构造函数
@@ -97,17 +123,59 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         /// </summary>
         /// <returns></returns>
         public RState Monitor()
-        {
-            Runner.Delay(RunRecipeStep.Delay, 5000)
-                .RunIf(RunRecipeStep.InterRinse, _recipe.RinseBeforeEntryEnable,() => { return _interRinseRoutine.Start(_recipe,_rotationAxis, _device, _rotationProviderAxis) == RState.Running; })
-                .WaitWithStopConditionIf(RunRecipeStep.CheckInterRinse, _recipe.RinseBeforeEntryEnable,CheckInterRinseEndStatus,
+        {        //vertical去rinse位置
+            Runner.RunIf(RunRecipeStep.VerticalGotoRinse, _recipe.RinseBeforeEntryEnable, () => { return StartVertical("Rinse",_recipe.IntervalRinseZoffset); }, _delay_1ms)
+                .WaitWithStopConditionIf(RunRecipeStep.CheckVerticalGotoRinse, _recipe.RinseBeforeEntryEnable, CheckVerticalEnd, CheckVerticalError)
+                 //执行interval rinse
+                .RunIf(RunRecipeStep.InterRinse, _recipe.RinseBeforeEntryEnable, () => { return _interRinseRoutine.Start(_recipe, _rotationAxis, _device, _rotationProviderAxis, _targetPositionList[0]) == RState.Running; })
+                .WaitWithStopConditionIf(RunRecipeStep.CheckInterRinse, _recipe.RinseBeforeEntryEnable, CheckInterRinseEndStatus,
                         () => CommonFunction.CheckRoutineStopState(_interRinseRoutine))
-                .Run(RunRecipeStep.Vertical, StartVertical)
-                .WaitWithStopCondition(RunRecipeStep.CheckVertical, CheckVerticalEnd, CheckVerticalError)
+                 //启动Rotation/Rotation 设置为entry 转速
+                .RunIf(RunRecipeStep.RotationStartEntry, !_recipe.RinseBeforeEntryEnable, RotationStartEntry, _delay_1ms)  //没有intercal rinse 在entry开始的时候启动rotation
+                .RunIf(RunRecipeStep.RotationChangeToEntrySpeed, _recipe.RinseBeforeEntryEnable, () => { return ChangeSpeed(_recipe.EntrySpinSpeed); }, _delay_1ms)  //有intercal rinse 直接变速
+                 //Angle tilt 操作
+                .Run(RunRecipeStep.AngleTilt, _device.HeadtTiltAction, () => { return _device.PlatingCellDeviceData.HeadTilt; }, _delay_1s)
+                .Run(RunRecipeStep.VerticalGotoEntry, () => { return StartVertical("Entry", _recipe.EntryZoffset); }, _delay_1ms)
+                .DelayIf(RunRecipeStep.WaitEntryCurrentProtectedFromRinse, !_recipe.RinseBeforeEntryEnable,CalculateVerticaMoveTime("Rinse","Entry") - 100 > 0 ? CalculateVerticaMoveTime("Rinse", "Entry"):0)
+                .DelayIf(RunRecipeStep.WaitEntryCurrentProtectedFromHome, _recipe.RinseBeforeEntryEnable,CalculateVerticaMoveTime("Home","Entry") - 100 > 0 ? CalculateVerticaMoveTime("Home", "Entry") : 0)
                 .End(RunRecipeStep.End, NullFun);
             return Runner.Status;
         }
-
+        /// <summary>
+        /// 计算vertical 从一个位置移动到另一个位置用时
+        /// </summary>
+        /// <param name="sourceLocation"></param>
+        /// <param name="destinationLocation"></param>
+        /// <returns>返回值单位毫秒</returns>
+        private int CalculateVerticaMoveTime(string sourceLocation,string destinationLocation) 
+        {
+            Station sourceStation = _verticalBeckhoffStation.Stations.FirstOrDefault(p => p.Name == $"{_verticalEntity.Module}.{sourceLocation}");
+            Station destinationStation = _verticalBeckhoffStation.Stations.FirstOrDefault(p => p.Name == $"{_verticalEntity.Module}.{destinationLocation}");
+            Double.TryParse(sourceStation.Position, out double sourcePosition);
+            Double.TryParse(destinationStation.Position, out double destinationPosition);
+            double time = Math.Abs(destinationPosition - sourcePosition) / _verticalEntity.MotionData.ProfileVelocity * 10;
+            if (time <= 0)
+            {
+                NotifyError(eEvent.WARN_PLATINGCELL, "Calculate Vertica Move Time is 0", 0);
+                return 0;
+            }
+            return (int)time;
+        }
+        /// <summary>
+        /// change speed
+        /// </summary>
+        /// <returns></returns>
+        private bool ChangeSpeed(int speed)  //参数speed单位是rmp
+        {
+            double realSpeed = BeckhoffVelocityUtil.ConvertVelocityToDegPerSecondByRPM(speed);
+            bool result = _rotationAxis.ChangeSpeed((int)realSpeed);
+            if (!result)
+            {
+                NotifyError(eEvent.ERR_PLATINGCELL, "Change Speed failed", 0);
+                return false;
+            }
+            return true;
+        }
         private bool CheckInterRinseEndStatus()
         {
             bool result = CommonFunction.CheckRoutineEndState(_interRinseRoutine);
@@ -115,17 +183,45 @@ namespace PunkHPX8_RT.Modules.PlatingCell
             return result;
         }
         /// <summary>
-        /// 垂直电机运行(仅示例只做参考)
+        /// rotation 从entry步骤开始旋转
+        /// </summary>
+        /// <returns></returns>
+        private bool RotationStartEntry()
+        {
+            bool result = _rotationAxis.ProfilePosition(_targetPositionList[0], _recipe.IntervalRinseSpeed * SPEED_RATIO, 0, 0);
+            if (!result)
+            {
+                NotifyError(eEvent.ERR_PLATINGCELL, "Start Rotation is failed", 0);
+                return false;
+            }
+            return true;
+        }
+        /// <summary>
+        /// vertical 运行
         /// </summary>
+        /// <param name="positionName"></param> 目标位置名称
+        /// <param name="offset"></param> 偏移量
         /// <returns></returns>
-        private bool StartVertical()
+        private bool StartVertical(string positionName,double offset) 
         {
-            double position = 101;
+            double position = 0;
+            Station station = _verticalBeckhoffStation.Stations.FirstOrDefault(p => p.Name == $"{_verticalEntity.Module}.{positionName}");
+            if (station != null)
+            {
+                if(!Double.TryParse(station.Position, out position))
+                {
+                    LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "vertical station position is error");
+                    return false;
+                }
+            }
+            else
+            {
+                LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, $"vertical station {_verticalEntity.Module}.{positionName} is null");
+                return false;
+            }
             return _verticalEntity.CheckToPostMessage<PlatingCellVerticalState, PlatingCellVerticalEntity.VerticalMsg>(Aitex.Core.RT.Log.eEvent.INFO_PLATINGCELL,
-                Module, (int)PlatingCellVerticalEntity.VerticalMsg.Position, position);
+                    Module, (int)PlatingCellVerticalEntity.VerticalMsg.Position, position + offset);
         }
-
-
         /// <summary>
         /// 检验垂直电机是否运动完成
         /// </summary>
@@ -175,6 +271,8 @@ namespace PunkHPX8_RT.Modules.PlatingCell
             //获取对应reservoir eneity
             string reservoir = ReservoirItemManager.Instance.GetReservoirByPlatingCell(Module);
             _reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(reservoir);
+            //获取vertical station信息对象
+             _verticalBeckhoffStation = BeckhoffStationLocationManager.Instance.GetStationAxis($"{_verticalEntity.Module}", "Vertical");
             if (!CheckPreCondition())
             {
                 return RState.Failed;

+ 14 - 2
PunkHPX8_RT/Modules/PlatingCell/PlatingCellVerticalEntity.cs

@@ -1,12 +1,15 @@
-using Aitex.Core.RT.Fsm;
+using Aitex.Core.RT.Device;
+using Aitex.Core.RT.Fsm;
 using Aitex.Core.RT.Log;
 using Aitex.Core.Util;
 using Aitex.Core.Utilities;
+using MECF.Framework.Common.CommonData.PUF;
 using MECF.Framework.Common.Equipment;
 using MECF.Framework.Common.Persistent.Reservoirs;
 using MECF.Framework.Common.Persistent.Temperature;
 using MECF.Framework.Common.ToolLayout;
 using PunkHPX8_Core;
+using PunkHPX8_RT.Devices.AXIS;
 using PunkHPX8_RT.Modules.Reservoir;
 using PunkHPX8_RT.Modules.VpwCell;
 using System;
@@ -35,6 +38,10 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         #region 内部变量
         private PlatingCellVerticalInitializeRoutine _initializeRoutine;
         private PlatingCellVerticalPositionRoutine _positionRoutine;
+        /// <summary>
+        /// vertical axis
+        /// </summary>
+        private JetAxisBase _verticalAxis;
         #endregion
 
         #region 属性
@@ -84,6 +91,11 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         public bool IsEngineering { get { return false; } }
 
         public bool IsProduction { get { return true; } }
+
+        /// <summary>
+        /// 运动数据对象
+        /// </summary>
+        public CommandMotionData MotionData { get { return _verticalAxis.MotionData; } }
         #endregion
 
         /// <summary>
@@ -93,7 +105,7 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         public PlatingCellVerticalEntity(ModuleName module)
         {
             Module = module;
-            
+            _verticalAxis = DEVICE.GetDevice<JetAxisBase>($"{Module}.Vertical");
             InitialFsm();
         }
         /// <summary>

+ 4 - 4
PunkHPX8_RT/Modules/PlatingCell/PlatingCellVerticalPositionRoutine.cs

@@ -76,7 +76,7 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         public RState Monitor()
         {
             Runner.Wait(PositionStep.WaitMatcher,CheckMatcher,_delay_2s)
-                .Run(PositionStep.GotoPosition, VerticalGotoLoad, 100)
+                .Run(PositionStep.GotoPosition, VerticalGotoPosition, 100)
                 .WaitWithStopCondition(PositionStep.GoToPositionCheck, CheckVerticalPositionStatus, CheckVerticalPositionRunStop)
                 .End(PositionStep.End, NullFun, _delay_1ms);
             return Runner.Status;
@@ -110,10 +110,10 @@ namespace PunkHPX8_RT.Modules.PlatingCell
             return true;
         }
         /// <summary>
-        /// vertical 运动到Load位置
+        /// vertical 运动到位置
         /// </summary>
         /// <returns></returns>
-        private bool VerticalGotoLoad()
+        private bool VerticalGotoPosition()
         {
             if(_verticalAxis != null )
             {
@@ -160,7 +160,7 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         public RState Start(params object[] objs)
         {
             _position=(double)objs[0];
-            _matcher = ModuleMatcherManager.Instance.GetMatcherListByVertical(Module);
+            _matcher = ModuleMatcherManager.Instance.GetMatcherListByVertical(Module); //获取电机所在的platingcell 列表
             _cellEntities.Clear();
             foreach (string str in _matcher) 
             {

+ 1 - 0
PunkHPX8_RT/PunkHPX8_RT.csproj

@@ -228,6 +228,7 @@
     <Compile Include="Devices\LinMot\LinMotStartVAIPositionRoutine.cs" />
     <Compile Include="Devices\LinMot\LinMotStopMotorRoutine.cs" />
     <Compile Include="Devices\LinMot\LinMotResetRoutine.cs" />
+    <Compile Include="Devices\PlatingCell\ClamShellCloseRoutine.cs" />
     <Compile Include="Devices\PlatingCell\DIPlatingCellDevice.cs" />
     <Compile Include="Devices\PlatingCell\DMPlatingCellDevice.cs" />
     <Compile Include="Devices\PlatingCell\HSPlatingCellDevice.cs" />

+ 37 - 0
PunkHPX8_Twincate/PunkHPX8/PlcTest/POUs/MAIN.TcPOU

@@ -1454,6 +1454,33 @@ ELSE
 	PlatingCell3_4_DI_16CHANNEL_EL1819_N430_5:=TRUE;
 END_IF
 
+//platingCell1 ClamShell
+IF PlatingCell1_2_DO_16CHANNEL_EL2809_N401_9 = TRUE THEN
+	PlatingCell1_2_AI_8CHANNEL_0_10V_EL3068_N402_1:=1300;
+ELSE
+	PlatingCell1_2_AI_8CHANNEL_0_10V_EL3068_N402_1:=19660;
+END_IF
+
+//platingCell2 ClamShell
+IF PlatingCell1_2_DO_16CHANNEL_EL2809_N401_10 = TRUE THEN
+	PlatingCell1_2_AI_8CHANNEL_0_10V_EL3068_N402_2:=1300;
+ELSE
+	PlatingCell1_2_AI_8CHANNEL_0_10V_EL3068_N402_2:=19660;
+END_IF
+
+//platingCell3 ClamShell
+IF PlatingCell1_2_DO_16CHANNEL_EL2809_N401_11 = TRUE THEN
+	PlatingCell3_4_AI_8CHANNEL_0_10V_EL3068_N432_1:=1300;
+ELSE
+	PlatingCell3_4_AI_8CHANNEL_0_10V_EL3068_N432_1:=19660;
+END_IF
+
+//platingCell4 ClamShell
+IF PlatingCell1_2_DO_16CHANNEL_EL2809_N401_12 = TRUE THEN
+	PlatingCell3_4_AI_8CHANNEL_0_10V_EL3068_N432_2:=1300;
+ELSE
+	PlatingCell3_4_AI_8CHANNEL_0_10V_EL3068_N432_2:=19660;
+END_IF
 ]]></ST>
     </Implementation>
     <LineIds Name="MAIN">
@@ -1609,7 +1636,17 @@ END_IF
       <LineId Id="6359" Count="1" />
       <LineId Id="6362" Count="0" />
       <LineId Id="6354" Count="0" />
+      <LineId Id="7107" Count="0" />
       <LineId Id="3181" Count="0" />
+      <LineId Id="7109" Count="1" />
+      <LineId Id="7112" Count="1" />
+      <LineId Id="7108" Count="0" />
+      <LineId Id="7116" Count="5" />
+      <LineId Id="7115" Count="0" />
+      <LineId Id="7123" Count="5" />
+      <LineId Id="7122" Count="0" />
+      <LineId Id="7130" Count="5" />
+      <LineId Id="7129" Count="0" />
       <LineId Id="2849" Count="0" />
     </LineIds>
   </POU>