using Aurora; using Aurora.Api; using Aurora.Api.Manager; using AuroraIO; using AuroraLaser; using AuroraLaser.Trumpf; using AuroraLaserScanner; using AuroraLBAD.Services; using CoreUnit.Control.UserControl.Canvas; using CoreUnit.Scanner.UserControl.ScannerCanvas; using GUI; using Hermes; using MilCommon; using MilUI; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using VisionCommon; using WeldingCommon; using WeldingCommon.Alarm; using WeldingCommon.Devices; using WeldingCommon.Devices.Laser; using WeldingCommon.Recipes; using WeldingCommon.Sequences; using WeldingCommon.Settings; using WeldingCommon.Vision.WeldingObjectGenerator; using static AuroraIO.AJINEXTEK.AjinIO.IOModuleInfo; using static ILSOS_PrismaticRD_PTOP.Device.PLCControllerPTOP; using static WeldingCommon.Devices.Laser.PAIX_PrismaticScanner; using static WeldingCommon.Devices.PLCController; namespace ILSOS_PrismaticRD_TDC.Sequences { internal class SeqTestRun { static readonly Logger Log = new Logger("SeqWaitWeldOrChangePage"); const string SEQ_ENTER = "[SeqWaitWeldOrChangePage] SEQ_ENTER"; const string SEQ_CHECK_INIT_CONDITION = "[SeqAutoRunLFW] Check Init Condition"; const string SEQ_CHECK_LOAD_COMPLETE = "[SeqAutoRunKS] Check Load Complete"; const string SEQ_GET_PLC_PAGE_CHANGE_REQ_ON = "[SeqWaitWeldOrChangePage] Get PLC Page Change Request On"; // PLC Page Change Request ON const string SEQ_SET_PC_PAGE_CHANGE_ACK_ON = "[SeqWaitWeldOrChangePage] Set PC Page Change Ack On"; // PC Page Change Reqeust ACK ON const string SEQ_GET_PLC_PAGE_CHANGE_REQ_OFF = "[SeqWaitWeldOrChangePage] Get PLC Page Change Request Off"; // PLC Page Change Request OFF const string SEQ_SET_PC_PAGE_CHANGE_ACK_OFF = "[SeqWaitWeldOrChangePage] Set PC Page Change Ack Off"; // PC Page Change Reqeust OFF const string SEQ_GET_PLC_WELD_REQ_ON = "[SeqWaitWeldOrChangePage] Get PLC Weld Request On"; // PLC Weld Request ON const string SEQ_EXECUTE_WELDING = "[SeqAutoRunKS] Execute Welding"; const string SEQ_COMPLETE = "[SeqWaitWeldOrChangePage] SEQ_COMPLETE"; // 완료 private PLCController _PLC; private Scanner _Scanner; // 레이저 상태 변화 //private IODevice _IOLaser; private LaserIOControl _IOLaser; private static DataModel Models { get; set; } private static List _UnpackDrawObject; private SeqTestRun_InitParam _InitParam; private SeqTestRun_OutParam _OutParam; private eListNo _WeldingScannerListNo; private List _SelectedObjectList; private static short _PLCPageNo = 1; private DateTime _AutoRunStartTime; private DateTime _WeldingStartTime; private TimeSpan _WeldingSpanTime; private DateTime _WeldEndTime; private TimeSpan _InterfaceSpanTime; private DateTime _InterfaceStartTime; const int PLC_TIMEOUT = 60; private string _CurrentModelName; private SeqTestRun _ModelItem; public SequenceBuilder Builder() { var sb = new SequenceBuilder(1000, true); ////var sb = new SequenceBuilder(1000, false); // With log sb.AddAction(SEQ_ENTER, Sequence_Enter); sb.AddAction(SEQ_CHECK_INIT_CONDITION, CheckInitCondition); //분기 sb.AddAction(SEQ_CHECK_LOAD_COMPLETE, CheckLoadComplete); // Page Change Request sb.AddAction(SEQ_GET_PLC_PAGE_CHANGE_REQ_ON, GetPLCPageChangeRequestOn); sb.AddAction(SEQ_SET_PC_PAGE_CHANGE_ACK_ON, SetPCPageChangeRequestACKOn); sb.AddAction(SEQ_GET_PLC_PAGE_CHANGE_REQ_OFF, GetPLCPageChangeRequestOff); sb.AddAction(SEQ_SET_PC_PAGE_CHANGE_ACK_OFF, SetPCPageChangeRequestACKOff); // Weld Reqeust // Weld Request I/F는 없어도 됨. 왜냐하면, PLC에서 Busy 신호만 보기 때문임. sb.AddAction(SEQ_GET_PLC_WELD_REQ_ON, GetPLCWeldRequestOn); sb.AddAction(SEQ_EXECUTE_WELDING, ExecuteWelding); sb.AddAction(SEQ_COMPLETE, Complete); sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_LOAD_COMPLETE] > sb[SEQ_GET_PLC_PAGE_CHANGE_REQ_ON] > sb[SEQ_SET_PC_PAGE_CHANGE_ACK_ON] > sb[SEQ_GET_PLC_PAGE_CHANGE_REQ_OFF] > sb[SEQ_SET_PC_PAGE_CHANGE_ACK_OFF] > sb[SEQ_EXECUTE_WELDING] > sb[SEQ_COMPLETE] > sb.Final); sb.OnForceError(OnForceError); sb.OnStopped(OnStopped); sb.Draw("SeqTestRun.pdf"); return sb; } private SequenceActionResult Sequence_Enter(SequenceContext context, string id, SequenceActionResult param) { Log.I("SeqTestRun Start"); Log.I("[SeqTestRun]Sequence_Enter"); InitDev(context); if (!CheckDeviceReady(context)) { Log.E("The devices are not active."); return null; } if (InitSequenceVariable(context) == false) { return null; } _InitParam = param.Param as SeqTestRun_InitParam; if (_InitParam.NeedPageNo) _PLCPageNo = _InitParam.CurrentPageNo; else _PLCPageNo = 1; // 레이저 Word 값을 위함 Models = _InitParam.Models; return SequenceAction.Ok(); } // 용접리스트1 확인 private SequenceActionResult CheckInitCondition(SequenceContext context, string id, SequenceActionResult param) { Log.I("[SeqTestRun]CheckInitCondition"); var startTime = DateTime.Now; _WeldingScannerListNo = eListNo.LIST1; return SequenceAction.Ok(); } private SequenceActionResult CheckLoadComplete (SequenceContext context, string id, SequenceActionResult param) { Log.I("[SeqTestRun]CheckLoadComplete"); Status.SetWorkingPosition(eWorkingPosition.LOADING_CELL); while (!context.Stopped) { if (_PLC.ReadBit((int)eBitInput.PLC_WELD_TRIGGER_REQ).data) { Log.I(string.Format($"[PLCInterface]GET PLC_WELD_TRIGGER_REQ True")); _PLC.WriteBit((int)eBitOutput.PC_WELD_TRIGGER_ACK, true); Log.I(string.Format($"[PLCInterface]SET PC_WELD_TRIGGER_ACK True")); break; } _InterfaceSpanTime = DateTime.Now.Subtract(_InterfaceStartTime); if (_InterfaceSpanTime.TotalMilliseconds > (PLC_TIMEOUT * 1000)) { Log.E("TIMEOUT_PLC_WELD_TRIGGER_REQEUST"); _InterfaceStartTime = DateTime.Now; } Thread.Sleep(10); } return SequenceAction.Ok(); } private SequenceActionResult GetPLCPageChangeRequestOn(SequenceContext context, string id, SequenceActionResult param) { Log.I("[SeqTestRun]GetPLCPageChangeRequestOn"); var res = context.RetryUntilSuccess(() => _PLC.ReadBit(eCommonBitInput.PLC_PAGE_CHANGE_REQ).data, _InitParam.TimeoutSec * 1000, interval: 10); if (res == E2.TIMEOUT) { Log.FuncE("Get PLC Page Change Request On Timeout !"); return null; } Log.W(string.Format("PLC Page Change Request On")); return SequenceAction.Ok(); } private SequenceActionResult SetPCPageChangeRequestACKOn(SequenceContext context, string id, SequenceActionResult param) { Log.I("[SeqTestRun]SetPCPageChangeRequestACKOn"); if (_InitParam.NeedPageNo) { Thread.Sleep(100); _PLCPageNo = _PLC.ReadWord(eCommonWordInput.PLC_PAGE_NO).data; _PLC.WriteWord(eCommonWordOutput.PC_PAGE_NO, (short)_PLCPageNo); Log.D($"When PageChangeReq is ON;{_PLCPageNo}"); #region Tact Time 절감을 위한 페이지 체인지 인터페이스 중 Program No 변경 // Unpack 관련 함수 _UnpackDrawObject?.Clear(); _UnpackDrawObject = new List(); if (Models.Layers.Count() > _PLCPageNo - 1) UnpackRecipes(Models.Layers[_PLCPageNo - 1].Objects); else { Log.E($"[Page Change Req] Page No is not proper;{Models.Layers.Count()};{_PLCPageNo}"); return null; } int paramIndex = 0; if (_UnpackDrawObject.Count > 0) { paramIndex = _UnpackDrawObject[0].ScannerParamID - 1; } else { paramIndex = 0; Log.E("[Page Change Req] Draw Objects is zero"); } _CenterBeamPower = (int)ScannerCanvasUserCtrl.ScannerParams[paramIndex].LaserPower1; _RingBeamPower = (int)ScannerCanvasUserCtrl.ScannerParams[paramIndex].LaserPower2; _CenterRingRatio = 0; if (_CenterBeamPower == 0 && _RingBeamPower == 0) _CenterRingRatio = 100; else _CenterRingRatio = (int)Math.Round((double)(100 * _CenterBeamPower) / (double)(_CenterBeamPower + _RingBeamPower), 0); // Discrete 한 값이라서 Ring은 오차 발생 // Ready 상태 변경 확인(Complete 상태에서 Laser Ready로 변환되기까지 시간이 걸림) var res = context.RetryUntilSuccess(_IOLaser.GetLaserReady, _InitParam.TimeoutSec * 1000, 1); if (res == E2.TIMEOUT) { Log.E(string.Format($"[Page Change Req] Laser Program Ready Timeout When LaserReady")); return null; } Log.D(string.Format($"[Page Change Req] Laser Program Ready OK")); // Laser Program Parameters 설정(Laser Ready 상태는 용접 직전에 확인) List<(int, int, bool)> datas = new List<(int, int, bool)>(); datas.Add((csWriteNodeNo.IW03, _CenterBeamPower, true)); datas.Add((csWriteNodeNo.IW04, _RingBeamPower, true)); datas.Add((csWriteNodeNo.IW05, _CenterRingRatio, true)); // Ready 상태 변경 확인 res = context.RetryUntilSuccess(() => LaserReadyResponse(), _InitParam.TimeoutSec * 1000, 1); if (res == E2.TIMEOUT) { Log.E(string.Format($"[Page Change Req] Laser Program Ready Timeout When LaserReadyResponse")); return null; } Log.D(string.Format($"[Page Change Req] Laser Program Ready OK When ReadyResponse")); #endregion } _PLC.WriteBit(eCommonBitOutput.PC_PAGE_CHANGE_COMPLETE, true); Log.W(string.Format("Set PC Page Change Request ACK On")); Log.I($"Welding List Space : {_Scanner.GetListSpace()}"); DateTime weldingTime = DateTime.Now; _Scanner.ExecuteList(0); //_Scanner.WaitForListTaskCompleted(_SystemParameter.WeldLinesTaskTimeOut); //_MeasurementSpanTime = DateTime.Now.Subtract(weldingTime); //Log.D(string.Format($"[ComponentTeachingRun] Component Welding Complete Time : {_MeasurementSpanTime.TotalMilliseconds}")); return SequenceAction.Ok(); } #region 레이저 값 변경을 위함 private int _CenterBeamPower; private int _RingBeamPower; private int _CenterRingRatio; private static void UnpackRecipes(List recipes) { // Recipe를 재귀적으로 탐색해서 List로 재구성하는 함수 if (recipes == null) return; for (int i = 0; i < recipes.Count; i++) { if (recipes[i] is Group) { Group subGroup = recipes[i] as Group; List subrecipes = subGroup.SubObjects as List; UnpackRecipes(subrecipes); } else { _UnpackDrawObject.Add(recipes[i]); } } } private bool LaserReadyResponse() { //if (ApplicationExt.IsSimulation) return true; } #endregion private SequenceActionResult GetPLCPageChangeRequestOff(SequenceContext context, string id, SequenceActionResult param) { Log.I("[SeqTestRun]GetPLCPageChangeRequestOff"); //// 계속 페이지를 저장해줄 필요는 없음. //var res = context.RetryUntilSuccess(UpdatePLCPageWord, _InitParam.TimeoutSec * 1000, interval: 10); var res = context.RetryUntilSuccess(() => !_PLC.ReadBit(eCommonBitInput.PLC_PAGE_CHANGE_REQ).data, _InitParam.TimeoutSec * 1000, interval: 10); if (res == E2.TIMEOUT) { Log.FuncE(string.Format("Get PLC Page Change Request OFF Timeout ! : {0}", eCommonBitInput.PLC_PAGE_CHANGE_REQ)); return null; } else Log.W(string.Format("Get PLC Page Change Request OFF Complete : {0}", eCommonBitInput.PLC_PAGE_CHANGE_REQ)); return SequenceAction.Ok(); } private SequenceActionResult SetPCPageChangeRequestACKOff(SequenceContext context, string id, SequenceActionResult param) { Log.I("[SeqTestRun]SetPCPageChangeRequestACKOff"); if (_InitParam.NeedPageNo) { _PLCPageNo = _PLC.ReadWord(eCommonWordInput.PLC_PAGE_NO).data; // PLC와 Request ON 시점에서 써주기로 하였으므로, 여기서는 굳이 써주지 않음.(확인용) //_PLC.WriteWord(_InitParam.SetPageNoAddress, (short)_PLCPageNo, AuroraPLC.PLCBase.ePLCDevice.D); Log.D($"When PageChangeReq is OFF;{_PLCPageNo}"); } _PLC.WriteBit(eCommonBitOutput.PC_PAGE_CHANGE_COMPLETE, false); Log.W(string.Format("Set PC Page Change Request ACK Off")); return SequenceAction.Ok(); } static DateTime WeldReqTime; private SequenceActionResult GetPLCWeldRequestOn(SequenceContext context, string id, SequenceActionResult param) { Log.I("[SeqTestRun]GetPLCWeldRequestOn"); WeldReqTime = DateTime.Now; context.RetryUntilSuccess(() => _PLC.ReadBit(eCommonBitInput.PLC_WELD_TRIGGER_REQ).data, _InitParam.TimeoutSec * 1000, interval: 10); Log.W(string.Format("Get PLC Weld Request On")); return SequenceAction.Ok(); } private SequenceActionResult ExecuteWelding(SequenceContext context, string id, SequenceActionResult param) { Log.I("[SeqTestRun]ExecuteWelding"); Status.SetWorkingPosition(eWorkingPosition.EXECUTING_WELD); Log.D(string.Format($"[TeachingRun] Welding Start")); DateTime weldingTime = DateTime.Now; _Scanner.ExecuteList(_WeldingScannerListNo); _WeldingSpanTime = DateTime.Now.Subtract(weldingTime); Log.D(string.Format($"[TeachingRun] Welding Complete Time : {_WeldingSpanTime.TotalMilliseconds}")); double dExecuteListTime = _Scanner.GetTime(); Log.I(string.Format($"[TeachingRun] ExecuteList Time : {dExecuteListTime * 1000} msec")); // OCT File Fomrat Record Test //SaveOCTFileFormat(); // File Format Record Test weldingTime = DateTime.Now; //SaveScannerRecordFileForamt(); _WeldingSpanTime = DateTime.Now.Subtract(weldingTime); Log.D(string.Format($"[TeachingRun] SaveScannerRecordFileForamt Time : {_WeldingSpanTime.TotalMilliseconds}")); weldingTime = DateTime.Now; _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); //용접 완료 후 CorrectionFile Vision으로 원복 _Scanner.SelectCorrectionTable(1); _WeldingSpanTime = DateTime.Now.Subtract(weldingTime); Log.D(string.Format($"[TeachingRun] Change SelectCorrectionTable Time : {_WeldingSpanTime.TotalMilliseconds}")); //int recipeNo = _RecipeManager.ActivatedRecipe().Id; _IOLaser._iOUnit.WriteDoBit(Convert.ToInt32(ePrismaticDOAddress.EX_Red_Control), true); if() _PLC.WriteBit((int)eBitOutput.PC_WELD_TRIGGER_ACK, false); Log.I(string.Format($"[PLCInterface]SET PC_WELD_REQEUST_ACK False")); _PLC.WriteBit((int)eBitOutput.PC_WELD_BUSY, true); Log.I(string.Format($"[PLCInterface]SET PC_WELD_BUSY False")); return SequenceAction.Ok(); } private SequenceActionResult Complete(SequenceContext context, string id, SequenceActionResult param) { SeqTestRun_OutParam result = new SeqTestRun_OutParam() { PLCPageNo = (short)_PLCPageNo, Success = true, _WeldReqTime = WeldReqTime }; Log.D("CheckWeldingComplete Sequence Complete"); _PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE, true); Log.I(string.Format($"[PLCInterface]SET PC_WELD_COMPLETE True")); _PLC.WriteBit((int)eBitOutput.PC_WELD_BUSY, false); Log.I(string.Format($"[PLCInterface]SET PC_WELD_BUSY False")); return SequenceAction.Ok(result); } private void OnStopped(SequenceContext context) { Log.W("SequenceAction Ok : OnStopped"); } private void OnForceError(SequenceContext context, string arg2) { Log.W("SequenceAction Ok : OnForceError"); } private bool UpdatePLCPageWord() { if (_InitParam.NeedPageNo) { _PLCPageNo = _PLC.ReadWord(eCommonWordInput.PLC_PAGE_NO).data; _PLC.WriteWord(eCommonWordOutput.PC_PAGE_NO, (short)_PLCPageNo); } return !_PLC.ReadBit(eCommonBitInput.PLC_PAGE_CHANGE_REQ).data; } static private bool pageChangeRequestBit = false; static private bool weldRequestBit = false; private bool CheckRequest() { pageChangeRequestBit = _PLC.ReadBit(eCommonBitInput.PLC_PAGE_CHANGE_REQ).data; weldRequestBit = _PLC.ReadBit(eCommonBitInput.PLC_WELD_TRIGGER_REQ).data; return (pageChangeRequestBit || weldRequestBit); } #region Device 및 상태 확인 함수 (시퀸스 공용) private bool InitSequenceVariable(SequenceContext context) { int recipeNo = _PLC.ReadWord((int)eWordInput.PLC_PAGE_NO).data; if (recipeNo == 1) { } //_RecipeDrawObjects = _ScannerCanvasUserCtrl.Model.Layers[0].Objects; //_WeldingScannerListNo = eListNo.LIST1; return true; } private void InitDev(SequenceContext context) { //Device Init //_IODevice = context.GetIOUnit(); _IOLaser = VisionEnv.AuroraEnv.DeviceManager[CommonDeviceIds.IODevice] as LaserIOControl; _Scanner = context.GetLaserScanner(); _PLC = context.GetPLC(); } private bool CheckDeviceReady(SequenceContext context) { List deviceListToCheck = new List() { CommonDeviceIds.PLCDevice }; bool isAllDeviceActivated = true; foreach (string item in deviceListToCheck) { if (!context.Devices[item].IsActivated) { isAllDeviceActivated = isAllDeviceActivated && false; } } return isAllDeviceActivated; } private bool CheckCondition(SequenceContext context) { if (CheckCondition_Interlock()) { if (InitializeDeviceStatus(context)) { return true; } } return false; } private bool InitializeDeviceStatus(SequenceContext context) { // format 유지, ReceiveCellInfo 없음 return true; } private bool CheckCondition_Interlock() { // PLC, Data, IO 등 Interlock checking return true; } #endregion } public class SeqTestRun_InitParam : InitParam { public short CurrentPageNo { get; set; } public bool NeedPageNo { get; set; } public DataModel Models { get; set; } public int TimeoutSec { get; set; } } public class SeqTestRun_OutParam : OutParam { public bool IsComplete { get; set; } public short PLCPageNo { get; set; } public DateTime _WeldReqTime { get; set; } } }