Browse Source

add dunmmyRinse run recipe

chenzk 2 days ago
parent
commit
98591f14eb

+ 15 - 3
Framework/Common/RecipeCenter/DqdrRecipe.cs

@@ -31,7 +31,6 @@ namespace MECF.Framework.Common.RecipeCenter
 
         private int _drySpeed;
         private int _dryTime;
-        private double _dryZoffset;
         private bool _rinseBeforeEntryEnable;
         private int _intervalRinseSpeed;
         private int _intervalRinseTime;
@@ -85,8 +84,6 @@ namespace MECF.Framework.Common.RecipeCenter
         [JsonProperty]
         public int DryTime { get { return _dryTime; } set { _dryTime = value; InvokePropertyChanged(nameof(DryTime)); } }
 
-        [JsonProperty]
-        public double DryZoffset { get { return _dryZoffset; } set { _dryZoffset = value; InvokePropertyChanged(nameof(DryZoffset)); } }
 
         [JsonProperty]
         public bool RinseBeforeEntryEnable { get { return _rinseBeforeEntryEnable; } set { _rinseBeforeEntryEnable = value; InvokePropertyChanged(nameof(RinseBeforeEntryEnable)); } }
@@ -97,5 +94,20 @@ namespace MECF.Framework.Common.RecipeCenter
         [JsonProperty]
         public int IntervalRinseTime { get { return _intervalRinseTime; } set { _intervalRinseTime = value; InvokePropertyChanged(nameof(IntervalRinseTime)); } }
         #endregion
+
+        /// <summary>
+        /// 计算Recipe总时间,不包含vertical运动时间
+        /// </summary>
+        /// <returns></returns>
+        public int CalculateRecipeTotalTime()
+        {
+            int count = 0;
+            count += this.ReclaimTime + this.RinseTime + this.DryTime;
+            if (this.RinseBeforeEntryEnable)
+            {
+                count += IntervalRinseTime;
+            }
+            return count;
+        }
     }
 }

+ 32 - 5
PunkHPX8_RT/Devices/AXIS/JetAxisBase.cs

@@ -6,10 +6,14 @@ using Aitex.Core.RT.OperationCenter;
 using Aitex.Core.RT.Routine;
 using Aitex.Core.RT.SCCore;
 using Aitex.Core.Util;
+using CommunityToolkit.HighPerformance.Buffers;
 using MECF.Framework.Common.Beckhoff.AxisProvider;
 using MECF.Framework.Common.Beckhoff.IOAxis;
 using MECF.Framework.Common.Beckhoff.Station;
 using MECF.Framework.Common.CommonData.PUF;
+using MECF.Framework.Common.Device;
+using MECF.Framework.Common.Device.Galil;
+using MECF.Framework.Common.IOCore;
 using MECF.Framework.Common.TwinCat;
 using MECF.Framework.Common.Utilities;
 using PunkHPX8_Core;
@@ -21,11 +25,8 @@ using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Timers;
-using CommunityToolkit.HighPerformance.Buffers;
 using System.Windows.Documents;
-using MECF.Framework.Common.Device.Galil;
-using MECF.Framework.Common.Device;
-using MECF.Framework.Common.IOCore;
+using System.Windows.Input;
 
 namespace PunkHPX8_RT.Devices.AXIS
 {
@@ -473,7 +474,33 @@ namespace PunkHPX8_RT.Devices.AXIS
             }
             return true;
         }
-
+        /// <summary>
+        /// 判断电机当前位置是否在参数提供的某个位置
+        /// </summary>
+        /// <returns></returns>
+        public bool CheckMotoPositionInPosition(string position,double offset)
+        {
+            double checkPosition = 0;
+            foreach (Station item in _stationAxis.Stations)
+            {
+                if (item.Name == position)
+                {
+                    checkPosition = double.Parse(item.Position);
+                    break;
+                }
+            }
+            checkPosition = checkPosition + offset;
+            
+            if(MotionData.MotorPosition < checkPosition + _stationAxis.ToleranceDefault &&
+                MotionData.MotorPosition > checkPosition + _stationAxis.ToleranceDefault)
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
         /// <summary>
         /// 计算所处当前工位
         /// </summary>

+ 110 - 95
PunkHPX8_RT/Modules/PlatingCell/DunmmyRinseRunRecipeRoutine.cs

@@ -22,19 +22,35 @@ using System.Threading.Tasks;
 
 namespace PunkHPX8_RT.Modules.PlatingCell
 {
-    public class DunmmyRinseRunRecipeRoutine : RoutineBase, IRoutine
+    public class DummyRinseRunRecipeRoutine : RoutineBase, IRoutine
     {
         private enum RunRecipeStep
         {
             LoopStart,
-            InterRinse,
-            CheckInterRinse,
-            Reclaim,
-            CheckReclaim,
-            Rinse,
-            CheckRinse,
-            Dry,
-            CheckDry,
+            
+            //interval rinse
+            LoopCheckVerticalIntervalRinseStation,
+            IntervalRinseOpenRinseValve,
+            StartRotation,
+            WaitRotation,
+            IntervalRinseCloseRinseValve,
+            //reclaim
+            LoopCheckVerticalRelciamStation,
+            ReclaimChangeRotationSpeed,
+            ReclaimRotationDelay,
+            //rinse
+            LoopCheckVerticalRinseStation,
+            RinseOpenRinseValve,
+            RinseChangeRotationSpeed,
+            RinseRotationDelay,
+            RinseCloseRinseValve,
+            //Dry
+            LoopCheckVerticalDryStation,
+            DryChangeRotationSpeed,
+            DryRotationDelay,
+            RotationStop,
+            CheckRotationStoped,
+
             LoopEnd,
             End
         }
@@ -54,7 +70,11 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         /// <summary>
         /// recipe
         /// </summary>
-        private DepRecipe _recipe;
+        private DqdrRecipe _recipe;
+        /// <summary>
+        /// 匹配的platingcell的dep recipe
+        /// </summary>
+        private DepRecipe _matchPlatingCellDepDeprecipe;
         /// <summary>
         /// Platingcell device
         /// </summary>
@@ -77,7 +97,11 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         /// <summary>
         /// platingcell entity
         /// </summary>
-        private PlatingCellEntity _platingCellEntity;
+        private PlatingCellEntity _platingCellEntity; 
+        /// <summary>
+        /// 另一边的platingcell entity
+        /// </summary>
+        private PlatingCellEntity _matchPlatingCellEntity; 
         /// <summary>
         /// 对应reservoir entity
         /// </summary>
@@ -87,37 +111,9 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         /// </summary>
         private PlatingCellVerticalEntity _verticalEntity;
         /// <summary>
-        /// vertical 轴的位置数据
-        /// </summary>
-        private BeckhoffStationAxis _verticalBeckhoffStation;
-        /// <summary>
         /// run recipe 过程中电机会停的位置(需要根据recipe计算出来)
         /// </summary>
-        #region 电镀通电相关
-        /// <summary>
-        /// 不通电
-        /// </summary>
-        private bool _isZeroCurrent = false;
-        #endregion
 
-        #region routine
-        /// <summary>
-        /// interbal rinse routien
-        /// </summary>
-        private PlatingCellInterRinseRoutine _interRinseRoutine;
-        /// <summary>
-        /// reclaim routien
-        /// </summary>
-        private PlatingCellReclaimRoutine _reclaimRoutine;
-        /// <summary>
-        /// Rinse routien
-        /// </summary>
-        private PlatingCellRinseRoutine _rinseRoutine;
-        /// <summary>
-        /// Dry routien
-        /// </summary>
-        private PlatingCellDryRoutine _dryRoutine;
-        #endregion
 
         #region 属性
         #endregion
@@ -127,12 +123,9 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         /// 构造函数
         /// </summary>
         /// <param name="module"></param>
-        public DunmmyRinseRunRecipeRoutine(string module) : base(module)
+        public DummyRinseRunRecipeRoutine(string module) : base(module)
         {
-            _interRinseRoutine = new PlatingCellInterRinseRoutine(module);
-            _reclaimRoutine = new PlatingCellReclaimRoutine(module);
-            _rinseRoutine = new PlatingCellRinseRoutine(module);
-            _dryRoutine = new PlatingCellDryRoutine(module);
+
         }
         /// <summary>
         /// 中止
@@ -148,82 +141,107 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         public RState Monitor()
         {
 
-            Runner.LoopStart(RunRecipeStep.LoopStart, "Loop Start Cycle Run Platingcell Recipe Routine", _cycle, NullFun, _delay_1ms)
-                //interval rinse
-                .LoopRunIf(RunRecipeStep.InterRinse, _recipe.RinseBeforeEntryEnable, () => { return _interRinseRoutine.Start(_recipe, LARGETARGETPOSITION) == RState.Running; })
-                .LoopRunIfWithStopStatus(RunRecipeStep.CheckInterRinse, _recipe.RinseBeforeEntryEnable, CheckInterRinseEndStatus,
-                        () => CommonFunction.CheckRoutineStopState(_interRinseRoutine))
+            Runner.LoopStart(RunRecipeStep.LoopStart, "Loop Start Cycle Run DummyRinse Recipe Routine", _cycle, NullFun, _delay_1ms)
+                //interval risne
+                .LoopRunIfOnlyTimeOutFault(RunRecipeStep.LoopCheckVerticalIntervalRinseStation, _matchPlatingCellEntity.IsInRecipe && _recipe.RinseBeforeEntryEnable,
+                () => CheckVerticalInStation("Rinse", _matchPlatingCellDepDeprecipe.IntervalRinseZoffset), ALL_DAY_MILLOSECONDS)
+                .LoopRunIf(RunRecipeStep.IntervalRinseOpenRinseValve, _matchPlatingCellEntity.IsInRecipe && _recipe.RinseBeforeEntryEnable, _device.RinseEnableAction, _delay_1ms)
+                .LoopRunIf(RunRecipeStep.StartRotation, _matchPlatingCellEntity.IsInRecipe && _recipe.RinseBeforeEntryEnable, () => { return StartRotation(LARGETARGETPOSITION); }, _delay_1ms)
+                .LoopDelayIf(RunRecipeStep.WaitRotation, _matchPlatingCellEntity.IsInRecipe && _recipe.RinseBeforeEntryEnable, _recipe.IntervalRinseTime * 1000)
+                .LoopRunIf(RunRecipeStep.IntervalRinseCloseRinseValve, _matchPlatingCellEntity.IsInRecipe && _recipe.RinseBeforeEntryEnable, _device.RinseDisableAction, _delay_1ms)
+
                 //Reclaim
-                .LoopRun(RunRecipeStep.Reclaim, () => { return _reclaimRoutine.Start(_recipe, _isZeroCurrent, _device.PowerSupplier) == RState.Running; })
-                .LoopRunWithStopStatus(RunRecipeStep.CheckReclaim, CheckReclaimEndStatus, () => CommonFunction.CheckRoutineStopState(_reclaimRoutine))
+                .LoopRunIfOnlyTimeOutFault(RunRecipeStep.LoopCheckVerticalIntervalRinseStation, _matchPlatingCellEntity.IsInRecipe,
+                               () => CheckVerticalInStation("Reclaim", _matchPlatingCellDepDeprecipe.ReclaimZoffset), ALL_DAY_MILLOSECONDS)
+                .LoopRunIf(RunRecipeStep.ReclaimChangeRotationSpeed, _matchPlatingCellEntity.IsInRecipe , () => { return ChangeRotationSpeed(_recipe.ReclaimSpeed); }, _delay_1ms)
+                .LoopDelayIf(RunRecipeStep.ReclaimRotationDelay, _matchPlatingCellEntity.IsInRecipe , _recipe.ReclaimTime * 1000)
 
-                //Rinse
-                .LoopRun(RunRecipeStep.Rinse, () => { return _rinseRoutine.Start(_recipe) == RState.Running; })
-                .LoopRunWithStopStatus(RunRecipeStep.CheckRinse, CheckRinseEndStatus,
-                        () => CommonFunction.CheckRoutineStopState(_rinseRoutine))
+                 //Rinse
+                .LoopRunIfOnlyTimeOutFault(RunRecipeStep.LoopCheckVerticalRinseStation, _matchPlatingCellEntity.IsInRecipe,
+                               () => CheckVerticalInStation("Rinse", _matchPlatingCellDepDeprecipe.RinseZoffset), ALL_DAY_MILLOSECONDS)
+                .LoopRunIf(RunRecipeStep.RinseOpenRinseValve, _matchPlatingCellEntity.IsInRecipe, _device.RinseEnableAction, _delay_1ms)
+                .LoopRunIf(RunRecipeStep.RinseChangeRotationSpeed, _matchPlatingCellEntity.IsInRecipe, () => { return ChangeRotationSpeed(_recipe.RinseSpeed); }, _delay_1ms)
+                .LoopDelayIf(RunRecipeStep.RinseRotationDelay, _matchPlatingCellEntity.IsInRecipe, _recipe.RinseTime * 1000)
+                .LoopRunIf(RunRecipeStep.RinseCloseRinseValve, _matchPlatingCellEntity.IsInRecipe, _device.RinseDisableAction, _delay_1ms)
 
                 //Dry
-                .LoopRun(RunRecipeStep.Dry, () => { return _dryRoutine.Start(_recipe) == RState.Running; })
-                .LoopRunWithStopStatus(RunRecipeStep.CheckDry, CheckDryEndStatus, () => CommonFunction.CheckRoutineStopState(_dryRoutine))
+                .LoopRunIfOnlyTimeOutFault(RunRecipeStep.LoopCheckVerticalDryStation, _matchPlatingCellEntity.IsInRecipe && _matchPlatingCellDepDeprecipe.RinseZoffset != _matchPlatingCellDepDeprecipe.DryZoffset,
+                               () => CheckVerticalInStation("Rinse", _matchPlatingCellDepDeprecipe.DryZoffset), ALL_DAY_MILLOSECONDS)
+                .LoopRunIf(RunRecipeStep.DryChangeRotationSpeed, _matchPlatingCellEntity.IsInRecipe, () => { return ChangeRotationSpeed(_recipe.DrySpeed); }, _delay_1ms)
+                .LoopDelayIf(RunRecipeStep.DryRotationDelay, _matchPlatingCellEntity.IsInRecipe, _recipe.DryTime * 1000)
+
+                .LoopRun(RunRecipeStep.RotationStop, _rotationAxis.StopPositionOperation, _delay_1ms)
+                .LoopRunWithStopStatus(RunRecipeStep.CheckRotationStoped,  CheckRotationPositionStatus, CheckRotationPositionRunStop)
+
                 .LoopEnd(RunRecipeStep.LoopEnd, UpdateCycleCount, _delay_1ms)
                 .End(RunRecipeStep.End, NullFun);
             return Runner.Status;
         }
-        /// 统计完成的Cycle次数
+        /// <summary>
+        /// 查询vertical是否到达某个位置
         /// </summary>
         /// <returns></returns>
-        private bool UpdateCycleCount()
+        private bool CheckVerticalInStation(string station,double offset)
         {
-            _currentCycle += 1;
-            return true;
+            return _verticalEntity.ChecVerticalInPosition(station, offset);
         }
         /// <summary>
-        /// 获取当前Cycle次数
+        /// rotation开始旋转
         /// </summary>
+        /// <param name="param"></param>
         /// <returns></returns>
-        public int GetCurrentCycle()
+        private bool StartRotation(int targetPosition)
         {
-            return _currentCycle;
+            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);
+                return false;
+            }
+            return true;
         }
         /// <summary>
-        /// 检查interval rinse是否完成
+        /// rotation改变速度
         /// </summary>
+        /// <param name="speed"></param>
         /// <returns></returns>
-        private bool CheckInterRinseEndStatus()
+        private bool ChangeRotationSpeed(int speed)
         {
-            bool result = CommonFunction.CheckRoutineEndState(_interRinseRoutine);
-            SubRoutineStep = _interRinseRoutine.CurrentStep;
-            return result;
+            double _scale = _rotationAxis.ScaleFactor;
+            speed = (int)Math.Round(_scale * BeckhoffVelocityUtil.ConvertVelocityToDegPerSecondByRPM(speed), 0);
+            return _rotationAxis.ChangeSpeed(speed);
         }
         /// <summary>
-        /// 检查Reclaim是否完成
+        /// 检验Rotation移动状态
         /// </summary>
         /// <returns></returns>
-        private bool CheckReclaimEndStatus()
+        private bool CheckRotationPositionStatus()
         {
-            bool result = CommonFunction.CheckRoutineEndState(_reclaimRoutine);
-            SubRoutineStep = _reclaimRoutine.CurrentStep;
-            return result;
+            return _rotationAxis.Status == RState.End;
         }
         /// <summary>
-        /// 检查Rinse是否完成
+        /// 检验Rotation是否运动失败
         /// </summary>
         /// <returns></returns>
-        private bool CheckRinseEndStatus()
+        private bool CheckRotationPositionRunStop()
         {
-            bool result = CommonFunction.CheckRoutineEndState(_rinseRoutine);
-            SubRoutineStep = _rinseRoutine.CurrentStep;
-            return result;
+            return _rotationAxis.Status == RState.Failed || _rotationAxis.Status == RState.Timeout;
+        }
+        /// 统计完成的Cycle次数
+        /// </summary>
+        /// <returns></returns>
+        private bool UpdateCycleCount()
+        {
+            _currentCycle += 1;
+            return true;
         }
         /// <summary>
-        /// 检查Dry是否完成
+        /// 获取当前Cycle次数
         /// </summary>
         /// <returns></returns>
-        private bool CheckDryEndStatus()
+        public int GetCurrentCycle()
         {
-            bool result = CommonFunction.CheckRoutineEndState(_dryRoutine);
-            SubRoutineStep = _dryRoutine.CurrentStep;
-            return result;
+            return _currentCycle;
         }
         /// <summary>
         /// 启动
@@ -232,7 +250,7 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         /// <returns></returns>
         public RState Start(params object[] objs)
         {
-            _recipe = objs[0] as DepRecipe;
+            _recipe = objs[0] as DqdrRecipe;
             if (_recipe == null)
             {
                 LOG.WriteLog(eEvent.ERR_METAL, Module, "recipe is null");
@@ -250,22 +268,24 @@ namespace PunkHPX8_RT.Modules.PlatingCell
                 NotifyError(eEvent.ERR_PLATINGCELL, $"{Module}.Rotation Provider is not exist", 0);
                 return RState.Failed;
             }
-            //获取vertical entity
-            string vertical = ModuleMatcherManager.Instance.GetPlatingVerticalByCell(Module);
+            //获取相匹配的platingcell 的 vertical entity
+            string MatchModule = ModuleMatcherManager.Instance.GetMatcherByModule(Module);
+            string vertical = ModuleMatcherManager.Instance.GetPlatingVerticalByCell(MatchModule);
             _verticalEntity = Singleton<RouteManager>.Instance.GetModule<PlatingCellVerticalEntity>(vertical);
             //获取platingcell eneity
             _platingCellEntity = Singleton<RouteManager>.Instance.GetModule<PlatingCellEntity>(Module);
+            //获取match的platingcell的dep recipe
+            _matchPlatingCellEntity = Singleton<RouteManager>.Instance.GetModule<PlatingCellEntity>(MatchModule);
+            _matchPlatingCellDepDeprecipe = _matchPlatingCellEntity.CurrentRecipe;
             //获取对应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;
             }
             _currentCycle = 0;
-            return Runner.Start(Module, "PlatingCell Run Recipe");
+            return Runner.Start(Module, "PlatingCell Run DummyRecipe Recipe");
         }
         
         /// <summary>
@@ -279,11 +299,6 @@ namespace PunkHPX8_RT.Modules.PlatingCell
                 LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "Recipe is null");
                 return false;
             }
-            //if (_recipe.DepSteps.Count == 0)
-            //{
-            //    LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "Recipe DepSteps count is 0");
-            //    return false;
-            //}
             if (!CheckAxisHome())
             {
                 NotifyError(eEvent.ERR_PLATINGCELL, "Check Axis home error", 0);

+ 67 - 13
PunkHPX8_RT/Modules/PlatingCell/PlatingCellEntity.cs

@@ -5,6 +5,7 @@ using Aitex.Core.RT.Fsm;
 using Aitex.Core.RT.Log;
 using Aitex.Core.RT.OperationCenter;
 using Aitex.Core.RT.RecipeCenter;
+using Aitex.Core.RT.Routine;
 using Aitex.Core.RT.SCCore;
 using Aitex.Core.Util;
 using Aitex.Core.Utilities;
@@ -79,6 +80,10 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         /// </summary>
         private PlatingCellRunRecipeRoutine _runRecipeRoutine;
         /// <summary>
+        /// dummy risne Run recipe routine
+        /// </summary>
+        private DummyRinseRunRecipeRoutine _dummyRinseRunRecipeRoutine;
+        /// <summary>
         /// Unload Routine
         /// </summary>
         private PlatingCellUnloadRoutine _unloadRoutine;
@@ -122,7 +127,14 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         /// </summary>
         public bool IsBusy
         {
-            get { return fsm.State == (int)PlatingCellState.Initializing; }
+            get { return fsm.State == (int)PlatingCellState.Initializing ; }
+        }
+        /// <summary>
+        /// 正在Run recipe
+        /// </summary>
+        public bool IsInRecipe
+        {
+            get { return fsm.State == (int)PlatingCellState.RunReciping; }
         }
         /// <summary>
         /// 已完成的RunRecipeCycle次数
@@ -136,6 +148,13 @@ namespace PunkHPX8_RT.Modules.PlatingCell
             get { return _currentRecipe != null ? _currentRecipe.Chemistry : ""; }
         }
         /// <summary>
+        /// 当前正在run 的recipe
+        /// </summary>
+        public DepRecipe CurrentRecipe
+        {
+            get { return _currentRecipe; }
+        }
+        /// <summary>
         /// 是否禁用
         /// </summary>
         public bool IsDisable { get { return _persistentValue == null || _persistentValue.OperatingMode == DISABLED; } }
@@ -227,6 +246,7 @@ namespace PunkHPX8_RT.Modules.PlatingCell
             _initializeRoutine = new PlatingCellInitializeRoutine(Module.ToString());
             _platingCellCRRoutine = new PlatingCellCCRRoutine(Module.ToString());
             _runRecipeRoutine=new PlatingCellRunRecipeRoutine(Module.ToString());   
+            _dummyRinseRunRecipeRoutine=new DummyRinseRunRecipeRoutine(Module.ToString());   
             _unloadRoutine=new PlatingCellUnloadRoutine(Module.ToString());
         }
         /// <summary>
@@ -257,11 +277,25 @@ namespace PunkHPX8_RT.Modules.PlatingCell
             OP.Subscribe($"{Module}.ManualCCRStop", (cmd, args) => { return CheckToPostMessage<PlatingCellState, PlatingCellMsg>(eEvent.ERR_RESERVOIR, Module.ToString(), (int)PlatingCellMsg.CCRAbort); });
             OP.Subscribe($"{Module}.CycleManualProcessRecipe", (cmd, args) =>
             {
-                DepRecipe recipe = RecipeFileManager.Instance.LoadGenericityRecipe<DepRecipe>(args[0].ToString());
-                if (recipe == null)
+                bool isDummyLoad = (bool)args[1];
+                object recipe = null;
+                if (!isDummyLoad)
                 {
-                    LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module.ToString(), $"{args[0]} recipe is null");
-                    return false;
+                    recipe = RecipeFileManager.Instance.LoadGenericityRecipe<DepRecipe>(args[0].ToString());
+                    if (recipe == null)
+                    {
+                        LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module.ToString(), $"{args[0]} recipe is null");
+                        return false;
+                    }
+                }
+                else
+                {
+                    recipe = RecipeFileManager.Instance.LoadGenericityRecipe<DqdrRecipe>(args[0].ToString());
+                    if (recipe == null)
+                    {
+                        LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module.ToString(), $"{args[0]} recipe is null");
+                        return false;
+                    }
                 }
                 object[] objects = new object[args.Length];
                 objects[0] = recipe;
@@ -473,16 +507,34 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         /// <returns></returns>
         private bool CycleManualProcess(object[] param)
         {
-            bool result = _runRecipeRoutine.Start(param) == RState.Running;
-            _currentStepState = "";
-            DepRecipe recipe = param[0] as DepRecipe;
-            _cycle = (int)param[2];
-            if (result)
+            bool _isDummyLoad = (bool)param[1];
+            if (!_isDummyLoad)
             {
-                _recipeTime = recipe.CalculateRecipeTotalTime() * _cycle;
-                _currentRecipe = recipe;
+                bool result = _runRecipeRoutine.Start(param) == RState.Running;
+                _currentStepState = "";
+                DepRecipe recipe = param[0] as DepRecipe;
+                _cycle = (int)param[2];
+                if (result)
+                {
+                    _recipeTime = recipe.CalculateRecipeTotalTime() * _cycle;
+                    _currentRecipe = recipe;
+                }
+                return result;
+
+            }
+            else
+            {
+                bool result = _dummyRinseRunRecipeRoutine.Start(param) == RState.Running;
+                _currentStepState = "";
+                DqdrRecipe recipe = param[0] as DqdrRecipe;
+                _cycle = (int)param[2];
+                if (result)
+                {
+                    _recipeTime = recipe.CalculateRecipeTotalTime() * _cycle;
+                    //run dummy recipe不需要纪律当前recipe
+                }
+                return result;
             }
-            return result;
         }
         /// <summary>
         /// 监控
@@ -499,12 +551,14 @@ namespace PunkHPX8_RT.Modules.PlatingCell
             {
                 PostMsg(PlatingCellMsg.Error);
                 _currentStepState = "";
+                _currentRecipe = null;
                 return false;
             }
             bool result = state == RState.End;
             if (result)
             {
                 _currentStepState = "";
+                _currentRecipe = null;
             }
             return result;
         }

+ 9 - 0
PunkHPX8_RT/Modules/PlatingCell/PlatingCellVerticalEntity.cs

@@ -239,6 +239,15 @@ namespace PunkHPX8_RT.Modules.PlatingCell
         }
         #endregion
 
+        /// <summary>
+        /// 检验vertical是否在某个位置
+        /// </summary>
+        /// <returns></returns>
+        public bool ChecVerticalInPosition(string postion,double offset)
+        {
+            string position = $"{_verticalAxis.Module}.Vertical.{postion}";
+            return _verticalAxis.CheckMotoPositionInPosition(position,offset);
+        }
 
         public bool Check(int msg, out string reason, params object[] args)
         {

+ 1 - 0
PunkHPX8_RT/PunkHPX8_RT.csproj

@@ -299,6 +299,7 @@
     <Compile Include="Modules\LPs\LoadPortUnDockRoutine.cs" />
     <Compile Include="Devices\Reservoir\CAPumpOnRoutine.cs" />
     <Compile Include="Modules\ModuleMatcherManager.cs" />
+    <Compile Include="Modules\PlatingCell\DummyRinseRunRecipeRoutine.cs" />
     <Compile Include="Modules\PlatingCell\PlatingCellCCRRoutine.cs" />
     <Compile Include="Modules\PlatingCell\PlatingCellDepositionRoutine.cs" />
     <Compile Include="Modules\PlatingCell\PlatingCellDryRoutine.cs" />