|
@@ -0,0 +1,355 @@
|
|
|
|
+using Aitex.Core.Common;
|
|
|
|
+using Aitex.Core.RT.Log;
|
|
|
|
+using Aitex.Core.RT.Routine;
|
|
|
|
+using Aitex.Core.RT.SCCore;
|
|
|
|
+using Aitex.Core.Util;
|
|
|
|
+using Aitex.Sorter.Common;
|
|
|
|
+using CyberX8_Core;
|
|
|
|
+using CyberX8_RT.Devices.EFEM;
|
|
|
|
+using CyberX8_RT.Modules.LPs;
|
|
|
|
+using MECF.Framework.Common.Beckhoff.Station;
|
|
|
|
+using MECF.Framework.Common.Equipment;
|
|
|
|
+using MECF.Framework.Common.Schedulers;
|
|
|
|
+using MECF.Framework.Common.SubstrateTrackings;
|
|
|
|
+using MECF.Framework.Common.Utilities;
|
|
|
|
+using System;
|
|
|
|
+using System.Collections.Generic;
|
|
|
|
+using System.Linq;
|
|
|
|
+using System.Text;
|
|
|
|
+using System.Threading.Tasks;
|
|
|
|
+
|
|
|
|
+namespace CyberX8_RT.Modules.EFEM
|
|
|
|
+{
|
|
|
|
+ public class RobotCycleRoutine : ModuleRoutineBase, IRoutine
|
|
|
|
+ {
|
|
|
|
+ private enum RobotCycleStep
|
|
|
|
+ {
|
|
|
|
+
|
|
|
|
+ LPCycleStrat,
|
|
|
|
+
|
|
|
|
+ PickFromLP,
|
|
|
|
+ PickFromLPCheck,
|
|
|
|
+
|
|
|
|
+ PlaceToAligner,
|
|
|
|
+ PlaceToAlignerCheck,
|
|
|
|
+
|
|
|
|
+ PickFromAligner,
|
|
|
|
+ PickFromAlignerCheck,
|
|
|
|
+
|
|
|
|
+ PlaceToDummy,
|
|
|
|
+ PlaceToDummyCheck,
|
|
|
|
+
|
|
|
|
+ PickFromDummy,
|
|
|
|
+ PickFromDummyCheck,
|
|
|
|
+
|
|
|
|
+ PlaceToSrd,
|
|
|
|
+ PlaceToSrdCheck,
|
|
|
|
+
|
|
|
|
+ PickFromSrd,
|
|
|
|
+ PickFromSrdCheck,
|
|
|
|
+
|
|
|
|
+ PlaceToLP,
|
|
|
|
+ PlaceToLPCheck,
|
|
|
|
+
|
|
|
|
+ LPCycleEnd,
|
|
|
|
+
|
|
|
|
+ End
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ EfemBase _efem;
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// 当前Cycle选中的LP里面的Wafer数量
|
|
|
|
+ /// </summary>
|
|
|
|
+ private int _waferCount;
|
|
|
|
+
|
|
|
|
+ private EfemPickRoutine _efemPickRoutine;
|
|
|
|
+ private EfemPlaceRoutine _efemPlaceRoutine;
|
|
|
|
+
|
|
|
|
+ private ModuleName _targetLP;
|
|
|
|
+ private ModuleName _targetAligner;
|
|
|
|
+ private ModuleName _targetDummy;
|
|
|
|
+ private ModuleName _targetSrd;
|
|
|
|
+
|
|
|
|
+ private Queue<MoveItem> _lpToAlignerMoveItem = new Queue<MoveItem>();
|
|
|
|
+ private Queue<MoveItem> _alignerToDummyMoveItem = new Queue<MoveItem>();
|
|
|
|
+ private Queue<MoveItem> _alignerToSrdMoveItem = new Queue<MoveItem>();
|
|
|
|
+ private Queue<MoveItem> _dummyToLpMoveItem = new Queue<MoveItem>();
|
|
|
|
+ private Queue<MoveItem> _dummyToSrdMoveItem = new Queue<MoveItem>();
|
|
|
|
+ private Queue<MoveItem> _srdToLpMoveItem = new Queue<MoveItem>();
|
|
|
|
+
|
|
|
|
+ private Queue<int> _lpWaferIndex = new Queue<int>(); //记录有LP有Wafer的slot号
|
|
|
|
+
|
|
|
|
+ private int _moveTimeout = 20 * 1000;
|
|
|
|
+
|
|
|
|
+ public RobotCycleRoutine(EfemBase efem) : base(ModuleName.EfemRobot)
|
|
|
|
+ {
|
|
|
|
+ _efem = efem;
|
|
|
|
+ _efemPickRoutine = new EfemPickRoutine(efem);
|
|
|
|
+ _efemPlaceRoutine = new EfemPlaceRoutine(efem);
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public RState Start(params object[] objs)
|
|
|
|
+ {
|
|
|
|
+ _lpWaferIndex.Clear();//初始化LP 有wafer的slot号
|
|
|
|
+ _waferCount = 0; //初始化wafercount的数量
|
|
|
|
+ if (objs.Length >= 5)
|
|
|
|
+ {
|
|
|
|
+ _targetLP = (ModuleName)objs[0];
|
|
|
|
+ _targetAligner = (ModuleName)objs[1];
|
|
|
|
+ _targetDummy = (ModuleName)objs[2];
|
|
|
|
+ _targetSrd = (ModuleName)objs[3];
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ return RState.Failed;
|
|
|
|
+ }
|
|
|
|
+ if (!CheckPreCondition())
|
|
|
|
+ {
|
|
|
|
+ return RState.Failed;
|
|
|
|
+ }
|
|
|
|
+ _moveTimeout = SC.GetValue<int>($"EFEM.MotionTimeout") * 1000;
|
|
|
|
+
|
|
|
|
+ MoveItem lpToAlignerMoveItem = new MoveItem //LP To Aligner
|
|
|
|
+ {
|
|
|
|
+ SourceModule = _targetLP,
|
|
|
|
+ SourceSlot = _lpWaferIndex.Dequeue(),
|
|
|
|
+ DestinationModule = ModuleName.Aligner1,
|
|
|
|
+ DestinationSlot = 0,
|
|
|
|
+ RobotHand = 0 //表示blade1
|
|
|
|
+ };
|
|
|
|
+ _lpToAlignerMoveItem.Enqueue(lpToAlignerMoveItem);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ MoveItem alignerToDummyMoveItem = new MoveItem //Aligner To Dummy
|
|
|
|
+ {
|
|
|
|
+ SourceModule = ModuleName.Aligner1,
|
|
|
|
+ SourceSlot = 0,
|
|
|
|
+ DestinationModule = _targetDummy,
|
|
|
|
+ DestinationSlot = 0,
|
|
|
|
+ RobotHand = 0
|
|
|
|
+ };
|
|
|
|
+ _alignerToDummyMoveItem.Enqueue(alignerToDummyMoveItem);
|
|
|
|
+
|
|
|
|
+ MoveItem alignerToSrdMoveItem = new MoveItem //Aligner To Srd
|
|
|
|
+ {
|
|
|
|
+ SourceModule = ModuleName.Aligner1,
|
|
|
|
+ SourceSlot = 0,
|
|
|
|
+ DestinationModule = _targetSrd,
|
|
|
|
+ DestinationSlot = 0,
|
|
|
|
+ RobotHand = 0
|
|
|
|
+ };
|
|
|
|
+ _alignerToSrdMoveItem.Enqueue(alignerToSrdMoveItem);
|
|
|
|
+
|
|
|
|
+ MoveItem dummyToLpMoveItem = new MoveItem //Dummy To LP
|
|
|
|
+ {
|
|
|
|
+ SourceModule = _targetDummy,
|
|
|
|
+ SourceSlot = 0,
|
|
|
|
+ DestinationModule = _targetLP,
|
|
|
|
+ DestinationSlot = _lpToAlignerMoveItem.Peek().SourceSlot, //放回原来LP的slot位置
|
|
|
|
+ RobotHand = 0
|
|
|
|
+ };
|
|
|
|
+ _dummyToLpMoveItem.Enqueue(dummyToLpMoveItem);
|
|
|
|
+
|
|
|
|
+ MoveItem dummyToSrdMoveItem = new MoveItem //Dummy To Srd
|
|
|
|
+ {
|
|
|
|
+ SourceModule = _targetDummy,
|
|
|
|
+ SourceSlot = 0,
|
|
|
|
+ DestinationModule = _targetSrd,
|
|
|
|
+ DestinationSlot = 0,
|
|
|
|
+ RobotHand = 0
|
|
|
|
+ };
|
|
|
|
+ _dummyToSrdMoveItem.Enqueue(dummyToSrdMoveItem);
|
|
|
|
+
|
|
|
|
+ MoveItem srdToLpMoveItem = new MoveItem //SRD To LP
|
|
|
|
+ {
|
|
|
|
+ DestinationModule = _targetLP,
|
|
|
|
+ DestinationSlot = _lpToAlignerMoveItem.Peek().SourceSlot, //放回原来LP的slot位置
|
|
|
|
+ RobotHand = 0
|
|
|
|
+ };
|
|
|
|
+ _srdToLpMoveItem.Enqueue(srdToLpMoveItem);
|
|
|
|
+
|
|
|
|
+ return Runner.Start(Module, "Robot Cycle start");
|
|
|
|
+ }
|
|
|
|
+ //更新dummy的位置
|
|
|
|
+ private bool UpdateMoveItem()
|
|
|
|
+ {
|
|
|
|
+ if (_lpWaferIndex.Count > 0)
|
|
|
|
+ {
|
|
|
|
+ _lpToAlignerMoveItem.Peek().SourceSlot = _lpWaferIndex.Dequeue(); //更新从LP取片的位置
|
|
|
|
+ if (_targetDummy != ModuleName.Unknown)
|
|
|
|
+ {
|
|
|
|
+ _alignerToDummyMoveItem.Peek().DestinationSlot++; //更新放到Dummy的位置
|
|
|
|
+ _dummyToLpMoveItem.Peek().SourceSlot++; //更新从dummy取片的位置,送回LP
|
|
|
|
+ _dummyToSrdMoveItem.Peek().SourceSlot++;//更新从dummy取片的位置,送到Srd
|
|
|
|
+ }
|
|
|
|
+ _dummyToLpMoveItem.Peek().DestinationSlot = _lpToAlignerMoveItem.Peek().SourceSlot;//更新放回LP的位置。
|
|
|
|
+ _srdToLpMoveItem.Peek().DestinationSlot = _lpToAlignerMoveItem.Peek().SourceSlot;//更新放回LP的位置。
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ //清除MoveItem
|
|
|
|
+ private bool ClearMoveItem()
|
|
|
|
+ {
|
|
|
|
+ _lpToAlignerMoveItem.Clear();
|
|
|
|
+ _alignerToDummyMoveItem.Clear();
|
|
|
|
+ _alignerToSrdMoveItem.Clear();
|
|
|
|
+ _dummyToLpMoveItem.Clear();
|
|
|
|
+ _dummyToSrdMoveItem.Clear();
|
|
|
|
+ _srdToLpMoveItem.Clear();
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public RState Monitor()
|
|
|
|
+ {
|
|
|
|
+ Runner.LoopStart(RobotCycleStep.LPCycleStrat, "LP Cycle Start", _waferCount, NullFun, _delay_1ms)
|
|
|
|
+
|
|
|
|
+ .LoopRun(RobotCycleStep.PickFromLP, () => { return _efemPickRoutine.Start(_lpToAlignerMoveItem) == RState.Running; }, _delay_1ms)
|
|
|
|
+ .LoopRunWithStopStatus(RobotCycleStep.PickFromLPCheck, () => { return CommonFunction.CheckRoutineEndState(_efemPickRoutine); },
|
|
|
|
+ () => CheckRoutineStopStatus(_efemPickRoutine, "Efem pick from LP failed"))
|
|
|
|
+
|
|
|
|
+ .LoopRun(RobotCycleStep.PlaceToAligner, () => { return _efemPlaceRoutine.Start(_lpToAlignerMoveItem) == RState.Running; }, _delay_1ms)
|
|
|
|
+ .LoopRunWithStopStatus(RobotCycleStep.PlaceToAlignerCheck, () => { return CommonFunction.CheckRoutineEndState(_efemPlaceRoutine); },
|
|
|
|
+ () => CheckRoutineStopStatus(_efemPlaceRoutine, "Efem place to aligner failed"))
|
|
|
|
+
|
|
|
|
+ .LoopRun(RobotCycleStep.PickFromAligner, () => { return _efemPickRoutine.Start(_alignerToDummyMoveItem) == RState.Running; }, _delay_1ms)
|
|
|
|
+ .LoopRunWithStopStatus(RobotCycleStep.PickFromAlignerCheck, () => { return CommonFunction.CheckRoutineEndState(_efemPickRoutine); },
|
|
|
|
+ () => CheckRoutineStopStatus(_efemPickRoutine, "Efem pick from aligner failed"))
|
|
|
|
+
|
|
|
|
+ .LoopRunIf(RobotCycleStep.PlaceToDummy, _targetDummy != ModuleName.Unknown, () => { return _efemPlaceRoutine.Start(_alignerToDummyMoveItem) == RState.Running; }, _delay_1ms)
|
|
|
|
+ .LoopRunIfWithStopStatus(RobotCycleStep.PlaceToDummyCheck, _targetDummy != ModuleName.Unknown,() => { return CommonFunction.CheckRoutineEndState(_efemPlaceRoutine); },
|
|
|
|
+ () => CheckRoutineStopStatus(_efemPlaceRoutine, "Efem place to dummy failed"))
|
|
|
|
+
|
|
|
|
+ .LoopRunIf(RobotCycleStep.PickFromDummy, _targetDummy != ModuleName.Unknown, () => { return _efemPickRoutine.Start(_dummyToLpMoveItem) == RState.Running; }, _delay_1ms)
|
|
|
|
+ .LoopRunIfWithStopStatus(RobotCycleStep.PickFromDummyCheck, _targetDummy != ModuleName.Unknown,() => { return CommonFunction.CheckRoutineEndState(_efemPickRoutine); },
|
|
|
|
+ () => CheckRoutineStopStatus(_efemPickRoutine, "Efem pick from dummy failed"))
|
|
|
|
+
|
|
|
|
+ //从Dummy到SRD的
|
|
|
|
+ .LoopRunIf(RobotCycleStep.PlaceToSrd, _targetSrd != ModuleName.Unknown && _targetDummy!=ModuleName.Unknown, () => { return _efemPlaceRoutine.Start(_alignerToSrdMoveItem) == RState.Running; }, _delay_1ms)
|
|
|
|
+ .LoopRunIfWithStopStatus(RobotCycleStep.PlaceToSrdCheck, _targetSrd != ModuleName.Unknown && _targetDummy != ModuleName.Unknown, () => { return CommonFunction.CheckRoutineEndState(_efemPlaceRoutine); },
|
|
|
|
+ () => CheckRoutineStopStatus(_efemPlaceRoutine, "Efem place to srd failed"))
|
|
|
|
+ .LoopRunIf(RobotCycleStep.PickFromSrd, _targetSrd != ModuleName.Unknown && _targetDummy != ModuleName.Unknown, () => { return _efemPickRoutine.Start(_alignerToSrdMoveItem) == RState.Running; }, _delay_1ms)
|
|
|
|
+ .LoopRunIfWithStopStatus(RobotCycleStep.PickFromSrdCheck, _targetSrd != ModuleName.Unknown && _targetDummy != ModuleName.Unknown, () => { return CommonFunction.CheckRoutineEndState(_efemPickRoutine); },
|
|
|
|
+ () => CheckRoutineStopStatus(_efemPickRoutine, "Efem pick from srd failed"))
|
|
|
|
+
|
|
|
|
+ //从Aligner到SRD的
|
|
|
|
+ .LoopRunIf(RobotCycleStep.PlaceToSrd, _targetSrd != ModuleName.Unknown && _targetDummy == ModuleName.Unknown, () => { return _efemPlaceRoutine.Start(_dummyToSrdMoveItem) == RState.Running; }, _delay_1ms)
|
|
|
|
+ .LoopRunIfWithStopStatus(RobotCycleStep.PlaceToSrdCheck, _targetSrd != ModuleName.Unknown && _targetDummy == ModuleName.Unknown, () => { return CommonFunction.CheckRoutineEndState(_efemPlaceRoutine); },
|
|
|
|
+ () => CheckRoutineStopStatus(_efemPlaceRoutine, "Efem place to srd failed"))
|
|
|
|
+ .LoopRunIf(RobotCycleStep.PickFromSrd, _targetSrd != ModuleName.Unknown && _targetDummy == ModuleName.Unknown, () => { return _efemPickRoutine.Start(_dummyToSrdMoveItem) == RState.Running; }, _delay_1ms)
|
|
|
|
+ .LoopRunIfWithStopStatus(RobotCycleStep.PickFromSrdCheck, _targetSrd != ModuleName.Unknown && _targetDummy == ModuleName.Unknown, () => { return CommonFunction.CheckRoutineEndState(_efemPickRoutine); },
|
|
|
|
+ () => CheckRoutineStopStatus(_efemPickRoutine, "Efem pick from srd failed"))
|
|
|
|
+
|
|
|
|
+ //从Dummy回LP
|
|
|
|
+ .LoopRunIf(RobotCycleStep.PlaceToLP, _targetDummy != ModuleName.Unknown && _targetSrd == ModuleName.Unknown, () => { return _efemPlaceRoutine.Start(_dummyToLpMoveItem) == RState.Running; }, _delay_1ms)
|
|
|
|
+ .LoopRunIfWithStopStatus(RobotCycleStep.PlaceToLPCheck, _targetDummy != ModuleName.Unknown && _targetSrd == ModuleName.Unknown, () => { return CommonFunction.CheckRoutineEndState(_efemPlaceRoutine); },
|
|
|
|
+ () => CheckRoutineStopStatus(_efemPlaceRoutine, "Efem place to LP failed"))
|
|
|
|
+
|
|
|
|
+ //从SRD回LP
|
|
|
|
+ .LoopRunIf(RobotCycleStep.PlaceToLP, _targetSrd != ModuleName.Unknown, () => { return _efemPlaceRoutine.Start(_srdToLpMoveItem) == RState.Running; }, _delay_1ms)
|
|
|
|
+ .LoopRunIfWithStopStatus(RobotCycleStep.PlaceToLPCheck, _targetSrd != ModuleName.Unknown, () => { return CommonFunction.CheckRoutineEndState(_efemPlaceRoutine); },
|
|
|
|
+ () => CheckRoutineStopStatus(_efemPlaceRoutine, "Efem place to LP failed"))
|
|
|
|
+
|
|
|
|
+ .LoopEnd(RobotCycleStep.LPCycleEnd, UpdateMoveItem, _delay_1ms)
|
|
|
|
+ .End(RobotCycleStep.End, ClearMoveItem, _delay_1ms);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ return Runner.Status;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public void Abort()
|
|
|
|
+ {
|
|
|
|
+ _efem.Halt();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #region 功能方法
|
|
|
|
+ private bool CheckPreCondition()
|
|
|
|
+ {
|
|
|
|
+ if (WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 0))
|
|
|
|
+ {
|
|
|
|
+ Stop($"Efem robot arm already has a wafer, cannot do the RobotCycle action");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ //LoadPort状态判断
|
|
|
|
+ if (ModuleHelper.IsLoadPort(_targetLP) && ModuleHelper.IsInstalled(_targetLP))
|
|
|
|
+ {
|
|
|
|
+ Loadport loadPort = GetLoadPort(_targetLP);
|
|
|
|
+ if (loadPort == null)
|
|
|
|
+ {
|
|
|
|
+ Stop($"{_targetLP} is null");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ if (!loadPort.IsLoaded)
|
|
|
|
+ {
|
|
|
|
+ Stop($"{_targetLP} is not load");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ WaferInfo[] waferInfos = WaferManager.Instance.GetWafers(_targetLP);
|
|
|
|
+ for (int i = 0; i < waferInfos.Length; i++)
|
|
|
|
+ {
|
|
|
|
+ if (waferInfos[i] != null && !waferInfos[i].IsEmpty)
|
|
|
|
+ {
|
|
|
|
+ _waferCount++;
|
|
|
|
+ _lpWaferIndex.Enqueue(i);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (_waferCount < 1)
|
|
|
|
+ {
|
|
|
|
+ Stop($"there is no wafer in {_targetLP}");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ //Aligner状态判断
|
|
|
|
+ //if (!ModuleHelper.IsInstalled(_targetAligner))
|
|
|
|
+ //{
|
|
|
|
+ // Stop($"{_targetAligner} is not installed");
|
|
|
|
+ // return false;
|
|
|
|
+ //}
|
|
|
|
+ //Dummy状态判断
|
|
|
|
+ if (!ModuleHelper.IsInstalled(_targetDummy))
|
|
|
|
+ {
|
|
|
|
+ Stop($"{_targetDummy} is not installed");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ //若dummy存在wafer,需要人工处理
|
|
|
|
+ DummyDevice dummyDevice = Singleton<RouteManager>.Instance.EFEM.GetDummyDevice(_targetDummy - ModuleName.Dummy1);
|
|
|
|
+ if(dummyDevice != null)
|
|
|
|
+ {
|
|
|
|
+ if (!dummyDevice.HasCassette)
|
|
|
|
+ {
|
|
|
|
+ Stop($"{_targetDummy} dose not have cassette");
|
|
|
|
+ }
|
|
|
|
+ WaferInfo[] waferInfos = WaferManager.Instance.GetWafers(_targetDummy);
|
|
|
|
+ foreach (var item in waferInfos)
|
|
|
|
+ {
|
|
|
|
+ if (item != null && !item.IsEmpty)
|
|
|
|
+ {
|
|
|
|
+ Stop($"There are wafers inside the {_targetDummy},cannot do the RobotCycle action");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private Loadport GetLoadPort(ModuleName station)
|
|
|
|
+ {
|
|
|
|
+ LoadPortModule loadPortModule = Singleton<RouteManager>.Instance.EFEM.GetLoadportModule(station - ModuleName.LP1);
|
|
|
|
+ return loadPortModule.LPDevice;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private bool CheckRoutineStopStatus(IRoutine routine, string error)
|
|
|
|
+ {
|
|
|
|
+ bool result = CommonFunction.CheckRoutineStopState(routine);
|
|
|
|
+ if (result)
|
|
|
|
+ {
|
|
|
|
+ Stop( $"{error}");
|
|
|
|
+ }
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ #endregion
|
|
|
|
+ }
|
|
|
|
+}
|