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, DropBlockLockoff, ElevatorGotoUp, ElevatorGotoUpWait, SafeMoveTo, CheckMoveToStatus, GantryPosition, GantryPoisitionWait, ElevatorPositionToCell, ElevatorPositionToCellWait, Delay, DropBlockLockOn, CalculateLiftupSpeed, PickupDelay, ElevatorPositionToUp, ElevatorPositionToUpWait, UpdateWaferShuttle, CheckWSPresent, //ReadBarcodeConfirm, End } #region 内部变量 private string _cellName; private JetAxisBase _gantryAxis; private JetAxisBase _elevatorAxis; private LoaderEntity _loaderEntity; private JetAxisBase _loaderRotationAxis; private SystemFacilities _facilities; private TransporterConflictRoutine _conflictRoutine; private TransporterCommon _transporterCommon; 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) //1. 确认DropBlockLock是否off .Run(PickUpStep.DropBlockLockoff, DropBlockLockoff, _delay_1ms) //2. Elevator go to up .Run(PickUpStep.ElevatorGotoUp, ElevatorGotoUP, _delay_1ms) .WaitWithStopCondition(PickUpStep.ElevatorGotoUpWait, CheckElevatorPositionEndStatus, CheckElevatorPositionEndStatus) //3. other Transporter Safe Move .Run(PickUpStep.SafeMoveTo, SafeMoveTo, _delay_1ms) .WaitWithStopCondition(PickUpStep.CheckMoveToStatus, () => CommonFunction.CheckRoutineEndState(_conflictRoutine), CheckSafeMoveToStopStatus) //4. Gantry 移动到目标位置 .Run(PickUpStep.GantryPosition, GantryPositionToCell, _delay_1ms) .WaitWithStopCondition(PickUpStep.GantryPoisitionWait, CheckGantryPositionStatus, CheckGantryPositionRunStop) //5. Elevator 移动至对应cell位 .Run(PickUpStep.ElevatorPositionToCell, ElevatorPositionToCell, _delay_1ms) .WaitWithStopCondition(PickUpStep.ElevatorPositionToCellWait, CheckElevatorPositionEndStatus, CheckElevatorPositionStopStatus) .Delay(PickUpStep.Delay,500) //6. Drop Block Lock on,抓取WS .Run(PickUpStep.DropBlockLockOn, DropBlockLockon, _delay_1ms) //7. 确认Elevator lift speed .Run(PickUpStep.CalculateLiftupSpeed,CalculateLiftupSpeed,_delay_1ms) //8. Pickup delay .Delay(PickUpStep.PickupDelay,_pickupDelayTime * 1000) //9. Elevator goto Up .Run(PickUpStep.ElevatorPositionToUp, ElevatorGotoUP, 100) .WaitWithStopCondition(PickUpStep.ElevatorPositionToUpWait, CheckElevatorPositionEndStatus, CheckElevatorPositionStopStatus) //10. 确认Transporter的Wafer shuttle hold present信号为on .Wait(PickUpStep.CheckWSPresent, CheckWSPresent, _delay_2s) //11. Material Tracking Update .Run(PickUpStep.UpdateWaferShuttle, WaferShuttleTransfer,_delay_1ms) //12. Read Barcode 确认与Material Tracking的转移是否一致 //.Run(PickUpStep.ReadBarcodeConfirm,ReadBarcode,_delay_1ms) .End(PickUpStep.End,NullFun,100); return Runner.Status; } /// /// 关闭DropBlockLock /// /// private bool DropBlockLockoff() { if (_transporterCommon.TransporterData.Lock) { return _transporterCommon.UnlockOperation("", null); } return true; } /// /// 打开DropBlockLock /// /// private bool DropBlockLockon() { if (!_transporterCommon.TransporterData.Lock) { return _transporterCommon.LockOperation("", null); } return true; } /// /// 安全避障移动 /// /// 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 ElevatorPositionToCell() { 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 CheckElevatorPositionEndStatus() { return _elevatorAxis.Status == RState.End; } /// /// 检验Vertical是否还在运动 /// /// private bool CheckElevatorPositionStopStatus() { 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; } /// /// 计算提升速度 /// /// 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 WaferShuttleTransfer() { 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 CheckWSPresent() { bool locked = _transporterCommon.TransporterData.Lock; bool whPresent= _transporterCommon.TransporterData.WSHoldPresent; bool result= locked && (whPresent||_bypassWaferHolderPresent); if (!result) { LOG.WriteLog(eEvent.INFO_TRANSPORTER, Module, "check wafer Shuttle present and locked failed"); } 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"); _conflictRoutine = new TransporterConflictRoutine(Module); _transporterCommon = DEVICE.GetDevice($"{Module}.Common"); _loaderCommonDevice = DEVICE.GetDevice($"{ModuleName.Loader1}.Common"); _bypassWaferHolderPresent = SC.GetValue("Transporter.BypassWaferHolderPresent"); _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() { //所有轴上电并Homed bool result = CheckPreCondition(); if(!result) { return false; } //Transporter的Wafer shuttle hold present信号为off if (!_bypassWaferHolderPresent && _transporterCommon.TransporterData.WSHoldPresent) { NotifyError(eEvent.ERR_TRANSPORTER, $"{Module} WaferShuttleHoldPresent is on", -1); return false; } //Loader is Home if (_loaderEntity!=null&&!_loaderEntity.IsHomed) { NotifyError(eEvent.ERR_TRANSPORTER, $"{ModuleName.Loader1} is not homed", -1); return false; } //若目标Cell为Loader, 则Loader需在TRNA或TRANB位置且WaferShuttlePresent信号on 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(!_loaderCommonDevice.CommonData.WaferHolderPresent) { NotifyError(eEvent.ERR_TRANSPORTER, $"{ModuleName.Loader1} WaferShuttlePresent is off", -1); return false; } } //Transporter没有WS信息 if (WaferHolderManager.Instance.HasWaferHolder(Module)) { NotifyError(eEvent.ERR_TRANSPORTER, $"{Module} already has wafer Shuttle", -1); return false; } //目标Cell应有WS信息 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; } } }