using HalconDotNet; using NPOI.SS.Formula.Eval; using Rs.Camera; using Rs.Controls; using Rs.Framework; using Rs.Motion; using Rs.MotionPlat.Commom; using Rs.MotionPlat.Entitys; using Rs.MotionPlat.Entitys.Trays; using Rs.MotionPlat.Flow.Camera; using Rs.MotionPlat.Flow.Common; using Rs.MotionPlat.Flow.SafePosFlow; using Rs.MotionPlat.Flow.SubFlow; using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.Eventing.Reader; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using static Rs.MotionPlat.Commom.SchedulingMessageBox; namespace Rs.MotionPlat.Flow { public enum EDischargeFlowStep { 等待任务, /*取料*/ 到取料位上方, 等待到取料位上方, 到取料位下方, 等待到取料位下方, 开真空, 取料完成后真空检测, 取料失败报警, 取料完成抬起, 等待取料完成抬起, /*拍照*/ 到下相机拍照起始位, 等待到下相机拍照起始位, 到下相机拍照结束位, 等待到下相机拍照结束位, 等待相机拍照完成, 等待视觉处理结果, /*放料*/ 到放料位上方, 等待到放料位上方, 丢料检测, 到放料位下方, 等待到放料位下方, 到放料关破真空位, 等待到放料关破真空位, 周转盘放料位真空检测, 放料完成抬起, 等待放料完成抬起, 放料真空检测, 粘料检测, 周转盘放料真空报警, 放料任务完成, 任务结束到安全位, 等待任务结束到安全位, IDLE } /// /// 排料流程 /// public class DischargeFlow : BaseFlow { private DischargeFlow() { } private static DischargeFlow instance; public event Action> OnMatchResult; public event Action> OnUpCameraGrabResult; public event Action OnShowGrabResult; public event Action OnStockTrayProductHasOrNotResult; public event Action OnTurnoverTrayProductHasOrNotResult; public static DischargeFlow Instance { get { if (instance == null) { instance = new DischargeFlow(); } return instance; } } private AlarmEntity alarmEntity; Stopwatch timeout = new Stopwatch(); EDischargeFlowStep flowStep = EDischargeFlowStep.等待任务; EDischargeFlowStep restoreFlowStep = EDischargeFlowStep.IDLE; HObject[] imgs = new HObject[2]; List mrs = new List(); int reFetchNum = 0;//重取料次数 bool bFetchBack = false; double targetX = 0.0; double targetY = 0.0; double targetZ = 0.0; double targetR = 0.0; //double targetPos = 0.0; TraySlot tray = new TraySlot(); // List totalTask = new List(); List dealTask = new List(); //TurnoverInfo curTurnoverTask = new TurnoverInfo(); TurnoverInfo curTask = new TurnoverInfo(); List idleNozzle = new List(); Nozzle curNozzle = new Nozzle(); /// /// 当前穴位的点位 /// SlotPoint curSlotPoint = new SlotPoint(); SlotPoint nozzleDist = new SlotPoint(); //List unloadNozzles = new List(); TraySlot downSlot = new TraySlot(); OffsetPoint turnoverOffsetPoint = new OffsetPoint(); int needGrabNum = 0;//需要拍照的吸嘴数量 int reGrabCount = 0;//重拍次数 ErrorCode errCode = ErrorCode.Ok; List testLoadList = new List(); List testUnLoadList = new List(); /// /// 从料仓到周转盘 /// private bool StockTrayToTurnoverTray = true; SchedulingMessageBox msgBox; /// /// 未执行的任务数量 /// private int undoTaskNum = 0; int scanNum = 0; public override void Run() { switch (flowStep) { case EDischargeFlowStep.等待任务: if (LoadAndUnloadTask.Instance.GetTaskNum(ETaskType.Load) > 0 || LoadAndUnloadTask.Instance.GetTaskNum(ETaskType.Unload) > 0 || LoadAndUnloadTask.Instance.GetTaskNum(ETaskType.Change) > 0) { StockTrayToTurnoverTray = true; logInfo = GetClassName() + $"接收到排料任务"; MessageQueue.Instance.Insert(logInfo); if (GlobalVar.CleanOut && GlobalVar.DischargeNozzleHasProduct) { foreach (TurnoverInfo ti in LoadAndUnloadTask.Instance.GetUnDealedTask()) { ti.Dealed = true; } mrs = new List(); for (int i = 0; i < 8; i++) { mrs.Add(new MatchResult()); } flowStep = EDischargeFlowStep.到放料位上方; } else { if (GlobalVar.FirstDischarge) { GlobalVar.FirstDischarge = false; //设备遗留产品检测 //吸嘴全部用真空吸检测,周转盘用上相机检测,SOCKET用镭射头检测 flowStep = EDischargeFlowStep.到取料位上方; } else { flowStep = EDischargeFlowStep.到取料位上方; } } } break; case EDischargeFlowStep.到取料位上方: //先取上料任务,再取下料任务,最后取换料任务 if(StockTrayToTurnoverTray) { if (LoadAndUnloadTask.Instance.GetTaskNum(ETaskType.Load) > 0) { curTask = LoadAndUnloadTask.Instance.GetLoadTask(); } else if (LoadAndUnloadTask.Instance.GetTaskNum(ETaskType.Unload) > 0) { curTask = LoadAndUnloadTask.Instance.GetUnLoadTask(); } else if (LoadAndUnloadTask.Instance.GetTaskNum(ETaskType.Change) > 0) { curTask = LoadAndUnloadTask.Instance.GetChangeTask(); } } else { if (LoadAndUnloadTask.Instance.GetTaskNum(ETaskType.Unload) > 0) { curTask = LoadAndUnloadTask.Instance.GetUnLoadTask(); } else if (LoadAndUnloadTask.Instance.GetTaskNum(ETaskType.Load) > 0) { curTask = LoadAndUnloadTask.Instance.GetLoadTask(); } else if (LoadAndUnloadTask.Instance.GetTaskNum(ETaskType.Change) > 0) { curTask = LoadAndUnloadTask.Instance.GetChangeTask(); } } curNozzle = NozzleManager.GetIdelNozzle(); if (curTask!=null && curNozzle != null) { if (XYCanGoLocalArea() || GlobalVar.VirtualAxis) { curSlotPoint = null; curNozzle.FromType=curTask.FromType; if (curTask.FromType == TurnoverType.Turnover) { curSlotPoint = TrayPointManager.GetSlotPoint( ETrayType.Turnover, curTask.FromIndex + 1); curNozzle.FromIndex = curTask.FromIndex; logInfo = GetClassName()+ $"排料{curNozzle.NozzleIndex}号吸嘴到{curTask.FromType.ToString()}盘{curNozzle.FromIndex + 1}号穴位取料"; MessageQueue.Instance.Insert(logInfo); } else if (curTask.FromType == TurnoverType.ToBeTested) { TraySlot slot = GlobalTray.Input1Tray.GetSlot(ESlotStatus.Have); if (slot != null) { curSlotPoint = TrayPointManager.GetSlotPoint( ETrayType.Input1, slot.Index); curNozzle.FromIndex= slot.Index-1; logInfo =GetClassName()+ $"排料{curNozzle.NozzleIndex}号吸嘴到{curTask.FromType.ToString()}盘{curNozzle.FromIndex+1}号穴位取料"; MessageQueue.Instance.Insert(logInfo); } else { GlobalTray.Input1Tray.ChangeStatus(ESlotStatus.Have); //slot = GlobalTray.Input2Tray.GetSlot(ESlotStatus.Have); //if (slot != null) //{ // curSlotPoint = TrayPointManager.GetSlotPoint(ETrayType.Input2, slot.Index); // curNozzle.FromIndex = slot.Index - 1; // logInfo = GetClassName() + $"排料{curNozzle.NozzleIndex}号吸嘴到{curTask.FromType.ToString()}盘{curNozzle.FromIndex + 1}号穴位取料"; // MessageQueue.Instance.Insert(logInfo); //} //else //{ // slot = GlobalTray.Input3Tray.GetSlot(ESlotStatus.Have); // if (slot != null) // { // curSlotPoint = TrayPointManager.GetSlotPoint(ETrayType.Input3, slot.Index); // curNozzle.FromIndex = slot.Index - 1; // logInfo = GetClassName() + $"排料{curNozzle.NozzleIndex}号吸嘴到{curTask.FromType.ToString()}盘{curNozzle.FromIndex + 1}号穴位取料"; // MessageQueue.Instance.Insert(logInfo); // } // else // { // //这里报警,input已经没有产品了 // } //} } } if (curSlotPoint != null) { nozzleDist = TrayPointManager.GetDistToNozzle1(curNozzle.NozzleIndex); targetX = curSlotPoint.X + nozzleDist.X; targetY = curSlotPoint.Y + nozzleDist.Y; errCode = AxisControl.LoadX.MovePos(targetX, GlobalVar.WholeSpeed); if (errCode == ErrorCode.Ok || GlobalVar.VirtualAxis) { //if(Ops.IsHomedAndNearStartPos($"NozzleR{NozzleIndex}")) { errCode = AxisControl.LoadY.MovePos(targetY, (int)(GlobalVar.WholeSpeed)); if(errCode== ErrorCode.Ok|| GlobalVar.VirtualAxis) { targetR = SysConfigParam.GetValue($"NozzleR{curNozzle.NozzleIndex}StartPos"); errCode = AxisControl.GetAxis($"NozzleR{curNozzle.NozzleIndex}").MovePos(targetR, GlobalVar.WholeSpeed); if (errCode == ErrorCode.Ok | GlobalVar.VirtualAxis) { if (GlobalVar.VirtualAxis) { Thread.Sleep(GlobalVar.VirtualAxisMoveTime); } flowStep = EDischargeFlowStep.等待到取料位上方; } else { //MsgBox.ShowAxisAlarmDialog($"NozzleR{curNozzle.NozzleIndex}", errCode); alarmEntity = AlarmCollection.Get($"NozzleR{curNozzle.NozzleIndex}运动异常").Transform(errCode.ToString()); AlarmMessageBox.ShowDialog(alarmEntity, ETipButton.Ok, null); } } else { //MsgBox.ShowAxisAlarmDialog(AxisControl.LoadY, errCode); AlarmMessageBox.ShowDialog(true, ETipButton.Ok, null, AlarmConstID.LoadY运动异常, errCode.ToString()); } } //else // { // Msg.ShowError($"吸头 NozzleR{NozzleIndex} 不在起始位,请手动手动回原后运动到起始位"); // } } else { //MsgBox.ShowAxisAlarmDialog(AxisControl.LoadX, errCode); AlarmMessageBox.ShowDialog(true, ETipButton.Ok, null, AlarmConstID.LoadX运动异常,errCode.ToString()); } } } else { //logInfo = "x y r move is unsafe"; //Msg.ShowError(logInfo); MessageQueue.Instance.Warn($"LoadY运动不安全,请检查TurnoverY的位置"); AlarmMessageBox.ShowDialog(true, ETipButton.Ok, null, AlarmConstID.运动不安全, $"{AxisAlias.LoadY}", $"{ AxisAlias.TurnoverY}"); } } break; case EDischargeFlowStep.等待到取料位上方: if (Ops.IsStop("LoadX", "LoadY", $"NozzleR{curNozzle.NozzleIndex}") || GlobalVar.VirtualAxis) { if (AxisArrived.LoadXYIsArrived(targetX, targetY)) { logInfo = GetClassName() + $"已运动到{WitchTrayWitchSlot(curNozzle.FromType, curNozzle.FromIndex)}取料位上方"; MessageQueue.Instance.Insert(logInfo); flowStep = EDischargeFlowStep.到取料位下方; } else { flowStep = EDischargeFlowStep.到取料位上方; } } break; case EDischargeFlowStep.到取料位下方: if (AxisControl.GetAxis($"NozzleZ{curNozzle.NozzleIndex}").HomeStatus == EHomeStatus.Finished || GlobalVar.VirtualAxis) { if (curTask.FromType == TurnoverType.Turnover) { targetZ = GetVacOffsetHeight(reFetchNum) + SysConfigParam.GetValue($"TurnoverNozzle{curNozzle.NozzleIndex}TakeHeight"); //在周转盘取料,提前把真空吸打开 VacManager.DischargeVacSuction(EVacOperator.Open, false, curNozzle.NozzleIndex); VacManager.TurnoverTrayVacSuction(EVacOperator.Close, false, curNozzle.FromIndex + 1); } else if (curTask.FromType == TurnoverType.ToBeTested) { targetZ = GetVacOffsetHeight(reFetchNum) + SysConfigParam.GetValue($"TrayNozzle{curNozzle.NozzleIndex}TakeHeight"); } errCode = AxisControl.GetAxis($"NozzleZ{curNozzle.NozzleIndex}").MovePos(targetZ, GlobalVar.WholeSpeed); if (errCode == ErrorCode.Ok || GlobalVar.VirtualAxis) { logInfo = GetClassName() + $"到{WitchTrayWitchSlot(curNozzle.FromType, curNozzle.FromIndex)}号穴位取料位下方"; MessageQueue.Instance.Insert(logInfo); if (GlobalVar.VirtualAxis) { Thread.Sleep(GlobalVar.VirtualAxisMoveTime); } flowStep = EDischargeFlowStep.等待到取料位下方; } else { //MsgBox.ShowAxisAlarmDialog($"NozzleZ{curNozzle.NozzleIndex}", errCode); //AlarmMessageBox.ShowDialog(true,ETipButton.Ok,null,) alarmEntity = AlarmCollection.Get($"NozzleZ{curNozzle.NozzleIndex}运动异常").Transform(errCode.ToString()); AlarmMessageBox.ShowDialog(alarmEntity, ETipButton.Ok, null); } } else { logInfo = GetClassName()+ $"NozzleZ{curNozzle.NozzleIndex} 轴状态未回原,请手动回原后点击确定"; MessageQueue.Instance.Warn(logInfo); //MsgBox.ShowDialog(AlarmConstID.AxisNotAtHomeAlarm, logInfo, ETipButton.Ok); AlarmMessageBox.ShowDialog(true, ETipButton.Ok, null, AlarmConstID.轴不在原点, $"NozzleZ{curNozzle.NozzleIndex}"); } break; case EDischargeFlowStep.等待到取料位下方: if (Ops.IsStop($"NozzleZ{curNozzle.NozzleIndex}") || GlobalVar.VirtualAxis) { if (AxisArrived.LoadXYIsArrived(targetX, targetY)) { logInfo = GetClassName() + $"已运动到{WitchTrayWitchSlot(curNozzle.FromType, curNozzle.FromIndex)}号穴位取料位下方"; MessageQueue.Instance.Insert(logInfo); if (curTask.FromType == TurnoverType.Turnover) { VacManager.TurnoverTrayVacBreak(EVacOperator.Open, true, curNozzle.FromIndex + 1); } else { VacManager.DischargeVacSuction(EVacOperator.Open, true, curNozzle.NozzleIndex); } flowStep = EDischargeFlowStep.取料完成抬起; } else { flowStep = EDischargeFlowStep.到取料位上方; } } break; case EDischargeFlowStep.取料完成抬起: errCode = AxisControl.GetAxis($"NozzleZ{curNozzle.NozzleIndex}").MovePos(0, GlobalVar.WholeSpeed); if (errCode == ErrorCode.Ok || GlobalVar.VirtualAxis) { if(GlobalVar.VirtualAxis) { Thread.Sleep(GlobalVar.VirtualAxisMoveTime); } logInfo = GetClassName()+ $"取{WitchTrayWitchSlot(curNozzle.FromType, curNozzle.FromIndex)}号穴位产品完成抬起"; MessageQueue.Instance.Insert(logInfo); flowStep = EDischargeFlowStep.等待取料完成抬起; } else { alarmEntity = AlarmCollection.Get($"NozzleZ{curNozzle.NozzleIndex}运动异常").Transform(errCode.ToString()); AlarmMessageBox.ShowDialog(alarmEntity, ETipButton.Ok, null); } break; case EDischargeFlowStep.等待取料完成抬起: if (Ops.IsStop($"NozzleZ{curNozzle.NozzleIndex}") || GlobalVar.VirtualAxis) { logInfo = GetClassName()+$"取{WitchTrayWitchSlot(curNozzle.FromType, curNozzle.FromIndex)}号穴位产品完成已抬起"; MessageQueue.Instance.Insert(logInfo); flowStep = EDischargeFlowStep.取料完成后真空检测; } break; case EDischargeFlowStep.取料完成后真空检测: if (Ops.IsOn($"{curNozzle.NozzleIndex}号吸嘴真空吸检测") || GlobalVar.RunSpace) { reFetchNum = 0; logInfo = GetClassName()+$"排料吸嘴{curNozzle.NozzleIndex}号真空检测OK"; MessageQueue.Instance.Insert(logInfo); GlobalTray.DischargeNozzle.ChangeStatus(curNozzle.NozzleIndex, ESlotStatus.Have); UpdateNozzleStatus(curNozzle, curTask); undoTaskNum = LoadAndUnloadTask.Instance.GetTaskNum(curTask.taskMode); if (undoTaskNum > 0 && NozzleManager.GetNozzlesByStatus(ENozzleStatus.IDLE).Count > 0) { logInfo =GetClassName()+ $"还有{undoTaskNum}条任务未执行,并且有空闲吸嘴,继续取料"; MessageQueue.Instance.Insert(logInfo); flowStep = EDischargeFlowStep.到取料位上方; } else { flowStep = EDischargeFlowStep.到下相机拍照起始位; } } else { if(reFetchNum==0) { //这个时候Z&R回原一次,然后再重新取料 ZRHomeFlow.Instance.GoHome(curNozzle.NozzleIndex); } reFetchNum++; if (reFetchNum >= GlobalVar.DischargeRetakeNum) { DischargeDumpFlow.Instance.Start(curTask.FromType, curNozzle.NozzleIndex, curNozzle.FromIndex); //alarmInfo = $"排料{curNozzle.NozzleIndex}号吸嘴取{curNozzle.FromIndex+1}号穴位产品{reFetchNum}次失败"; if(curTask.FromType== TurnoverType.ToBeTested) { //alarmInfo = string.Format(AlarmCollection.GetAlarm(AlarmConstID.料仓tray盘取料报警), curNozzle.NozzleIndex, curNozzle.FromIndex + 1); alarmEntity = AlarmCollection.Get(AlarmConstID.料仓tray盘取料报警).Transform(curNozzle.NozzleIndex, (curNozzle.FromIndex + 1)); } else if(curTask.FromType== TurnoverType.Turnover) { //alarmInfo = string.Format(AlarmCollection.GetAlarm(AlarmConstID.排料头在周转盘取料失败报警), curNozzle.NozzleIndex, curNozzle.FromIndex + 1); alarmEntity = AlarmCollection.Get(AlarmConstID.排料头在周转盘取料失败报警).Transform(curNozzle.NozzleIndex, curNozzle.FromIndex + 1); } flowStep = EDischargeFlowStep.取料失败报警; } else { flowStep = EDischargeFlowStep.到取料位下方; } } break; case EDischargeFlowStep.取料失败报警: ETipButton btnText = (ETipButton.Retry | ETipButton.Skip| ETipButton.Yes); Dictionary buttonText = new Dictionary(); buttonText.Add(ETipButton.Retry, "重试|Retry"); buttonText.Add(ETipButton.Skip, "跳过|Skip"); buttonText.Add(ETipButton.Yes, "移动到安全位|MoveToSafePos"); if (curTask.FromType == TurnoverType.ToBeTested) { buttonText.Add(ETipButton.No, "结束上料|EndInput"); btnText |= ETipButton.No; } ETipButton button = AlarmMessageBox.ShowDialog(alarmEntity, btnText, buttonText); //switch (box.Button) switch(button) { case ETipButton.Retry: logInfo = GetClassName() + $"选择了重试,继续取料"; MessageQueue.Instance.Insert(logInfo); reFetchNum = 0; flowStep = EDischargeFlowStep.到取料位上方; break; case ETipButton.Skip: SlotProductHasOrNotResult haveProduct = null; logInfo = GetClassName() + "选择了跳过"; MessageQueue.Instance.Insert(logInfo); if(curTask.FromType== TurnoverType.ToBeTested) { haveProduct = UpCameraCheckFlow.Instance.CheckStockTrayHasProduct(ETrayType.Input1, curNozzle.FromIndex+1, true); OnStockTrayProductHasOrNotResult?.Invoke(haveProduct); } else if(curTask.FromType== TurnoverType.Turnover) { haveProduct = UpCameraCheckFlow.Instance.CheckTurnoverTrayHasProduct(null, curTask.FromIndex + 1); OnStockTrayProductHasOrNotResult?.Invoke(haveProduct); } if(!haveProduct.HasProduct) { logInfo = GetClassName() + "检测到产品已拿走,流程继续"; MessageQueue.Instance.Insert(logInfo); reFetchNum = 0; //执行料仓Tray取料NG时的处理流程,流程处理结束后,流程继续 if (curTask.FromType == TurnoverType.Turnover) { TurnoverTrayManager.Instance.Slot(curTask.FromIndex + 1).ClearProduct(); GlobalTray.TurnoverTray.ChangeStatus(curTask.FromIndex + 1, ESlotStatus.NotHave); curTask.Dealed = true; } else if (curTask.FromType == TurnoverType.ToBeTested) { GlobalTray.Input1Tray.ChangeStatus(curNozzle.FromIndex+1, ESlotStatus.NotHave); } undoTaskNum = LoadAndUnloadTask.Instance.GetTaskNum(curTask.taskMode); if (undoTaskNum > 0 && NozzleManager.GetNozzlesByStatus(ENozzleStatus.IDLE).Count > 0) { logInfo = GetClassName()+ $"跳过后检测到还有{undoTaskNum}条任务未执行,继续取料"; MessageQueue.Instance.Insert(logInfo); flowStep = EDischargeFlowStep.到取料位上方; } else { flowStep = EDischargeFlowStep.到下相机拍照起始位; } } else { //alarmInfo = $"检测到{curNozzle.FromIndex+1}号穴位产品未取出,请处理"; alarmEntity = AlarmCollection.Get(AlarmConstID.料仓产品未取出).Transform(curNozzle.FromIndex + 1); flowStep = EDischargeFlowStep.取料失败报警; } break; case ETipButton.Yes://移动到安全位 //通知料仓把料盘退回到安全位 if(curTask.FromType== TurnoverType.Turnover) { logInfo = GetClassName() + $"通知排料头回安全位"; MessageQueue.Instance.Insert(logInfo); DischargeModuleGoSafePosFlow.Instance.GoSafePostion(); logInfo = GetClassName() + $"排料头已回到安全位"; MessageQueue.Instance.Insert(logInfo); } alarmEntity = AlarmCollection.Get(AlarmConstID.料仓tray盘取料报警).Transform(curNozzle.NozzleIndex, (curNozzle.FromIndex + 1)); flowStep = EDischargeFlowStep.取料失败报警; break; case ETipButton.No://结束上料 logInfo = GetClassName() + $"选择了结束上料,通知中控结束上料"; MessageQueue.Instance.Insert(logInfo); reFetchNum = 0; TestCenter.Instance.EndInput(); LoadAndUnloadTask.Instance.ClearUndoTask(); if (NozzleManager.GetNozzlesByStatus(ENozzleStatus.ToUnload).Count > 0) { flowStep = EDischargeFlowStep.到下相机拍照起始位; } else { if (LoadAndUnloadTask.Instance.GetUnDealedTask().Count > 0) { ScanBarCode(); StockTrayToTurnoverTray = !StockTrayToTurnoverTray; flowStep = EDischargeFlowStep.到取料位上方; } else { ScanBarCode(); flowStep = EDischargeFlowStep.任务结束到安全位; } } break; default: break; } break; case EDischargeFlowStep.到下相机拍照起始位: if (XYCanGoTurnoverTray() || GlobalVar.VirtualAxis) { if (NozzleManager.GetNozzlesByStatus(ENozzleStatus.ToUnload).Count > 0) { logInfo = GetClassName() + $"到下相机拍照起始位"; Ops.On("下相机光源"); MessageQueue.Instance.Insert(logInfo); if(!GlobalVar.VirtualAxis) { ImageProcess.ClearAutoTrigger(); HikCamera.Instance.SetExposure("locationCamera", GlobalVar.FlyGrabExposureTime); HikCamera.Instance.SetGain("locationCamera", GlobalVar.FlyGrabGain); } if (NozzleManager.GetNozzlesByStatus(ENozzleStatus.ToUnload)[0].ToType == TurnoverType.Turnover) { needGrabNum = NozzleManager.GetNozzlesByStatus(ENozzleStatus.ToUnload).Count(); targetX = SysConfigParam.GetValue($"Nozzle{needGrabNum}CenterX") - 30; targetY = SysConfigParam.GetValue($"Nozzle2CenterY"); errCode = AxisControl.LoadX.MovePos(targetX, GlobalVar.WholeSpeed); if (errCode == ErrorCode.Ok || GlobalVar.VirtualAxis) { errCode = AxisControl.LoadY.MovePos(targetY, GlobalVar.WholeSpeed); if (errCode == ErrorCode.Ok || GlobalVar.VirtualAxis) { flowStep = EDischargeFlowStep.等待到下相机拍照起始位; } } } else { targetX = SysConfigParam.GetValue("Nozzle1CenterX") + 30; targetY = SysConfigParam.GetValue($"Nozzle1CenterY"); errCode = AxisControl.LoadX.MovePos(targetX, GlobalVar.WholeSpeed); if (errCode == ErrorCode.Ok || GlobalVar.VirtualAxis) { errCode = AxisControl.LoadY.MovePos(targetY, GlobalVar.WholeSpeed); if (errCode == ErrorCode.Ok || GlobalVar.VirtualAxis) { flowStep = EDischargeFlowStep.等待到下相机拍照起始位; } else { //PromptMessageBox.ShowAxisAlarmDialog(AxisControl.LoadY, errCode); alarmEntity = AlarmCollection.Get(AlarmConstID.LoadY运动异常).Transform(errCode.ToString()); AlarmMessageBox.ShowDialog(alarmEntity, ETipButton.Ok, null); } } else { //PromptMessageBox.ShowAxisAlarmDialog(AxisControl.LoadX, errCode); alarmEntity = AlarmCollection.Get(AlarmConstID.LoadX运动异常).Transform(errCode.ToString()); AlarmMessageBox.ShowDialog(alarmEntity, ETipButton.Ok, null); } } } else { logInfo = GetClassName() + $"检测到排料吸嘴没有需要下料的产品,任务结束回安全位"; MessageQueue.Instance.Insert(logInfo); flowStep = EDischargeFlowStep.任务结束到安全位; } } break; case EDischargeFlowStep.等待到下相机拍照起始位: if (Ops.IsStop("LoadX", "LoadY") || GlobalVar.VirtualAxis) { if(AxisArrived.LoadXYIsArrived(targetX,targetY)) { logInfo = GetClassName() + $"已运动到下相机拍照起始位"; MessageQueue.Instance.Insert(logInfo); if (!GlobalVar.VirtualAxis) { HikCamera.Instance.SetTrigger("locationCamera", ETriggerMode.Auto); } List grabPoints = new List(); //获取有几个吸嘴需要拍照 needGrabNum = NozzleManager.GetNozzlesByStatus(ENozzleStatus.ToUnload).Count(); if (NozzleManager.GetNozzlesByStatus(ENozzleStatus.ToUnload)[0].ToType == TurnoverType.Turnover) { for (int i = needGrabNum; i >= 1; i--) { grabPoints.Add(SysConfigParam.GetValue($"Nozzle{i}CenterX")); } } else { for (int i = 1; i < needGrabNum + 1; i++) { grabPoints.Add(SysConfigParam.GetValue($"Nozzle{i}CenterX")); } } //LogHelper.Debug(GetClassName()+$"拍照点位:{grabPoints.ToJoinString(",")}"); errCode = AxisControl.LoadX.SetPosCompare(2, grabPoints.ToArray()); flowStep = EDischargeFlowStep.到下相机拍照结束位; } else { flowStep = EDischargeFlowStep.到下相机拍照起始位; } } break; case EDischargeFlowStep.到下相机拍照结束位: if (XYCanGoTurnoverTray() || GlobalVar.VirtualAxis) { logInfo = GetClassName() + $"到下相机拍照结束位"; MessageQueue.Instance.Insert(logInfo); //IoManager.Instance.WriteOut("下左相机光源触发", 1); //Thread.Sleep(50); if (NozzleManager.GetNozzlesByStatus(ENozzleStatus.ToUnload)[0].ToType == TurnoverType.Turnover) { targetX = SysConfigParam.GetValue($"Nozzle1CenterX") + 10; } else { targetX = SysConfigParam.GetValue($"Nozzle{needGrabNum}CenterX") - 10; } errCode = AxisControl.LoadX.MovePos(targetX, GlobalVar.FlyCameraSpeed); if (errCode== ErrorCode.Ok || GlobalVar.VirtualAxis) { flowStep = EDischargeFlowStep.等待到下相机拍照结束位; } else { //PromptMessageBox.ShowAxisAlarmDialog(AxisControl.LoadX, errCode); alarmEntity = AlarmCollection.Get(AlarmConstID.LoadX运动异常).Transform(errCode.ToString()); AlarmMessageBox.ShowDialog(alarmEntity, ETipButton.Ok, null); } } break; case EDischargeFlowStep.等待到下相机拍照结束位: if (Ops.IsStop("LoadX") || GlobalVar.VirtualAxis) { if(AxisArrived.LoadXYIsArrived(targetX,targetY)) { logInfo = GetClassName() + $"已运动到下相机拍照结束位"; MessageQueue.Instance.Insert(logInfo); if (!GlobalVar.VirtualAxis) { AxisControl.LoadX.ClearCompare(1); } Ops.Off("下相机光源"); timeout.Restart(); flowStep = EDischargeFlowStep.等待相机拍照完成; } else { flowStep = EDischargeFlowStep.到下相机拍照结束位; } } break; case EDischargeFlowStep.等待相机拍照完成: if(timeout.ElapsedMilliseconds<3000) { imgs = ImageProcess.GetAutoImage(); if ((imgs != null && imgs.Length == needGrabNum) || GlobalVar.VirtualAxis) { logInfo = GetClassName() + $"相机拍照完成,准备处理照片"; MessageQueue.Instance.Insert(logInfo); if (NozzleManager.GetNozzlesByStatus(ENozzleStatus.ToUnload)[0].ToType == TurnoverType.Turnover) { imgs = imgs.Reverse().ToArray(); } if (GlobalVar.RunSpace) { if(GlobalVar.EnableScanBarCodeByDownCamera) { foreach (Nozzle nl in NozzleManager.GetNozzlesByStatus(ENozzleStatus.ToUnload)) { if (string.IsNullOrEmpty(nl.SN)) { nl.SN = VirtualBarCode.Code;// (nl.FromIndex + 1).ToString().PadLeft(18, '0'); } } } mrs = new List(); for (int i = 0; i < needGrabNum; i++) { mrs.Add(new MatchResult()); } flowStep = EDischargeFlowStep.到放料位上方; } else { //拍照完成 flowStep = EDischargeFlowStep.等待视觉处理结果; } } } else { MessageQueue.Instance.Warn("下相机拍照超时,重拍"); flowStep = EDischargeFlowStep.到下相机拍照起始位; } break; case EDischargeFlowStep.等待视觉处理结果: if (mrs != null && mrs.Count > 0) { mrs.Clear(); GC.Collect(); } mrs = VisionProcess.Instance.MatchDownCam(imgs); if (mrs != null && mrs.Count == imgs.Length && (mrs.Where(m=>m.IsOK==true).Count()==imgs.Length || GlobalVar.DownCameraFlyRegrabNum==0)) { logInfo = GetClassName() + $"图片处理完成,准备放料"; MessageQueue.Instance.Insert(logInfo); int count = 0; if(GlobalVar.EnableScanBarCodeByDownCamera) { foreach (Nozzle nozzle in NozzleManager.GetNozzlesByStatus(ENozzleStatus.ToUnload)) { nozzle.SN = mrs[count].SN; count++; } } //int ni = 1; //foreach (MatchResult item in mrs) //{ // NozzleManager.GetNozzle(ni).SN = item.SN; // ni++; //} reGrabCount = 0; OnMatchResult?.Invoke(mrs); flowStep = EDischargeFlowStep.到放料位上方; } else { int ni = 1; List errCodeList = new List(); foreach (MatchResult item in mrs) { if(item.IsOK) { if(GlobalVar.EnableScanBarCodeByDownCamera) { NozzleManager.GetNozzle(ni).SN = item.SN; } } else { errCodeList.Add(ni); NozzleManager.GetNozzle(ni).SN = null; } ni++; } OnMatchResult?.Invoke(mrs); if(reGrabCount < GlobalVar.DownCameraFlyRegrabNum) { reGrabCount++; flowStep = EDischargeFlowStep.到下相机拍照起始位; } else { if(GlobalVar.LocationFailAutoSkip) { reGrabCount = 0; flowStep = EDischargeFlowStep.到放料位上方; } else { reGrabCount = 0; //alarmInfo = $"{string.Join(",", errCodeList)}号排料吸嘴拍照失败"; alarmEntity = AlarmCollection.Get(AlarmConstID.下相机拍照定位失败).Transform(errCodeList.ToJoinString(",")); //DialogResult dr = Msg.ShowQuestion(, System.Windows.Forms.MessageBoxButtons.RetryCancel); //TestCenterMessageBox.Show(AlarmConstID.DownCameraFlyFailAlarm, alarmInfo, ETipButton.Retry | ETipButton.Cancel); //box = MsgBox.ShowDialog(AlarmConstID.DownCameraFlyFailAlarm, alarmInfo, ETipButton.Retry | ETipButton.Cancel);// TestCenterMessageBox.WaitResult(AlarmConstID.DownCameraFlyFailAlarm); ETipButton box = AlarmMessageBox.ShowDialog(alarmEntity, ETipButton.Retry | ETipButton.Cancel, null, true); // if (box.Button == ETipButton.Cancel) if(box== ETipButton.Cancel) { flowStep = EDischargeFlowStep.到放料位上方; } //else if (box.Button == ETipButton.Retry) else if(box== ETipButton.Retry) { Thread.Sleep(500); flowStep = EDischargeFlowStep.到下相机拍照起始位; } } } } break; case EDischargeFlowStep.到放料位上方: { bool canGo = false; if (curNozzle.ToType == TurnoverType.Turnover) { canGo = XYCanGoTurnoverTray(); } else { canGo = XYCanGoLocalArea(); } if (canGo || GlobalVar.VirtualAxis) { turnoverOffsetPoint.Reset(); tray = null; targetX = 0.0; targetY = 0.0; ///获取需要放料的吸嘴 curSlotPoint = null; curNozzle = NozzleManager.GetToUnloadNozzle(); if (curNozzle != null) { if (curNozzle.ToType == TurnoverType.Turnover) { logInfo = GetClassName() + $"排料吸嘴{curNozzle.NozzleIndex}号到{curNozzle.ToType}盘{curNozzle.ToIndex + 1}号穴位上方"; MessageQueue.Instance.Insert(logInfo); curSlotPoint = TrayPointManager.GetSlotPoint(ETrayType.Turnover, curNozzle.ToIndex + 1); turnoverOffsetPoint = TurnoverSlotOffset.GetOffsetPoint(curNozzle.ToIndex + 1); } else if (curNozzle.ToType == TurnoverType.ToBeTested) { downSlot = GlobalTray.Input1Tray.GetSlot(ESlotStatus.NotHave); if (downSlot != null) { curNozzle.ToIndex = downSlot.Index - 1; curSlotPoint = TrayPointManager.GetSlotPoint(ETrayType.Input1, downSlot.Index); logInfo = GetClassName() + $"排料吸嘴{curNozzle.NozzleIndex}号到{curNozzle.ToType}盘{curNozzle.ToIndex + 1}号穴位上方"; MessageQueue.Instance.Insert(logInfo); } else { } } else if (curNozzle.ToType == TurnoverType.Passed) { downSlot = GlobalTray.Good1Tray.GetSlot(ESlotStatus.NotHave); if (downSlot != null) { curNozzle.ToIndex = downSlot.Index - 1; curSlotPoint = TrayPointManager.GetSlotPoint(ETrayType.Good1, downSlot.Index); logInfo = GetClassName() + $"排料吸嘴{curNozzle.NozzleIndex}号到{curNozzle.ToType}盘{curNozzle.ToIndex + 1}号穴位上方"; MessageQueue.Instance.Insert(logInfo); } else { GlobalTray.Good1Tray.ChangeStatus(ESlotStatus.NotHave); //downSlot = GlobalTray.Good2Tray.GetSlot(ESlotStatus.NotHave); //if (downSlot != null) //{ // curNozzle.ToIndex = downSlot.Index - 1; // curSlotPoint = TrayPointManager.GetSlotPoint(ETrayType.Good2, downSlot.Index); // logInfo = GetClassName() + $"排料吸嘴{curNozzle.NozzleIndex}号到{curNozzle.ToType}盘{curNozzle.ToIndex + 1}号穴位上方"; // MessageQueue.Instance.Insert(logInfo); //} //else //{ // downSlot = GlobalTray.Good3Tray.GetSlot(ESlotStatus.NotHave); // if (downSlot != null) // { // curNozzle.ToIndex = downSlot.Index - 1; // curSlotPoint = TrayPointManager.GetSlotPoint(ETrayType.Good3, downSlot.Index); // logInfo = GetClassName() + $"排料吸嘴{curNozzle.NozzleIndex}号到{curNozzle.ToType}盘{curNozzle.ToIndex + 1}号穴位上方"; // MessageQueue.Instance.Insert(logInfo); // } // else // { // //在这里报警,产品没有地方放了 // } //} } } else if (curNozzle.ToType == TurnoverType.Failed) { downSlot = GlobalTray.RejectTray.GetSlot(ESlotStatus.NotHave); if (downSlot != null) { curNozzle.ToIndex = downSlot.Index - 1; curSlotPoint = TrayPointManager.GetSlotPoint(ETrayType.Reject, downSlot.Index); logInfo = GetClassName() + $"排料吸嘴{curNozzle.NozzleIndex}号到{curNozzle.ToType}盘{curNozzle.ToIndex + 1}号穴位上方"; MessageQueue.Instance.Insert(logInfo); } else { //在这里报警,产品没有地方放了 } } else if (curNozzle.ToType == TurnoverType.Multifunction) { //如果吸嘴是1,并且最后一列 downSlot = GlobalTray.MultiTray.GetSlot(ESlotStatus.NotHave); if (downSlot != null) { curNozzle.ToIndex = downSlot.Index - 1; curSlotPoint = TrayPointManager.GetSlotPoint(ETrayType.Multi, downSlot.Index); logInfo = GetClassName() + $"排料吸嘴{curNozzle.NozzleIndex}号到{curNozzle.ToType}盘{curNozzle.ToIndex + 1}号穴位上方,SN={curNozzle.SN}"; MessageQueue.Instance.Insert(logInfo); } else { //在这里报警,产品没有地方放了 } } } if (curSlotPoint != null) { nozzleDist = TrayPointManager.GetDistToNozzle1(curNozzle.NozzleIndex); if (mrs!=null && mrs.Count>0 && mrs.Count>=curNozzle.NozzleIndex && mrs[curNozzle.NozzleIndex - 1].OffsetRow < 3 && mrs[curNozzle.NozzleIndex - 1].OffsetCol < 3) { targetX = mrs[curNozzle.NozzleIndex - 1].OffsetCol + curSlotPoint.X + nozzleDist.X + turnoverOffsetPoint.X; targetY = mrs[curNozzle.NozzleIndex - 1].OffsetRow + curSlotPoint.Y + nozzleDist.Y + turnoverOffsetPoint.Y; } else { targetX = curSlotPoint.X + nozzleDist.X + turnoverOffsetPoint.X; targetY = curSlotPoint.Y + nozzleDist.Y + turnoverOffsetPoint.Y; } //在这里保存图片,图片的名称以 时间+穴位定义 if(curNozzle.ToType== TurnoverType.Turnover) { //判断文件夹是否存在 string dirname = $"d://images/{DateTime.Now.ToString("yyyyMMdd")}/load"; if (!Directory.Exists(dirname)) { Directory.CreateDirectory(dirname); } if(mrs != null && mrs.Count > 0 && mrs.Count >= curNozzle.NozzleIndex && mrs[curNozzle.NozzleIndex - 1].Himage!=null) { HOperatorSet.WriteImage(mrs[curNozzle.NozzleIndex - 1].Himage, "bmp", 0, $"{dirname}//{DateTime.Now.ToString("yyyyMMddHHmmssfff")}_{curNozzle.ToIndex + 1}"); } } else { //判断文件夹是否存在 string dirname = $"d://images/{DateTime.Now.ToString("yyyyMMdd")}/unload"; if (!Directory.Exists(dirname)) { Directory.CreateDirectory(dirname); } if (mrs != null && mrs.Count > 0 && mrs.Count >= curNozzle.NozzleIndex && mrs[curNozzle.NozzleIndex - 1].Himage != null) { HOperatorSet.WriteImage(mrs[curNozzle.NozzleIndex - 1].Himage, "bmp", 0, $"{dirname}//{DateTime.Now.ToString("yyyyMMddHHmmssfff")}_{curNozzle.FromIndex + 1}"); } } logInfo =GetClassName()+ $"运动到放料位上方 X:{targetX}Y:{targetY}"; MessageQueue.Instance.Insert(logInfo); errCode = AxisControl.LoadX.MovePos(targetX, GlobalVar.WholeSpeed); if (errCode == ErrorCode.Ok || GlobalVar.VirtualAxis) { errCode = AxisControl.LoadY.MovePos(targetY, GlobalVar.WholeSpeed); if (errCode == ErrorCode.Ok || GlobalVar.VirtualAxis) { errCode = AxisControl.GetAxis($"NozzleR{curNozzle.NozzleIndex}").MoveOffset((mrs[curNozzle.NozzleIndex - 1].OffsetA) + turnoverOffsetPoint.A, GlobalVar.WholeSpeed); if (errCode == ErrorCode.Ok || GlobalVar.VirtualAxis) { if (GlobalVar.VirtualAxis) { Thread.Sleep(GlobalVar.VirtualAxisMoveTime); } flowStep = EDischargeFlowStep.等待到放料位上方; } else { //AlarmMessageBox.ShowDialog(true, ETipButton.Ok, null, AlarmConstID.轴运动异常, $"NozzleR{curNozzle.NozzleIndex}", errCode.ToString()); //MsgBox.ShowAxisAlarmDialog($"NozzleR{curNozzle.NozzleIndex}", errCode); alarmEntity = AlarmCollection.Get($"NozzleR{curNozzle.NozzleIndex}运动异常").Transform(errCode.ToString()); AlarmMessageBox.ShowDialog(alarmEntity, ETipButton.Ok, null); } } else { //MsgBox.ShowAxisAlarmDialog(AxisControl.LoadY, errCode); //AlarmMessageBox.ShowDialog(true, ETipButton.Ok, null, AlarmConstID.轴运动异常, $"{AxisAlias.LoadY}", errCode.ToString()); alarmEntity = AlarmCollection.Get(AlarmConstID.LoadY运动异常).Transform(errCode.ToString()); AlarmMessageBox.ShowDialog(alarmEntity, ETipButton.Ok, null); } } else { //MsgBox.ShowAxisAlarmDialog(AxisControl.LoadX, errCode); alarmEntity = AlarmCollection.Get(AlarmConstID.LoadX运动异常).Transform(errCode.ToString()); AlarmMessageBox.ShowDialog(alarmEntity, ETipButton.Ok, null); } } } else { alarmInfo = "loady r move isn't safe"; MessageQueue.Instance.Warn(alarmInfo); //MsgBox.ShowDialog(AlarmConstID.MoveUnsafeAlarm, alarmInfo, ETipButton.Ok); AlarmMessageBox.ShowDialog(true, ETipButton.Ok, null, AlarmConstID.运动不安全, $"{AxisAlias.LoadY}", $"{AxisAlias.TurnoverY }"); } } break; case EDischargeFlowStep.等待到放料位上方: if (Ops.IsStop("LoadX", "LoadY",$"NozzleR{curNozzle.NozzleIndex}") || GlobalVar.VirtualAxis) { if(AxisArrived.LoadXYIsArrived(targetX, targetY)) { //当放料到tray盘区域时,并且周转再盘已经没有要下料的穴位时,通知周转模组可以运动了 //if (curNozzle.ToType != TurnoverType.Turnover && TurnoverTrayManager.Instance.GetSlots(ETurnoverTraySlotType.Tested, ETurnoverTraySlotStatus.Have).Count() == 0) //{ // LogHelper.Debug("通知周转模组可以运动"); // TurnoverFlow.Instance.CanMoveFromTestTrayToTurnoverTray(); //} logInfo = GetClassName() + $"排料吸嘴{curNozzle.NozzleIndex}号已运动到{WitchTrayWitchSlot(curNozzle.ToType, curNozzle.ToIndex)}放料位上方"; MessageQueue.Instance.Insert(logInfo); flowStep = EDischargeFlowStep.丢料检测; } else { flowStep = EDischargeFlowStep.到放料位上方; } } break; case EDischargeFlowStep.丢料检测: if (!curNozzle.HasProduct()&&!GlobalVar.RunSpace) { bool exit = false; while (!exit) { //弹框报警 //alarmInfo = $"{curNozzle.NozzleIndex}吸嘴真空吸异常,可能丢料,请检查吸嘴的状态"; if(curNozzle.ToType== TurnoverType.Turnover) { //alarmInfo = string.Format(AlarmCollection.GetAlarm(AlarmConstID.排料投在周转盘放料时丢料报警), curNozzle.NozzleIndex); alarmEntity = AlarmCollection.Get(AlarmConstID.排料投在周转盘放料时丢料报警).Transform(curNozzle.NozzleIndex); } else { //alarmInfo = string.Format(AlarmCollection.GetAlarm(AlarmConstID.料仓tray盘放料时丢料报警), curNozzle.NozzleIndex,curNozzle.ToType.ToString()); alarmEntity = AlarmCollection.Get(AlarmConstID.料仓tray盘放料时丢料报警).Transform(curNozzle.NozzleIndex, curNozzle.ToType.ToString()); } //alarmid = AlarmConstID.料仓tray盘放料时丢料报警; //if (curNozzle.ToType == TurnoverType.Turnover) //{ // //alarmid = AlarmConstID.排料投在周转盘放料时丢料报警; //} //else //{ //} //TestCenterMessageBox.Show(AlarmConstID.DischargeNozzleLostProductAlarm, alarmInfo, MessageButtonManager.GetSkip_MoveToSafe_Button(), MessageButtonManager.GetSkip_MoveToSafe_ButtonText()); //msgBox = MsgBox.ShowDialog(alarmid, alarmInfo, MessageButtonManager.GetSkip_MoveToSafe_Button(), MessageButtonManager.GetSkip_MoveToSafe_ButtonText());// TestCenterMessageBox.WaitResult(AlarmConstID.DischargeNozzleLostProductAlarm); ETipButton buttonRet = AlarmMessageBox.ShowDialog(alarmEntity, MessageButtonManager.GetSkip_MoveToSafe_Button(), MessageButtonManager.GetSkip_MoveToSafe_ButtonText()); //switch (msgBox.Button) switch(buttonRet) { case ETipButton.Skip: if (!curNozzle.HasProduct()) { curNozzle.Reset(); curNozzle.VacSuction(EIoOperate.Close); curNozzle.VacBreak(EIoOperate.Open); curNozzle.VacBreak(EIoOperate.Close); exit = true; flowStep = EDischargeFlowStep.放料任务完成; } break; case ETipButton.Yes: DischargeModuleGoSafePosFlow.Instance.GoSafePostion(); DischargeModuleGoSafePosFlow.Instance.Wait(); break; default: break; } } } else { flowStep = EDischargeFlowStep.到放料位下方; } break; case EDischargeFlowStep.到放料位下方: if (curNozzle.ToType == TurnoverType.Turnover) { targetZ = SysConfigParam.GetValue($"TurnoverNozzle{curNozzle.NozzleIndex}TakeHeight"); /*提前打开周转盘真空吸*/ VacManager.TurnoverTrayVacSuction(EVacOperator.Open, false, curNozzle.ToIndex + 1); } else { targetZ = SysConfigParam.GetValue($"TrayNozzle{curNozzle.NozzleIndex}TakeHeight") + GlobalVar.DischargeNozzleDumpStockTrayOffsetHeight; } errCode = AxisControl.GetAxis($"NozzleZ{curNozzle.NozzleIndex}").MovePos(targetZ, GlobalVar.WholeSpeed); if (errCode == ErrorCode.Ok || GlobalVar.VirtualAxis) { logInfo = GetClassName() + $"排料吸嘴{curNozzle.NozzleIndex}号到{WitchTrayWitchSlot(curNozzle.ToType, curNozzle.ToIndex)}放料位下方"; MessageQueue.Instance.Insert(logInfo); VirtualAxisSleep(); flowStep = EDischargeFlowStep.等待到放料位下方; } else { //PromptMessageBox.ShowAxisAlarmDialog($"NozzleZ{curNozzle.NozzleIndex}", errCode); alarmEntity = AlarmCollection.Get($"NozzleZ{curNozzle.NozzleIndex}运动异常").Transform(errCode.ToString()); AlarmMessageBox.ShowDialog(alarmEntity, ETipButton.Ok, null); } break; case EDischargeFlowStep.等待到放料位下方: if (Ops.IsStop($"NozzleZ{curNozzle.NozzleIndex}") || GlobalVar.VirtualAxis) { if(AxisArrived.LoadXYIsArrived(targetX,targetY)) { logInfo = GetClassName() + $"排料吸嘴{curNozzle.NozzleIndex}号已运动到{WitchTrayWitchSlot(curNozzle.ToType, curNozzle.ToIndex)}放料位下方"; MessageQueue.Instance.Insert(logInfo); if (curNozzle.ToType == TurnoverType.Turnover) { /*关闭排料吸嘴真空吸*/ //logInfo = GetClassName() + $"关闭{curNozzle.NozzleIndex}号排料吸嘴真空吸"; //MessageQueue.Instance.Insert(logInfo); //Ops.Off($"{curNozzle.NozzleIndex}号吸嘴真空吸电磁阀");//关闭真空 //Thread.Sleep(GlobalVar.LoadNozzleCloseVacSuctionDelaytime); VacManager.DischargeVacSuction(EVacOperator.Close, true, curNozzle.NozzleIndex); /*打开排料吸嘴真空破*/ //logInfo = GetClassName() + $"打开{curNozzle.NozzleIndex}号排料吸嘴真空破"; //MessageQueue.Instance.Insert(logInfo); //Ops.On($"{curNozzle.NozzleIndex}号吸嘴真空破电磁阀"); //Thread.Sleep(GlobalVar.LoadNozzleOpenVacBreakDelaytime); VacManager.DischargeVacBreak(EVacOperator.Open, true, curNozzle.NozzleIndex); flowStep = EDischargeFlowStep.到放料关破真空位; } else { GlobalTray.DischargeNozzle.ChangeStatus(curNozzle.NozzleIndex, ESlotStatus.NotHave); /*关闭排料吸嘴真空吸*/ //logInfo = GetClassName() + $"关闭{curNozzle.NozzleIndex}号排料吸嘴真空吸"; //MessageQueue.Instance.Insert(logInfo); //Ops.Off($"{curNozzle.NozzleIndex}号吸嘴真空吸电磁阀"); //Thread.Sleep(GlobalVar.LoadNozzleCloseVacSuctionDelaytime); VacManager.DischargeVacSuction(EVacOperator.Close, true, curNozzle.NozzleIndex); /*打开排料吸嘴真空破*/ //logInfo = GetClassName() + $"打开{curNozzle.NozzleIndex}号排料吸嘴真空破"; //MessageQueue.Instance.Insert(logInfo); //Ops.On($"{curNozzle.NozzleIndex}号吸嘴真空破电磁阀"); //Thread.Sleep(GlobalVar.LoadNozzleOpenVacBreakDelaytime); VacManager.DischargeVacBreak(EVacOperator.Open, true, curNozzle.NozzleIndex); /*关闭排料吸嘴真空破*/ //logInfo = GetClassName() + $"关闭{curNozzle.NozzleIndex}号排料吸嘴真空破"; //MessageQueue.Instance.Insert(logInfo); //Ops.Off($"{curNozzle.NozzleIndex}号吸嘴真空破电磁阀"); //Thread.Sleep(GlobalVar.LoadNozzleCloseVacBreakDelaytime); VacManager.DischargeVacBreak(EVacOperator.Close, false, curNozzle.NozzleIndex); flowStep = EDischargeFlowStep.放料完成抬起; } } else { flowStep = EDischargeFlowStep.到放料位上方; } } break; case EDischargeFlowStep.到放料关破真空位: targetZ = SysConfigParam.GetValue($"TurnoverNozzle{curNozzle.NozzleIndex}TakeHeight")+GlobalVar.DischargeNozzleDumpTurnoverTrayOffset; errCode = AxisControl.GetAxis($"NozzleZ{curNozzle.NozzleIndex}").MovePos(targetZ, GlobalVar.WholeSpeed); if (errCode == ErrorCode.Ok || GlobalVar.VirtualAxis) { logInfo = GetClassName() + $"排料吸嘴{curNozzle.NozzleIndex}号周转盘放料完成,准备抬起{GlobalVar.DischargeNozzleDumpTurnoverTrayOffset}mm后关闭破真空"; MessageQueue.Instance.Insert(logInfo); flowStep = EDischargeFlowStep.等待到放料关破真空位; } else { PromptMessageBox.ShowAxisAlarmDialog($"NozzleZ{curNozzle.NozzleIndex}", errCode); } break; case EDischargeFlowStep.等待到放料关破真空位: if (Ops.IsStop($"NozzleZ{curNozzle.NozzleIndex}") || GlobalVar.VirtualAxis) { /*关闭排料吸嘴真空破*/ //Ops.Off($"{curNozzle.NozzleIndex}号吸嘴真空破电磁阀"); //Thread.Sleep(GlobalVar.LoadNozzleCloseVacBreakDelaytime); VacManager.DischargeVacBreak(EVacOperator.Close,false,curNozzle.NozzleIndex); logInfo = GetClassName() + $"关闭排料{curNozzle.NozzleIndex}号吸嘴真空破"; MessageQueue.Instance.Insert(logInfo); flowStep = EDischargeFlowStep.放料完成抬起; } break; case EDischargeFlowStep.放料完成抬起: errCode = AxisControl.GetAxis($"NozzleZ{curNozzle.NozzleIndex}").MovePos(0, GlobalVar.WholeSpeed); if (errCode == ErrorCode.Ok || GlobalVar.VirtualAxis) { logInfo = GetClassName() + $"排料吸嘴{curNozzle.NozzleIndex}号{WitchTrayWitchSlot(curNozzle.ToType, curNozzle.ToIndex)}放料完成抬起"; MessageQueue.Instance.Insert(logInfo); if (GlobalVar.VirtualAxis) { Thread.Sleep(GlobalVar.VirtualAxisMoveTime); } flowStep = EDischargeFlowStep.等待放料完成抬起; } else { //PromptMessageBox.ShowAxisAlarmDialog($"NozzleZ{curNozzle.NozzleIndex}", errCode); alarmEntity = AlarmCollection.Get($"NozzleZ{curNozzle.NozzleIndex}运动异常").Transform(errCode.ToString()); AlarmMessageBox.ShowDialog(alarmEntity, ETipButton.Ok, null); } break; case EDischargeFlowStep.等待放料完成抬起: if (Ops.IsStop($"NozzleZ{curNozzle.NozzleIndex}") || GlobalVar.VirtualAxis) { logInfo = GetClassName()+$"排料吸嘴{curNozzle.NozzleIndex}号{WitchTrayWitchSlot(curNozzle.ToType, curNozzle.ToIndex)}放料完成已起位"; MessageQueue.Instance.Insert(logInfo); if(curNozzle.ToType== TurnoverType.Turnover) { flowStep = EDischargeFlowStep.放料真空检测; } else { flowStep = EDischargeFlowStep.粘料检测; } } break; case EDischargeFlowStep.放料真空检测: if (curNozzle.ToType == TurnoverType.Turnover) { if (Ops.IsOn($"周转盘{curNozzle.ToIndex + 1}号穴位真空吸检测") || GlobalVar.RunSpace) { logInfo = GetClassName() + $"周转盘{curNozzle.ToIndex + 1}号穴位真空吸检测OK"; MessageQueue.Instance.Insert(logInfo); flowStep = EDischargeFlowStep.放料任务完成; } else { //打开真空吸 curNozzle.VacSuction(EIoOperate.Open); //如果粘料 if (curNozzle.HasProduct()) { bool skip = false; while (!skip) { //粘料报警,提示用户粘料,移动到安全位,或者点击跳过 //alarmInfo = $"排料{curNozzle.NozzleIndex}号吸嘴可能粘料,请查看吸嘴状态后处理"; //alarmInfo = string.Format(AlarmCollection.GetAlarm(AlarmConstID.排料头粘料报警), curNozzle.NozzleIndex); alarmEntity = AlarmCollection.Get(AlarmConstID.排料头粘料报警).Transform(curNozzle.NozzleIndex); MessageQueue.Instance.Warn(GetClassName() + alarmEntity.CN); //TestCenterMessageBox.Show(AlarmConstID.NozzleTackinessAlarm, alarmInfo, MessageButtonManager.GetSkip_MoveToSafe_Button(), MessageButtonManager.GetSkip_MoveToSafe_ButtonText()); //msgBox = MsgBox.ShowDialog(AlarmConstID.排料头粘料报警, alarmInfo, MessageButtonManager.GetSkip_MoveToSafe_Button(), MessageButtonManager.GetSkip_MoveToSafe_ButtonText());// TestCenterMessageBox.WaitResult(AlarmConstID.NozzleTackinessAlarm); ETipButton btnRet = AlarmMessageBox.ShowDialog(alarmEntity, MessageButtonManager.GetSkip_MoveToSafe_Button(), MessageButtonManager.GetSkip_MoveToSafe_ButtonText()); //switch (msgBox.Button) switch(btnRet) { case ETipButton.Skip: logInfo = GetClassName() + "选择了跳过按钮"; MessageQueue.Instance.Insert(logInfo); if (!curNozzle.HasProduct()) { curNozzle.VacSuction(EIoOperate.Close); curNozzle.Reset(); skip = true; flowStep = EDischargeFlowStep.放料任务完成; } break; case ETipButton.Yes: logInfo = GetClassName() + "选择了移动到安全位按钮"; MessageQueue.Instance.Insert(logInfo); DischargeModuleGoSafePosFlow.Instance.GoSafePostion(); break; } } } else { //如果没有粘料,说明产品放下去了,这个时候用相机检测产品是否在穴位种 VisionResult vr = UpCameraScanBarCodeFlow.Instance.ScanSingle(curNozzle.ToIndex + 1, true,true,false); //VisionResult vr = UpCameraScanBarCodeFlow.Instance.WaitSingle(); if (UpCameraScanBarCodeFlow.Instance.CheckResult(vr)) { logInfo = GetClassName() + $"排料吸嘴{curNozzle.NozzleIndex}号SN={curNozzle.SN}放{WitchTrayWitchSlot(curNozzle.ToType, curNozzle.ToIndex)}"; MessageQueue.Instance.Insert(logInfo); curNozzle.VacSuction(EIoOperate.Close); flowStep = EDischargeFlowStep.放料任务完成; } else { //异常处理 bool exit = false; Dictionary buttons = new Dictionary() { { ETipButton.Retry,"重拍|Regrab" }, {ETipButton.Skip,"跳过|Skip" }, {ETipButton.Yes,"移动到安全位|MoveToSafePos" } }; while (!exit) { //alarmInfo = $"周转盘{curNozzle.ToIndex + 1}号穴位真空吸异常"; alarmInfo = string.Format(AlarmCollection.GetAlarm(AlarmConstID.排料头放料到周转盘后周转盘真空吸报警), curNozzle.NozzleIndex, curNozzle.ToIndex + 1); MessageQueue.Instance.Warn(GetClassName() + alarmInfo); //TestCenterMessageBox.Show(AlarmConstID.TurnoverDumpFailAlarm, alarmInfo, ETipButton.Retry | ETipButton.Skip | ETipButton.Yes, buttons); msgBox = PromptMessageBox.ShowDialog(AlarmConstID.排料头放料到周转盘后周转盘真空吸报警, alarmInfo, ETipButton.Retry | ETipButton.Skip | ETipButton.Yes, buttons);// TestCenterMessageBox.WaitResult(AlarmConstID.TurnoverDumpFailAlarm); if (msgBox != null) { switch (msgBox.Button) { case ETipButton.Retry://重拍 logInfo = GetClassName() + $"选择了重拍"; MessageQueue.Instance.Insert(logInfo); vr = UpCameraScanBarCodeFlow.Instance.ScanSingle(curNozzle.ToIndex + 1, true,true,true); //vr = UpCameraScanBarCodeFlow.Instance.WaitSingle(); if (UpCameraScanBarCodeFlow.Instance.CheckResult(vr)) { logInfo = GetClassName() + $"排料吸嘴{curNozzle.NozzleIndex}号SN={curNozzle.SN}放{WitchTrayWitchSlot(curNozzle.ToType, curNozzle.ToIndex)}"; MessageQueue.Instance.Insert(logInfo); curNozzle.VacSuction(EIoOperate.Close); exit = true; flowStep = EDischargeFlowStep.放料任务完成; } break; case ETipButton.Skip://跳过 logInfo = GetClassName() + $"选择了跳过"; MessageQueue.Instance.Insert(logInfo); if (!UpCameraCheckFlow.Instance.CheckTurnoverTrayHasProduct(null, curNozzle.ToIndex + 1).HasProduct) { VacManager.TurnoverTrayVacSuction(EVacOperator.Close, true, curNozzle.ToIndex + 1); curNozzle.Reset(); flowStep = EDischargeFlowStep.放料任务完成; exit = true; } break; case ETipButton.Yes://移动到安全位 logInfo = GetClassName() + $"选择了移动到安全位"; MessageQueue.Instance.Insert(logInfo); DischargeModuleGoSafePosFlow.Instance.GoSafePostion(); DischargeModuleGoSafePosFlow.Instance.Wait(); break; default: break; } } } } } } } break; case EDischargeFlowStep.粘料检测: //打开真空吸 curNozzle.VacSuction(EIoOperate.Open); if(!GlobalVar.RunSpace && curNozzle.HasProduct()) { bool skip = false; while(!skip) { //粘料报警,提示用户粘料,移动到安全位,或者点击跳过 //alarmInfo = $"排料{curNozzle.NozzleIndex}号吸嘴可能粘料,请查看吸嘴状态后处理"; //alarmInfo = string.Format(AlarmCollection.GetAlarm(AlarmConstID.排料头粘料报警), curNozzle.NozzleIndex); alarmEntity = AlarmCollection.Get(AlarmConstID.排料头粘料报警).Transform(curNozzle.NozzleIndex); MessageQueue.Instance.Warn(GetClassName()+ alarmEntity.CN); //TestCenterMessageBox.Show(AlarmConstID.NozzleTackinessAlarm, alarmInfo, MessageButtonManager.GetSkip_MoveToSafe_Button(), MessageButtonManager.GetSkip_MoveToSafe_ButtonText()); //msgBox = MsgBox.ShowDialog(AlarmConstID.排料头粘料报警, alarmInfo, MessageButtonManager.GetSkip_MoveToSafe_Button(), MessageButtonManager.GetSkip_MoveToSafe_ButtonText());// TestCenterMessageBox.WaitResult(AlarmConstID.NozzleTackinessAlarm); ETipButton btnRet = AlarmMessageBox.ShowDialog(alarmEntity, MessageButtonManager.GetSkip_MoveToSafe_Button(), MessageButtonManager.GetSkip_MoveToSafe_ButtonText()); //switch (msgBox.Button) switch(btnRet) { case ETipButton.Skip: logInfo = GetClassName() + "选择了跳过按钮"; MessageQueue.Instance.Insert(logInfo); if (!curNozzle.HasProduct()) { curNozzle.VacSuction(EIoOperate.Close); curNozzle.Reset(); skip = true; flowStep = EDischargeFlowStep.放料任务完成; } break; case ETipButton.Yes: logInfo = GetClassName() + "选择了移动到安全位按钮"; MessageQueue.Instance.Insert(logInfo); DischargeModuleGoSafePosFlow.Instance.GoSafePostion(); break; } } } else { logInfo = GetClassName() + $"排料吸嘴{curNozzle.NozzleIndex}号SN={curNozzle.SN}放{WitchTrayWitchSlot(curNozzle.ToType, curNozzle.ToIndex)}"; MessageQueue.Instance.Insert(logInfo); curNozzle.VacSuction(EIoOperate.Close); flowStep = EDischargeFlowStep.放料任务完成; } break; case EDischargeFlowStep.放料任务完成: //AxisControl.GetAxis($"NozzleZ{curNozzle.NozzleIndex}").Home(); //MessageQueue.Instance.Insert($"{curNozzle.NozzleIndex}号排料吸嘴回原"); //Ops.HomeAndGoStartPos($"NozzleR{NozzleIndex}"); if (curNozzle.Status == ENozzleStatus.ToUnload) { GlobalTray.DischargeNozzle.ChangeStatus(curNozzle.NozzleIndex, ESlotStatus.NotHave); logInfo = GetClassName() + $"排料吸嘴{curNozzle.NozzleIndex}号{WitchTrayWitchSlot(curNozzle.ToType, curNozzle.ToIndex)}放料任务完成"; MessageQueue.Instance.Insert(logInfo); if (curNozzle.ToType == TurnoverType.Turnover) { GlobalTray.TurnoverTray.ChangeStatus(curNozzle.ToIndex + 1, ESlotStatus.Have); TurnoverTrayManager.Instance.Slot(curNozzle.ToIndex + 1).AddProduct(curNozzle); } else if (curNozzle.ToType == TurnoverType.ToBeTested) { //curNozzle.ToFloor = StockManager.Instance.GetStock(ETrayType.Input).GetFloor(); GlobalTray.Input1Tray.ChangeStatus(curNozzle.ToIndex+1, ESlotStatus.Have); TrayStatusManager.Fill(ETrayType.Input1, curNozzle.ToIndex + 1); } else if (curNozzle.ToType == TurnoverType.Passed) { //curNozzle.ToFloor = StockManager.Instance.GetStock(ETrayType.Ok).GetFloor(); GlobalTray.Good1Tray.ChangeStatus(curNozzle.ToIndex + 1, ESlotStatus.Have); TrayStatusManager.Fill(ETrayType.Good1, curNozzle.ToIndex + 1); } else if (curNozzle.ToType == TurnoverType.Failed) { //curNozzle.ToFloor = StockManager.Instance.GetStock(ETrayType.Ng).GetFloor(); GlobalTray.RejectTray.ChangeStatus(curNozzle.ToIndex + 1, ESlotStatus.Have); TrayStatusManager.Fill(ETrayType.Reject, curNozzle.ToIndex + 1); } else if (curNozzle.ToType == TurnoverType.Multifunction) { //curNozzle.ToFloor = StockManager.Instance.GetStock(ETrayType.Multi).GetFloor(); GlobalTray.MultiTray.ChangeStatus(curNozzle.ToIndex + 1, ESlotStatus.Have); TrayStatusManager.Fill(ETrayType.Multi, curNozzle.ToIndex + 1); } LoadAndUnloadTask.Instance.AddTurnoverResult(curNozzle); } curNozzle.Reset(); if (NozzleManager.GetNozzlesByStatus(ENozzleStatus.ToUnload).Count > 0) { flowStep = EDischargeFlowStep.到放料位上方; } else { //release memory //foreach (var item in mrs) //{ // item.Dispose(); //} //mrs.Clear(); if(mrs!=null&&mrs.Count>0) { Array.Clear(imgs, 0, imgs.Length); mrs.Clear(); GC.Collect(); } //GC.Collect(); if(curNozzle.ToType== TurnoverType.Turnover) { ScanBarCode(); } if (LoadAndUnloadTask.Instance.GetUnDealedTask().Count > 0) { StockTrayToTurnoverTray = !StockTrayToTurnoverTray; flowStep = EDischargeFlowStep.到取料位上方; } else { flowStep = EDischargeFlowStep.任务结束到安全位; } } break; case EDischargeFlowStep.任务结束到安全位: //检测一下是否需要换盘 { #region 通知中控排料任务结束 if(curNozzle.ToType!= TurnoverType.Turnover && !GlobalVar.CleanOut) { if (TestCenter.Instance.LoadResult()) { logInfo = GetClassName() + $"通知中控任务完成"; MessageQueue.Instance.Insert(logInfo); LoadAndUnloadTask.Instance.Clear(); logInfo = GetClassName() + $"任务完成,清除任务"; MessageQueue.Instance.Insert(logInfo); MachineManage.Instance.SetLoadUnloadStatus(ERunState.Waiting); } } #endregion errCode = AxisControl.LoadX.MovePos(SysConfigParam.GetValue("LoadXStartPos"), GlobalVar.WholeSpeed); if (errCode == ErrorCode.Ok || GlobalVar.VirtualAxis) { errCode = AxisControl.LoadY.MovePos(SysConfigParam.GetValue("LoadYStartPos"), GlobalVar.WholeSpeed); if (errCode == ErrorCode.Ok || GlobalVar.VirtualAxis) { if (GlobalVar.VirtualAxis) { Thread.Sleep(GlobalVar.VirtualAxisMoveTime); } logInfo = GetClassName() + $"排料任务结束到安全位"; MessageQueue.Instance.Insert(logInfo); flowStep = EDischargeFlowStep.等待任务结束到安全位; } else { //MsgBox.ShowAxisAlarmDialog(AxisControl.LoadY, errCode); alarmEntity = AlarmCollection.Get(AlarmConstID.LoadY运动异常).Transform(errCode.ToString()); AlarmMessageBox.ShowDialog(alarmEntity, ETipButton.Ok, null); } } else { //MsgBox.ShowAxisAlarmDialog(AxisControl.LoadX, errCode); alarmEntity = AlarmCollection.Get(AlarmConstID.LoadX运动异常).Transform(errCode.ToString()); AlarmMessageBox.ShowDialog(alarmEntity, ETipButton.Ok, null); } } break; case EDischargeFlowStep.等待任务结束到安全位: if(Ops.IsStop("LoadX", "LoadY") || GlobalVar.VirtualAxis) { if (curNozzle.ToType == TurnoverType.Turnover) { if (TestCenter.Instance.LoadResult()) { logInfo = GetClassName() + $"通知中控任务完成"; MessageQueue.Instance.Insert(logInfo); LoadAndUnloadTask.Instance.Clear(); logInfo = GetClassName() + $"任务完成,清除任务"; MessageQueue.Instance.Insert(logInfo); MachineManage.Instance.SetLoadUnloadStatus(ERunState.Waiting); } } TurnoverFlow.Instance.CanMoveFromTestTrayToTurnoverTray(); logInfo = GetClassName()+ $"任务结束已回到安全位"; MessageQueue.Instance.Insert(logInfo); flowStep = EDischargeFlowStep.等待任务; } break; default: break; } } /// /// 判断排料轴是否可以干其他的活 /// public void WaitCanMove() { while(true) { if(flowStep== EDischargeFlowStep.等待任务) { return; } Thread.Sleep(10); } } public void ScanBarCode() { SchedulingMessageBox box = new SchedulingMessageBox(); if(GlobalVar.RunSpace) { List slots = TurnoverTrayManager.Instance.GetSlots(ETurnoverTraySlotType.WaitTest, ETurnoverTraySlotStatus.Have); foreach (var slot in slots) { LoadAndUnloadTask.Instance.CopyBarcodeToTask(slot.Index - 1, VirtualBarCode.Code); } } else { if (LoadAndUnloadTask.Instance.GetUndealedLoadToTurnoverTask().Count == 0) { if (GlobalVar.GRR) { scanNum++; } if (scanNum == 1 || !GlobalVar.GRR) { if (GlobalVar.EnableVirtuleBarCode) { List slots = TurnoverTrayManager.Instance.GetSlots(ETurnoverTraySlotType.WaitTest, ETurnoverTraySlotStatus.Have); foreach (var slot in slots) { LoadAndUnloadTask.Instance.CopyBarcodeToTask(slot.Index - 1, VirtualBarCode.Code); } } else { //没有需要给周转盘上料的任务后,就开始上相机扫码 //判断周转盘第一行有没有产品,如果有产品则拍第一行 if (TurnoverTrayManager.Instance.HasProduct(ETrayRow.One)) { //找拍照起点和终点 SlotPoint grabStartPoint = TrayPointManager.GetSlotPoint(ETrayType.Turnover, 1); SlotPoint grabEndPoint = TrayPointManager.GetSlotPoint(ETrayType.Turnover, 8); List result = UpCameraScanBarCodeFlow.Instance.ScanMulti(1, false); //List result = UpCameraScanBarCodeFlow.Instance.Wait(); foreach (var vr in result) { if (TurnoverTrayManager.Instance.Slot(vr.SlotIndex).IsHasProduct) { if (vr.SearchModelOK)//定位成功 { if (!GlobalVar.EnableScanBarCodeByDownCamera) { if (GlobalVar.RunSpace) { LoadAndUnloadTask.Instance.CopyBarcodeToTask(vr.SlotIndex - 1, VirtualBarCode.Code); } else { if (vr.ScanBarCodeOK) { OnShowGrabResult?.Invoke(vr, true); //复制二维码 LoadAndUnloadTask.Instance.CopyBarcodeToTask(vr.SlotIndex - 1, vr.SN); TurnoverTrayManager.Instance.Slot(vr.SlotIndex).SN = vr.SN; } else { int failNum = 1; while (true) { if (failNum < 4) { //如果扫码失败再重扫一次 VisionResult vrsigle =UpCameraScanBarCodeFlow.Instance.ScanSingle(vr.SlotIndex, true,false,true); //VisionResult vrsigle = UpCameraScanBarCodeFlow.Instance.WaitSingle(); if (vrsigle.ScanBarCodeOK) { OnShowGrabResult?.Invoke(vrsigle, true); LoadAndUnloadTask.Instance.CopyBarcodeToTask(vr.SlotIndex - 1, vrsigle.SN); TurnoverTrayManager.Instance.Slot(vr.SlotIndex).SN = vrsigle.SN; break; } else { failNum++; OnShowGrabResult?.Invoke(vrsigle, true); //复制二维码 //LoadAndUnloadTask.Instance.CopyBarcodeToTask(vr.SlotIndex - 1, ""); Thread.Sleep(500); } if(vrsigle != null) { vrsigle=null; GC.Collect(); } } else { alarmInfo = string.Format(AlarmCollection.GetAlarm(AlarmConstID.扫码失败), vr.SlotIndex); Dictionary buttonTexts = new Dictionary() { { ETipButton.Retry,"重试|Retry"}, { ETipButton.Cancel,"自动移走|Auto remove"} }; box = PromptMessageBox.ShowDialog(AlarmConstID.扫码失败, alarmInfo, ETipButton.Retry | ETipButton.Cancel, buttonTexts); if (box.Button == ETipButton.Retry) { failNum = 1; } else if(box.Button== ETipButton.Cancel) { //OnShowGrabResult?.Invoke(vrsigle, true); //复制二维码 LoadAndUnloadTask.Instance.CopyBarcodeToTask(vr.SlotIndex - 1, ""); TurnoverTrayManager.Instance.Slot(vr.SlotIndex).SN = ""; break; } } } } } } } else { //定位失败,或者超出指定范围 } } else { OnShowGrabResult?.Invoke(vr, false); } //vr.Dispose(); } if (result != null && result.Count > 0) { result.Clear(); GC.Collect(); } //OnUpCameraGrabResult?.Invoke(result); } //判断周转盘第三行有没有产品,如果有产品则拍第三行 if (TurnoverTrayManager.Instance.HasProduct(ETrayRow.Three)) { //找拍照起点和终点 SlotPoint grabStartPoint = TrayPointManager.GetSlotPoint(ETrayType.Turnover, 17); SlotPoint grabEndPoint = TrayPointManager.GetSlotPoint(ETrayType.Turnover, 24); List result = UpCameraScanBarCodeFlow.Instance.ScanMulti(24, true); // List result = UpCameraScanBarCodeFlow.Instance.Wait(); foreach (var vr in result) { if (TurnoverTrayManager.Instance.Slot(vr.SlotIndex).IsHasProduct) { if (vr.SearchModelOK)//定位成功 { if (!GlobalVar.EnableScanBarCodeByDownCamera) { if (GlobalVar.RunSpace) { LoadAndUnloadTask.Instance.CopyBarcodeToTask(vr.SlotIndex - 1, VirtualBarCode.Code); } else { if (vr.ScanBarCodeOK) { OnShowGrabResult?.Invoke(vr, true); //复制二维码 LoadAndUnloadTask.Instance.CopyBarcodeToTask(vr.SlotIndex - 1, vr.SN); TurnoverTrayManager.Instance.Slot(vr.SlotIndex).SN = vr.SN; } else { int failNum = 1; while (true) { if (failNum < 4) { //如果扫码失败再重扫一次 VisionResult vrsigle =UpCameraScanBarCodeFlow.Instance.ScanSingle(vr.SlotIndex, true,false,true); //VisionResult vrsigle = UpCameraScanBarCodeFlow.Instance.WaitSingle(); if (vrsigle.ScanBarCodeOK) { OnShowGrabResult?.Invoke(vrsigle, true); LoadAndUnloadTask.Instance.CopyBarcodeToTask(vr.SlotIndex - 1, vrsigle.SN); TurnoverTrayManager.Instance.Slot(vr.SlotIndex).SN = vrsigle.SN; break; } else { failNum++; OnShowGrabResult?.Invoke(vrsigle, true); //复制二维码 //LoadAndUnloadTask.Instance.CopyBarcodeToTask(vr.SlotIndex - 1, ""); Thread.Sleep(500); } if(vrsigle != null) { vrsigle = null; GC.Collect(); } } else { //box = MsgBox.ShowDialog(AlarmConstID.ScanBarCodeFailAlarm, $"{vr.SlotIndex}穴位扫码失败", ETipButton.Retry | ETipButton.Skip); alarmInfo = string.Format(AlarmCollection.GetAlarm(AlarmConstID.扫码失败), vr.SlotIndex); Dictionary buttonTexts = new Dictionary() { { ETipButton.Retry,"重试|Retry"}, { ETipButton.Cancel,"自动移走|Auto remove"} }; box = PromptMessageBox.ShowDialog(AlarmConstID.扫码失败, alarmInfo, ETipButton.Retry | ETipButton.Cancel, buttonTexts); if (box.Button == ETipButton.Retry) { failNum = 1; } else if (box.Button == ETipButton.Cancel) { //OnShowGrabResult?.Invoke(vrsigle, true); //复制二维码 LoadAndUnloadTask.Instance.CopyBarcodeToTask(vr.SlotIndex - 1, ""); TurnoverTrayManager.Instance.Slot(vr.SlotIndex).SN = ""; break; } } } } } } } else { //定位失败,或者超出指定范围 } } else { OnShowGrabResult?.Invoke(vr, false); } //vr.Dispose(); } if (result != null && result.Count > 0) { result.Clear(); GC.Collect(); } //OnUpCameraGrabResult?.Invoke(result); } } } } } } /// /// 取料完成后更新吸嘴状态 /// private void UpdateNozzleStatus(Nozzle nozzle,TurnoverInfo turnoverInfo) { nozzle.Status = ENozzleStatus.ToUnload; //nozzle.FromType = turnoverInfo.FromType; nozzle.ToType = turnoverInfo.ToType; nozzle.ToIndex = turnoverInfo.ToIndex; turnoverInfo.SuckerNo = nozzle.NozzleIndex; nozzle.TurnoverGUID = turnoverInfo.GUID; if (turnoverInfo.FromType == TurnoverType.Turnover) { TurnoverTrayManager.Instance.Slot(turnoverInfo.FromIndex + 1).ClearProduct(); nozzle.FromFloor = turnoverInfo.FromFloor; nozzle.SN = turnoverInfo.SN; //nozzle.FromIndex = turnoverInfo.FromIndex; GlobalTray.TurnoverTray.ChangeStatus(nozzle.FromIndex + 1, ESlotStatus.NotHave); } else if (turnoverInfo.FromType == TurnoverType.ToBeTested) { //nozzle.FromFloor = StockManager.Instance.GetStock(ETrayType.Input).GetFloor(); nozzle.SN = ""; //nozzle.FromIndex = GlobalTray.InputTray.GetSlot(ESlotStatus.Have).Index - 1; GlobalTray.Input1Tray.ChangeStatus(nozzle.FromIndex+1, ESlotStatus.NotHave); TrayStatusManager.Clear(ETrayType.Input1, nozzle.FromIndex + 1); } nozzle.Update(); turnoverInfo.Dealed = true; } /// /// 获取吸嘴取料取不起来时,吸嘴在原取料位的偏移 /// 奇数向下偏移 /// 偶数向上偏移 /// /// /// private double GetVacOffsetHeight(int fetchNum) { if(fetchNum==0) return 0; //先判断是奇数还是偶数 int count = 0; int oddOrEven = fetchNum & 0x01; double offsetDisct = 0.0; if (oddOrEven == 1) { count = (fetchNum / 2) + 1; offsetDisct = -0.1 * count; } else if (oddOrEven == 0) { count = (fetchNum / 2); offsetDisct = 0.1 * count; } return offsetDisct; } /// /// 检测排料Y轴是否可以到周转盘 /// /// private bool CanGoTurnoverTray() { //获取周转Y轴的位置,当排料Y轴去周转盘的时候,检测是否安全 double turnoverYPos = Ops.GetCurPosition("TurnoverY"); if (turnoverYPos - SysConfigParam.GetValue("PressY") < -1) return false; return true; } /// /// 检测XY是否可以去周转盘 /// /// public bool XYCanGoTurnoverTray() { if (!CanGoTurnoverTray()) return false; return true; } /// /// 判断XY是否可以在本区域运动 /// /// public bool XYCanGoLocalArea() { //获取周转Y轴的位置,当排料Y轴去周转盘的时候,检测是否安全 double turnoverYPos = Ops.GetCurPosition("TurnoverY"); if (turnoverYPos - SysConfigParam.GetValue("TurnoverDumpY") < -0.5) return false; return true; } public string GetCurStep() { return flowStep.ToString(); } /// /// 到哪个盘哪个穴位 /// /// /// /// public string WitchTrayWitchSlot(TurnoverType trayType,int slotIndex) { return $"{trayType}盘{slotIndex+1}穴位"; } /// /// 复位流程步序 /// private void ResetFlow() { flowStep = EDischargeFlowStep.等待任务; } ///// ///// 检测XY是否在目标位置上 ///// ///// ///// ///// //private bool XYIsInTargetPos(double xTargetPos, double yTargetPos) //{ // Stopwatch timer = new Stopwatch(); // timer.Start(); // while (timer.ElapsedMilliseconds<3000) // { // double xCurPos = Ops.GetCurPosition(AxisControl.LoadX); // double yCurPos = Ops.GetCurPosition(AxisControl.LoadY); // if ((Math.Abs(xTargetPos - xCurPos) < AxisControl.LoadX.Config.Tolerance // && Math.Abs(yTargetPos - yCurPos)