1220 lines
59 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|