| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 | using Aitex.Core.RT.Log;using Aitex.Core.RT.Routine;using Aitex.Core.RT.SCCore;using Aitex.Core.Util;using Aitex.Sorter.Common;using MECF.Framework.Common.Equipment;using MECF.Framework.Common.Schedulers;using MECF.Framework.Common.SubstrateTrackings;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Venus_Core;using Venus_RT.Devices;using Venus_RT.Devices.PreAligner;using Venus_RT.Modules.VCE;namespace Venus_RT.Modules.TM.VenusEntity{    public class SEMFPickRoutine : ModuleRoutineBase, IRoutine    {        private enum PickStep        {            seWaitModuleReady,            sePrepareModule,            seDoorOpen,            sePAQuery,            sePicking,            seNotifyDone,        }        private HongHuTM _tm;        private IPreAlign _vpa;        private ITransferRobot _robot;        private VceEntity _vceModule;        private ModuleName _targetModule;        private int _targetSlot;        private int _pickingTimeout;        public int currentStepNo;        Hand _hand;        /// <summary>        /// 完整pick动作仅可vce vpa取片        /// </summary>        /// <param name="tm"></param>        /// <param name="robot"></param>        /// <param name="vpa"></param>        public SEMFPickRoutine(HongHuTM tm, ITransferRobot robot, IPreAlign vpa) : base(ModuleName.SETM)        {            _tm = tm;            _robot = robot;            _vpa = vpa;        }        public RState Start(params object[] objs)        {            if (!_robot.IsHomed)            {                LOG.Write(eEvent.ERR_TM, Module, $"TM Robot is not homed, please home it first");                return RState.Failed;            }            //MoveItem pickItem = new MoveItem() { SourceModule = , };            var pickItem = (Queue<MoveItem>)objs[0];            _targetModule = pickItem.Peek().SourceModule;            _targetSlot = pickItem.Peek().SourceSlot;            _hand = pickItem.Peek().RobotHand;            //如果目标是Vce 否则是vpa            if (ModuleHelper.IsVCE(_targetModule) && ModuleHelper.IsInstalled(_targetModule))            {                _vceModule = Singleton<RouteManager>.Instance.GetVCE(_targetModule);                //如果vce有错误 报错                if (_vceModule.IsError)                {                    LOG.Write(eEvent.ERR_TM, Module, $"Invalid target module : {_targetModule} is Error! Please solve Error first!");                    return RState.Failed;                }                if (_targetSlot < 0)                {                    LOG.Write(eEvent.ERR_TM, Module, $"VCE target slot cannot be {_targetSlot}. Please check it first.");                    return RState.Failed;                }                //if (_tm.VCESlitDoorClosed)                //{                //    LOG.Write(eEvent.ERR_TM, Module, $"cannot pick cause vce slitdoor not open.");                //    return RState.Failed;                //}                //如果VCE门是关闭的 说明还未进行pump 无法取片等                //if (_tm.VCESlitDoorClosed)                //{                //    LOG.Write(eEvent.ERR_TM, Module, $"Invalid target module : {_targetModule} slitdoor not open! Please pump down vce and open it first!");                //    return RState.Failed;                //}            }               //如果目标又不是VPA 报错            else if (!ModuleHelper.IsVPA(_targetModule))            {                LOG.Write(eEvent.ERR_TM, Module, $"Invalid target module : {_targetModule} for pick action");                return RState.Failed;            }            //检查目标手臂上没有wafer            if (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, (int)_hand))            {                LOG.Write(eEvent.ERR_TM, Module, $"Cannot pick as TM Robot Arm: {_hand} already has a wafer");                return RState.Failed;            }            //检查目标槽位上有wafer            if (WaferManager.Instance.CheckNoWafer(_targetModule, _targetSlot))            {                LOG.Write(eEvent.ERR_TM, Module, $"Cannot pick as {_targetModule} Slot {_targetSlot + 1} has no wafer");                return RState.Failed;            }            //2023/10/13 朱永吉 atm mode的判断不允许自动pump vent 信号不满足手动pump vent            //if (RouteManager.IsATMMode && _targetModule == ModuleName.VCE1)            //{            //    if (!_tm.IsVCEATM)            //    {            //        LOG.Write(eEvent.ERR_TM, Module, $"System in ATM Mode but VCE is not ATM!");            //        return RState.Failed;            //    }            //            //    if (!_tm.IsTMATM)            //    {            //        LOG.Write(eEvent.ERR_TM, Module, $"System in ATM Mode but TM is not ATM!");            //        return RState.Failed;            //    }            //}            //else            //{            //    if (_tm.IsVCEATM)            //    {            //        LOG.Write(eEvent.ERR_TM, Module, $"System not in ATM Mode but VCE is ATM!");            //        return RState.Failed;            //    }            //            //    if (_tm.IsTMATM)            //    {            //        LOG.Write(eEvent.ERR_TM, Module, $"System not in ATM Mode but TM is ATM!");            //        return RState.Failed;            //    }            //}            Reset();            _pickingTimeout = SC.GetValue<int>("SETM.PickTimeout") * 1000;            return Runner.Start(Module, $"Pick from {_targetModule}");        }        public RState Monitor()        {            Runner.Wait(PickStep.seWaitModuleReady,         CheckModuleReady,       _delay_60s)                  .Run(PickStep.sePrepareModule,            PrepareModule,          CheckModuleReady)                  .RunIf(PickStep.seDoorOpen,               _targetModule == ModuleName.VCE1, VCEDoorOpen, CheckVCEDoorOpen)                  .RunIf(PickStep.sePAQuery,                _targetModule == ModuleName.VPA,              QueryOffset,        VPAIsIdle,  _pickingTimeout)                  .Run (PickStep.sePicking,                 Picking,                WaitPickDone,       _pickingTimeout)                  .End (PickStep.seNotifyDone,              NullFun,                500);            return Runner.Status;        }        private bool PrepareModule()        {            switch (_targetModule)            {                case ModuleName.VCE1:                    return _vceModule.CheckToPostMessage((int)VceMSG.Goto, _targetSlot);//移动到目标槽位                case ModuleName.VPA:                    return true;//10/17暂时为true 后可能要求旋转到0                default:                    return false;            }        }        private bool WaitPickDone()        {            if (_robot.Status == RState.Running)            {                return false;            }            else if (_robot.Status == RState.End)            {                WaferManager.Instance.WaferMoved(_targetModule, _targetSlot, ModuleName.TMRobot, (int)_hand);                return true;            }            else            {                Runner.Stop($"TM Robot Picking failed, {_robot.Status}");                return true;            }        }        private bool VCEDoorOpen()        {            return _tm.TurnSlitDoor(_targetModule, true);        }        private bool CheckVCEDoorOpen()        {            return _tm.CheckSlitValveOpen(_targetModule);        }        private bool CheckIsPA() => _targetModule == ModuleName.VPA;        private bool QueryOffset()        {            return _vpa.QueryOffset();        }        private bool VPAIsIdle()        {            if (_vpa.Status == RState.Running)            {                return false;            }            else if (_vpa.Status == RState.End)            {                return true;            }            else            {                Runner.Stop($"VPA Query Offset failed, {_vpa.Status}");                return true;            }        }        private bool WaitRobotIsIdle()        {            if (_robot.Status == RState.Running)            {                return false;            }            else if (_robot.Status == RState.End)            {                return true;            }            else            {                Runner.Stop($"TM Robot QueryOffset failed, {_robot.Status}");                return true;            }        }        private bool Picking()        {            //到达目标点位 pick固定槽位点的wafer            if (_targetModule == ModuleName.VPA && (_vpa.ROffset!=0 || _vpa.TOffset!=0))            {                int[] RT = calculateRT(_vpa.ROffset, _vpa.TOffset);                LOG.Write(eEvent.INFO_TM_ROBOT, ModuleName.TMRobot, $"will pick from PA with R:{RT[1]} D:{RT[0]}");                return _robot.PickWithOffset(_targetModule, 0, _hand, RT[1], RT[0]);            }            else                return _robot.Pick(_targetModule, 0, _hand);        }        private int[] calculateRT(int OriginR,int OriginS)        {            int[] RT = new int[2];            try            {                bool desflag = false;                double angle = 0;                if (OriginR / 10 < 90)                    angle = OriginR / 10;                if (OriginR / 10 < 270 && OriginR / 10 > 90)                {                    desflag = true;                    angle = OriginR / 10 - 90;                }                if (OriginR / 10 > 270)                    angle = 450 - OriginR / 10;                double angleInRadians = angle * Math.PI / 180;                //OriginS * 25.4 inch 转化为 mm                double Robot2PA = OriginS * 25.4 / 10000;                double Robot2Wafer = Math.Sqrt(Robot2PA * Robot2PA + 402.5 * 402.5 - 2 * Robot2PA * 402.5 * Math.Cos(angleInRadians));                //距离(mm)                double distance = Robot2Wafer - 402.5;                //角度(度)                double angleA = Math.Asin(Robot2PA * Math.Sin(angleInRadians) / Robot2Wafer) * 180 / Math.PI;                if (desflag)                    angleA = -angleA;                RT[0] = (int)(angleA * 1000);                RT[1] = (int)(distance * 1000);            }            catch             {                LOG.Write(eEvent.ERR_TM_ROBOT,ModuleName.TMRobot,"错误纠偏计算");                RT[0] = 0;                RT[1] = 0;            }            return RT;        }        private bool CheckModuleReady()        {            switch (_targetModule)            {                case ModuleName.VCE1:                    return _vceModule.IsIdle;                case ModuleName.VPA:                    return _vpa.Status == RState.End;                default:                    return false;            }        }        public void Abort()         {            _robot.Halt();        }    }}
 |