using Aurora.Api; using AuroraCellTracker; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using WeldingCommon.Sequences; using WeldingCommon; using AuroraLaserScanner; using WeldingCommon.Settings; using WeldingCommon.Utils; using AuroraLaser; using AuroraOCT; using AuroraPLC; using AuroraIO; using VisionCommon; using CoreUnit.Scanner.UserControl.ScannerCanvas; using Aurora.Api.Manager; using AuroraLBAD; using CoreUnit.Control.UserControl.Canvas; using Matrox.MatroxImagingLibrary; using WeldingCommon.Vision.WeldingObjectGenerator; using OpenCvSharp; using System.Diagnostics; using ILSOS_SMW.Models; using Aurora; using DB.Recipe; using System.Runtime.Remoting.Contexts; using System.IO; using System.Text.RegularExpressions; using System.Threading; using OpenCvSharp.Dnn; using static AuroraIO.AJINEXTEK.AjinIO.IOModuleInfo; using DB; using System.Configuration; using System.Runtime.InteropServices.ComTypes; using System.Windows.Media.Imaging; using OpenCvSharp.WpfExtensions; using System.Windows; using Aurora.View; using System.Drawing; using System.Collections.ObjectModel; using WeldingCommon.Views; using WeldingCommon.Data; using Hermes; using ILSOS_SMW.RMS; using System.CodeDom.Compiler; using static Aurora.Api.SequenceBuilder; using WeldingCommon.Devices; using static ILSOS_SMW.Device.PLCControllerSMW; using System.Windows.Forms.VisualStyles; using WeldingCommon.Alarm; using System.Windows.Forms; using System.Runtime.Remoting.Metadata.W3cXsd2001; using SystemParameter = WeldingCommon.Settings.SystemParameter; using Application = System.Windows.Application; using Point = OpenCvSharp.Point; using System.Windows.Shapes; using WeldingCommon.Vision.WeldingObjectGenerator.GeometryLibrary; using WeldingCommon.Vision.WeldingObjectGenerator.PathEditorLibrary; using Path = System.IO.Path; using static ILSOS_SMW.Device.IOController_SMW; using WeldingCommon.Recipes; namespace ILSOS_SMW.Sequences { class SeqAutoRunSMW_New { static readonly Logger Log = new Logger("SeqAutoRunSMW_New"); const string SEQ_ENTER = "[SeqAutoRunSMW] SEQ_ENTER"; // inputParam 으로 받자. const string SEQ_CHECK_INIT_CONDITION = "[SeqAutoRunSMW] Check Init Condition"; // Check Init Condition const string SEQ_CHECK_LOAD_COMPLETE = "[SeqAutoRunSMW] Check Load Complete"; const string SEQ_MEASURE_CELL_POSITION = "[SeqAutoRunSMW] Measure CellPosition"; const string SEQ_SET_SCOUT_FLYING_VISION_SEQ = "[SeqAutoRunSMW] Set Sequence Param (ScoutFlyingVision Seq)"; const string SEQ_DO_ID_SCOUT_FLYING_VISION_SEQ = "[SeqAutoRunSMW] Process (ScoutFlyingVision Seq)"; const string SEQ_GET_SCOUT_FLYING_VISION_SEQ = "[SeqAutoRunSMW] Get Sequence Result (ScoutFlyingVision Seq)"; const string SEQ_SEND_EVENT_SENDER = "[SeqAutoRunSMW] Event Sender"; const string SEQ_EVENT_Q_SAVE_FILE = "[SeqAutoRunSMW] EventQ Save File"; const string SEQ_SAVE_SCOUT_IMAGE = "[SeqAutoRunSMW] Save ScoutImage"; const string SEQ_FIND_EDGE = "[SeqAutoRunSMW] Find Edge"; const string SEQ_DECISION_RCC_ALGORITHM_TYPE = "[SeqAutoRunSMW] Decision RCC Algorithm Type"; const string SEQ_APPLY_OFFSET_OBJECT = "[SeqAutoRunSMW] Apply Offset Object"; const string SEQ_GENERATE_WELDING_OBJECT = "[SeqAutoRunSMW] Generate WeldingObject"; const string SEQ_READY_SCANNER_LIST = "[SeqAutoRunSMW] Ready ScannerList"; const string SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ = "[SeqAutoRunSMW] Set Sequence Param (UploadWeldingList Seq)"; const string SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ = "[SeqAutoRunSMW] Process (UploadWeldingList Seq)"; const string SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ = "[SeqAutoRunSMW] Get Sequence Result (UploadWeldingList Seq)"; const string SEQ_WAIT_WELDING_START = "[SeqAutoRunSMW] Wait Welding Start"; const string SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ = "[SeqAutoRunSMW] Set Sequence Param (ReceiveCellInfo Seq)"; const string SEQ_DO_ID_RECEIVE_CELL_INFO_SEQ = "[SeqAutoRunSMW] Process (ReceiveCellInfo Seq)"; const string SEQ_GET_PARAMS_RECEIVE_CELL_INFO_SEQ = "[SeqAutoRunSMW] Get Sequence Result (ReceiveCellInfo Seq)"; const string SEQ_EXECUTE_WELDING = "[SeqAutoRunSMW] Execute Welding"; const string SEQ_REQUEST_UNLOAD_CELL = "[SeqAutoRunSMW] Request Unload Cell"; const string SEQ_WAIT_LBAD_JUDGE = "[SeqAutoRunSMW] Wait LBAD Judge"; const string SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ = "[SeqAutoRunSMW] Set Sequence Param (ReportCellResult Seq)"; const string SEQ_DO_ID_REPORT_CELL_RESULT_SEQ = "[SeqAutoRunSMW] Process (ReportCellResult Seq)"; const string SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ = "[SeqAutoRunSMW] Get Sequence Result (ReportCellResult Seq)"; const string SEQ_REPORT_CELLINFO_TO_PLC = "[SeqAutoRunSMW] ReportCellInfoToPLC"; const string SEQ_CHECK_CYCLE_STOP = "[SeqAutoRunSMW] Check Cycle Stop"; const string SEQ_SAVE_RESULT_DATA = "[SeqAutoRunSMW] Save Result Data"; const string SEQ_WRITE_COMPLETION_PLC_BIT = "[SeqAutoRunSMW] Write Completion PLC Bit"; const string SEQ_COMPLETE = "[SeqAutoRunSMW] SEQ_COMPLETE"; // 완료 static class ContextKey { public const string KEY_SEQUENCE_RESULT = "KEY_SEQUENCE_RESULT_SeqAutoRunSMW"; public const string KEY_SEQUENCE_START_TIME = "KEY_SEQUENCE_START_TIME_SeqAutoRunSMW"; } const int PLC_TIMEOUT = 60; // sec, Timeout은 시퀀스 정지가 아니라 타임아웃 시간마다 로그만 남기도록 한다 private SeqAutoRunSMW_New_InitParam _InitParam; private Scanner _Scanner; private LaserDevice _Laser; private OCT _OCT; private PLCController _PLC; private IODevice _IO; private LBAD _LBAD; private SystemParameter _SystemParameter; private IRecipeManager _RecipeManager; private ScannerCanvasUserCtrl _ScannerCanvasUserCtrl; //스캐너 동작관련 객체 선언 private FovRecipe _FovRecipe; private CameraAgentBase _CameraAgent; private ICameraDisplay _CameraDisplay; private CamConfig _CamConfig; private eListNo _WeldingScannerListNo; private List _SelectedDrawObjectList; private MIL_ID _GrabImage = MIL.M_NULL; private ObjectGenerator _ObjGenerator; private Mat _ConvMatImage; private uint _TodayProduct; private uint _TotalProduct; private uint _OCT_QA_ERROR_COUNT; private DateTime _AutoRunStartTime; private DateTime _WeldingStartTime; private TimeSpan _WeldingSpanTime; private DateTime _WeldEndTime; private TimeSpan _InterfaceSpanTime; private DateTime _InterfaceStartTime; private string _LotId = "N/A"; private string _CellId = "N/A"; private bool _IncludeListStartEnd = false; // ==> local private int _SeqRunCount; // For RCC private List _GeneratedDrawObjects; private List _RecipeDrawObjects; // ==> local private Stopwatch _StopwatchGenObj; private int _Radius_Pixel; // End For RCC private int _ModelNo; private bool _IsRealTimeScout; private double _CellMeasureCenterOffsetX; private double _CellMeasureCenterOffsetY; public string EVENT_TRIGGER_SAVE_FILE = "EventTriggerSaveFile"; private UnitPoint _DetectedContourCenter; private Point[][] _MaxContour; private List _Polygon; private List _Paths; private List _SelectedArcs; public SequenceBuilder Builder() { var sb = new SequenceBuilder(5000, true); ////var sb = new SequenceBuilder(1000, false); // With log sb.AddAction(SEQ_ENTER, Sequence_Enter); sb.AddDecision(SEQ_CHECK_INIT_CONDITION, CheckInitCondition); //분기 sb.AddDecision(SEQ_CHECK_LOAD_COMPLETE, CheckLoadComplete); // CellCenterOffset sb.AddAction(SEQ_MEASURE_CELL_POSITION, MeasureCellPosition); // RCC sb.AddAction(SEQ_SET_SCOUT_FLYING_VISION_SEQ, SetScoutFlyingVision_SeqParams); sb.AddSubsequence(SEQ_DO_ID_SCOUT_FLYING_VISION_SEQ, SequenceManager.GetSeqBuilder_SeqScoutFlyingVision()); sb.AddAction(SEQ_GET_SCOUT_FLYING_VISION_SEQ, GetScoutFlyingVision_SeqResult); sb.AddEventSender(SEQ_SEND_EVENT_SENDER, SendEvent); sb.AddEventQ(SEQ_EVENT_Q_SAVE_FILE, 2); sb.AddAction(SEQ_SAVE_SCOUT_IMAGE, SaveScoutImageEvent); sb.AddAction(SEQ_FIND_EDGE, FindEdge); sb.AddDecision(SEQ_DECISION_RCC_ALGORITHM_TYPE, DecisionRCCAlgorithmType); sb.AddAction(SEQ_APPLY_OFFSET_OBJECT, ApplyOffsetObejct); sb.AddAction(SEQ_GENERATE_WELDING_OBJECT, GenerateWeldingObject); // ALL (Normal & RCC & CellCenterOffset) sb.AddAction(SEQ_READY_SCANNER_LIST, ReadyScannerList); sb.AddAction(SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ, SetUploadWeldingList_SeqParams); sb.AddSubsequence(SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ, SequenceManager.GetSeqBuilder_SeqUploadWeldingList()); sb.AddAction(SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ, GetUploadWeldingList_SeqResult); sb.AddAction(SEQ_WAIT_WELDING_START, WaitWeldingStart); sb.AddAction(SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ, SetReceiveCellInfo_SeqParams); sb.AddSubsequence(SEQ_DO_ID_RECEIVE_CELL_INFO_SEQ, SequenceManager.GetSeqBuilder_SeqReceiveCellInfo()); sb.AddAction(SEQ_GET_PARAMS_RECEIVE_CELL_INFO_SEQ, GetReceiveCellInfo_SeqResult); sb.AddAction(SEQ_EXECUTE_WELDING, ExecuteWelding); sb.AddAction(SEQ_REQUEST_UNLOAD_CELL, RequestUnloadCell); sb.AddAction(SEQ_WAIT_LBAD_JUDGE, WaitLBADJudge); sb.AddAction(SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ, SetReportCellResult_SeqParams); sb.AddSubsequence(SEQ_DO_ID_REPORT_CELL_RESULT_SEQ, SequenceManager.GetSeqBuilder_SeqReportCellResult()); sb.AddAction(SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ, GetReportCellResult_SeqResult); sb.AddAction(SEQ_REPORT_CELLINFO_TO_PLC, ReportCellInfoToPLC); sb.AddDecision(SEQ_CHECK_CYCLE_STOP, CheckCycleStop); sb.AddAction(SEQ_SAVE_RESULT_DATA, SaveResultData); // 해당 공정의 정보를 기록 함. sb.AddAction(SEQ_WRITE_COMPLETION_PLC_BIT, WriteCompletionPLCBit); // 정상적으로 종료 되면, complete bit write sb.AddAction(SEQ_COMPLETE, Complete); sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_CHECK_LOAD_COMPLETE] > sb[SEQ_READY_SCANNER_LIST] > sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_WAIT_WELDING_START] > sb[SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ] > sb[SEQ_DO_ID_RECEIVE_CELL_INFO_SEQ] > sb[SEQ_GET_PARAMS_RECEIVE_CELL_INFO_SEQ] > sb[SEQ_EXECUTE_WELDING] > sb[SEQ_REQUEST_UNLOAD_CELL] > sb[SEQ_WAIT_LBAD_JUDGE] > sb[SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ] > sb[SEQ_DO_ID_REPORT_CELL_RESULT_SEQ] > sb[SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ] > sb[SEQ_REPORT_CELLINFO_TO_PLC] > sb[SEQ_CHECK_CYCLE_STOP] > sb[SEQ_SAVE_RESULT_DATA] > sb[SEQ_WRITE_COMPLETION_PLC_BIT] > sb[SEQ_COMPLETE]); // CellCenterOffset sb.Flows(sb[SEQ_CHECK_LOAD_COMPLETE] > sb[SEQ_MEASURE_CELL_POSITION] > sb[SEQ_READY_SCANNER_LIST]); // RCC sb.Flows(sb[SEQ_CHECK_LOAD_COMPLETE] > sb[SEQ_SET_SCOUT_FLYING_VISION_SEQ] > sb[SEQ_DO_ID_SCOUT_FLYING_VISION_SEQ] > sb[SEQ_GET_SCOUT_FLYING_VISION_SEQ] > sb[SEQ_SEND_EVENT_SENDER].Send(EVENT_TRIGGER_SAVE_FILE) > sb[SEQ_FIND_EDGE] > sb[SEQ_DECISION_RCC_ALGORITHM_TYPE] > sb[SEQ_GENERATE_WELDING_OBJECT] > sb[SEQ_READY_SCANNER_LIST]) .Flows(sb[SEQ_DECISION_RCC_ALGORITHM_TYPE] > sb[SEQ_APPLY_OFFSET_OBJECT] > sb[SEQ_READY_SCANNER_LIST]) .Flows(sb[SEQ_DECISION_RCC_ALGORITHM_TYPE] > sb[SEQ_READY_SCANNER_LIST]); // Scout Image Save Event Seq sb.Flows(sb[SEQ_EVENT_Q_SAVE_FILE].On(EVENT_TRIGGER_SAVE_FILE) > sb[SEQ_SAVE_SCOUT_IMAGE] > sb.FlowFinal); sb.Flows(sb[SEQ_CHECK_CYCLE_STOP] > sb[SEQ_CHECK_LOAD_COMPLETE]); sb.Flows(sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_COMPLETE] > sb.Final); sb.OnStopped(OnStopped); sb.OnForceError(OnForceError); sb.Draw("SeqAutoRunSMW_New.pdf"); return sb; } private SequenceActionResult Sequence_Enter(SequenceContext context, string id, SequenceActionResult param) { Log.I("SeqAutoRunSMW_New Start"); Status.SetWorkingPosition(eWorkingPosition.CHECKING_CONDITION); _InitParam = param.Param as SeqAutoRunSMW_New_InitParam; _RecipeManager = Application.Current.AuroraEnv().RecipeManager; _SystemParameter = context.GetSetting(CommonSettingIds.SystemParameter); InitDev(context); if (!CheckDeviceReady(context)) { //Check Device AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_AutoRun_DeviceNotReady); Log.E("The devices are not active."); return null; } if (InitSequenceVariable(context) == false) { AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_AutoRun_InitVariableError); return null; } return SequenceAction.Ok(); } private bool InitSequenceVariable(SequenceContext context) { _AutoRunStartTime = DateTime.Now; _SeqRunCount = 0; _TodayProduct = _SystemParameter.TodayProductCount; _TotalProduct = _SystemParameter.TotalProductCount; _SelectedDrawObjectList = _ScannerCanvasUserCtrl.Model.Layers[0].Objects; if (_SystemParameter.SequenceType == eSequenceType.Normal) { _IsRealTimeScout = false; } else if (_SystemParameter.SequenceType == eSequenceType.RCC) { double dPixelResolution = ((_SystemParameter.CameraPixelSize) / _SystemParameter.LensMagnification) / 1000.0; //ConvEdgeObjectViewModel에서도 생성되지만.. Seq에서 재생성하고 쓰고 버리자 _ObjGenerator = new ObjectGenerator(dPixelResolution); if (_SystemParameter.OffsetType == eOffsetType.manual) _ObjGenerator.SetOffsetType("Manual"); else { _ObjGenerator.SetOffsetType("CSV"); _ObjGenerator.SetOffsetTable(_SystemParameter.OffsetCSVFile, _SystemParameter.LensMagnification, _SystemParameter.CameraPixelSize); } _ObjGenerator.SetInterlockProperties(_SystemParameter.DrawObjectDistanceRange, _SystemParameter.DrawObjectArcLengthMax, _SystemParameter.DrawObjectLengthSumDiffRange, _SystemParameter.DrawObjectCenterXYDiffRange, _SystemParameter.MaxMinDiffHigh, _SystemParameter.MaxMinDiffLow, _SystemParameter.CheckCenterDiff, _SystemParameter.DistortionCenterDiff, _SystemParameter.AutoMissAlignHigh, _SystemParameter.AutoMissAlignLow); if (!_ObjGenerator.GetArcInfoFromRecipe(_RecipeDrawObjects, out _SelectedArcs)) { Log.E(string.Format("Recipe Infomation Register Error")); return false; } _IsRealTimeScout = true; } else if (_SystemParameter.SequenceType == eSequenceType.CellCenterOffset) { // VisionDevice 추가 // InitializeCameraDevice _FovRecipe = VisionRecipeManager.GetFovRecipe(_InitParam.ScoutSeqParams.FovInfo); _CameraAgent = CameraAgentManager.GetCameraAgent(_InitParam.ScoutSeqParams.FovInfo); _CameraDisplay = CameraDisplayManager.GetDisplay(_InitParam.ScoutSeqParams.FovInfo, _InitParam.ScoutSeqParams.DisplayType); // InitGrabImageBuffer 함수 try { IpAdapter.Instance.IpEnvironment.FreeImage(_GrabImage); _GrabImage = (MIL_ID)_CameraAgent.CloneImageBuffer(); } catch (Exception e) { Log.E(e.Message); } _IsRealTimeScout = false; } else { Log.E("Invalid SequenceType."); return false; } var mainPage = WeldingRecipeManager.GetWeldingPage(); _ScannerCanvasUserCtrl = mainPage.ScannerCanvasCtrlTeaching; _RecipeDrawObjects = _ScannerCanvasUserCtrl.Model.Layers[0].Objects; _WeldingScannerListNo = eListNo.LIST1; _CellMeasureCenterOffsetX = 0.0; _CellMeasureCenterOffsetY = 0.0; var currentModelName = context.Recipes.ActivatedModelName(); var modelItem = context.GetModel(currentModelName, CommonModelIds.EquipmentSpecificModel); _ModelNo = modelItem.Model_No; return true; } private void InitDev(SequenceContext context) { //Device Init _Scanner = context.GetLaserScanner(); _Laser = context.GetLaser(); _OCT = context.GetOCT(); _PLC = context.GetPLC(); _IO = context.GetIOUnit(); _LBAD = context.GetLBAD(); } private bool CheckDeviceReady(SequenceContext context) { List deviceListToCheck = new List() { CommonDeviceIds.Scanner, CommonDeviceIds.Laser, CommonDeviceIds.OCT, CommonDeviceIds.PLCDevice, CommonDeviceIds.IODevice, CommonDeviceIds.LBAD }; bool isAllDeviceActivated = true; foreach (string item in deviceListToCheck) { if (!context.Devices[item].IsActivated) { isAllDeviceActivated = isAllDeviceActivated && false; } } return isAllDeviceActivated; } private bool CheckCondition(SequenceContext context) { if (CheckCondition_Interlock()) { if (InitializeDeviceStatus(context)) { return true; } } return false; } private bool CheckCondition_Interlock() { // PLC, Data, IO 등 Interlock checking return true; } private bool InitializeDeviceStatus(SequenceContext context) { // PLC Interface AutoStatus Start InitAutoRunBit(); // Laser Initialize _Laser.PilotLaserOff(); _Laser.LaserOn(); Thread.Sleep(100); if (!_Laser.GetLaserReady()) { Log.E("ERROR Initialize Laser"); return false; } // Scanner Initialize // Scanner 없음. // OCT Initialize // TODO: EnterSequenceModeOCT 와 함께 Initialize 하는 것을 재구현 필요함. 초반에 한번만 check 하고 돌아 갈수 있도록 _OCT_QA_ERROR_COUNT = 0; _OCT.OCT_QA_Error = false; int octStatus = _OCT.GetStatus(); if ((octStatus == 1 || octStatus == 2) == false) { int ret = _OCT.GetRemoteControl(); if (ret == -1) { Log.E("ERROR Initialize OCT"); return false; } else if (ret == 0) { ret = _OCT.EnterRemoteMode(20000); Log.I("OCT Enter Remote Mode"); } } else { Log.I("OCT Already Remote Mode"); } // PLC Initialize if (_PLC.ReadBit((int)eBitInput.PLC_AUTO_STATUS).data == false) { Log.E(string.Format("ERROR Initialize PLC, Bit Off PLC_AUTO_STATUS")); return false; } // LBAD Initialize // LBAD 는 server 이기 때문에, 만약 끊어졌으면 다시 접속이 필요함 if (!_LBAD.GetConnected()) { _LBAD.DisConnect(); Thread.Sleep(500); int ret = _LBAD.Open(_LBAD.Config); if (ret == -1) { Log.E($"LBAD Open Error : {ret}"); return false; } } _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADReadyStatus), true); Log.I(string.Format($"[IOInterface]SET PCLBADReadyStatus true")); Stopwatch sw = Stopwatch.StartNew(); while (!context.Stopped) { if (_IO._iOUnit.ReadDiBit(Convert.ToInt32(eADIAddress.LBADReadyStatus))) { // TODO: AlarmMonitor 들어 오면서 추가된 부분으로, Sequence 가 돌고 있을 때, Device 상태 체크를 하는 Alarm 을 안띄우도록 하는 로직 임. // TODO: 수정 필요함. _LBAD.SetReadybyAuto(true); Log.I(string.Format($"[IOInterface]SET DI_LBADReadyStatus True")); break; } // LBAD 가 Ready 되지 않으면 지속적으로 log 발생하는 요구 사항. 종료조건은 없음 // false 가 없음. if (sw.ElapsedMilliseconds > PLC_TIMEOUT * 1000) { Log.E("TIMEOUT_DI_LBAD_READY_STATUS"); sw.Restart(); } Thread.Sleep(10); } if (_SystemParameter.SequenceType == eSequenceType.Normal) { _Scanner.SelectCorrectionTable(2); Log.I(string.Format("Normal, Select Laser Correction File")); } else if (_SystemParameter.SequenceType == eSequenceType.RCC) { _Scanner.SelectCorrectionTable(1); Log.I(string.Format("RCC, Select Vision Correction File")); } else if (_SystemParameter.SequenceType == eSequenceType.CellCenterOffset) { _Scanner.SelectCorrectionTable(1); Log.I(string.Format("CellCenterOffset, Select Vision Correction File")); } else { Log.I(string.Format("Invalid SequenceType.")); } return true; } private void InitAutoRunBit() { Log.I(string.Format($"[PLCInterface] Start AutoRun PLC Bit Initialize")); _PLC.WriteBit((int)eBitOutput.PC_WELD_REQEUST_ACK, false); Log.I(string.Format($"[PLCInterface]SET PC_WELD_REQEUST_ACK False")); _PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE, false); Log.I(string.Format($"[PLCInterface]SET PC_WELD_COMPLETE False")); _PLC.WriteBit((int)eBitOutput.PC_WELD_READY, false); Log.I(string.Format($"[PLCInterface]SET PC_WELD_READY False")); _PLC.WriteBit((int)eBitOutput.PC_AUTO_STATUS, true); Log.I(string.Format($"[PLCInterface]SET PC_AUTO_STATUS True")); _PLC.WriteBit((int)eBitOutput.PC_LBAD_RESULT_NG, false); Log.I(string.Format($"[PLCInterface]SET PC_LBAD_RESULT_NG False")); _PLC.WriteBit((int)eBitOutput.PC_LDD_RESULT_NG, false); Log.I(string.Format($"[PLCInterface]SET PC_LDD_RESULT_NG False")); _PLC.WriteBit((int)eBitOutput.PC_LDD_DATA_RECEIVE_TIME_OUT, false); Log.I(string.Format($"[PLCInterface]SET PC_LDD_DATA_RECEIVE_TIME_OUT False")); _PLC.WriteBit((int)eBitOutput.PC_LBAD_RESULT_OK, false); Log.I(string.Format($"[PLCInterface]SET PC_LBAD_RESULT_OK False")); _PLC.WriteBit((int)eBitOutput.PC_LDD_RESULT_OK, false); Log.I(string.Format($"[PLCInterface]SET PC_LDD_RESULT_OK False")); _PLC.WriteBit((int)eBitOutput.PC_RECIPE_PARAM_UPLOAD_COMPLETE, false); Log.I(string.Format($"[PLCInterface]SET PC_RECIPE_PARAM_UPLOAD_COMPLETE false")); Log.I(string.Format($"[PLCInterface] Complete AutoRun PLC Bit Initialize")); Log.I(string.Format($"[IOInterface] Start AutoRun IO Bit Initialize")); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADReadyStatus), false); Log.I(string.Format($"[IOInterface]SET PCLBADReadyStatus False")); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingTrigger), false); Log.I(string.Format($"[IOInterface]SET PCLBADWeldingTrigger False")); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingStop), false); Log.I(string.Format($"[IOInterface]SET PCLBADWeldingStop False")); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADJudgementCompleteAck), false); Log.I(string.Format($"[IOInterface]SET PCLBADJudgementCompleteAck False")); Log.I(string.Format($"[IOInterface] Complete AutoRun IO Bit Initialize")); } private string CheckInitCondition(SequenceContext context, string id, ICollection branches, SequenceActionResult param) { if (!CheckCondition(context)) { AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_AutoRun_CheckInitCondition); Log.E("Condition is not in state to start sequence."); context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, false); return SEQ_COMPLETE; } var startTime = DateTime.Now; context.PutValue(ContextKey.KEY_SEQUENCE_START_TIME, startTime); Log.D("ReceiveCellInfo Sequence CheckInitCondition"); return SEQ_CHECK_LOAD_COMPLETE; } // 지그 상태 확인 private string CheckLoadComplete(SequenceContext context, string id, ICollection branches, SequenceActionResult param) { Status.SetWorkingPosition(eWorkingPosition.LOADING_CELL); TimeSpan spanTime; DateTime startTime = DateTime.Now; if (!StartInterfaceOCT(context)) { Log.E(string.Format($"AutoRun Sequence Stopped because of OCT SequenceMode Fail")); return null; } if (_SystemParameter.SequenceType == eSequenceType.Normal) { // CorrectionTable ==> 2 return SEQ_READY_SCANNER_LIST; } else { // RCC, CellCenterOffset // RCC의 경우 LoadCompleteCheck 전 Scout 첫번째 위치로 스캐너 이동 해놓는게 시간을 벌듯.. // CellCenterOffset은 중심위치에서 그랩하니깐 해당 기능 필요없을 것이라 우선 여기서 if문 처리하자 // 즉 정리하면, RCC 만 이동하고, CellCenterOffset은 이동 하지 않음. if (_SystemParameter.SequenceType == eSequenceType.RCC) { int scoutNo = 0; if (_CamConfig.ChildImage.ChildBufRowCols[scoutNo].Enabled) { double XPos = _CamConfig.ChildImage.ChildBufRowCols[scoutNo].MotorPos.X + _CamConfig.ChildImage.ChildBufRowCols[scoutNo].MotorPosOffset.X; //카메라 위치에 대한 보정값 입력 double YPos = _CamConfig.ChildImage.ChildBufRowCols[scoutNo].MotorPos.Y + _CamConfig.ChildImage.ChildBufRowCols[scoutNo].MotorPosOffset.Y; //카메라 위치에 대한 보정값 입력 Log.I(string.Format($"Move No.{scoutNo + 1} Field Scan Pos(X,Y:{XPos},{YPos})")); //1.스캐너 필드 위치 이동(Jump) _Scanner.JumpAbs(XPos, YPos, eFunctionType.COMMAND); } } // Cell 이 Load 완료되어서 Scout 가 가능한 상태인지 확인 _InterfaceStartTime = DateTime.Now; while (!context.Stopped) { if (_PLC.ReadBit((int)eBitInput.PLC_JIG_LOAD_COMPLETE).data) { Log.I(string.Format("Cell Loading is completed.")); break; } _InterfaceSpanTime = DateTime.Now.Subtract(_InterfaceStartTime); if (_InterfaceSpanTime.TotalMilliseconds > (PLC_TIMEOUT * 1000)) { Log.E("TIMEOUT_PLC_JIG_LOAD_COMPLETE"); _InterfaceStartTime = DateTime.Now; } Thread.Sleep(10); } if (_SystemParameter.SequenceType == eSequenceType.RCC) { return SEQ_SET_SCOUT_FLYING_VISION_SEQ; } else { return SEQ_MEASURE_CELL_POSITION; } } } private SequenceActionResult SetReceiveCellInfo_SeqParams(SequenceContext context, string id, SequenceActionResult param) { SeqReceiveCellInfo_InitParam seqParams = new SeqReceiveCellInfo_InitParam() { }; return SequenceAction.Ok(seqParams); } private SequenceActionResult GetReceiveCellInfo_SeqResult(SequenceContext context, string id, SequenceActionResult param) { var resultOutParam = param.Param as SeqReceiveCellInfo_OutParam; if (resultOutParam.Success == false) { return null; } return SequenceAction.Ok(); } // For Only CellCenterOffset private SequenceActionResult MeasureCellPosition(SequenceContext context, string id, SequenceActionResult param) { // Lid Holl 측정하려면 Camera ROI 센터에 Lid가 보여야 함 // Manual로 센터값을 찾은 뒤 SystemParameter로 넣어주면 Scanner가 최초 시작 시 해당 위치로 이동함 double ScannerPosX = _SystemParameter.CellPosMeasureCenterOffsetX; double ScannerPosY = _SystemParameter.CellPosMeasureCenterOffsetY; Log.I(string.Format($"ScannerPosX : {ScannerPosX},ScannerPosY : {ScannerPosY} ")); if (Math.Abs(ScannerPosX) > 10.0 || Math.Abs(ScannerPosY) > 10.0) { _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); } else { _Scanner.JumpAbs(ScannerPosX, ScannerPosY, eFunctionType.COMMAND); } // Vision Grab Log.I(string.Format($"Start Grab Image")); _GrabImage = DoGrab(); // Vision 인식 //WPF Bitmapsource로 변환 int width = (int)MIL.MbufInquire(_GrabImage, MIL.M_SIZE_X, MIL.M_NULL); int height = (int)MIL.MbufInquire(_GrabImage, MIL.M_SIZE_Y, MIL.M_NULL); //int stride = width; // Assuming 8-bit grayscale image int stride = width * 3; // Assuming 24-bit BRG image byte[] imageData = new byte[width * height * 3]; MIL.MbufGetColor(_GrabImage, MIL.M_PACKED + MIL.M_BGR24, MIL.M_ALL_BANDS, imageData); //32-bit 3ch bgr BitmapSource bitmapSource = BitmapSource.Create( width, height, 96, 96, System.Windows.Media.PixelFormats.Bgr24, null, imageData, stride); //Convert bitmapsource to Mat Mat ConvImg; ConvImg = bitmapSource.ToMat(); OpenCvSharp.Point[][] minContour; //SystemParameter 추가 필요 double CVThreshold = _SystemParameter.CVThreshold; minContour = ImageUtil.FindMinContourForCenter(ConvImg, CVThreshold); OpenCvSharp.Rect minRect = Cv2.BoundingRect(minContour[0]); double centerX = minRect.X + (minRect.Width / 2); double centerY = minRect.Y + (minRect.Height / 2); double mCenterX = (((centerX - ConvImg.Width / 2) * _SystemParameter.CameraPixelSize) / _SystemParameter.LensMagnification) / 1000.0; double mCenterY = (((ConvImg.Height / 2 - centerY) * _SystemParameter.CameraPixelSize) / _SystemParameter.LensMagnification) / 1000.0; mCenterX += ScannerPosX; mCenterY += ScannerPosY; // Logging ImageUtil.SaveCenterImage(ConvImg); string savepath = Path.Combine(ConfigurationManager.AppSettings.Get("DATA_PATH"), "_vision", "EdgeContour", "Auto", string.Format($"CenterDetect_{DateTime.Now.Year}_{DateTime.Now.Month}_{DateTime.Now.Day}.csv")); List centerPositionDataList = new List(); var centerPosition = new CenterPositionData(); centerPosition.CenterX = mCenterX; centerPosition.CenterY = mCenterY; centerPositionDataList.Add(centerPosition); bool result = CSV_Manager.GetInstance().Save_ListToCsv(savepath, centerPositionDataList, true); //SaveCenterToCsv(mCenterX, mCenterY _CellMeasureCenterOffsetX = mCenterX; _CellMeasureCenterOffsetY = mCenterY; return SequenceAction.Ok(); } public MIL_ID DoGrab() { var image = (object)_GrabImage; _CameraAgent.GrabSync(_CameraDisplay, ref image); _GrabImage = (MIL_ID)image; return _GrabImage; } // For Only RCC private SequenceActionResult SetScoutFlyingVision_SeqParams(SequenceContext context, string id, SequenceActionResult param) { Log.I($"AutoRun Seq Run Count : {_SeqRunCount}"); var scoutSeqParams = new ScoutSeqParams(VisionRecipeManager.GetFovInfos()[0], eDisplayType.Machine_B); SeqScoutFlyingVision_InitParam seqParams = new SeqScoutFlyingVision_InitParam() { IsRealTimeScout = _IsRealTimeScout, ScoutSeqParams = scoutSeqParams, SequenceAutoRunCount = _SeqRunCount, WeldingScannerListNo = eListNo.LIST2, }; return SequenceAction.Ok(seqParams); } private SequenceActionResult GetScoutFlyingVision_SeqResult(SequenceContext context, string id, SequenceActionResult param) { var resultOutParam = param.Param as SeqScoutFlyingVision_OutParam; if (resultOutParam.Success == false) { return null; } return SequenceAction.Ok(); } // For RCC Only private SequenceActionResult SaveScoutImageEvent(SequenceContext context, string id, SequenceActionResult param) { MIL_ID ScannerFieldImage = Status.GetProcessingWeldingData().ScannerFiledImage; if (ScannerFieldImage != null) { SaveScoutImage(ScannerFieldImage); } else { Log.E("ScannerFieldImage is Null"); } return SequenceAction.Ok(); } private object SendEvent(SequenceContext context, string id, SequenceActionResult param) { //Event로 넘겨줄 Param은 따로 없다. return null; } private SequenceActionResult FindEdge(SequenceContext context, string id, SequenceActionResult param) { MIL_ID ScannerFieldImage = Status.GetProcessingWeldingData().ScannerFiledImage; //RCC Error로 인해 시퀀스를 종료하고 있는데, NG배출해야 될지 확인 필요 _StopwatchGenObj = Stopwatch.StartNew(); #region Find Edge _ObjGenerator.ConvertMILToMat(ScannerFieldImage, out _ConvMatImage); if (_ConvMatImage == null) { Log.E(string.Format("[GenerateWeldingObject] Scout Image is empty. Check Camera or Cell.")); return null; } var (centerX, centerY) = FindCenterReicpeSingleArc(_ConvMatImage); if (_ObjGenerator.FindEdge(_ConvMatImage, _Radius_Pixel, _SystemParameter.Margin, _SystemParameter.PointNum, _SystemParameter.CVThreshold, centerX, centerY, _SystemParameter.DetectPointPercent, _SystemParameter.CVJigSize, out Point[][] maxContour, out _DetectedContourCenter) == false) { Log.E(string.Format("[GenerateWeldingObject] Edge Detection Interlock.")); return null; } if (maxContour[0].Count() < 1 || maxContour == null) { Log.E(string.Format("[GenerateWeldingObject] MaxContour is Null. Check Scout Image.")); return null; } context.PutValue("MAX_CONTOUR_FIND_EDGE", maxContour); _StopwatchGenObj.Stop(); Log.I(string.Format($"[GenerateWeldingObject] Find Edge Complete Time : {_StopwatchGenObj.ElapsedMilliseconds} msec")); #endregion return SequenceAction.Ok(); } private (int centerX, int centerY) FindCenterReicpeSingleArc(Mat image) { int centerX = 0, centerY = 0; foreach (var item in _RecipeDrawObjects) { if (item is Arc) { Arc arc = (Arc)item; centerX = (int)(arc.Center.X * 1000.0 / _SystemParameter.CameraPixelSize * _SystemParameter.LensMagnification + image.Width / 2); centerY = (int)(-arc.Center.Y * 1000.0 / _SystemParameter.CameraPixelSize * _SystemParameter.LensMagnification + image.Height / 2); break; } } return (centerX, centerY); } private string DecisionRCCAlgorithmType(SequenceContext context, string id, ICollection branches, SequenceActionResult param) { // FindEdge의 maxContour를 param으로 받아오기 Point[][] maxContour = context.GetValue("MAX_CONTOUR_FIND_EDGE"); // CheckEdge의 Return 결과를 param 으로 받아와서 현재 노드에서 4가지 경우로 분류하자 var (centerX, centerY) = FindCenterReicpeSingleArc(_ConvMatImage); int[] shrinkList = new int[] { _SystemParameter.CVShrinkPixel, _SystemParameter.CVShrinkPixel2, _SystemParameter.CVShrinkPixel3, _SystemParameter.CVShrinkPixel4 }; int resultCheckEdge = _ObjGenerator.CheckEdge(maxContour, shrinkList, _ConvMatImage.Height, _ConvMatImage.Width, centerX, centerY, _SystemParameter.EnableAutoMissAlign, out _MaxContour); if (resultCheckEdge == 3) { Log.E("Error Check Edge. Check EdgeDetect Center or Over LocalMaxMinDiff Upper"); return null; } if (_SystemParameter.RCCAlgorithmType == eRCCAlgorithmType.OnlyGenObject) { return SEQ_GENERATE_WELDING_OBJECT; } else if (_SystemParameter.RCCAlgorithmType == eRCCAlgorithmType.OnlyOffsetObject) { return SEQ_APPLY_OFFSET_OBJECT; } else { if (resultCheckEdge == 0) { return SEQ_READY_SCANNER_LIST; } else if (resultCheckEdge == 1) { return SEQ_APPLY_OFFSET_OBJECT; } else if (resultCheckEdge == 2) { return SEQ_GENERATE_WELDING_OBJECT; } else { Log.E("Error Check Edge. Check EdgeDetect Center or Over LocalMaxMinDiff Upper"); return null; } } } private SequenceActionResult ApplyOffsetObejct(SequenceContext context, string id, SequenceActionResult param) { // Recipe Arc Center점을 기준(DOE)으로 새로 찾은 Center만 더해서 용접해야 함 _CellMeasureCenterOffsetX = _DetectedContourCenter.X; _CellMeasureCenterOffsetY = _DetectedContourCenter.Y; Log.I(string.Format($"Object CenterOffsetX : {_DetectedContourCenter.X.ToString("F3")}, CenterOffsetY : {_DetectedContourCenter.Y.ToString("F3")}")); return SequenceAction.Ok(); } private SequenceActionResult GenerateWeldingObject(SequenceContext context, string id, SequenceActionResult param) { #region Generate Object _StopwatchGenObj.Restart(); // Reicpe Arc의 Center만큼 객체 생성후 옮겨서 용접해야 함. 즉, Recipe Arc Center가 DOE가 되어있어야 함 var (centerX, centerY) = FindCenterReicpeSingleArc(_ConvMatImage); _CellMeasureCenterOffsetX = centerX; _CellMeasureCenterOffsetY = centerY; _ObjGenerator.SetPolygonFromList(_MaxContour, out _Polygon); if (_SystemParameter.ObjectGenType == eObjectGenType.FitArcsAndLines) { _ObjGenerator.CalculateAutoPath(_ConvMatImage, _SelectedArcs[0], _Polygon, _SystemParameter.dMergeDist, _SystemParameter.nMaxArcRadius, _SystemParameter.nLineTolerance, _SystemParameter.nArcTolerance, _DetectedContourCenter, out _Paths); } else { _ObjGenerator.CalculateAutoPathAngle(_ConvMatImage, _SelectedArcs[0], _Polygon, _SystemParameter.dMergeDist, _SystemParameter.ObjectNumber, _DetectedContourCenter, out _Paths); } //Generate 한 object 를 SelectedDrawObjects 에 넣어두고 쓴다. _ObjGenerator.ConvertPathItemToDrawingObjects(_Paths, _SystemParameter.fLineDefualtWidth, _ConvMatImage, _SelectedArcs[0], out _GeneratedDrawObjects); //objGenerator.SaveDrawingObjectsToCSV(GeneratedDrawObjects, "SeqAutoRunSMW_RCC_before"); if (_ObjGenerator.CheckInterlockDrawingObjectPosition(_GeneratedDrawObjects, _DetectedContourCenter, _SelectedArcs[0]) == false) { Log.E(string.Format("[GenerateWeldingObject]Interlock DrawingObject.")); return null; } List tempobject = new List(); int startindex = 0; int nCount = _RecipeDrawObjects.Count; for (int i = startindex; i < _RecipeDrawObjects.Count; i++) { if (i >= startindex + nCount) break; tempobject.Add(_RecipeDrawObjects[i]); } _SelectedDrawObjectList = tempobject; //현재 Recipe의 Arc객체를 RCC로 생성된 객체로 대체하면서 Group화 해준다 _ObjGenerator.ReplaceRCCObject(eArcCount.FirstArc, _SelectedDrawObjectList, _GeneratedDrawObjects, _DetectedContourCenter); _ObjGenerator.SaveDrawingObjectsToCSV(_GeneratedDrawObjects, "SeqAutoRunSMW_RCC"); _StopwatchGenObj.Stop(); Log.I(string.Format($"[GenerateWeldingObject] Generate Object Complete Time : {_StopwatchGenObj.ElapsedMilliseconds} msec")); #endregion return SequenceAction.Ok(); } private SequenceActionResult ReadyScannerList(SequenceContext context, string id, SequenceActionResult param) { Status.SetWorkingPosition(eWorkingPosition.UPLOADING_WELD_LIST); return SequenceAction.Ok(); } private SequenceActionResult SetUploadWeldingList_SeqParams(SequenceContext context, string id, SequenceActionResult param) { SeqUploadWeldingList_InitParam seqParams = new SeqUploadWeldingList_InitParam() { NeedSetLaserTiming = false, IncludeListStartEnd = true, CellMeasureCenterOffsetX = _CellMeasureCenterOffsetX, CellMeasureCenterOffsetY = _CellMeasureCenterOffsetY, SelectedDrawObjectList = _SelectedDrawObjectList, WeldingScannerListNo = _WeldingScannerListNo, }; return SequenceAction.Ok(seqParams); } private SequenceActionResult GetUploadWeldingList_SeqResult(SequenceContext context, string id, SequenceActionResult param) { var resultOutParam = param.Param as SeqUploadWeldingList_OutParam; if (resultOutParam.Success == false) { AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_UploadWeldingList_ResultFailed); return null; } return SequenceAction.Ok(); } private SequenceActionResult WaitWeldingStart(SequenceContext context, string id, SequenceActionResult param) { //if (!StartInterfaceOCT(context)) { // Log.E(string.Format($"AutoRun Sequence Stopped because of OCT SequenceMode Fail")); // return null; //} _PLC.WriteBit((int)eBitOutput.PC_WELD_READY, true); Log.I(string.Format($"[PLCInterface]SET PC_WELD_READY True")); _InterfaceStartTime = DateTime.Now; while (!context.Stopped) { if (_PLC.ReadBit((int)eBitInput.PLC_WELD_REQEUST).data) { Log.I(string.Format($"[PLCInterface]GET PLC_WELD_REQEUST True")); _PLC.WriteBit((int)eBitOutput.PC_WELD_REQEUST_ACK, true); Log.I(string.Format($"[PLCInterface]SET PC_WELD_REQEUST_ACK True")); break; } _InterfaceSpanTime = DateTime.Now.Subtract(_InterfaceStartTime); if (_InterfaceSpanTime.TotalMilliseconds > (PLC_TIMEOUT * 1000)) { Log.E("TIMEOUT_PLC_WELD_REQEUST"); _InterfaceStartTime = DateTime.Now; } Thread.Sleep(10); } return SequenceAction.Ok(); } private bool StartInterfaceOCT(SequenceContext context) { _InterfaceStartTime = DateTime.Now; if (!EnterSequenceModeOCT()) { while (!context.Stopped) { if (EnterSequenceModeOCT()) break; _InterfaceSpanTime = DateTime.Now.Subtract(_InterfaceStartTime); if (_InterfaceSpanTime.TotalMilliseconds > (PLC_TIMEOUT * 1000)) { Log.E("Fail to Enter OCT SequenceMode"); _InterfaceStartTime = DateTime.Now; return false; } Thread.Sleep(10); } } //Trigger 상태 체크 추가 필요 _InterfaceStartTime = DateTime.Now; while (!context.Stopped) { if (_OCT.GetStatus() == 2) { Log.I("OCT Status Completed in Waiting For Trigger"); break; } _InterfaceSpanTime = DateTime.Now.Subtract(_InterfaceStartTime); if (_InterfaceSpanTime.TotalMilliseconds > (PLC_TIMEOUT * 1000)) { Log.E("Time Out Waiting for Trigger of OCT Status"); return false; } Thread.Sleep(10); } return true; } private SequenceActionResult ExecuteWelding(SequenceContext context, string id, SequenceActionResult param) { Status.SetWorkingPosition(eWorkingPosition.EXECUTING_WELD); // Laser Correction 파일로 변경, 레이저를 사용해야 하므로 2 _Scanner.SelectCorrectionTable(2); _CellId = Status.GetProcessingWeldingData().WorkCellId; _LotId = Status.GetProcessingWeldingData().WorkLotId; int recipeNo = _RecipeManager.ActivatedRecipe().Id; _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingTrigger), true); int sendresult = _LBAD.SendCellData(_LotId, _CellId, recipeNo, _ModelNo); Log.I(string.Format($"SendCellData result :{sendresult}")); _OCT.AddWorkPieceID(_CellId); _PLC.WriteBit((int)eBitOutput.PC_WELD_REQEUST_ACK, false); Log.I(string.Format($"[PLCInterface]SET PC_WELD_REQEUST_ACK False")); _PLC.WriteBit((int)eBitOutput.PC_WELD_READY, false); Log.I(string.Format($"[PLCInterface]SET PC_WELD_READY False")); _WeldingStartTime = DateTime.Now; Status.GetProcessingWeldingData().WeldStartTime = _WeldingStartTime.ToString("yyyyMMddHHmmss"); _Scanner.ExecuteList(_WeldingScannerListNo); Log.I(string.Format($"START Welding : ExecuteList_{_WeldingScannerListNo}")); //WaitForListTaskCompleted 함수에서 List 완료 여부를 Check함, List실행이 끝나면 while문을 빠져나옴 _Scanner.WaitForListTaskCompleted(_SystemParameter.WeldLinesTaskTimeOut, context); _WeldEndTime = DateTime.Now; _WeldingSpanTime = DateTime.Now.Subtract(_WeldingStartTime); Log.I(string.Format($"Welding Complete Time : {_WeldingSpanTime.TotalMilliseconds} msec")); Status.GetProcessingWeldingData().WeldTime = _WeldingSpanTime.TotalSeconds.ToString(); double dExecuteListTime = _Scanner.GetTime(); Log.I(string.Format($"ExecuteList Time : {dExecuteListTime * 1000} msec")); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingTrigger), false); Log.I(string.Format($"[IOInterface]SET PCWeldingTrigger false")); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingStop), true); Log.I(string.Format($"[IOInterface]SET PCWeldingStop true")); return SequenceAction.Ok(); } private SequenceActionResult RequestUnloadCell(SequenceContext context, string id, SequenceActionResult param) { Status.SetWorkingPosition(eWorkingPosition.UNLOADING_CELL); // PC → PLC , Unload Cell Request _PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE, true); Log.I(string.Format($"[PLCInterface]SET PC_WELD_COMPLETE True")); _InterfaceStartTime = DateTime.Now; while (!context.Stopped) { if (_PLC.ReadBit((int)eBitInput.PLC_WELD_COMPLETE_ACK).data) { Log.I(string.Format($"[PLCInterface]GET PLC_WELD_COMPLETE_ACK True")); _PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE, false); Log.I(string.Format($"[PLCInterface]SET PC_WELD_COMPLETE False")); break; } _InterfaceSpanTime = DateTime.Now.Subtract(_InterfaceStartTime); if (_InterfaceSpanTime.TotalMilliseconds > (PLC_TIMEOUT * 1000)) { Log.E("TIMEOUT_PLC_WELD_COMPLETE_ACK"); _InterfaceStartTime = DateTime.Now; } Thread.Sleep(10); } UpdateProductCount(context); UpdateProductInfoForView(); _PLC.WriteBit((int)eBitOutput.PC_LBAD_RESULT_NG, false); Log.I(string.Format($"[PLCInterface]SET PC_LBAD_RESULT_NG False")); _PLC.WriteBit((int)eBitOutput.PC_LDD_RESULT_NG, false); Log.I(string.Format($"[PLCInterface]SET PC_LDD_RESULT_NG False")); _PLC.WriteBit((int)eBitOutput.PC_LDD_DATA_RECEIVE_TIME_OUT, false); Log.I(string.Format($"[PLCInterface]SET PC_LDD_DATA_RECEIVE_TIME_OUT False")); _PLC.WriteBit((int)eBitOutput.PC_LBAD_RESULT_OK, false); Log.I(string.Format($"[PLCInterface]SET PC_LBAD_RESULT_OK False")); _PLC.WriteBit((int)eBitOutput.PC_LDD_RESULT_OK, false); Log.I(string.Format($"[PLCInterface]SET PC_LDD_RESULT_OK False")); return SequenceAction.Ok(); } private SequenceActionResult WaitLBADJudge(SequenceContext context, string id, SequenceActionResult param) { Int16 judgeFlag = 0; string judgeResult = ""; // 1. LBAD 결과 수신, 확인 & 처리 //LBAD 결과 받아오는 부분 우선 여기서 추가하여 테스트하고 Sub 시퀀스로 빼자 if (_LBAD.IsSimul) { _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingStop), false); Log.I(string.Format($"[IOInterface]SET PCLBADWeldingStop false, LBAD is Simul")); } else { _InterfaceStartTime = DateTime.Now; while (!context.Stopped) { if (_IO._iOUnit.ReadDiBit(Convert.ToInt32(eADIAddress.LBADJudgementComplete))) { Log.I(string.Format($"[IOInterface]SET LBADJudgementComplete true")); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingStop), false); Log.I(string.Format($"[IOInterface]SET PCWeldingStop false")); int result = _LBAD.GetResult(out judgeFlag); if (result == E1.OK) { switch (judgeFlag) { case 0: judgeResult = "OK"; break; case 1: judgeResult = "WARNING"; break; case 2: judgeResult = "NA"; break; case 3: judgeResult = "NG"; break; case 4: judgeResult = "ERROR"; break; default: judgeResult = "NG"; break; } } else { // TODO: LBAD 가 not Activated 인 상황이다. error 로 보내야 할꺼 같음. judgeFlag = 3; judgeResult = "NG"; } Log.I(string.Format($"LBAD Judge Flag : {judgeFlag} Result : {judgeResult}")); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADJudgementCompleteAck), true); Status.GetProcessingWeldingData().LBAD_Judge = (judgeFlag + 1).ToString(); Log.I(string.Format($"[IOInterface]SET PCJudgementCompleteAck true")); break; } _InterfaceSpanTime = DateTime.Now.Subtract(_InterfaceStartTime); if (_InterfaceSpanTime.TotalMilliseconds > (PLC_TIMEOUT * 1000)) { Log.E("TIMEOUT_DI_LBADJudgementComplete_TRUE"); _InterfaceStartTime = DateTime.Now; } Thread.Sleep(10); } // 2. LBAD 처리를 IO 에서 확인 _InterfaceStartTime = DateTime.Now; while (!context.Stopped) { if (!_IO._iOUnit.ReadDiBit(Convert.ToInt32(eADIAddress.LBADJudgementComplete))) { Log.I(string.Format($"[IOInterface]GET LBADJudgementComplete false")); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADJudgementCompleteAck), false); Log.I(string.Format($"[IOInterface]SET PCJudgementCompleteAck false")); break; } _InterfaceSpanTime = DateTime.Now.Subtract(_InterfaceStartTime); if (_InterfaceSpanTime.TotalMilliseconds > (PLC_TIMEOUT * 1000)) { Log.E("TIMEOUT_DI_LBADJudgementComplete_FALSE"); _InterfaceStartTime = DateTime.Now; } Thread.Sleep(10); } } return SequenceAction.Ok(); } private SequenceActionResult SetReportCellResult_SeqParams(SequenceContext context, string id, SequenceActionResult param) { Status.SetWorkingPosition(eWorkingPosition.REPORTING_RESULT); SeqReportCellResult_InitParam seqParams = new SeqReportCellResult_InitParam() { EDC_Interface = new EDC(), }; return SequenceAction.Ok(seqParams); } private SequenceActionResult GetReportCellResult_SeqResult(SequenceContext context, string id, SequenceActionResult param) { var resultOutParam = param.Param as SeqReportCellResult_OutParam; if (resultOutParam.Success == false) { return null; } return SequenceAction.Ok(); } private SequenceActionResult ReportCellInfoToPLC(SequenceContext context, string id, SequenceActionResult param) { string strLBADJudge = Status.GetProcessingWeldingData().LBAD_Judge; string strLDDJudge = Status.GetProcessingWeldingData().LDD_Judge; if (strLDDJudge == "1") { _OCT_QA_ERROR_COUNT = 0; _OCT.OCT_QA_Error = false; _PLC.WriteBit((int)eBitOutput.PC_LDD_RESULT_OK, true); Log.I(string.Format($"[PLCInterface]SET PC_LDD_RESULT_NG True, LDD Result : {strLDDJudge}")); } else { if (strLDDJudge == "4" || strLDDJudge == "") { _OCT_QA_ERROR_COUNT++; Log.I(string.Format($"OCT QA Data Error Count : {_OCT_QA_ERROR_COUNT}")); _PLC.WriteBit((int)eBitOutput.PC_LDD_DATA_RECEIVE_TIME_OUT, true); Log.I(string.Format($"[PLCInterface]SET PC_LDD_DATA_RECEIVE_TIME_OUT True, LDD Result : {strLDDJudge}")); } else { _OCT_QA_ERROR_COUNT = 0; _OCT.OCT_QA_Error = false; _PLC.WriteBit((int)eBitOutput.PC_LDD_RESULT_NG, true); Log.I(string.Format($"[PLCInterface]SET PC_LDD_RESULT_NG True, LDD Result : {strLDDJudge}")); } if (_SystemParameter.OCT_QA_Error_Count <= _OCT_QA_ERROR_COUNT) { _OCT.OCT_QA_Error = true; _OCT_QA_ERROR_COUNT = 0; } } if (strLBADJudge == "4") { _PLC.WriteBit((int)eBitOutput.PC_LBAD_RESULT_NG, true); Log.I(string.Format($"[PLCInterface]SET PC_LBAD_RESULT_NG True, LBAD Result : {strLBADJudge}")); } else if (strLBADJudge != "4") { _PLC.WriteBit((int)eBitOutput.PC_LBAD_RESULT_OK, true); Log.I(string.Format($"[PLCInterface]SET PC_LBAD_RESULT_OK True, LBAD Result : {strLBADJudge}")); } return SequenceAction.Ok(); } private static string CheckCycleStop(SequenceContext context, string id, ICollection branches, SequenceActionResult param) { Status.SetWorkingPosition(eWorkingPosition.CHECKING_CYCLE); // TODO: 확인 필요, CybleStop 에 대한 내용, cycle stop 여부 가져오기 //bCycleStop = GetCycleStopRequest(); // TODO: 한번만 돌도록 설정함, PLC 로 받으면 좋음. //Jin : cycleStop 명령을 용접 프로그램에서 할 경우가 현재는 없음.. // CheckCycleStop 노드와 Complete 노드 사이 다른 노드가 필요하다면 해당 노드를 CheckCycleStop 노드 위로 올리자 bool cycleStop = false; if (cycleStop) { return SEQ_SAVE_RESULT_DATA; } else { return SEQ_CHECK_LOAD_COMPLETE; } } private void UpdateProductCount(SequenceContext context) { string currentDate = DateTime.Now.ToString("yyyy-MM-dd"); if (_SystemParameter.CurrentDate != currentDate) { _TodayProduct = 0; _SystemParameter.CurrentDate = currentDate; } else { _TodayProduct = _SystemParameter.TodayProductCount; } if (_TodayProduct < uint.MaxValue) { _TodayProduct++; } if (_TotalProduct < uint.MaxValue) { _TotalProduct++; } _SystemParameter.TodayProductCount = _TodayProduct; _SystemParameter.TotalProductCount = _TotalProduct; //Systemparameter Save context.Settings.Save(CommonSettingIds.SystemParameter, _SystemParameter, "SeqAutoRunSMW_New"); } private void UpdateProductInfoForView() { Status.GetProcessingWeldingData().TotalProduct = _TotalProduct; Status.GetProcessingWeldingData().TodayProduct = _TodayProduct; Status.GetProcessingWeldingData().AutoRunStartTime = _AutoRunStartTime; Status.GetProcessingWeldingData().WeldingStartTime = _WeldingStartTime; Status.GetProcessingWeldingData().WeldingEndTime = _WeldEndTime; Status.GetProcessingWeldingData().WeldingSpanTimeMilliseconds = _WeldingSpanTime.TotalMilliseconds.ToString(); Status.GetProcessingWeldingData().LotId = _LotId; Status.GetProcessingWeldingData().CellId = _CellId; } // TODO: EnterSequenceModeOCT 와 함께 Initialize 하는 것을 재구현 필요함. 초반에 한번만 check 하고 돌아 갈수 있도록 private bool EnterSequenceModeOCT() { //initOCT 부분에서 EnterRemoteMode 명령 후 실제 Remote seq Mode 진입시까지 약 10~20초 가량 소모됨 // GetStatus 의 return이 2일경우 이미 Trigger 상태이므로 추가 명령은 필요 없음 // GetStatus 의 return이 1일경우 Remote mode로 전환만 된 상태이므로 Trigger 명령을 해줘야 함 // 둘다 아닌 경우 remote 모드가 아닌것으로 간주, GetRemoteControl() 명령으로 확인 if (_OCT == null) { return false; } if (_OCT.IsSimul) { return true; } int nStatus = _OCT.GetStatus(); //nStatus = 1 Ready for Command , nStatus = 2 Waiting For Tirgger if (nStatus != 2) { int nRet = _OCT.GetRemoteControl(); // nRet = 0 OFF ,nRet = 1 Remote job , nRet = 2 remote sequence if (nRet == -1 || nRet == 0) { //Log.E("ERROR OCT"); return false; } else { _OCT.SetProgram(1); Log.I("OCT Trigger On"); Thread.Sleep(500); } } return true; } // TODO: ImageUtil 에 있는 함수를 사용하도록 수정 필요 private void SaveScoutImage(MIL_ID imageID) { // 테스트를 위해서 저장한다. 테스트 끝나고 삭제할것 Log.I(string.Format($"Start to store completed field scan image")); string fieldScanImageFile = ""; //4.스캐너 필드 이미지 파일 저장 fieldScanImageFile = System.IO.Path.Combine(ConfigurationManager.AppSettings.Get("DATA_PATH"), "_vision", "RealTimeScout", string.Format($"{DateTime.Now.Year}_{DateTime.Now.Month}_{DateTime.Now.Day}/{DateTime.Now.ToString("HHmmss")}.PNG")); //5.압축하여 저장 //CompressSaveImage(imageID, fieldScanImageFile, MIL.M_JPEG_LOSSY, 10); SaveImage(imageID, fieldScanImageFile, MIL.M_PNG); } private bool SaveImage(MIL_ID image, string filePath, MIL_INT format) { string directoryName = Path.GetDirectoryName(filePath); if (Directory.Exists(directoryName) == false) { Directory.CreateDirectory(directoryName); } MIL.MbufExport(filePath, format, image); return true; } private SequenceActionResult SaveResultData(SequenceContext context, string id, SequenceActionResult param) { context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, true); return SequenceAction.Ok(); } private SequenceActionResult WriteCompletionPLCBit(SequenceContext context, string id, SequenceActionResult param) { // 완료 비트 write 하는 Node 추가 필요. format 유지, ReceiveCellInfo 없음 Log.D("AutoRun Sequence WriteCompletionPLCBit"); return SequenceAction.Ok(); } private SequenceActionResult Complete(SequenceContext context, string id, SequenceActionResult param) { RestoreDeviceStatus(); Log.I("AutoRun Complete"); context.TryGetValue(ContextKey.KEY_SEQUENCE_RESULT, out bool seqResult); SeqAutoRunSMW_New_OutParam result = new SeqAutoRunSMW_New_OutParam() { Success = seqResult }; if (seqResult == false) { AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_AutoRun_ResultFailed); } Log.D("AutoRun Sequence Complete"); Status.SetWorkingPosition(eWorkingPosition.DONE); return SequenceAction.Ok(result); } private bool RestoreDeviceStatus() { //PLC All BIT OFF _PLC.WriteBit((int)eBitOutput.PC_WELD_REQEUST_ACK, false); _PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE, false); _PLC.WriteBit((int)eBitOutput.PC_WELD_READY, false); _PLC.WriteBit((int)eBitOutput.PC_AUTO_STATUS, false); _PLC.WriteBit((int)eBitOutput.PC_RECIPE_PARAM_UPLOAD_COMPLETE, false); Log.I(string.Format("[PLCInterface]PC All Bit Off")); //LBAD IO All BIT OFF _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingTrigger), false); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADReadyStatus), false); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingStop), false); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADJudgementCompleteAck), false); Log.I(string.Format("[IOInterface]PC All Bit Off")); _LBAD.SetReadybyAuto(false); //Laser Off _Laser.LaserOff(); //List 실행 종료 _Scanner.StopExecution(); //Anlog 출력 0으로 변경, efunctiontype을 command로 변경해주면 list가 아니라 직접 변경됨 _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.COMMAND); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.COMMAND); //Scanner 원점 복귀 _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); //Vision Correctiong 파일 변경 _Scanner.SelectCorrectionTable(1); //Recipe를 기존에 Manual에서 작업하던 화면으로 rollback WeldingRecipeManager.RollbackRecipe(); return true; } private void OnForceError(SequenceContext arg1, string arg2) { OnSeqActionStop(); Log.I("SequenceAction Ok : OnForceError"); } private void OnStopped(SequenceContext obj) { OnSeqActionStop(); Log.I("SequenceAction Ok : OnStopped"); } private void OnSeqActionStop() { //PLC All BIT OFF _PLC.WriteBit((int)eBitOutput.PC_WELD_REQEUST_ACK, false); _PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE, false); _PLC.WriteBit((int)eBitOutput.PC_WELD_READY, false); _PLC.WriteBit((int)eBitOutput.PC_AUTO_STATUS, false); _PLC.WriteBit((int)eBitOutput.PC_RECIPE_PARAM_UPLOAD_COMPLETE, false); Log.I(string.Format("[PLCInterface]PC All Bit Off")); //LBAD IO All BIT OFF _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingTrigger), false); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADReadyStatus), false); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADWeldingStop), false); _IO._iOUnit.WriteDoBit(Convert.ToInt32(eADOAddress.PCLBADJudgementCompleteAck), false); Log.I(string.Format("[IOInterface]PC All Bit Off")); _LBAD.SetReadybyAuto(false); //Laser Off _Laser.LaserOff(); //List 실행 종료 _Scanner.StopExecution(); //Anlog 출력 0으로 변경, efunctiontype을 command로 변경해주면 list가 아니라 직접 변경됨 _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.COMMAND); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.COMMAND); //Scanner 원점 복귀 _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); //Vision Correctiong 파일 변경 _Scanner.SelectCorrectionTable(1); //Recipe를 기존에 Manual에서 작업하던 화면으로 rollback WeldingRecipeManager.RollbackRecipe(); } } // For CSV 저장용 public class CenterPositionData : NotifyPropertyChangedBase { private double _CenterX; public double CenterX { get => _CenterX; set => SetProperty(ref _CenterX, value); } private double _CenterY; public double CenterY { get => _CenterY; set => SetProperty(ref _CenterY, value); } } public class SeqAutoRunSMW_New_InitParam : InitParam { public ScoutSeqParams ScoutSeqParams { get; set; } } public class SeqAutoRunSMW_New_OutParam : OutParam { } }