using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Aitex.Sorter.Common; using CyberX8_RT.Devices; using MECF.Framework.Common.Routine; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.SubstrateTrackings; using CyberX8_Core; using Aitex.Core.RT.Log; using Aitex.Core.Util; using MECF.Framework.Common.Schedulers; using System.Collections.Generic; using CyberX8_RT.Devices.EFEM; using CyberX8_RT.Modules.LPs; using CyberX8_RT.Modules.SRD; using System.Runtime.InteropServices; using CyberX8_RT.Modules.PUF; using Aitex.Core.RT.Device; using CyberX8_RT.Devices.AXIS; using MECF.Framework.Common.Utilities; using CyberX8_RT.Devices.PUF; using CyberX8_RT.Modules.Transporter; using MECF.Framework.Common.WaferHolder; using System; using Aitex.Core.UI.ControlDataContext; namespace CyberX8_RT.Modules.EFEM { class EfemPickRoutine : RoutineBase, IRoutine { private enum PickStep { WaitModuleReady, PufVacuumOff, Picking1, Picking2, End, } private int _moveTimeout = 20 * 1000; private ModuleName _targetModule = ModuleName.System; int _targetSlot; int _targetSlot2; string _targetPufSlot; Hand _hand; Hand _hand2; EfemBase _efem; bool _bDoublePick = false; private SRDEntity _srdModule; private PUFEntity _pufModule; private Queue _moveQueue; public EfemPickRoutine(EfemBase efem) : base(ModuleName.EfemRobot.ToString()) { _efem = efem; } public RState Start(params object[] objs) { _bDoublePick = false; _moveQueue = (Queue)objs[0]; _targetModule = _moveQueue.Peek().SourceModule; _targetSlot = _moveQueue.Peek().SourceSlot; _hand = _moveQueue.Peek().RobotHand; if(_moveQueue.Count >= 2) { _bDoublePick = true; } if (!CheckPreCondition()) { return RState.Failed; } _moveTimeout = SC.GetValue($"EFEM.MotionTimeout") * 1000; return Runner.Start(Module, $"Pick from {_targetModule}"); } private Loadport GetLoadPort(ModuleName station) { LoadPortModule loadPortModule = Singleton.Instance.EFEM.GetLoadportModule(station - ModuleName.LP1); return loadPortModule.LPDevice; } private bool CheckPreCondition() { //LoadPort状态判断 if (ModuleHelper.IsLoadPort(_targetModule) && ModuleHelper.IsInstalled(_targetModule)) { Loadport loadPort=GetLoadPort(_targetModule); if (loadPort == null) { return false; } if (!loadPort.IsLoaded) { NotifyError(eEvent.ERR_EFEM_ROBOT, $"LoadPort not load, cannot do the pick action",-1); return false; } } if (ModuleHelper.IsSRD(_targetModule) && ModuleHelper.IsInstalled(_targetModule)) { _srdModule = Singleton.Instance.GetModule(_targetModule.ToString()); if (!_srdModule.IsHomed) { NotifyError(eEvent.ERR_EFEM_ROBOT, $"{_targetModule} is not homed, please home it first",-1); return false; } //判断arm是否在home位置上 JetAxisBase jetAxisBase = DEVICE.GetDevice($"{_targetModule}.Arm"); double position = jetAxisBase.MotionData.MotorPosition; bool result = jetAxisBase.CheckPositionIsInStation(position, "Home"); if (!result) { NotifyError(eEvent.ERR_EFEM_ROBOT, $"{_targetModule} armaxis {position} is not in homed place",-1); return false; } if (_srdModule.IsSrdDoorClosed) { NotifyError(eEvent.ERR_EFEM_ROBOT, $"{_targetModule} door closed, can not pick",-1); return false; } if (!_srdModule.IsSrdChuckVacuum) { NotifyError(eEvent.ERR_EFEM_ROBOT, $"{_targetModule} Vacuum on, can not pick",-1); return false; } } if (ModuleHelper.IsPUF(_targetModule) && ModuleHelper.IsInstalled(_targetModule)) { _pufModule = Singleton.Instance.GetModule(_targetModule.ToString()); if (!_pufModule.IsHomed) { NotifyError(eEvent.ERR_EFEM_ROBOT, $"{_targetModule} is not homed, please home it first",-1); return false; } if (!_pufModule.IsInRobotStation) { NotifyError(eEvent.ERR_EFEM_ROBOT, $"{_targetModule} not in robot station, cannot do the pick action",-1); return false; } } if (WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, (int)_hand)) { NotifyError(eEvent.ERR_EFEM_ROBOT, $"Efem robot arm{_hand} already has a wafer, cannot do the pick action",-1); return false; } if (WaferManager.Instance.CheckNoWafer(_targetModule, _targetSlot)) { if (ModuleHelper.IsPUF(_targetModule)) { _targetPufSlot = _targetSlot == 0 ? "SideA" : "SideB"; NotifyError(eEvent.ERR_EFEM_ROBOT, $"The target: {_targetModule}.{_targetPufSlot} has no wafer, cannot do the pick action",-1); } else { NotifyError(eEvent.ERR_EFEM_ROBOT, $"The target slot: {_targetModule}.{_targetSlot + 1} has no wafer, cannot do the pick action",-1); } return false; } if (_moveQueue.Count >= 2) { if (!ModuleHelper.IsLoadPort(_targetModule)) { NotifyError(eEvent.ERR_EFEM_ROBOT, $"Wrong double pick command, target is not loadport",-1); return false; } _hand2 = _hand != Hand.Blade1 ? Hand.Blade1 : Hand.Blade2; if (WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, (int)_hand2)) { NotifyError(eEvent.ERR_EFEM_ROBOT, $"Efem robot arm{_hand2} already has a wafer, cannot do the double pick action",-1); return false; } _targetSlot2 = _moveQueue.ToArray()[1].SourceSlot; if (WaferManager.Instance.CheckNoWafer(_targetModule, _targetSlot2)) { NotifyError(eEvent.ERR_EFEM_ROBOT, $"The target slot: {_targetModule}.{_targetSlot2 + 1} has no wafer, cannot do the double pick action",-1); return false; } } return true; } public RState Monitor() { if(_bDoublePick) { Runner.Wait(PickStep.WaitModuleReady, WaitModuleReady) .Run(PickStep.Picking1, Pick1, Pick1Done, _moveTimeout) .Run(PickStep.Picking2, Pick2, Pick2Done, _moveTimeout) .End(PickStep.End, ActionDone); } else { Runner.Wait(PickStep.WaitModuleReady, WaitModuleReady) .RunIf(PickStep.PufVacuumOff, ModuleHelper.IsPUF(_targetModule), PufVacuumOff, CheckPufVacuumOff, _delay_2s) .Run(PickStep.Picking1, Pick1, Pick1Done, _moveTimeout) .End(PickStep.End, ActionDone); } return Runner.Status; } /// /// Puf关闭真空 /// /// private bool PufVacuumOff() { PufVacuum pufVacuum = DEVICE.GetDevice($"{_targetModule}.Vacuum"); if (_targetSlot == 0) { return pufVacuum.VacuumAOff(); } else { return pufVacuum.VacuumBOff(); } } /// /// 检验Puf是否关闭真空 /// /// private bool CheckPufVacuumOff() { PufVacuum pufVacuum = DEVICE.GetDevice($"{_targetModule}.Vacuum"); if (_targetSlot == 0) { return pufVacuum.IsChuckAReleased; } else { return pufVacuum.ISChuckBReleased; } } public void Abort() { _efem.Halt(); } private bool WaitModuleReady() { return _efem.Status == RState.End; } private bool Pick1() { return _efem.Pick(_targetModule, _targetSlot, _hand); } private bool Pick1Done() { if (_efem.Status == RState.End) { WaferManager.Instance.WaferMoved(_targetModule, _targetSlot, ModuleName.EfemRobot, (int)_hand); return true; } else if (_efem.Status == RState.Failed) { NotifyError(eEvent.ERR_EFEM_ROBOT, $"Efem robot picking failed: {_efem.Status}",-1); return true; } return false; } private bool Pick2() { return _efem.Pick(_targetModule, _targetSlot2, _hand2); } private bool Pick2Done() { if (_efem.Status == RState.End) { WaferManager.Instance.WaferMoved(_targetModule, _targetSlot2, ModuleName.EfemRobot, (int)_hand2); return true; } else if (_efem.Status == RState.Failed) { NotifyError(eEvent.ERR_EFEM_ROBOT, $"Efem robot picking failed: {_efem.Status}",-1); return true; } return false; } private bool ActionDone() { return true; } /// /// 重试 /// /// public RState Retry(int step) { if(!CheckPreCondition()) { return RState.Failed; } _efem.Reset(); List preStepIds = new List(); AddPreSteps(PickStep.PufVacuumOff, preStepIds); return Runner.Retry(PickStep.PufVacuumOff, preStepIds, Module, "Pick Retry"); } /// /// 忽略前 /// /// /// private void AddPreSteps(PickStep step, List preStepIds) { for (int i = 0; i < (int)step; i++) { preStepIds.Add((PickStep)i); } } /// /// 检验前面完成状态 /// /// public bool CheckCompleteCondition(int index) { if (WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, (int)_hand)) { NotifyError(eEvent.ERR_EFEM_ROBOT, $"Efem robot arm{_hand} has no wafer", -1); return false; } if (WaferManager.Instance.CheckHasWafer(_targetModule, _targetSlot)) { NotifyError(eEvent.ERR_EFEM_ROBOT, $"{_targetModule} Slot{_targetSlot} has no wafer", -1); return false; } return true; } } }