using Aurora.Api; using AuroraIO; using AuroraLaserScanner; using AuroraLBAD.Services; using AuroraOCT; using CoreUnit.Control.UserControl.Canvas; using CoreUnit.Scanner.UserControl.ScannerCanvas; using Hermes; using LiveChartsCore.Measure; using Matrox.MatroxImagingLibrary; using OpenCvSharp; using System; using System.Collections.Generic; using System.Configuration; using System.Diagnostics; using System.IO; using System.Linq; using System.Numerics; using System.Text; using System.Threading; using System.Threading.Tasks; using VisionCommon; using WeldingCommon.Alarm; using WeldingCommon.Data; using WeldingCommon.Recipes; using WeldingCommon.Settings; using WeldingCommon.Utils; using WeldingCommon.Vision.WeldingObjectGenerator; using WeldingCommon.Vision.WeldingObjectGenerator.GeometryLibrary; using WeldingCommon.Vision.WeldingObjectGenerator.PathEditorLibrary; namespace WeldingCommon.Sequences { class SeqManualRunRCC { static readonly Logger Log = new Logger("SeqManualRunRCC"); const string SEQ_ENTER = "[SeqManualRunRCC] SEQ_ENTER"; // inputParam 으로 받자. const string SEQ_CHECK_INIT_CONDITION = "[SeqManualRunRCC] Check Init Condition"; // Check Init Condition const string SEQ_SET_PARAMS_SCOUT_FLYING_VISION = "[SeqManualRunRCC] Set Sequence Param (ScoutFlyingVision Seq)"; const string SEQ_DO_ID_SCOUT_FLYING_VISION = "[SeqManualRunRCC] Process (ScoutFlyingVision Seq)"; const string SEQ_GET_RESULT_SCOUT_FLYING_VISION = "[SeqManualRunRCC] Get Sequence Result (ScoutFlyingVision Seq)"; const string SEQ_SEND_EVENT_SENDER = "[SeqManualRunRCC] Event Sender"; const string SEQ_EVENT_Q_SAVE_FILE = "[SeqManualRunRCC] Event Q Save File"; const string SEQ_SAVE_SCOUT_IMAGE = "[SeqManualRunRCC] Save Scout Image"; const string SEQ_DECISION_MACHINE_TYPE = "[SeqManualRunRCC] Decision Machine Type"; const string SEQ_DECISION_CELL_TYPE = "[SeqManualRunRCC] Decision Cell Type"; const string SEQ_MULTICELL_SPLIT_SCOUT_IMAGE = "[SeqManualRunRCC] Multi Cell Split Scout Image"; const string SEQ_FORK_PROCESS_MULTI_CELL = "[SeqManualRunRCC] Fork Process Multi Cell"; const string SEQ_JOIN_PROCESS_MULTI_CELL = "[SeqManualRunRCC] Join Process Multi Cell"; const string SEQ_MULTICELL_1_GENERATE_WELDING_OBJECT = "[SeqManualRunRCC] MultiCell 1 Generate Welding Object"; const string SEQ_MULTICELL_2_GENERATE_WELDING_OBJECT = "[SeqManualRunRCC] MultiCell 2 Generate Welding Object"; const string SEQ_MULTICELL_COMBINE_WELDING_OBJECT = "[SeqManualRunRCC] MultiCell Combine Welding Object"; const string SEQ_FIND_EDGE = "[SeqManualRunRCC] Finde Edge"; const string SEQ_DECISION_RCC_ALGORITHM_TYPE = "[SeqManualRunRCC] Decision RCC Algorithm Type"; const string SEQ_GENERATE_WELDING_OBJECT = "[SeqManualRunRCC] Generate Welding Object"; const string SEQ_APPLY_OFFSET_OBJECT = "[SeqManualRunRCC] Apply Offset Object"; const string SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ = "[SeqManualRunRCC] Set Sequence Param (UploadWeldingList Seq)"; const string SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ = "[SeqManualRunRCC] Process (UploadWeldingList Seq)"; const string SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ = "[SeqManualRunRCC] Get Sequence Result (UploadWeldingList Seq)"; const string SEQ_EXECUTE_WELDLINES = "[SeqManualRunRCC] Execute WeldLines"; const string SEQ_DECISION_CHECK_CYCLE_STOP = "[SeqManualRunRCC] Decision Check Cycle Stop"; const string SEQ_SAVE_RESULT_DATA = "[SeqManualRunRCC] Save Result Data"; const string SEQ_WRITE_COMPLETION_PLC_BIT = "[SeqManualRunRCC] Write Completion PLC Bit"; const string SEQ_COMPLETE = "[SeqManualRunRCC] SEQ_COMPLETE"; // 완료 const string EVENT_TRIGGER_SAVE_FILE = "EventTriggerSaveFile"; static class ContextKey { public const string KEY_SEQUENCE_RESULT = "KEY_SEQUENCE_RESULT_SeqManualRunRCC"; public const string KEY_SEQUENCE_START_TIME = "KEY_SEQUENCE_START_TIME_SeqManualRunRCC"; } private static SeqManualRunRCC_InitParam _InitParam; private Scanner _Scanner; private StreamLBADClient _StreamLBADClient; private SystemParameter _SystemParameter; private FieldScanParams _FieldScanParams; private ObjectGenerator _ObjectGenerator; private ScannerCanvasUserCtrl _ScannerCanvasUserCtrl; //스캐너 동작관련 객체 선언 private List _RecipeDrawObject; private List _GeneratedDrawObject; private List _GeneratedDrawObject2; private List _SelectedDrawObject; private Mat _ConvMatImage; private eListNo _WeldingScannerListNo; private eListNo _ScoutScannerListNo; private List _ScoutNoList = new List(); private int _ScoutNo; private List _SelectedObjectList; private FovRecipe _FovRecipe; private CameraAgentBase _CameraAgent; private ICameraDisplay _CameraDisplay; private CamConfig _CamConfig; private MIL_ID _FlyingImage = MIL.M_NULL; private Mat _ConvertImageMat; private Point[][] _MaxContour; private Point[][] _MaxContour2; private Stopwatch _StopWatchTotal; private Stopwatch _StopWatchScout; private Stopwatch _StopWatchPath; private Stopwatch _StopWatchWeld; private int _ScoutRowCount; private int _ScoutColumnCount; private int seqRepeatNum; private double _CVThreshold; private int _CVShrinkPixel; private int _CVShrinkPixel2; private int _CVShrinkPixel3; private int _CVShrinkPixel4; private double _Radius; private int _RadiusPixel; private int _Margin; private int _PointNum; private double _DetectPointPercent; private int _MaxMinDiffHigh; private int _MaxMinDiffLow; private int _CheckCenterDiff; private int _DistortionCenterDiff; private float _AutoMissAlignHigh; private float _AutoMissAlignLow; private int _CVMorpMaskSize; private int _CVJigSize; private double _DrawObjectDistanceRange; private double _DrawObjectArcLengthMax; private double _DrawObjectLengthSumDiffRange; private double _DrawObjectCenterXYDiffRange; private List _SelectedArcs; private Mat _CroppedImage1; private Mat _CroppedImage2; private int _CenterX, _CenterY, _CenterX2, _CenterY2; private int _CropWidth, _CropHeight, _CropWidthHalf, _CropHeightHalf; private UnitPoint _DetectedContourCenter; private UnitPoint _DetectedContourCenter2; private int[] _ShrinkList; private double _CellMeasureCenterOffsetX; private double _CellMeasureCenterOffsetY; 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.AddAction(SEQ_SET_PARAMS_SCOUT_FLYING_VISION, SetScoutFlyingVision_SeqParams); sb.AddSubsequence(SEQ_DO_ID_SCOUT_FLYING_VISION, SequenceManager.GetSeqBuilder_SeqScoutFlyingVision()); sb.AddAction(SEQ_GET_RESULT_SCOUT_FLYING_VISION, GetScoutFlyingVision_SeqResult); sb.AddEventSender(SEQ_SEND_EVENT_SENDER, SendEvent); sb.AddEventQ(SEQ_EVENT_Q_SAVE_FILE, 3); sb.AddAction(SEQ_SAVE_SCOUT_IMAGE, SaveScoutImageEvent); sb.AddDecision(SEQ_DECISION_MACHINE_TYPE, DecisionMachineType); sb.AddDecision(SEQ_DECISION_CELL_TYPE, DecisionCellType); sb.AddAction(SEQ_MULTICELL_SPLIT_SCOUT_IMAGE, SplitScoutImage); sb.AddFork(SEQ_FORK_PROCESS_MULTI_CELL); sb.AddAction(SEQ_MULTICELL_1_GENERATE_WELDING_OBJECT, MultiCell1GenWeldingObject); sb.AddAction(SEQ_MULTICELL_2_GENERATE_WELDING_OBJECT, MultiCell2GenWeldingObject); sb.AddJoin(SEQ_JOIN_PROCESS_MULTI_CELL); sb.AddAction(SEQ_MULTICELL_COMBINE_WELDING_OBJECT, CombineWeldingObject); sb.AddAction(SEQ_FIND_EDGE, FindEdge); sb.AddDecision(SEQ_DECISION_RCC_ALGORITHM_TYPE, DecisionRCCAlgorithmType); sb.AddAction(SEQ_GENERATE_WELDING_OBJECT, GenerateWeldingObject); sb.AddAction(SEQ_APPLY_OFFSET_OBJECT, ApplyOffsetObject); 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_EXECUTE_WELDLINES, ExecuteWeldLines); sb.AddDecision(SEQ_DECISION_CHECK_CYCLE_STOP, DecisionCheckCycleStop); 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_SET_PARAMS_SCOUT_FLYING_VISION] > sb[SEQ_DO_ID_SCOUT_FLYING_VISION] > sb[SEQ_GET_RESULT_SCOUT_FLYING_VISION] > sb[SEQ_SEND_EVENT_SENDER].Send(EVENT_TRIGGER_SAVE_FILE) > sb[SEQ_DECISION_MACHINE_TYPE] > sb[SEQ_APPLY_OFFSET_OBJECT] > 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_EXECUTE_WELDLINES] > sb[SEQ_DECISION_CHECK_CYCLE_STOP] > sb[SEQ_SAVE_RESULT_DATA] > sb[SEQ_WRITE_COMPLETION_PLC_BIT] > sb[SEQ_COMPLETE]); sb.Flows(sb[SEQ_DECISION_MACHINE_TYPE] > sb[SEQ_DECISION_CELL_TYPE] > sb[SEQ_FIND_EDGE] > sb[SEQ_DECISION_RCC_ALGORITHM_TYPE] > sb[SEQ_GENERATE_WELDING_OBJECT] > sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ]) .Flows(sb[SEQ_DECISION_RCC_ALGORITHM_TYPE] > sb[SEQ_APPLY_OFFSET_OBJECT]); sb.Flows(sb[SEQ_DECISION_MACHINE_TYPE] > sb[SEQ_FIND_EDGE] > sb[SEQ_DECISION_CHECK_CYCLE_STOP]); sb.Flows(sb[SEQ_DECISION_CELL_TYPE] > sb[SEQ_MULTICELL_SPLIT_SCOUT_IMAGE] > sb[SEQ_FORK_PROCESS_MULTI_CELL] > sb[SEQ_MULTICELL_1_GENERATE_WELDING_OBJECT] > sb[SEQ_JOIN_PROCESS_MULTI_CELL] > sb[SEQ_MULTICELL_COMBINE_WELDING_OBJECT] > sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ]) .Flows(sb[SEQ_FORK_PROCESS_MULTI_CELL] > sb[SEQ_MULTICELL_2_GENERATE_WELDING_OBJECT] > sb[SEQ_JOIN_PROCESS_MULTI_CELL]); sb.Flows(sb[SEQ_DECISION_CHECK_CYCLE_STOP] > sb[SEQ_CHECK_INIT_CONDITION]); sb.Flows(sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_COMPLETE] > sb.Final); sb.Flows(sb[SEQ_EVENT_Q_SAVE_FILE].On(EVENT_TRIGGER_SAVE_FILE) > sb[SEQ_SAVE_SCOUT_IMAGE] > sb.FlowFinal); sb.OnStopped(OnStopped); sb.OnForceError(OnForceError); sb.Draw("SeqManualRunRCC.pdf"); return sb; } private SequenceActionResult Sequence_Enter(SequenceContext context, string id, SequenceActionResult param) { Log.I("SeqManualRunRCC Start"); _InitParam = param.Param as SeqManualRunRCC_InitParam; _SystemParameter = context.GetSetting(CommonSettingIds.SystemParameter); InitDev(context); if (!CheckDeviceReady(context)) { //Check Device AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_ManualRunRCC_DeviceNotReady); Log.E("The devices are not active."); return null; } if (InitSequenceVariable(context) == false) { AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_ManualRunRCC_InitVariableError); return null; } return SequenceAction.Ok(); } private bool InitSequenceVariable(SequenceContext context) { _StopWatchTotal = new Stopwatch(); _StopWatchScout = new Stopwatch(); _StopWatchPath = new Stopwatch(); _StopWatchWeld = new Stopwatch(); // VisionDevice 추가 // InitializeCameraDevice _FovRecipe = VisionRecipeManager.GetFovRecipe(_InitParam.ScoutSeqParams.FovInfo); _CameraAgent = CameraAgentManager.GetCameraAgent(_InitParam.ScoutSeqParams.FovInfo); _CameraDisplay = CameraDisplayManager.GetDisplay(_InitParam.ScoutSeqParams.FovInfo, _InitParam.ScoutSeqParams.DisplayType); _CamConfig = VisionEnv.AuroraEnv.DeviceManager.GetDeviceConfig(eCamId.CAM1.ToString()) as CamConfig; _FieldScanParams = FieldScanParams.GetInstance(); //FiledScanParams 클래스에서 변수 받아오도록 수정 var imageWidthChild = _FieldScanParams.GetimageSizeWidthChild(); var imageHeightChild = _FieldScanParams.GetimageSizeHeightChild(); _ScoutRowCount = _FieldScanParams.GetrowCount(); _ScoutColumnCount = _FieldScanParams.GetcolCount(); // IsRepeatEdgeDetectMode용 seqRepeatNum = 0; // 호출한 view 에서 parameter 를 받아온다. system 에서 받아오면 manual view 에서 parameter 수정한것을 반영하기 어렵다. // TODO: 향후에는 InitParam 에 넣어서 가져 오도록 하자. _CVThreshold = _SystemParameter.CVThreshold; _CVShrinkPixel = _SystemParameter.CVShrinkPixel; _CVShrinkPixel2 = _SystemParameter.CVShrinkPixel2; _CVShrinkPixel3 = _SystemParameter.CVShrinkPixel3; _CVShrinkPixel4 = _SystemParameter.CVShrinkPixel4; _CVMorpMaskSize = _SystemParameter.CVMorpMaskSize; _DrawObjectDistanceRange = _SystemParameter.DrawObjectDistanceRange; _DrawObjectArcLengthMax = _SystemParameter.DrawObjectArcLengthMax; _DrawObjectLengthSumDiffRange = _SystemParameter.DrawObjectLengthSumDiffRange; _DrawObjectCenterXYDiffRange = _SystemParameter.DrawObjectCenterXYDiffRange; _Radius = _SystemParameter.Radius; _RadiusPixel = (int)(((_Radius * _SystemParameter.LensMagnification) / _SystemParameter.CameraPixelSize) * 1000.0); _ShrinkList = new int[] { _CVShrinkPixel, _CVShrinkPixel2, _CVShrinkPixel3, _CVShrinkPixel4 }; _Margin = _SystemParameter.Margin; _PointNum = _SystemParameter.PointNum; _DetectPointPercent = _SystemParameter.DetectPointPercent; _CVJigSize = _SystemParameter.CVJigSize; _MaxMinDiffHigh = _SystemParameter.MaxMinDiffHigh; _MaxMinDiffLow = _SystemParameter.MaxMinDiffLow; _CheckCenterDiff = _SystemParameter.CheckCenterDiff; _DistortionCenterDiff = _SystemParameter.DistortionCenterDiff; _AutoMissAlignHigh = _SystemParameter.AutoMissAlignHigh; _AutoMissAlignLow = _SystemParameter.AutoMissAlignLow; //////////////////////////////////// // RCC CenterOffset _CellMeasureCenterOffsetX = 0; _CellMeasureCenterOffsetX = 0; double pixelResolution = ((_SystemParameter.CameraPixelSize) / _SystemParameter.LensMagnification) / 1000.0; _ObjectGenerator = new ObjectGenerator(pixelResolution); if (_SystemParameter.OffsetType == eOffsetType.manual) _ObjectGenerator.SetOffsetType("Manual"); else { _ObjectGenerator.SetOffsetType("CSV"); _ObjectGenerator.SetOffsetTable(_SystemParameter.OffsetCSVFile, _SystemParameter.LensMagnification, _SystemParameter.CameraPixelSize); } var mainPage = WeldingRecipeManager.GetWeldingPage(); _ScannerCanvasUserCtrl = mainPage.ScannerCanvasCtrlTeaching; _RecipeDrawObject = _ScannerCanvasUserCtrl.Model.Layers[0].Objects; if (_InitParam.SelectedOption == "SMW") { _ObjectGenerator.SetInterlockProperties(_DrawObjectDistanceRange, _DrawObjectArcLengthMax, _DrawObjectLengthSumDiffRange, _DrawObjectCenterXYDiffRange, _MaxMinDiffHigh, _MaxMinDiffLow, _CheckCenterDiff, _DistortionCenterDiff, _AutoMissAlignHigh, _AutoMissAlignLow); // TODO : MultiCell을 사용할 경우 아래 함수도 변경해줘야 함 if (!_ObjectGenerator.GetArcInfoFromRecipe(_RecipeDrawObject, out _SelectedArcs)) { Log.E(string.Format("Chekck recipe Arc RCCMode True.")); return false; } } //UploadWeldingList에서 List1을 사용. Flying Vision Scout는 List2를 사용하도록 하자 _WeldingScannerListNo = eListNo.LIST1; _ScoutScannerListNo = eListNo.LIST2; _ScoutNo = 0; return true; } private void InitDev(SequenceContext context) { //Device Init _Scanner = context.GetLaserScanner(); if (_InitParam.UseStream) { _StreamLBADClient = context.GetLBADClient(); } } private bool CheckDeviceReady(SequenceContext context) { List deviceListToCheck = new List() { CommonDeviceIds.Scanner }; if (_InitParam.UseStream) { deviceListToCheck.Add(CommonServiceIds.StreamLBADClient); } bool isAllDeviceActivated = true; foreach (string item in deviceListToCheck) { if (!context.Devices[item].IsActivated) { isAllDeviceActivated = isAllDeviceActivated && false; } } return isAllDeviceActivated; } private bool CheckCondition() { if (CheckCondition_Interlock()) { if (InitializeDeviceStatus()) { return true; } } return false; } private bool CheckCondition_Interlock() { // PLC, Data, IO 등 Interlock checking return true; } private bool InitializeDeviceStatus() { if (_InitParam.UseStream) { if (InitializeStream() == false) { Log.E("Fail Initialize Stream"); return false; } } //Vision Correction File 선택 //_Scanner.SelectCorrectionTable(1); _Scanner.SelectCorrectionTable(1); return true; } private string CheckInitCondition(SequenceContext context, string id, ICollection branches, SequenceActionResult param) { if (!CheckCondition()) { AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_TeachingRun_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("ManualRunRCC Sequence CheckInitCondition"); return SEQ_SET_PARAMS_SCOUT_FLYING_VISION; } private bool InitializeStream() { var ret = _StreamLBADClient.Activate(); if (ret != E1.OK) { return false; } return true; } private SequenceActionResult SetScoutFlyingVision_SeqParams(SequenceContext context, string id, SequenceActionResult param) { var scoutSeqParams = new ScoutSeqParams(VisionRecipeManager.GetFovInfos()[0], eDisplayType.Machine_B); SeqScoutFlyingVision_InitParam seqParams = new SeqScoutFlyingVision_InitParam() { IsRealTimeScout = true, ScoutSeqParams = scoutSeqParams, //SequenceAutoRunCount = _SeqRunCount, WeldingScannerListNo = eListNo.LIST2, }; return SequenceAction.Ok(seqParams); } private SequenceActionResult GetScoutFlyingVision_SeqResult(SequenceContext context, string id, SequenceActionResult param) { _FlyingImage = Status.GetProcessingWeldingData().ScannerFiledImage; return SequenceAction.Ok(); } private SequenceActionResult SaveScoutImageEvent(SequenceContext context, string id, SequenceActionResult param) { if (_FlyingImage != null) { SaveImageFile(_FlyingImage); Log.I("Complete Svae Image File"); } else { Log.E("ScannerFieldImage is Null"); } return SequenceAction.Ok(); } private object SendEvent(SequenceContext context, string id, SequenceActionResult param) { return null; } private string DecisionMachineType(SequenceContext context, string id, ICollection branches, SequenceActionResult param) { // Edge 반복 측정 모드 if (_InitParam.IsRepeatEdgeDetectMode) { return SEQ_FIND_EDGE; } // SMW 외 Inzi, LFW는 RCC Apply offset으로 사용 함 if (_InitParam.SelectedOption == "SMW") { return SEQ_DECISION_CELL_TYPE; } else { return SEQ_APPLY_OFFSET_OBJECT; } } private string DecisionCellType(SequenceContext context, string id, ICollection branches, SequenceActionResult param) { if (_InitParam.CellType == "Single") { return SEQ_FIND_EDGE; } else { return SEQ_MULTICELL_SPLIT_SCOUT_IMAGE; } } private SequenceActionResult SplitScoutImage(SequenceContext context, string id, SequenceActionResult param) { Stopwatch sw = Stopwatch.StartNew(); // MultiCell 기준 T/T 50~60msec 소요됨 _ObjectGenerator.ConvertMILToMat(_FlyingImage, out _ConvMatImage); sw.Stop(); Log.D(string.Format($"[SeqManualRunRCC] ConvertMILtoMat Complete Time : {sw.ElapsedMilliseconds}msec")); sw.Restart(); (_CenterX, _CenterY, _CenterX2, _CenterY2) = FindCenterRecipeMultiArc(); _CropWidth = 3200; _CropHeight = 3200; _CropWidthHalf = _CropWidth / 2; _CropHeightHalf = _CropHeight / 2; _CroppedImage1 = CropImage(_ConvMatImage, _CenterX, _CenterY, _CropWidth, _CropHeight); _CroppedImage2 = CropImage(_ConvMatImage, _CenterX2, _CenterY2, _CropWidth, _CropHeight); sw.Stop(); Log.D(string.Format($"[SeqManualRunRCC] Split ScoutImage Complete Time : {sw.ElapsedMilliseconds}msec")); return SequenceAction.Ok(); } private (int centerX, int centerY, int centerX2, int centerY2) FindCenterRecipeMultiArc() { int centerX = 0, centerY = 0, centerX2 = 0, centerY2 = 0; //Recipe에 그려진 Arc의 Center를 가져오기 위해 좌측과 우측의 Arc 순서가 고정되어있어야함 //item에서 LeftArc, RigthArc가 각 첫번째, 두번째로 고정되어 있어야 함 int arcCount = 0; foreach (var item in _RecipeDrawObject) { if (item is Arc) { Arc arc = (Arc)item; if (arcCount == 0) { centerX = (int)(arc.Center.X * 1000.0 / _SystemParameter.CameraPixelSize * _SystemParameter.LensMagnification + _ConvMatImage.Width / 2); centerY = (int)(-arc.Center.Y * 1000.0 / _SystemParameter.CameraPixelSize * _SystemParameter.LensMagnification + _ConvMatImage.Height / 2); } else if (arcCount == 1) { centerX2 = (int)(arc.Center.X * 1000.0 / _SystemParameter.CameraPixelSize * _SystemParameter.LensMagnification + _ConvMatImage.Width / 2); centerY2 = (int)(-arc.Center.Y * 1000.0 / _SystemParameter.CameraPixelSize * _SystemParameter.LensMagnification + _ConvMatImage.Height / 2); break; } arcCount++; } } return (centerX, centerY, centerX2, centerY2); } private Mat CropImage(Mat sourceImage, int centerX, int centerY, int width, int height) { // 잘라낼 영역의 시작 좌표 계산 int startX = centerX - width / 2; int startY = centerY - height / 2; // 잘라낼 영역의 끝 좌표 계산 int endX = startX + width; int endY = startY + height; // 이미지의 경계를 벗어나지 않도록 조정 startX = Math.Max(startX, 0); startY = Math.Max(startY, 0); endX = Math.Min(endX, sourceImage.Width); endY = Math.Min(endY, sourceImage.Height); // 잘라낼 영역의 크기 계산 int cropWidth = endX - startX; int cropHeight = endY - startY; // 잘라낸 이미지 생성 Rect cropRect = new Rect(startX, startY, cropWidth, cropHeight); Mat croppedImage = new Mat(sourceImage, cropRect); return croppedImage; } private SequenceActionResult MultiCell1GenWeldingObject(SequenceContext context, string id, SequenceActionResult param) { Stopwatch sw = Stopwatch.StartNew(); // EdgeDetect if (_ObjectGenerator.FindEdge(_CroppedImage1, _RadiusPixel, _Margin, _PointNum, _CVThreshold, _CropWidthHalf, _CropHeightHalf, _DetectPointPercent, _CVJigSize, out Point[][] maxContour, out _DetectedContourCenter) == false) { Log.E(string.Format("[MultiCell 1] Find Edge Interlock.")); return null; } if (maxContour[0].Count() < 1) { Log.E(string.Format("[MultiCell 1] MaxContour is Null. Check Scout Image.")); return null; } if (_SystemParameter.ImageType == eImageType.Full && _ObjectGenerator.CheckEdge(maxContour, _ShrinkList, _CropHeight, _CropWidth, _CenterX, _CenterY, _SystemParameter.EnableAutoMissAlign, out _MaxContour) == 3) { Log.E(string.Format("[MultiCell 1] Check Edge Interlock.")); return null; } // _DetectedContourCenter를 Pixel로 변경 _ObjectGenerator.ConvertPixelAxisFromDrawingObjectAxis(_DetectedContourCenter, _CroppedImage1.Width, _CroppedImage1.Height, out double detectedContourCenterPixelX, out double detectedContourCenterPixelY); // CropImage의 CenterPixel을 원본이미지 Pixel로 변경 detectedContourCenterPixelX += _CenterX - _CropWidthHalf; detectedContourCenterPixelY += _CenterY - _CropHeightHalf; // 원본이미지 Pixel을 다시 _DetectedContourCenter로 바꿔줌 _ObjectGenerator.ConvertDrawingObjectAxis((long)detectedContourCenterPixelX, (long)detectedContourCenterPixelY, _ConvMatImage.Width, _ConvMatImage.Height, out _DetectedContourCenter); _MaxContour = ConvertMaxContourPixel(_MaxContour, _CenterX, _CenterY, _CropWidthHalf, _CropHeightHalf); sw.Stop(); Log.I(string.Format($"[MultiCell 1] Find Edge Complete Time : {sw.ElapsedMilliseconds}msec")); sw.Restart(); // GenerateObject List paths; _ObjectGenerator.SetPolygonFromList(_MaxContour, out List polygon); if (_SystemParameter.ObjectGenType == eObjectGenType.ArcByAngle) { _ObjectGenerator.CalculateAutoPathAngle(_ConvMatImage, _SelectedArcs[0], polygon, _SystemParameter.dMergeDist, _SystemParameter.ObjectNumber, _DetectedContourCenter, out paths); } else { _ObjectGenerator.CalculateAutoPath(_ConvMatImage, _SelectedArcs[0], polygon, _SystemParameter.dMergeDist, _SystemParameter.nMaxArcRadius, _SystemParameter.nLineTolerance, _SystemParameter.nArcTolerance, _DetectedContourCenter, out paths); } _ObjectGenerator.ConvertPathItemToDrawingObjects(paths, _SystemParameter.fLineDefualtWidth, _ConvMatImage, _SelectedArcs[0], out _GeneratedDrawObject); //Temp //objGenerator.SaveDrawingObjectsToCSV(GeneratedDrawObjects, "SeqManualRunRCC_1"); if (_ObjectGenerator.CheckInterlockDrawingObjectPosition(_GeneratedDrawObject, _DetectedContourCenter, _SelectedArcs[0]) == false) { Log.E(string.Format("[MultiCell 1]Interlock DrawingObject.")); return null; } sw.Stop(); Log.I(string.Format($"[MultiCell 1] Generate Object Complete Time : {sw.ElapsedMilliseconds}msec")); return SequenceAction.Ok(); } private SequenceActionResult MultiCell2GenWeldingObject(SequenceContext context, string id, SequenceActionResult param) { Stopwatch sw = Stopwatch.StartNew(); // EdgeDetect if (_ObjectGenerator.FindEdge(_CroppedImage2, _RadiusPixel, _Margin, _PointNum, _CVThreshold, _CropWidthHalf, _CropHeightHalf, _DetectPointPercent, _CVJigSize, out Point[][] maxContour, out _DetectedContourCenter2) == false) { Log.E(string.Format("[MultiCell 2] Find Edge Interlock.")); return null; } if (maxContour[0].Count() < 1) { Log.E(string.Format("[MultiCell 2] MaxContour is Null. Check Scout Image.")); return null; } if (_SystemParameter.ImageType == eImageType.Full && _ObjectGenerator.CheckEdge(maxContour, _ShrinkList, _CropHeight, _CropWidth, _CenterX2, _CenterY2, _SystemParameter.EnableAutoMissAlign, out _MaxContour2) == 3) { Log.E(string.Format("[MultiCell 2] Check Edge Interlock.")); return null; } // _DetectedContourCenter를 Pixel로 변경 _ObjectGenerator.ConvertPixelAxisFromDrawingObjectAxis(_DetectedContourCenter2, _CroppedImage2.Width, _CroppedImage2.Height, out double detectedContourCenterPixelX, out double detectedContourCenterPixelY); // CropImage의 CenterPixel을 원본이미지 Pixel로 변경 detectedContourCenterPixelX += _CenterX2 - _CropWidthHalf; detectedContourCenterPixelY += _CenterY2 - _CropHeightHalf; // 원본이미지 Pixel을 다시 _DetectedContourCenter로 바꿔줌 _ObjectGenerator.ConvertDrawingObjectAxis((long)detectedContourCenterPixelX, (long)detectedContourCenterPixelY, _ConvMatImage.Width, _ConvMatImage.Height, out _DetectedContourCenter2); _MaxContour2 = ConvertMaxContourPixel(_MaxContour2, _CenterX2, _CenterY2, _CropWidthHalf, _CropHeightHalf); sw.Stop(); Log.I(string.Format($"[MultiCell 2] Find Edge Complete Time : {sw.ElapsedMilliseconds}msec")); sw.Restart(); // GenerateObject List paths; _ObjectGenerator.SetPolygonFromList(_MaxContour2, out List polygon); if (_SystemParameter.ObjectGenType == eObjectGenType.ArcByAngle) { _ObjectGenerator.CalculateAutoPathAngle(_ConvMatImage, _SelectedArcs[1], polygon, _SystemParameter.dMergeDist, _SystemParameter.ObjectNumber, _DetectedContourCenter2, out paths); } else { _ObjectGenerator.CalculateAutoPath(_ConvMatImage, _SelectedArcs[1], polygon, _SystemParameter.dMergeDist, _SystemParameter.nMaxArcRadius, _SystemParameter.nLineTolerance, _SystemParameter.nArcTolerance, _DetectedContourCenter2, out paths); } _ObjectGenerator.ConvertPathItemToDrawingObjects(paths, _SystemParameter.fLineDefualtWidth, _ConvMatImage, _SelectedArcs[1], out _GeneratedDrawObject2); //Temp //objGenerator.SaveDrawingObjectsToCSV(GeneratedDrawObjects2, "SeqManualRunRCC_2"); if (_ObjectGenerator.CheckInterlockDrawingObjectPosition(_GeneratedDrawObject2, _DetectedContourCenter2, _SelectedArcs[1]) == false) { Log.E(string.Format("[MultiCell 2]Interlock DrawingObject.")); return null; } sw.Stop(); Log.I(string.Format($"[MultiCell 2] Generate Object Complete Time : {sw.ElapsedMilliseconds}msec")); return SequenceAction.Ok(); } private static Point[][] ConvertMaxContourPixel(Point[][] maxContour, int centerX, int centerY, int cropWidthHalf, int cropHeightHalf) { if (maxContour[0].Count() < 1) { Log.E("MaxContour is Null"); return null; } for (int i = 0; i < maxContour[0].Length; i++) { maxContour[0][i].X += (centerX - cropWidthHalf); maxContour[0][i].Y += (centerY - cropHeightHalf); } return maxContour; } private SequenceActionResult CombineWeldingObject(SequenceContext context, string id, SequenceActionResult param) { List tempobject = new List(); int startindex = 0; int nCount = _RecipeDrawObject.Count; for (int i = startindex; i < _RecipeDrawObject.Count; i++) { if (i >= startindex + nCount) break; tempobject.Add(_RecipeDrawObject[i]); } _SelectedDrawObject = tempobject; //현재 Recipe의 Arc객체를 RCC로 생성된 객체로 대체하면서 Group화 해준다 _ObjectGenerator.ReplaceRCCObject(eArcCount.FirstArc, _SelectedDrawObject, _GeneratedDrawObject, _DetectedContourCenter); _ObjectGenerator.ReplaceRCCObject(eArcCount.SecondArc, _SelectedDrawObject, _GeneratedDrawObject2, _DetectedContourCenter2); //objGenerator.SaveDrawingObjectsToCSV(SelectedDrawObjects, "SeqManualRunRCC"); return SequenceAction.Ok(); } private SequenceActionResult FindEdge(SequenceContext context, string id, SequenceActionResult param) { _StopWatchPath.Start(); //ScannerFieldImage가 안들어올 경우 예외처리 필요 if (_FlyingImage == null) { Log.E(string.Format("Flying Scout Image is empty. Check camera or Cell.")); return null; } _ObjectGenerator.ConvertMILToMat(_FlyingImage, out _ConvMatImage); if (_ConvMatImage == null) { Log.E(string.Format("Converting Mat Image is empty. Check camera or Cell.")); return null; } var (centerX, centerY) = FindCenterReicpeSingleArc(_ConvMatImage); if (_ObjectGenerator.FindEdge(_ConvMatImage, _RadiusPixel, _Margin, _PointNum, _CVThreshold, centerX, centerY, _DetectPointPercent, _CVJigSize, out Point[][] maxContour, out _DetectedContourCenter) == false) { Log.E(string.Format("Find Edge Interlock.")); return null; } if (maxContour[0].Count() < 1 || maxContour == null) { Log.E(string.Format("MaxContour is Null. Check Scout Image.")); return null; } context.PutValue("MAX_CONTOUR_FIND_EDGE", maxContour); SaveContoursToCsv(maxContour); _StopWatchPath.Stop(); Log.D(string.Format($"[SeqManualRunRCC] Find Edge Time : {_StopWatchPath.ElapsedMilliseconds}msec")); return SequenceAction.Ok(); } private (int centerX, int centerY) FindCenterReicpeSingleArc(Mat image) { int centerX = 0, centerY = 0; foreach (var item in _RecipeDrawObject) { 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) { // CheckEdge 결과에 따라서 GenObject 또는 ApplyOffsetObject로 나눈다 _StopWatchPath.Restart(); Point[][] maxContour = context.GetValue("MAX_CONTOUR_FIND_EDGE"); var (centerX, centerY) = FindCenterReicpeSingleArc(_ConvMatImage); int resultCheckEdge = _ObjectGenerator.CheckEdge(maxContour, _ShrinkList, _ConvMatImage.Height, _ConvMatImage.Width, centerX, centerY, _SystemParameter.EnableAutoMissAlign, out _MaxContour); if (_SystemParameter.ImageType == eImageType.ThreeFourth) resultCheckEdge = 1; _StopWatchPath.Stop(); Log.D(string.Format($"[SeqManualRunRCC] Check Edge Time : {_StopWatchPath.ElapsedMilliseconds}msec")); if (resultCheckEdge == 3) { Log.E("Error Check Edge. Check EdgeDetect Center or Over LocalMaxMinDiff Upper"); return null; } // ManualRun RCC이기때문에 resultCheckEdge 0이면 시퀀스 종료한다 if (resultCheckEdge == 0) { return null; } 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 static void SaveContoursToCsv(Point[][] maxcotours) { string folderPath = Path.Combine(ConfigurationManager.AppSettings.Get("DATA_PATH"), "_vision", "EdgeContour", "Auto"); string filepath = Path.Combine(folderPath, string.Format($"EdgeContour_{DateTime.Now.Year}_{DateTime.Now.Month}_{DateTime.Now.Day}_{DateTime.Now:HHmmss}.csv")); try { if (!Directory.Exists(folderPath)) { Directory.CreateDirectory(folderPath); } using (StreamWriter writer = new StreamWriter(filepath)) { int index = 0; writer.WriteLine("Index,X_pixel,Y_pixel"); foreach (var contour in maxcotours) { foreach (var point in contour) { index++; writer.WriteLine($"{index},{point.X},{point.Y}"); } } } } catch (Exception e) { Log.E(e.Message); } } private SequenceActionResult ApplyOffsetObject(SequenceContext context, string id, SequenceActionResult param) { // 기존 코드는 Inzi, LFW용 // SMW도 해당 노드를 타므로 SWM에서 해당 노드를 타면 기존코드와 구분해주자 if (_InitParam.SelectedOption == "SMW") { _StopWatchPath.Restart(); Point2f contourCenter = _ObjectGenerator.CalculateCentroid(_MaxContour[0]); var dPixelResolution = (_SystemParameter.CameraPixelSize / _SystemParameter.LensMagnification) / 1000.0; //oint contourCenterPixel = new Point(contourCenter.X / dPixelResolution + _ConvMatImage.Width / 2, _ConvMatImage.Height / 2 - contourCenter.Y / dPixelResolution); Point contourCenterPixel = new Point( (int)Math.Round(contourCenter.X), (int)Math.Round(contourCenter.Y)); double[] radius_list = new double[_MaxContour[0].Count()]; for (int i = 0; i < _MaxContour[0].Count(); i++) { //계산중 오버플로우 발생하여 double 캐스팅으로 수정 var radius_i = Math.Sqrt((double)(contourCenterPixel.X - _MaxContour[0][i].X) * (double)(contourCenterPixel.X - _MaxContour[0][i].X) + (double)(contourCenterPixel.Y - _MaxContour[0][i].Y) * (double)(contourCenterPixel.Y - _MaxContour[0][i].Y)); radius_list[i] = radius_i; } var radius_list_avg = radius_list.Average(); var radius_final = radius_list_avg * _SystemParameter.CameraPixelSize / _SystemParameter.LensMagnification / 1000.0; var contourCenterX = (contourCenter.X - _ConvMatImage.Width / 2) * _SystemParameter.CameraPixelSize / _SystemParameter.LensMagnification / 1000.0; var contourCenterY = (_ConvMatImage.Height / 2 - contourCenter.Y) * _SystemParameter.CameraPixelSize / _SystemParameter.LensMagnification / 1000.0; // SMW RCC Offset은 DetectedCenter를 객체의 Offset값으로 넣어준다. _CellMeasureCenterOffsetX = contourCenterX; _CellMeasureCenterOffsetY = contourCenterY; Log.I(string.Format($"[RCC ApplyOffset] DetectedContourCenterX : {contourCenterX.ToString("F3")} mm, CenterY : {contourCenterY.ToString("F3")} mm")); // 측정 반지름과 Model의 CellRadiusOffset의 차이값과 Recipe의 Page에 설정된 Arc Radius와 비교하여 가장 근사한 Radius를 가진 페이지를 선택한다 int closestLayerIndex = -1; double minDifference = double.MaxValue; var recipelayersCnt = _ScannerCanvasUserCtrl.Model.Layers.Count(); UnitPoint ReceipeCenter = new UnitPoint(0, 0); //List> layerObjectsLists = new List>(); Arc selectedClosestArc = null; for (int i = 0; i < recipelayersCnt; i++) { var layerObjects = _ScannerCanvasUserCtrl.Model.Layers[i].Objects; Arc closestArc = null; foreach (var item in layerObjects) { if (item is Arc arc) { closestArc = arc; ReceipeCenter = arc.Center; break; } } if (closestArc != null) { double difference = Math.Abs(closestArc.Radius - (radius_final - _InitParam.CellRadiusOffset)); if (difference < minDifference) { minDifference = difference; closestLayerIndex = i; selectedClosestArc = closestArc; } } } // 이은지 선임 전달 코드 250825 _RecipeDrawObject = _ScannerCanvasUserCtrl.Model.Layers[closestLayerIndex].Objects; List tempobject = new List(); int startindex = 0; int nCount = _RecipeDrawObject.Count; for (int i = startindex; i < _RecipeDrawObject.Count; i++) { if (i >= startindex + nCount) break; tempobject.Add(_RecipeDrawObject[i]); } _SelectedDrawObject = tempobject; //_ObjectGenerator.ReplaceObject(_SelectedDrawObject, contourCenterX - ReceipeCenter.X, contourCenterY - ReceipeCenter.Y, 0, new UnitPoint(0, 0)); ///Log.I($"[RCC ApplyOffset] Recipe Center Offset: {_CellMeasureCenterOffsetX.ToString("F3")} mm, {_CellMeasureCenterOffsetY.ToString("F3")} mm"); Log.I($"[RCC ApplyOffset] Revision Center Offset: {_CellMeasureCenterOffsetX.ToString("F3")} mm, {_CellMeasureCenterOffsetY.ToString("F3")} mm"); // 250825 Log.I($"[RCC ApplyOffset] Detecte Radius - CellRadiusOffset : {(radius_final - _InitParam.CellRadiusOffset).ToString("F3")} mm, Detected Radius : {radius_final.ToString("F3")} mm, Model CellRadiusOffset : {_InitParam.CellRadiusOffset} mm"); Log.I($"[RCC ApplyOffset] Selected Recipe PageNo : {closestLayerIndex + 1}, Selected Reicpe Arc Radius : {selectedClosestArc.Radius} mm"); _StopWatchPath.Stop(); Log.D(string.Format($"[RCC ApplyOffset] Apply OffsetObejct Time : {_StopWatchPath.ElapsedMilliseconds}msec")); } else { //Inzi, LFW _StopWatchPath.Start(); _ObjectGenerator.ConvertMILToMat(_FlyingImage, out _ConvMatImage); var (offsetX, offsetY, _, offsetT, cX_pixel, cY_pixel, ScX_pixel, ScY_pixel, radius) = _ObjectGenerator.FindOffset(_ConvMatImage, 0, _SystemParameter.ReferenceX, _SystemParameter.ReferenceY, _SystemParameter.ReferenceTh, out _MaxContour, "LFW"); // 실제 Object 변경에 사용되는 Theta와 Center 값 cX_pixel -= _ConvMatImage.Width / 2; cY_pixel = (_ConvMatImage.Height / 2 - cY_pixel); var object_center = new UnitPoint((cX_pixel * _SystemParameter.CameraPixelSize / _SystemParameter.LensMagnification) / 1000.0, (cY_pixel * _SystemParameter.CameraPixelSize / _SystemParameter.LensMagnification) / 1000.0); var (offset_x, offset_y, offset_t) = ((offsetX * _SystemParameter.CameraPixelSize / _SystemParameter.LensMagnification) / 1000.0, (offsetY * _SystemParameter.CameraPixelSize / _SystemParameter.LensMagnification) / 1000.0, offsetT); offset_t = offset_t * Math.PI / 180; Log.I($"Center Offset: ({(float)offset_x}(mm), {(float)offset_y}(mm)), Theta Offset: {(float)(offset_t * 180 / Math.PI)},"); List tempobject = new List(); int startindex = 0; int nCount = _RecipeDrawObject.Count; for (int i = startindex; i < _RecipeDrawObject.Count; i++) { if (i >= startindex + nCount) break; tempobject.Add(_RecipeDrawObject[i]); } _SelectedDrawObject = tempobject; _ObjectGenerator.ReplaceObject(_SelectedDrawObject, offset_x, offset_y, offset_t, object_center); _StopWatchPath.Stop(); Log.D(string.Format($"[RCC ApplyOffset] RCC Complete Time : {_StopWatchPath.ElapsedMilliseconds}msec")); } return SequenceAction.Ok(); } private SequenceActionResult GenerateWeldingObject(SequenceContext context, string id, SequenceActionResult param) { _StopWatchPath.Restart(); // Reicpe Arc의 Center만큼 객체 생성후 옮겨서 용접해야 함. 즉, Recipe Arc Center가 DOE가 되어있어야 함 // Center만큼 움직여주니깐 너무많이 움직인다 ReferenceCenter잡고 새로찾은 Center의 Offset만큼만 옮겨줘야하나? //Manual 방식으로 동일양만큼 줄여서 객체 만들고 Recipe Arc의 Center만큼 더해주면 되는거아닌가? Arc arc = new Arc(); foreach (var item in _RecipeDrawObject) { if (item is Arc) { arc = (Arc)item; break; } } _CellMeasureCenterOffsetX = arc.Center.X; _CellMeasureCenterOffsetY = arc.Center.Y; _ObjectGenerator.SetPolygonFromList(_MaxContour, out List polygon); List paths; if (_SystemParameter.ObjectGenType == eObjectGenType.ArcByAngle) { _ObjectGenerator.CalculateAutoPathAngle(_ConvMatImage, _SelectedArcs[0], polygon, _SystemParameter.dMergeDist, _SystemParameter.ObjectNumber, _DetectedContourCenter, out paths); } else { _ObjectGenerator.CalculateAutoPath(_ConvMatImage, _SelectedArcs[0], polygon, _SystemParameter.dMergeDist, _SystemParameter.nMaxArcRadius, _SystemParameter.nLineTolerance, _SystemParameter.nArcTolerance, _DetectedContourCenter, out paths); } //Generate 한 object 를 SelectedDrawObjects 에 넣어두고 쓴다. _ObjectGenerator.ConvertPathItemToDrawingObjects(paths, _SystemParameter.fLineDefualtWidth, _ConvMatImage, _SelectedArcs[0], out _GeneratedDrawObject); if (_ObjectGenerator.CheckInterlockDrawingObjectPosition(_GeneratedDrawObject, _DetectedContourCenter, _SelectedArcs[0]) == false) { Log.E(string.Format("Invalid DrawObject is found.")); return null; } // Recipe 의 object 를 참조가 아닌 객체 생성으로 깊은 복사해서 recipe 가 바뀌지 않게 하자 List tempobject = new List(); int startindex = 0; int nCount = _RecipeDrawObject.Count; for (int i = startindex; i < _RecipeDrawObject.Count; i++) { if (i >= startindex + nCount) break; tempobject.Add(_RecipeDrawObject[i]); } _SelectedDrawObject = tempobject; _ObjectGenerator.ReplaceRCCObject(eArcCount.FirstArc, _SelectedDrawObject, _GeneratedDrawObject, _DetectedContourCenter); _StopWatchPath.Stop(); Log.D(string.Format($"[SeqManualRunRCC] Path Generating Complete Time : {_StopWatchPath.ElapsedMilliseconds}msec")); _StopWatchPath.Reset(); _ObjectGenerator.SaveDrawingObjectsToCSV(_GeneratedDrawObject, "SeqManualRunRCC"); return SequenceAction.Ok(); } private SequenceActionResult SetUploadWeldingList_SeqParams(SequenceContext context, string id, SequenceActionResult param) { SeqUploadWeldingList_InitParam seqParams = new SeqUploadWeldingList_InitParam() { NeedSetLaserTiming = false, // Trumpf 가 아니기 때문에 false IncludeListStartEnd = true, CellMeasureCenterOffsetX = _CellMeasureCenterOffsetX + _SystemParameter.CVScannerOffsetX, CellMeasureCenterOffsetY = _CellMeasureCenterOffsetY + _SystemParameter.CVScannerOffsetY, SelectedDrawObjectList = _SelectedDrawObject, WeldingScannerListNo = _WeldingScannerListNo, Rotation_Degree = 0, // 장비에 맞게 수정 필요 }; 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) { return null; } return SequenceAction.Ok(); } private bool StreamLBADBeforeWeldlines(SequenceContext context) { // 정지명 var client = context.GetLBADClient(); //RaedyStatus Check if (!client.CheckReadyStatus()) { return false; } //WeldTrigger On return client.SetWeldTriggerOn(); } private bool StreamLBADAfterWeldlines(SequenceContext context) { // 정지명 var client = context.GetLBADClient(); if (!client.SendWeldingStop()) { return false; } //Welding Stop On if (!client.SendWeldingStop()) { return false; } //JudgeFlag에 따라서 시퀀스 결정 var judgeFlag = client.CheckJudgeComplete(); if (judgeFlag == StreamLBADClient.eJudgeFlag.NO_RESPONSE) { return false; } return true; } private SequenceActionResult ExecuteWeldLines(SequenceContext context, string id, SequenceActionResult param) { if (_InitParam.UseStream) { if (!StreamLBADBeforeWeldlines(context)) { return null; } } _StopWatchWeld.Start(); Log.D(string.Format($"[SeqManualRunRCC] Welding Start")); _Scanner.SelectCorrectionTable(2); DateTime weldingTime = DateTime.Now; //_Scanner.ExecuteList(m_weldingScannerListNo); //_Scanner.WaitForListTaskCompleted(_systemParameter.WeldLinesTaskTimeOut); _Scanner.ExecuteList(_WeldingScannerListNo); _Scanner.WaitForListTaskCompleted(_SystemParameter.WeldLinesTaskTimeOut); _StopWatchWeld.Stop(); Log.D(string.Format($"[SeqManualRunRCC] Welding Complete Time : {_StopWatchWeld.ElapsedMilliseconds}msec")); _StopWatchWeld.Reset(); _StopWatchTotal.Stop(); Log.D(string.Format($"[SeqManualRunRCC] RCC Total Time : {_StopWatchTotal.ElapsedMilliseconds}msec")); _StopWatchTotal.Reset(); if (_InitParam.UseStream) { if (!StreamLBADAfterWeldlines(context)) { return null; } } return SequenceAction.Ok(); } // 미사용 code //private static string CheckCycleStop(SequenceContext context, string id, ICollection branches, SequenceActionResult param) //{ // Status.SetWorkingPosition(eWorkingPosition.CHECKING_CYCLE); // // TODO: 확인 필요, CybleStop 에 대한 내용, cycle stop 여부 가져오기 // //bCycleStop = GetCycleStopRequest(); // Log.I(string.Format("SequenceAction Start : CheckCycleStop")); // bool cycleStop = true; // 일단 true 로 set 해둔다. // if (cycleStop) { // return SEQ_SAVE_RESULT_DATA; // } else { // return SEQ_MANUALRUN_RCC_CHECK_WELDING_READY; // } //} private void SaveImageFile(MIL_ID imageID) { Log.I(string.Format($"Start to store completed field scan image")); string fieldScanImageFile = Path.Combine(ConfigurationManager.AppSettings.Get("DATA_PATH"), "_vision", "FieldScanImage", string.Format($"{DateTime.Now.Year}_{DateTime.Now.Month}_{DateTime.Now.Day}\\AutoFlyingScout_{DateTime.Now.ToString("HHmmss")}.PNG")); ImageUtil.SaveImage(_FlyingImage, fieldScanImageFile, 10, false); } private string DecisionCheckCycleStop(SequenceContext context, string id, ICollection branches, SequenceActionResult param) { Log.I(string.Format("SequenceAction Start : CheckCycleStop")); Log.I(string.Format($"SequenceRepeatNum : {seqRepeatNum}")); seqRepeatNum++; if (_InitParam.IsRepeatEdgeDetectMode) { if (seqRepeatNum <= 100) { return SEQ_CHECK_INIT_CONDITION; } else { return SEQ_SAVE_RESULT_DATA; } } else { return SEQ_SAVE_RESULT_DATA; } } private SequenceActionResult SaveResultData(SequenceContext context, string id, SequenceActionResult param) { // 결과 Data 를 업데이트 함. context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, true); return SequenceAction.Ok(); } private SequenceActionResult WriteCompletionPLCBit(SequenceContext context, string id, SequenceActionResult param) { // 완료 비트 write 하는 Node 추가 필요. format 유지, SeqScoutNormal 없음 Log.D("ManualRunRCC Sequence WriteCompletionPLCBit"); return SequenceAction.Ok(); } private SequenceActionResult Complete(SequenceContext context, string id, SequenceActionResult param) { RestoreDeviceStatus(); Log.I("ManualRunRCC Complete"); context.TryGetValue(ContextKey.KEY_SEQUENCE_RESULT, out bool seqResult); List paths = new List(); _ObjectGenerator.GetAutoPath(out paths); var resultManualRunData = new ResultManualRunData(_ConvertImageMat, paths); SeqManualRunRCC_OutParam result = new SeqManualRunRCC_OutParam() { Success = seqResult, ResultManualRunData = resultManualRunData, }; if (seqResult == false) { AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_ManualRunRCC_ResultFailed); } Log.D("ManualRunRCC Sequence Complete"); return SequenceAction.Ok(result); } private bool RestoreDeviceStatus() { //용접 Path Record string dataFilePath = ProjectUtil.GetDataLogSetting().GetFilePath_ScannerRecordLog("ManualRunRCC", true); _Scanner.SaveRecord(dataFilePath); Log.I(string.Format($"Complete RCC Path record")); //스캐너 원점 복귀 //용접 완료 후 CorrectionFile Vision으로 원복 //_Scanner.SelectCorrectionTable(1); //_Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); _Scanner.SelectCorrectionTable(1); Log.I(string.Format($"Complete Scanner move Origin")); _StopWatchTotal.Stop(); Log.D(string.Format($"[SeqManualRunRCC] Seq Total Complete Time : {_StopWatchTotal.ElapsedMilliseconds}msec")); return true; } private void OnForceError(SequenceContext arg1, string arg2) { //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); Log.I("SequenceAction Ok : OnForceError"); } private void OnStopped(SequenceContext obj) { //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); Log.I("SequenceAction Ok : OnStopped"); } } public class SeqManualRunRCC_InitParam : InitParam { public ScoutSeqParams ScoutSeqParams { get; set; } public bool UseStream { get; set; } public string SelectedOption { get; set; } public string CellType { get; set; } public bool IsRepeatEdgeDetectMode { get; set; } public double CellRadiusOffset { get; set; } } public class SeqManualRunRCC_OutParam : OutParam { public ResultManualRunData ResultManualRunData { get; set; } } public class ResultManualRunData { public Mat ResultImage { get; } public List PathItemList { get; } public ResultManualRunData(Mat resultImage, List pathitems) { ResultImage = resultImage; PathItemList = pathitems; } } }