2026-01-26 18:56:53 +09:00

1220 lines
59 KiB
C#

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<IDrawObject> _RecipeDrawObject;
private List<IDrawObject> _GeneratedDrawObject;
private List<IDrawObject> _GeneratedDrawObject2;
private List<IDrawObject> _SelectedDrawObject;
private Mat _ConvMatImage;
private eListNo _WeldingScannerListNo;
private eListNo _ScoutScannerListNo;
private List<int> _ScoutNoList = new List<int>();
private int _ScoutNo;
private List<IDrawObject> _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<Arc> _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<SystemParameter>(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<string> deviceListToCheck = new List<string>() { 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<string> 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<string> 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<string> 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<PathItem> paths;
_ObjectGenerator.SetPolygonFromList(_MaxContour, out List<TPoint> 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<PathItem> paths;
_ObjectGenerator.SetPolygonFromList(_MaxContour2, out List<TPoint> 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<IDrawObject> tempobject = new List<IDrawObject>();
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<string> branches, SequenceActionResult param)
{
// CheckEdge 결과에 따라서 GenObject 또는 ApplyOffsetObject로 나눈다
_StopWatchPath.Restart();
Point[][] maxContour = context.GetValue<Point[][]>("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<List<IDrawObject>> layerObjectsLists = new List<List<IDrawObject>>();
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<IDrawObject> tempobject = new List<IDrawObject>();
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<IDrawObject> tempobject = new List<IDrawObject>();
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<TPoint> polygon);
List<PathItem> 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<IDrawObject> tempobject = new List<IDrawObject>();
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<string> 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<string> 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<PathItem> paths = new List<PathItem>();
_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<PathItem> PathItemList { get; }
public ResultManualRunData(Mat resultImage, List<PathItem> pathitems)
{
ResultImage = resultImage;
PathItemList = pathitems;
}
}
}