using Aitex.Core.RT.Device; using Aitex.Core.RT.Log; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using MECF.Framework.Common.Beckhoff.Station; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.Layout; using MECF.Framework.Common.Routine; using MECF.Framework.Common.Utilities; using MECF.Framework.Common.WaferHolder; using CyberX8_Core; using CyberX8_RT.Devices.AXIS; using CyberX8_RT.Devices.AXIS.CANOpen; using CyberX8_RT.Devices.Facilities; using CyberX8_RT.Devices.Loader; using CyberX8_RT.Devices.TransPorter; using CyberX8_RT.Modules.Loader; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using CyberX8_RT.Devices.Rinse; using CyberX8_RT.Devices.Metal; using Aitex.Core.Common; namespace CyberX8_RT.Modules.Transporter { public class TransporterPickUpFromRoutine : RoutineBase, IRoutine { private enum PickUpStep { CheckPreCondition, TargetCellUnclamp, TargetCellUnclampWait, VerticalLow, VerticalLowWait, SafeMoveTo, CheckMoveToStatus, GantryPosition, GantryPoisitiolWait, UnlockTransporterClamp, UnlockTransporterClampWait, CellClampRetract, //CellClampRetractWait, LoopPickupRetry, LoopRetryUnlock, LoopRetryUnlockWait, LoopRetryBackToLow, LoopRetryBackToLowWait, ElevatorPosition, ElevatorPositionWait, Delay, ReadyToLockCheck, LockTransporterClamp, LockTransporterClampWait, LoopPickupRetryEnd, CalculateLiftupSpeed, PickupDelay, VerticalUp, VerticalUpWait, UpdateWaferHolder, CheckWHPresentAndLock, //ReadBarcodeConfirm, End } #region 内部变量 private string _cellName; private JetAxisBase _gantryAxis; private JetAxisBase _elevatorAxis; private LoaderEntity _loaderEntity; private JetAxisBase _loaderRotationAxis; private SystemFacilities _facilities; private TransporterUnlockRoutine _unlockRoutine; private TransporterLockRoutine _lockRoutine; private TransporterConflictRoutine _conflictRoutine; private TransporterCommon _transporterCommon; private LoaderPreTransferUnclampRoutine _preTransferUnclampRoutine; private LoaderCommonDevice _loaderCommonDevice; ProcessLayoutCellItem _cellItem; private int _pickupTime; private int _pickupDelayTime; private int _velocity; private int _acceleration; private bool _bypassWaferHolderPresent; private int _pickMaxRetries = 2; #endregion /// /// 构造函数 /// /// public TransporterPickUpFromRoutine(string module) : base(module) { } /// /// 中止 /// public void Abort() { Runner.Stop("Manual Abort"); } /// /// 监控 /// /// public RState Monitor() { Runner.Run(PickUpStep.CheckPreCondition, CheckStartPreConfition, _delay_1ms) //确认cell clamp Retracted .Run(PickUpStep.TargetCellUnclamp, TargetCellUnclamp, _delay_1ms) .WaitWithStopCondition(PickUpStep.TargetCellUnclampWait, TargetCellUnclampEndStatus, TargetCellUnclampStopStatus) .Run(PickUpStep.VerticalLow, ElevatorGotoLow, _delay_1ms) .WaitWithStopCondition(PickUpStep.VerticalLowWait, CheckVerticalPositionStatus, CheckVerticalPositionRunStop) //1.2 Move to 安全 .Run(PickUpStep.SafeMoveTo, SafeMoveTo, _delay_1ms) .WaitWithStopCondition(PickUpStep.CheckMoveToStatus, () => CommonFunction.CheckRoutineEndState(_conflictRoutine), CheckSafeMoveToStopStatus) //1.2 Gantry 移动 .Run(PickUpStep.GantryPosition, GantryPositionToCell, _delay_1ms) .WaitWithStopCondition(PickUpStep.GantryPoisitiolWait, CheckGantryPositionStatus, CheckGantryPositionRunStop) //1.3 Unlock Transporter clamp .Run(PickUpStep.UnlockTransporterClamp, () => { return _unlockRoutine.Start(null) == RState.Running; }, NullFun, _delay_1ms) .WaitWithStopCondition(PickUpStep.UnlockTransporterClampWait, () => CommonFunction.CheckRoutineEndState(_unlockRoutine), CheckUnlockRoutineStopStatus) //.WaitWithStopCondition(PickUpStep.CellClampRetractWait,CheckCellRetractRoutineEndState,CheckGantryPositionRunStop) .LoopRetryStart(PickUpStep.LoopPickupRetry,"Pick up loop retry",_pickMaxRetries,NullFun,_delay_1ms) .LoopRetrySecondRun(PickUpStep.LoopRetryUnlock, () => { return _unlockRoutine.Start(null) == RState.Running; }, NullFun, _delay_1ms) .LoopRetrySecondRunWithStopStatus(PickUpStep.LoopRetryUnlockWait, () => CommonFunction.CheckRoutineEndState(_unlockRoutine), CheckUnlockRoutineStopStatus) .LoopRetrySecondRun(PickUpStep.LoopRetryBackToLow,ElevatorGotoLow,NullFun,_delay_1ms) .LoopRetrySecondRunWithStopStatus(PickUpStep.LoopRetryBackToLowWait, CheckVerticalPositionStatus, CheckVerticalPositionRunStop) //1.4 Elevator 移动至cell .LoopRetryRun(PickUpStep.ElevatorPosition, () => { return VerticalPositionToCell(); }, NullFun, _delay_1ms) .LoopRetryRunWithStopStatus(PickUpStep.ElevatorPositionWait, CheckVerticalPositionStatus, CheckVerticalPositionRunStop) .LoopRetryDelay(PickUpStep.Delay,500) //1.5 确认Ready to Lock Sensor .LoopRetryWaitBack(PickUpStep.ReadyToLockCheck,CheckReadyToLock,_delay_1s) //1.6 Unlock Transporter clamp .LoopRetryRun(PickUpStep.LockTransporterClamp, () => { return _lockRoutine.Start(null) == RState.Running; }, NullFun, _delay_1ms) .LoopRetryRunWithStopStatusBack(PickUpStep.LockTransporterClampWait, () => { return CommonFunction.CheckRoutineEndState(_lockRoutine); }, CheckLockRoutineStopStatus) .LoopRetryEnd(PickUpStep.LoopPickupRetryEnd, _delay_1ms) //1.7 确认Elevator lift speed .Run(PickUpStep.CalculateLiftupSpeed,CalculateLiftupSpeed,_delay_1ms) //1.8 Pickup delay .Delay(PickUpStep.PickupDelay,_pickupDelayTime*1000) //1.9 Elevator goto Up .Run(PickUpStep.VerticalUp, ElevatorGotoUP, 100) .WaitWithStopCondition(PickUpStep.VerticalUpWait, CheckVerticalPositionStatus, CheckVerticalPositionRunStop) //2.0 Material Tracking Update .Run(PickUpStep.UpdateWaferHolder, WaferHolderTransfer,_delay_1ms) //2.0 确认WSPresent与Lock .Wait(PickUpStep.CheckWHPresentAndLock,CheckWHPresentAndLock,_delay_2s) //2.1 Read Barcode 确认与Material Tracking的转移是否一致 //.Run(PickUpStep.ReadBarcodeConfirm,ReadBarcode,_delay_1ms) .End(PickUpStep.End,NullFun,100); return Runner.Status; } /// /// 目标cell unclamp /// /// private bool TargetCellUnclamp() { if (_cellName == "Loader") { bool result= _preTransferUnclampRoutine.Start() == RState.Running; if(!result) { NotifyError(eEvent.ERR_TRANSPORTER, "Loader Unclamp failed",0); } return result; } else { _cellItem = ProcessLayoutManager.Instance.GetProcessLayoutCellItemByModuleName(_cellName); if(_cellItem!=null) { bool result = false; if(Enum.TryParse(_cellItem.ModuleName,out ModuleName cellModuleName)) { if (ModuleHelper.IsRinse(cellModuleName)) { RinseDevice rinseDevice = DEVICE.GetDevice(_cellItem.ModuleName); if (rinseDevice != null) { result= rinseDevice.WaferHolderClampValveOff(); if(!result) { NotifyError(eEvent.ERR_TRANSPORTER, $"{_cellItem.ModuleName} Clamp off failed", 0); } return result; } } else if (ModuleHelper.IsMetal(cellModuleName)) { MetalCellDevice metalCellDevice = DEVICE.GetDevice(_cellItem.ModuleName); if (metalCellDevice != null) { result= metalCellDevice.WaferHolderClampOff(); if (!result) { NotifyError(eEvent.ERR_TRANSPORTER, $"{_cellItem.ModuleName} Clamp off failed",0); } return result; } } } } } return true; } /// /// 目标Cell Unclamp状态 /// /// private bool TargetCellUnclampEndStatus() { if (_cellName == "Loader") { return CommonFunction.CheckRoutineEndState(_preTransferUnclampRoutine); } else { _cellItem = ProcessLayoutManager.Instance.GetProcessLayoutCellItemByModuleName(_cellName); if (_cellItem != null) { if (Enum.TryParse(_cellItem.ModuleName, out ModuleName cellModuleName)) { if (ModuleHelper.IsRinse(cellModuleName)) { RinseDevice rinseDevice = DEVICE.GetDevice(_cellItem.ModuleName); if (rinseDevice != null) { return !rinseDevice.RinseData.WaferHolderClamp; } } else if (ModuleHelper.IsMetal(cellModuleName)) { MetalCellDevice metalCellDevice = DEVICE.GetDevice(_cellItem.ModuleName); if (metalCellDevice != null) { return metalCellDevice.ClampOff; } } } } } return true; } /// /// 目标Cell Unclamp运行中止状态 /// /// private bool TargetCellUnclampStopStatus() { if (_cellName == "Loader") { bool result= CommonFunction.CheckRoutineStopState(_preTransferUnclampRoutine); if (result) { NotifyError(eEvent.ERR_TRANSPORTER, "Loader Unclamp failed", 0); } return result; } return false; } /// /// Elevator运动至LOW /// /// private bool ElevatorGotoLow() { bool result = _elevatorAxis.PositionStation("LOW"); if(!result) { NotifyError(eEvent.ERR_TRANSPORTER, "Elevator goto LOW failed",0); } return result; } /// /// 安全避障移动 /// /// private bool SafeMoveTo() { _cellItem = ProcessLayoutManager.Instance.GetProcessLayoutCellItemByModuleName(_cellName); string stationName = _cellName; if (_cellItem != null) { if (_cellName.ToLower() != "loader" && _cellName.ToLower() != "park") { stationName = $"Cell{_cellItem.CellId}"; } } else { NotifyError(eEvent.ERR_TRANSPORTER, $"{_cellName} not in layout", 0); return false; } var result = _gantryAxis.GetPositionByStation(stationName); if(result.success) { bool isPositive = false; if(_gantryAxis.MotionData.MotorPosition /// 检验安全避让异常结束状态 /// /// private bool CheckSafeMoveToStopStatus() { bool result = CommonFunction.CheckRoutineStopState(_conflictRoutine); if (result) { NotifyError(eEvent.ERR_TRANSPORTER, "Safe Move failed", 0); } return result; } /// /// Gantry Position To cell /// /// private bool GantryPositionToCell() { _cellItem= ProcessLayoutManager.Instance.GetProcessLayoutCellItemByModuleName(_cellName); bool result = false; if (_cellItem != null) { if (_cellName.ToLower() != "loader"&&_cellName.ToLower()!="park") { result= _gantryAxis.PositionStation($"Cell{_cellItem.CellId}", false); } else { result= _gantryAxis.PositionStation(_cellName,false); } if (!result) { NotifyError(eEvent.ERR_TRANSPORTER, "gantry axis motion failed", 0); } return result; } else { NotifyError(eEvent.ERR_TRANSPORTER, $"{_cellName} not in layout", 0); return false; } } /// /// Elevator Position to cell /// /// private bool VerticalPositionToCell() { bool result = false; if( _cellItem != null ) { if (_cellName.ToLower()!="loader") { result= _elevatorAxis.PositionStation($"Cell{_cellItem.CellId}", false); } else { result= _elevatorAxis.PositionStation(_cellName, false); } if (!result) { NotifyError(eEvent.ERR_TRANSPORTER, "elevator axis motion failed", 0); } return result; } else { NotifyError(eEvent.ERR_TRANSPORTER, $"{_cellName} not in layout",0); return false; } } /// /// 检验Vertical移动状态 /// /// private bool CheckVerticalPositionStatus() { return _elevatorAxis.Status == RState.End; } /// /// 检验Vertical是否还在运动 /// /// private bool CheckVerticalPositionRunStop() { bool result = _elevatorAxis.Status == RState.Failed || _elevatorAxis.Status == RState.Timeout ; if (result) { NotifyError(eEvent.ERR_TRANSPORTER, "elevator axis motion failed",0); } return result; } /// /// 检验Gantry移动状态 /// /// private bool CheckGantryPositionStatus() { return _gantryAxis.Status == RState.End; } /// /// 检验Gantry是否还在运动 /// /// private bool CheckGantryPositionRunStop() { bool result= _gantryAxis.Status == RState.Failed||_gantryAxis.Status==RState.Timeout; if(result) { NotifyError(eEvent.ERR_TRANSPORTER, "Gantry Motion failed", 0); } return result; } /// /// 检验Unlock异常状态 /// /// private bool CheckUnlockRoutineStopStatus() { bool result = CommonFunction.CheckRoutineStopState(_unlockRoutine); if (result) { NotifyError(eEvent.ERR_TRANSPORTER, "unlock failed", 0); } return result; } /// /// 检验Ready to lock /// /// private bool CheckReadyToLock() { if(! _transporterCommon.TransporterData.ReadyToLock1) { NotifyError(eEvent.WARN_TRANSPORTER, $"{Module} Ready to lock1 is off",0); return false; } if (!_transporterCommon.TransporterData.ReadyToLock2) { NotifyError(eEvent.WARN_TRANSPORTER, $"{Module} Ready to lock2 is off",0); return false; } return true; } /// /// 检验Lock Routine异常状态 /// /// private bool CheckLockRoutineStopStatus() { bool result = CommonFunction.CheckRoutineStopState(_lockRoutine); if(result) { NotifyError(eEvent.WARN_TRANSPORTER, "lock failed", 0); } return result; } /// /// 计算提升速度 /// /// private bool CalculateLiftupSpeed() { if(_pickupTime==0) { return true; } BeckhoffStationAxis stationAxis = BeckhoffStationLocationManager.Instance.GetStationAxis(Module, "Elevator", 0); Station upStation = stationAxis.Stations.Find(O => O.Name.EndsWith("UP")); Station cellStation = null; if (_cellName == "Loader") { cellStation = stationAxis.Stations.Find(O => O.Name.EndsWith("Loader")); } else { cellStation = stationAxis.Stations.Find(O => O.Name.EndsWith($"Cell{_cellItem.CellId}")); } if(upStation==null) { NotifyError(eEvent.ERR_TRANSPORTER, "UP is not in Station List",0); return false; } if(cellStation==null) { NotifyError(eEvent.ERR_TRANSPORTER, $"Cell{_cellItem.CellId} is not in Station List",0); return false; } if(!double.TryParse(cellStation.Position,out double cellStationPosition)) { NotifyError(eEvent.ERR_TRANSPORTER, $"Cell{_cellItem.CellId} Station Position is invalid",0); return false; } if (!double.TryParse(upStation.Position, out double upStationPosition)) { NotifyError(eEvent.ERR_TRANSPORTER, $"Cell{_cellItem.CellId} Station Position is invalid", 0); return false; } int distance =(int)Math.Round(Math.Abs(cellStationPosition - upStationPosition)); double tmpVelocity = (double) distance/ _pickupTime; _velocity = _elevatorAxis.CalculateMultiplySpeedRatio(_elevatorAxis.CalculateValueMultiplyScale(tmpVelocity)); double tmpAccelaration = (double)(2 * distance) / Math.Pow(_pickupTime, 2); _acceleration = _elevatorAxis.CalculateMultiplyAccelerationRatio(_elevatorAxis.CalculateValueMultiplyScale(tmpAccelaration)); LOG.WriteBackgroundLog(eEvent.INFO_TRANSPORTER, Module, "adjust profile speed"); return true; } /// /// Elevator运动至UP /// /// private bool ElevatorGotoUP() { bool result= _elevatorAxis.PositionStation("UP", false, _velocity, _acceleration, _acceleration); if(!result) { NotifyError(eEvent.ERR_TRANSPORTER, "elevator goto up failed",0); } return result; } /// /// 更新WaferHolder移动信息 /// /// private bool WaferHolderTransfer() { bool isMetal = false; DateTime lastMetalRecipeTime = DateTime.Now; if(Enum.TryParse(_cellName,out ModuleName moduleName)&&ModuleHelper.IsMetal(moduleName)) { isMetal = true; WaferHolderInfo info = WaferHolderManager.Instance.GetWaferHolder(_cellName); if (info != null) { lastMetalRecipeTime = info.LastMetalRecipeCompleteTime; } } bool result= WaferHolderManager.Instance.TransferWaferHolder(Module,_cellName, Module); if (!result) { NotifyError(eEvent.ERR_TRANSPORTER, "tranfer waferHolder message failed", 0); } else { if (!Singleton.Instance.IsAutoRunning) { return true; } WaferHolderInfo waferHolderInfo = WaferHolderManager.Instance.GetWaferHolder(Module); if (waferHolderInfo == null) { return true; } string strTime = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"); waferHolderInfo.SchedulerModules.Add($"{strTime} {_cellName} => {Module}"); if (isMetal) { int waferShuttleSoakMaxTime = SC.GetValue("Metal.WaferShuttleSoakMaxTime"); double soakTime = Math.Round(DateTime.Now.Subtract(lastMetalRecipeTime).TotalMinutes,2); if (soakTime > waferShuttleSoakMaxTime) { LOG.WriteLog(eEvent.WARN_METAL, _cellName, $"time of {waferHolderInfo.Id} soak in metal is {soakTime} minute over {waferShuttleSoakMaxTime}"); } else { LOG.WriteLog(eEvent.INFO_METAL, _cellName, $"time of {waferHolderInfo.Id} soak in metal is {soakTime} minute"); } } } return result; } /// /// 检验WHPresent与Lock状态 /// /// private bool CheckWHPresentAndLock() { bool locked = _transporterCommon.TransporterData.Locked1 && _transporterCommon.TransporterData.Locked2; bool whPresent= _transporterCommon.TransporterData.WhPresent1 && _transporterCommon.TransporterData.WhPresent2; bool result= locked && (whPresent||_bypassWaferHolderPresent); if (!result) { NotifyError(eEvent.ERR_TRANSPORTER, "check wafer Shuttle present and locked failed", 0); } return result; } /// /// 读取条码 /// /// private bool ReadBarcode() { string str=_transporterCommon.ReaderBarcode(); str = str.Trim(); if(!string.IsNullOrEmpty(str)) { TransporterEntity transporterEntity = Singleton.Instance.GetModule(Module.ToString()); if (transporterEntity == null) { return true; } WaferHolderInfo waferHolderInfo = transporterEntity.WaferHolderInfo; if (waferHolderInfo == null) { return true; } if (waferHolderInfo.Id == str) { return true; } WaferHolderManager.Instance.SwitchWaferHolderId(waferHolderInfo,Module,str); return true; } return true; } /// /// 启动 /// /// /// public RState Start(params object[] objs) { _cellName = objs[0].ToString(); _elevatorAxis = DEVICE.GetDevice($"{Module}.Elevator"); _gantryAxis = DEVICE.GetDevice($"{Module}.Gantry"); _loaderEntity = Singleton.Instance.GetModule(ModuleName.Loader1.ToString()); _loaderRotationAxis = DEVICE.GetDevice($"{ModuleName.Loader1}.Rotation"); _facilities = DEVICE.GetDevice("System.Facilities"); _unlockRoutine = new TransporterUnlockRoutine(Module); _lockRoutine = new TransporterLockRoutine(Module); _conflictRoutine = new TransporterConflictRoutine(Module); _transporterCommon = DEVICE.GetDevice($"{Module}.Common"); _loaderCommonDevice = DEVICE.GetDevice($"{ModuleName.Loader1}.Common"); _bypassWaferHolderPresent = SC.GetValue("Transporter.BypassWaferHolderPresent"); _preTransferUnclampRoutine = new LoaderPreTransferUnclampRoutine(ModuleName.Loader1.ToString()); _velocity = 0; _acceleration = 0; _pickMaxRetries = SC.GetValue("Transporter.MaxPickTries"); string preConfig = SC.GetConfigPreContent(_cellName); if (SC.ContainsItem($"{preConfig}.PickTimeSeconds")) { _pickupTime = SC.GetValue($"{preConfig}.PickTimeSeconds"); } if (SC.ContainsItem($"{preConfig}.PickDelaySeconds")) { _pickupDelayTime = SC.GetValue($"{preConfig}.PickDelaySeconds"); } return Runner.Start(Module, $"PickUpFrom {_cellName}"); } /// /// 启动校验条件 /// /// private bool CheckStartPreConfition() { bool result = CheckPreCondition(); if(!result) { return false; } double elevatorPosition = _elevatorAxis.MotionData.MotorPosition; if (!_elevatorAxis.CheckPositionIsInStation(elevatorPosition, "Up") && !_elevatorAxis.CheckPositionIsInStation(elevatorPosition, "Low")) { NotifyError(eEvent.ERR_TRANSPORTER, $"{Module} elevator axis {elevatorPosition} is not in Up or Low station",-1); return false; } if (!_loaderEntity.IsHomed) { NotifyError(eEvent.ERR_TRANSPORTER, $"{ModuleName.Loader1} is not homed",-1); return false; } if (_cellName == "Loader") { double loaderRotationPosition = _loaderRotationAxis.MotionData.MotorPosition; if (!_loaderRotationAxis.CheckPositionIsInStation(loaderRotationPosition, "TRNPA") && !_loaderRotationAxis.CheckPositionIsInStation(loaderRotationPosition, "TRNPB")) { NotifyError(eEvent.ERR_TRANSPORTER, $"{ModuleName.Loader1} rotation axis {loaderRotationPosition} is not int TRNPA or TRNPB station",-1); return false; } } if (!WaferHolderManager.Instance.HasWaferHolder(_cellName)) { NotifyError(eEvent.ERR_TRANSPORTER, $"{_cellName} does not has wafer Shuttle", -1); return false; } //检验Facilities var faciltiesResult = _facilities.CheckCDA(); if (!faciltiesResult.result) { NotifyError(eEvent.ERR_TRANSPORTER, faciltiesResult.reason,-1); return false; } return true; } /// /// 检验前置条件 /// /// private bool CheckPreCondition() { if (!_gantryAxis.IsSwitchOn) { NotifyError(eEvent.ERR_TRANSPORTER, $"{Module} gantry axis is not switch on ", -1); return false; } if (!_gantryAxis.IsHomed) { NotifyError(eEvent.ERR_TRANSPORTER, $"{Module} gantry axis is not homed ",-1); return false; } if (!_elevatorAxis.IsSwitchOn) { NotifyError(eEvent.ERR_TRANSPORTER, $"{Module} elevator axis is not switch on ", -1); return false; } if (!_elevatorAxis.IsHomed) { NotifyError(eEvent.ERR_TRANSPORTER, $"{Module} elevator axis is not homed ",-1); return false; } return true; } } }