From 45c1de6cc8dae36e8edf60079014760e4dcdb624 Mon Sep 17 00:00:00 2001 From: choieigun Date: Tue, 10 Mar 2026 00:40:19 +0900 Subject: [PATCH] =?UTF-8?q?=EC=85=80=20=ED=8C=8C=EC=9D=B4=ED=94=84?= =?UTF-8?q?=EB=9D=BC=EC=9D=B8=203=EB=8B=A8=EA=B3=84=20=EA=B5=AC=EC=A1=B0?= =?UTF-8?q?=ED=99=94=20=EB=B0=8F=20=EB=B3=B4=EA=B3=A0=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EC=86=8C=EC=8A=A4=20=EB=AA=85=ED=99=95=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [CellInfoScheduler] - ReportTarget 제거 → Complete 슬롯 추가 - Shift()가 Complete ← Prefetch1 ← Prefetch2 3단계 자동 전진 - Prefetch1 volatile 처리로 EncoderMonitor 스레드 가시성 보장 - HasReport에 IsCanExist·WeldComplete 조건 추가 [SeqAutoRunCCWH52A] - ReportCellResult: LotId/CellId/JigNo/WeldingSpanTime을 ActiveReportSlot에서 직접 읽도록 변경 (wd 경유 제거) - ReportCellResult: 레시피·레이저 파라미터를 Prefetch2.InnerCellInfo에서 읽도록 변경 - GetUploadWeldingList_SeqResult: 업로드 성공 후 InnerCellInfo 및 Status 한 번에 갱신 (ReadyScannerList 중복 제거) - UpdateProductCount/UpdateProductInfoForView 메서드 인라인화 - _TodayProduct/_TotalProduct 멤버변수 제거 - CheckCurrentEncoderAngle → CheckInsideWeldPosition 리네임 및 정리 - EncoderMonitor: JigNo > 0 방어 가드 추가 - _RecipeNo를 InitSequenceVariable에서 한 번만 설정 --- .../ILSOS_CCW_H52A/Datas/CellInfoScheduler.cs | 59 +- Machines/ILSOS_CCW_H52A/ILSOS_CCW_H52A.csproj | 1 - .../Sequences/SeqAutoRunCCWH52A.cs | 255 ++-- .../Sequences/SeqAutoRunRMOTF.cs | 1218 ----------------- 4 files changed, 142 insertions(+), 1391 deletions(-) delete mode 100644 Machines/ILSOS_CCW_H52A/Sequences/SeqAutoRunRMOTF.cs diff --git a/Machines/ILSOS_CCW_H52A/Datas/CellInfoScheduler.cs b/Machines/ILSOS_CCW_H52A/Datas/CellInfoScheduler.cs index f40e347..22dbdfb 100644 --- a/Machines/ILSOS_CCW_H52A/Datas/CellInfoScheduler.cs +++ b/Machines/ILSOS_CCW_H52A/Datas/CellInfoScheduler.cs @@ -21,15 +21,15 @@ namespace ILSOS_CCW_H52A.Data /// 파이프라인 단계 접근을 동시에 지원하는 셀 스케줄러. /// /// - 물리 지그 접근: scheduler[eJigNo.Jig5] - /// - 파이프라인 접근: scheduler.Prefetch1, scheduler.Prefetch2 + /// - 파이프라인 접근: scheduler.Prefetch2, scheduler.Prefetch1, scheduler.Complete /// - /// 3단계 파이프라인: Prefetch2 → Prefetch1 → ReportTarget - /// Prefetch2 : 셀 정보 수신 완료, 스캐너 리스트 업로드 전 - /// Prefetch1 : 업로드 완료, 실행 중 — EncoderMonitor 감시 + 완료 체크 대상 - /// ReportTarget: 완료, 보고 대기 + /// 3단계 파이프라인: Prefetch2 → Prefetch1 → Complete + /// Prefetch2 : 셀 정보 수신 완료, 스캐너 리스트 업로드 전 + /// Prefetch1 : 업로드 완료, 실행 중 — EncoderMonitor 감시 + 완료 체크 대상 + /// Complete : 용접 완료, 보고 대기 /// - /// Shift()는 Prefetch2→Prefetch1만 전진. GC 할당 없음. - /// Prefetch1 ← Prefetch2 ← this[nextJig] + /// Shift()가 3단계 전체를 전진. GC 할당 없음. + /// Complete ← Prefetch1 ← Prefetch2 ← this[nextJig] /// public class CellInfoScheduler : Dictionary { @@ -44,8 +44,7 @@ namespace ILSOS_CCW_H52A.Data private set => _prefetch1 = value; } - /// 현재 보고 대상 JigInfo (CheckScannerListComplete에서 지정, 보고 완료 후 null) - public JigInfo ReportTarget { get; set; } + public JigInfo Complete { get; private set; } // 전 셀: 용접 완료, 보고 대기 // 재시작 보존용 독립 슬롯 — Reset()에서 건드리지 않음 // 재시작 시, List를 최초 리스트 2번을 생성하는 로직 때문에.. 필요함 @@ -60,7 +59,7 @@ namespace ILSOS_CCW_H52A.Data public bool HasPendingComplete => _pendingSlot.IsCanExist && !_pendingSlot.ReportComplete; // 현재 활성 보고 슬롯 — 재시작 pending 우선 - public JigInfo ActiveReportSlot => HasPendingComplete ? _pendingSlot : ReportTarget; + public JigInfo ActiveReportSlot => HasPendingComplete ? _pendingSlot : Complete; // 정지 전 미용접 슬롯이 보존돼 있는지 (재시작 후 복원 가능 여부) public bool HasPendingPrefetch => @@ -68,7 +67,9 @@ namespace ILSOS_CCW_H52A.Data || !string.IsNullOrEmpty(_pendingPrefetch2.CellId); // 보고가 필요한 상태인지 (정상 + 재시작 모두 포함) >> 용접 완, 보고 미완 - public bool HasReport => HasPendingComplete || (ReportTarget != null && !ReportTarget.ReportComplete); + // Complete는 Shift()마다 갱신되므로 IsCanExist·WeldComplete 조건을 함께 확인한다. + public bool HasReport => HasPendingComplete || + (Complete != null && Complete.IsCanExist && Complete.WeldComplete && !Complete.ReportComplete); public CellInfoScheduler() { @@ -85,11 +86,11 @@ namespace ILSOS_CCW_H52A.Data public void SavePendingComplete() { // 용접 완료됐으나 보고 전 정지된 경우 (_pendingSlot) - if (ReportTarget != null - && ReportTarget.IsCanExist - && ReportTarget.WeldComplete - && !ReportTarget.ReportComplete) - _pendingSlot.CopyFrom(ReportTarget); + if (Complete != null + && Complete.IsCanExist + && Complete.WeldComplete + && !Complete.ReportComplete) + _pendingSlot.CopyFrom(Complete); // 업로드 완료됐으나 로터리 정지로 용접 자체가 안 된 경우 (_pendingPrefetch1/2) // (연속셀이 들어왔을때, 중간에 멈춘 경우) @@ -135,31 +136,33 @@ namespace ILSOS_CCW_H52A.Data return false; } - // 보고 완료 처리 — ReportTarget 마킹 및 _pendingSlot 클리어. + // 보고 완료 처리 — Complete 마킹 및 _pendingSlot 클리어. // GetReportCellResult_SeqResult 성공 시 호출. public void CompleteReport() { - _log.I($"Report >> CellId({ReportTarget.CellId}), JigNo({ReportTarget.JigNo})"); - ReportTarget?.SetReportComplete(true); - ReportTarget = null; - _pendingSlot.Clear(); + var reported = ActiveReportSlot; + _log.I($"Report >> CellId({reported?.CellId}), JigNo({reported?.JigNo})"); + Complete?.SetReportComplete(true); // 정상 보고 마킹 (pending 경로면 no-op) + _pendingSlot.Clear(); // 재시작 보존 슬롯 항상 클리어 } /// - /// Prefetch2→Prefetch1 한 칸 전진. GC 할당 없음. + /// 3단계 파이프라인 전진. GC 할당 없음. + /// Complete ← Prefetch1 ← Prefetch2 ← this[nextJig] (Clear) /// 새 Prefetch2 슬롯은 Clear 후 반환 — 호출자가 셀 정보를 채워야 한다. /// - /// 새 Prefetch2로 지정할 물리 지그 (eJigNo) public void Shift(eJigNo nextJig) { - Prefetch1 = Prefetch2; + Complete = Prefetch1; // Prefetch1 → Complete + Prefetch1 = Prefetch2; // Prefetch2 → Prefetch1 (volatile write: release fence) Prefetch2 = base[nextJig]; Prefetch2.Clear(); } // AutoRun에서 사용되는 자료형으로 추가 (편의 인덱서 사용) public void Shift(int nextJig) { - Prefetch1 = Prefetch2; + Complete = Prefetch1; // Prefetch1 → Complete + Prefetch1 = Prefetch2; // Prefetch2 → Prefetch1 (volatile write: release fence) Prefetch2 = this[nextJig]; Prefetch2.Clear(); } @@ -174,9 +177,9 @@ namespace ILSOS_CCW_H52A.Data foreach (var info in Values) info.Clear(); - Prefetch2 = null; - Prefetch1 = null; - ReportTarget = null; + Prefetch2 = null; + Prefetch1 = null; + Complete = null; // _pendingSlot, _pendingPrefetch1/2: SavePendingComplete()가 복사해 둔 데이터를 유지 } diff --git a/Machines/ILSOS_CCW_H52A/ILSOS_CCW_H52A.csproj b/Machines/ILSOS_CCW_H52A/ILSOS_CCW_H52A.csproj index 084871a..5296ec9 100644 --- a/Machines/ILSOS_CCW_H52A/ILSOS_CCW_H52A.csproj +++ b/Machines/ILSOS_CCW_H52A/ILSOS_CCW_H52A.csproj @@ -111,7 +111,6 @@ - UCMainAutoRun.xaml diff --git a/Machines/ILSOS_CCW_H52A/Sequences/SeqAutoRunCCWH52A.cs b/Machines/ILSOS_CCW_H52A/Sequences/SeqAutoRunCCWH52A.cs index 349d214..3a14931 100644 --- a/Machines/ILSOS_CCW_H52A/Sequences/SeqAutoRunCCWH52A.cs +++ b/Machines/ILSOS_CCW_H52A/Sequences/SeqAutoRunCCWH52A.cs @@ -21,10 +21,12 @@ using ILSOS_CCW_H52A.RMS; using ILSOS_CCW_H52A.Sequences.ProcessObjects; using Microsoft.Win32; using OpenCvSharp; +using OpenCvSharp.Aruco; using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reactive.Subjects; using System.Reflection; using System.Threading; using System.Windows; @@ -107,6 +109,7 @@ namespace ILSOS_CCW_H52A.Sequences private SystemParameter _SystemParameter; private ScannerCanvasUserCtrl _ScannerCanvasUserCtrl; //스캐너 동작관련 객체 선언 + private int _RecipeNo; private int _ModelNo; private IRecipeManager _RecipeManager; @@ -117,9 +120,6 @@ namespace ILSOS_CCW_H52A.Sequences private SeqAutoRunCCWH52A_InitParam _InitParam; - private uint _TodayProduct; - private uint _TotalProduct; - private double _LaserPowerByLBAD; private bool _ModulationMode; @@ -141,7 +141,6 @@ namespace ILSOS_CCW_H52A.Sequences private double _WeldingStartAngle; private bool isTheFirstListExecute; - private int _RecipeNo; private bool UsePlcShotThemAll { get; set; } = false; private bool UsePlcPositionCompensation { get; set; } = false; @@ -283,8 +282,6 @@ namespace ILSOS_CCW_H52A.Sequences private bool InitSequenceVariable(SequenceContext context) { _AutoRunStartTime = DateTime.Now; - _TodayProduct = _SystemParameter.TodayProductCount; - _TotalProduct = _SystemParameter.TotalProductCount; var ActivateRecipeName = _RecipeManager.ActivatedRecipe(); Log.I($"Current Activate Recipe, ID : {ActivateRecipeName.Id}, Name : {ActivateRecipeName.Name}"); @@ -294,8 +291,9 @@ namespace ILSOS_CCW_H52A.Sequences _WeldingScannerListNo = eListNo.LIST1; + _RecipeNo = ActivateRecipeName.Id; var currentModelName = context.Recipes.ActivatedModelName(); - var modelItem = context.GetModel(currentModelName, CommonModelIds.EquipmentSpecificModel); + var modelItem = context.Models.ModelItem(currentModelName, CommonModelIds.EquipmentSpecificModel) as EquipmentSpecificModel_CCW_H52A; _ModelNo = modelItem.Model_No; return true; @@ -445,7 +443,7 @@ namespace ILSOS_CCW_H52A.Sequences // JigInfo 풀 스케줄러 초기화 (전전/전/대기/완료 셀 파이프라인) // ── 재시작 전 미완료 보고 보존 ─────────────────────────────────────────────── - // ReportTarget이 있는 상태로 정지가 들어오면 Reset() 후 슬롯이 Clear()되어 보고 불가. + // Complete가 있는 상태로 정지가 들어오면 Reset() 후 슬롯이 Clear()되어 보고 불가. // SavePendingComplete()로 _pendingSlot에 복사한 뒤 Reset()을 호출한다. _CellScheduler.SavePendingComplete(); @@ -563,7 +561,7 @@ namespace ILSOS_CCW_H52A.Sequences Log.I($"[Warmup] ScannerList {_WeldingCount}: pipeline not ready, skip complete check"); return SequenceAction.Ok(); } - if (!CheckCurrentEncoderAngle(jigComplete.StartAngle)) { + if (!CheckInsideWeldPosition(jigComplete.StartAngle)) { // IsCanExist=false(공 지그)는 리스트 실행은 하지만 용접이 없으므로 // 엔코더 범위를 벗어나도 에러가 아님 if (jigComplete.IsCanExist) { @@ -583,9 +581,7 @@ namespace ILSOS_CCW_H52A.Sequences TimeSpan weldInterval = jigComplete.WeldEndTime - _prevWeldEndTime; _prevWeldEndTime = jigComplete.WeldEndTime; - // 보고 대상 슬롯 지정 (스케줄러가 관리) - _CellScheduler.ReportTarget = jigComplete; - + // 보고 대상 지정 불필요 — Shift()가 Prefetch1 → Complete로 자동 전진 Log.I(string.Format("JigNo : {0}, Weld start : {1}, Weld End : {2}, WeldTime : {3}, interval : {4:F3}", jigComplete.JigNo, jigComplete.WeldStartTime.ToString("HH:mm:ss.fff"), @@ -597,8 +593,36 @@ namespace ILSOS_CCW_H52A.Sequences _PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE_1 + jigComplete.JigNo - 1, true); Log.I(string.Format($"PC_WELD_COMPLETE_{jigComplete.JigNo} -> true)")); } - UpdateProductCount(context); - UpdateProductInfoForView(); + + if (_SystemParameter.LastResetTime < DateTime.Now.Date) { + _SystemParameter.LastResetTime = DateTime.Now.Date; + Log.I($"Today Count Reset. {_SystemParameter.TodayProductCount} -> 0"); + _SystemParameter.TodayProductCount = 0; + } + + if (_SystemParameter.TodayProductCount < uint.MaxValue) { + _SystemParameter.TodayProductCount++; + } + if (_SystemParameter.TotalProductCount < uint.MaxValue) { + _SystemParameter.TotalProductCount++; + } + + Status.GetProcessingWeldingData().TotalProduct = _SystemParameter.TotalProductCount; + Status.GetProcessingWeldingData().TodayProduct = _SystemParameter.TodayProductCount; + Status.GetProcessingWeldingData().AutoRunStartTime = _AutoRunStartTime; + Status.GetProcessingWeldingData().RecipeNo = _RecipeNo; + Status.GetProcessingWeldingData().LaserPowerByLBAD = _LaserPowerByLBAD.ToString(); + + // 보고 데이터는 스케줄러의 ActiveReportSlot(Complete 또는 PendingComplete)에서 읽음 + var report = _CellScheduler.ActiveReportSlot; + if (report != null) { + Status.GetProcessingWeldingData().LotId = report.LotId; + Status.GetProcessingWeldingData().CellId = report.CellId; + Status.GetProcessingWeldingData().WeldingStartTime = report.WeldStartTime; + Status.GetProcessingWeldingData().WeldingEndTime = report.WeldEndTime; + Status.GetProcessingWeldingData().WeldingSpanTimeMilliseconds = report.WeldingSpanTime.TotalMilliseconds.ToString(); + Status.GetProcessingWeldingData().WeldingJigNo = report.JigNo.ToString(); + } SaveCellAPD(); } @@ -633,25 +657,37 @@ namespace ILSOS_CCW_H52A.Sequences return SequenceAction.Ok(); } - public bool CheckCurrentEncoderAngle(double startAngle) + /// + /// startAngle startAngle+45 + /// │←── OK 구간 ────►│ + /// ────┼─────────────────┼──────────────► 로터리 각도 + /// 리스트 여기까지 + /// 시작 와야 완료 체크 가능 + /// 판정 로직: + /// currentAngle < startAngle → Too early (아직 리스트 실행 중, 완료 체크 너무 이름) + /// startAngle ≤ current < start+45 → OK (정상 완료 구간) + /// currentAngle ≥ startAngle + 45 → Too late (너무 늦음, 타임오버 에러) + /// + /// 현재 지그의 시작 각도 + /// 지나갔으면 True + public bool CheckInsideWeldPosition(double startAngle) { double encoderX, currentAngle; - _Scanner.GetEncoder(out encoderX, out currentAngle, true); - if (0 < startAngle && currentAngle < 0) { - // Encoder 반전되는 순간이며, 이 때만 인터락 무시 + // Encoder 반전되는 순간이며, 이 때만 인터락 무시 + if (0 < startAngle && currentAngle < 0) + return false; + + if (startAngle <= currentAngle && currentAngle < startAngle + 45) { + Log.I(string.Format("Current encoder check OK, startAngle : {0}, currentAngle : {1})", startAngle, currentAngle)); + return true; } - else if (startAngle <= currentAngle) { - // 다음 리스트 구간이 끝나기 전까지는 완료가 되어야 한다 - if (currentAngle < startAngle + 45) { - Log.I(string.Format("Current encoder check OK, startAngle : {0}, currentAngle : {1})", startAngle, currentAngle)); - return true; - } else - Log.W(string.Format("Current encoder check NG(Too late), startAngle : {0}, currentAngle : {1})", startAngle, currentAngle)); - } - else + + if (currentAngle < startAngle) Log.W(string.Format("Current encoder check NG(Too early), startAngle : {0}, currentAngle : {1})", startAngle, currentAngle)); + else + Log.W(string.Format("Current encoder check NG(Too late), startAngle : {0}, currentAngle : {1})", startAngle, currentAngle)); return false; } @@ -717,12 +753,11 @@ namespace ILSOS_CCW_H52A.Sequences #warning OC2 ACW 기준 >> Cell Tracker는 어느 시점에 데이터는 주는지 모르겠지만, '전전전 셀' 쯤에서 이미 건네받음! 다른 프로젝트에서 확인 필요함 // 복원 우선: 정지 전 업로드됐으나 로터리 감속·정지로 용접 미완된 셀 정보 복원. // canExist=false 지그도 TryRestoreCell을 호출하여 슬롯 소비(폐기) — 이후 오염 방지. + (string LotId, string CellId) recvInfo = (string.Empty, string.Empty); if (_CellScheduler.TryRestoreCell(_WeldingJigNo, out var rLot, out var rCell)) { if (canExist) { - _CellScheduler.Prefetch2.LotId = rLot; - _CellScheduler.Prefetch2.CellId = rCell; - Status.GetProcessingWeldingData().WorkLotId = rLot; - Status.GetProcessingWeldingData().WorkCellId = rCell; + recvInfo.LotId = rLot; + recvInfo.CellId = rCell; Log.I($"[PendingRestore] Jig{_WeldingJigNo} 셀 복원 >> CellId({rCell})"); } else { @@ -730,25 +765,26 @@ namespace ILSOS_CCW_H52A.Sequences } } else if (canExist && ProcessManager.Instance.ReceivedCellInfoQueue.TryDequeue(out var cell)) { - _CellScheduler.Prefetch2.LotId = cell.LotId; - _CellScheduler.Prefetch2.CellId = cell.CellId; - Status.GetProcessingWeldingData().WorkLotId = cell.LotId; - Status.GetProcessingWeldingData().WorkCellId = cell.CellId; + recvInfo.LotId = cell.LotId; + recvInfo.CellId = cell.CellId; } else { _CellTracker.getDummyData(out string lotId, out string cellId); - _CellScheduler.Prefetch2.LotId = lotId; - _CellScheduler.Prefetch2.CellId = cellId; - Status.GetProcessingWeldingData().WorkLotId = lotId; - Status.GetProcessingWeldingData().WorkCellId = cellId; + recvInfo.LotId = lotId; + recvInfo.CellId = cellId; } + _CellScheduler.Prefetch2.LotId = recvInfo.LotId; + _CellScheduler.Prefetch2.CellId = recvInfo.CellId; + Status.GetProcessingWeldingData().WorkLotId = recvInfo.LotId; + Status.GetProcessingWeldingData().WorkCellId = recvInfo.CellId; + if (_CellScheduler.Prefetch2 != null) - Log.I($"상태 시프트(Rotate) >> 용접 전전셀({_CellScheduler.Prefetch2.CellId}) [CanExist({_CellScheduler.Prefetch2.IsCanExist})] [JigNo({_CellScheduler.Prefetch2.JigNo})] " + + Log.I($"Prefetch2 >> CellId({_CellScheduler.Prefetch2.CellId}) [CanExist({_CellScheduler.Prefetch2.IsCanExist})] [JigNo({_CellScheduler.Prefetch2.JigNo})] " + $"[ListNo({_CellScheduler.Prefetch2.ListNo})] [WeldingCount({_CellScheduler.Prefetch2.WeldingCount})]" + $"[StartAngle(Y)({_CellScheduler.Prefetch2.StartAngle})]"); if(_CellScheduler.Prefetch1 != null) - Log.I($"이번 용접대상 >> 용접 전셀({_CellScheduler.Prefetch1.CellId}) [CanExist({_CellScheduler.Prefetch1.IsCanExist})] [JigNo({_CellScheduler.Prefetch1.JigNo})] " + + Log.I($"Prefetch1 >> CellId({_CellScheduler.Prefetch1.CellId}) [CanExist({_CellScheduler.Prefetch1.IsCanExist})] [JigNo({_CellScheduler.Prefetch1.JigNo})] " + $"[ListNo({_CellScheduler.Prefetch1.ListNo})] [WeldingCount({_CellScheduler.Prefetch1.WeldingCount})]" + $"[StartAngle(Y)({_CellScheduler.Prefetch1.StartAngle})]"); @@ -764,9 +800,6 @@ namespace ILSOS_CCW_H52A.Sequences } #endregion - _RecipeNo = _RecipeManager.ActivatedRecipe().Id; - - SetWeldingData(); return SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ; } else { @@ -786,20 +819,6 @@ namespace ILSOS_CCW_H52A.Sequences return null; } - private void SetWeldingData() - { - ScannerParam laserParam = null; - laserParam = GetSelectedDrawObjectData(_SelectedDrawObjectList[0]); - - if (laserParam != null) { - // EDC 보내는 용도 - Status.GetProcessingWeldingData().LaserPowerCore = laserParam.LaserPower1.ToString(); - Status.GetProcessingWeldingData().LaserPowerRing = laserParam.LaserPower2.ToString(); - Status.GetProcessingWeldingData().MarkSpeed = laserParam.MarkSpeed.ToString(); - Status.GetProcessingWeldingData().FocalLength = (_PLC.ReadDWord((int)eWordInput.PLC_WELDING_FOCAL_LENGTH).data / 1000f).ToString(); - Status.GetProcessingWeldingData().WeldingJigNo = _WeldingJigNo.ToString(); - } - } public void WaitForEncoderNextRotarySection(int weldingCount, int rotaryJigCount, double rotaryAngleOffset, double encoderResetOffset, out double sectionStartAngle) { @@ -833,28 +852,7 @@ namespace ILSOS_CCW_H52A.Sequences public bool GetRotaryCanExist(int jigNo) { - #region 지그 16개 요청기록 로그 남기기, 빠져나간 캔에 대한 Complete Bit 초기화 - //string result = ""; - - //for (int i = 1; i <= _RotaryJigCount; i++) { - // if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + i).data) - // result += "1, "; - // else { - // result += "0, "; - - // string outId = string.Format("PC_WELD_COMPLETE_{0}", i); - - // if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + i).data) { - // _PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE_1 + i, false); - // Log.I(string.Format($"PC_WELD_COMPLETE_{1 + i} -> FALSE)")); - // } - // } - //} - //UtilUnit.logUnit.SetLog(LogUnit.eLogType.DEBUG, MethodBase.GetCurrentMethod().Name, string.Format("PLC -> PC 용접 Cmd : ({0})", result)); - #endregion - if (jigNo <= _RotaryJigCount) - //return m_rscPlc.GetDIStatus(string.Format("PLC_USE_WELD_JIG_{0}", jigNo)); return _PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + (jigNo - 1)).data; else return false; @@ -884,14 +882,22 @@ namespace ILSOS_CCW_H52A.Sequences return SequenceAction.ForceStopByAlarm(AlarmCode.ALARM_SEQUENCE_UploadWeldingList_ResultFailed); //return null; } - // 입력한 Scanner List를 완료대기열에 추가 - // Won : GetProcessingWeldingData().WorkLotId 는 CellTrakcer로 부터 받은 상태의 LotId - // GetProcessingWeldingData().LotId 는 AutorunView에 표기할 용접이 완료 된 LotID - string LotId = Status.GetProcessingWeldingData().WorkLotId; // CellTracker로 부터 WorkLotID, WorkCellID 받는 구문 추가 후 해당 데이터로 입력 필요 - string CellId = Status.GetProcessingWeldingData().WorkCellId; + ScannerParam laserParam = null; + laserParam = GetSelectedDrawObjectData(_SelectedDrawObjectList[0]); - _CellScheduler.Prefetch2.LotId = LotId; - _CellScheduler.Prefetch2.CellId = CellId; + _CellScheduler.Prefetch2.InnerCellInfo.RecipeNo = _RecipeNo; + _CellScheduler.Prefetch2.InnerCellInfo.LaserPowerCore = laserParam.LaserPower1.ToString(); + _CellScheduler.Prefetch2.InnerCellInfo.LaserPowerRing = laserParam.LaserPower2.ToString(); + _CellScheduler.Prefetch2.InnerCellInfo.MarkSpeed = laserParam.MarkSpeed.ToString(); + _CellScheduler.Prefetch2.InnerCellInfo.FocalLength = (_PLC.ReadDWord((int)eWordInput.PLC_WELDING_FOCAL_LENGTH).data / 1000f).ToString(); + _CellScheduler.Prefetch2.InnerCellInfo.WeldingJigNo = _WeldingJigNo.ToString(); + + // 업로드 성공 확인 후 뷰/EDC용 Status 갱신 (ReadyScannerList에서 중복 갱신 제거) + Status.GetProcessingWeldingData().LaserPowerCore = laserParam.LaserPower1.ToString(); + Status.GetProcessingWeldingData().LaserPowerRing = laserParam.LaserPower2.ToString(); + Status.GetProcessingWeldingData().MarkSpeed = laserParam.MarkSpeed.ToString(); + Status.GetProcessingWeldingData().FocalLength = _CellScheduler.Prefetch2.InnerCellInfo.FocalLength; + Status.GetProcessingWeldingData().WeldingJigNo = _WeldingJigNo.ToString(); Log.FuncI("CellTracker Load"); return SequenceAction.Ok(); } @@ -948,7 +954,6 @@ namespace ILSOS_CCW_H52A.Sequences private SequenceActionResult EncoderMonitor(SequenceContext context, string id, SequenceActionResult param) { double send_time_offset = 0.1; - string LotID = "", CellID = ""; while (!context.Stopped) { double encoderX, currentAngle; @@ -968,15 +973,13 @@ namespace ILSOS_CCW_H52A.Sequences Log.I($"Fork Before Min Rotate Encoder X : ({encoderX}), Encoder Y : ({currentAngle}), PLC Rotary : ({CurrentPosPLC}), List {executeTarget.ListNo}, JigNo : ({executeTarget.JigNo})"); if (!_SystemParameter.BypassModeLBAD) { if (!executeTarget.CheckSendCellinfo) { - LotID = executeTarget.LotId; - CellID = executeTarget.CellId; if (currentAngle > executeTarget.StartAngle) { - executeTarget.CheckSendCellinfo = _StreamLightLBAD.SendCellInfo(LotID, CellID, _RecipeNo, _ModelNo, executeTarget.JigNo); + executeTarget.CheckSendCellinfo = _StreamLightLBAD.SendCellInfo(executeTarget.LotId, executeTarget.CellId, _RecipeNo, _ModelNo, executeTarget.JigNo); if (!executeTarget.CheckSendCellinfo) - Log.I($"[LBAD Interface]SendCellInfo null, LotID [{LotID}], CellID [{CellID}], JigNo [{executeTarget.JigNo}]"); + Log.I($"[LBAD Interface]SendCellInfo null, LotID [{executeTarget.LotId}], CellID [{executeTarget.CellId}], JigNo [{executeTarget.JigNo}]"); else - Log.I($"[StreamLight]SendCellInfo LotID [{LotID}], CellID [{CellID}], JigNo [{executeTarget.JigNo}]"); + Log.I($"[StreamLight]SendCellInfo LotID [{executeTarget.LotId}], CellID [{executeTarget.CellId}], JigNo [{executeTarget.JigNo}]"); } } } @@ -1015,46 +1018,6 @@ namespace ILSOS_CCW_H52A.Sequences return SequenceAction.Ok(); } - private void UpdateProductCount(SequenceContext context) - { - if (_SystemParameter.LastResetTime < DateTime.Now.Date) { - _SystemParameter.LastResetTime = DateTime.Now.Date; - Log.I($"Today Count Reset. {_SystemParameter.TodayProductCount} -> 0"); - _SystemParameter.TodayProductCount = 0; - } - - _TodayProduct = _SystemParameter.TodayProductCount; - _TotalProduct = _SystemParameter.TotalProductCount; - if (_TodayProduct < uint.MaxValue) { - _TodayProduct++; - } - if (_TotalProduct < uint.MaxValue) { - _TotalProduct++; - } - _SystemParameter.TodayProductCount = _TodayProduct; - _SystemParameter.TotalProductCount = _TotalProduct; - } - - private void UpdateProductInfoForView() - { - Status.GetProcessingWeldingData().TotalProduct = _TotalProduct; - Status.GetProcessingWeldingData().TodayProduct = _TodayProduct; - Status.GetProcessingWeldingData().AutoRunStartTime = _AutoRunStartTime; - Status.GetProcessingWeldingData().RecipeNo = _RecipeNo; - Status.GetProcessingWeldingData().LaserPowerByLBAD = _LaserPowerByLBAD.ToString(); - - // 보고 데이터는 스케줄러의 ActiveReportSlot(ReportTarget 또는 PendingComplete)에서 읽음 - var report = _CellScheduler.ActiveReportSlot; - if (report != null) { - Status.GetProcessingWeldingData().LotId = report.LotId; - Status.GetProcessingWeldingData().CellId = report.CellId; - Status.GetProcessingWeldingData().WeldingStartTime = report.WeldStartTime; - Status.GetProcessingWeldingData().WeldingEndTime = report.WeldEndTime; - Status.GetProcessingWeldingData().WeldingSpanTimeMilliseconds = report.WeldingSpanTime.TotalMilliseconds.ToString(); - Status.GetProcessingWeldingData().WeldingJigNo = report.JigNo.ToString(); - } - } - private SequenceActionResult ReportCellResult(SequenceContext context, string id, SequenceActionResult param) { Status.SetWorkingPosition(eWorkingPosition.REPORTING_RESULT); @@ -1062,7 +1025,11 @@ namespace ILSOS_CCW_H52A.Sequences string strDate = DateTime.Now.Date.ToString("yyyyMMdd"); string strTime = DateTime.Now.ToString("HHmmss"); + // 셀 식별 정보는 스케줄러 슬롯에서 직접 읽음 (Complete 또는 pendingSlot) + var report = _CellScheduler.ActiveReportSlot; + // 레시피·장비 계측값은 Status에서 읽음 (TodayProduct/TotalProduct 포함) var wd = Status.GetProcessingWeldingData(); + string reportDataLocalPath = _CellTracker._CellTrackerConfig.reportDataLocalPath; string equipName = _CellTracker._CellTrackerConfig.EquipmentName; @@ -1085,23 +1052,23 @@ namespace ILSOS_CCW_H52A.Sequences equipName + "DATA007={10}," + equipName + "DATA008={11}," + equipName + "DATA009={12}", - strDate, strTime, wd.LotId, wd.CellId, - wd.RecipeNo, wd.LaserPowerCore, wd.MarkSpeed, wd.FocalLength, - wd.WeldingJigNo, wd.WeldingSpanTimeMilliseconds, wd.LaserPowerByLBAD, + strDate, strTime, report.LotId, report.CellId, + report.InnerCellInfo.RecipeNo, report.InnerCellInfo.LaserPowerCore, report.InnerCellInfo.MarkSpeed, report.InnerCellInfo.FocalLength, + report.JigNo, report.WeldingSpanTime.TotalMilliseconds.ToString(), wd.LaserPowerByLBAD, wd.TodayProduct, wd.TotalProduct); - _CellTracker.SendEcsData(wd.CellId, strPath, strData + ""); - Log.I($"Report to CellTracker >> [LotID({wd.LotId.Replace("\0", "").Trim()})] [CellID({wd.CellId.Replace("\0", "").Trim()})]"); + _CellTracker.SendEcsData(report.CellId, strPath, strData + ""); + Log.I($"Report to CellTracker >> [LotID({report.LotId})] [CellID({report.CellId})]"); // 로컬 CSV 저장 string strItem = "//Date, Time, LotID, CellID, RecipeNo, LaserPower, MarkSpeed, FocalLength, HeadNo, WeldingTime, LaserPowerByLBAD, TodayCount, TotalCount"; string strCsvData = string.Format("{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {12}", - strDate, strTime, wd.LotId, wd.CellId, - wd.RecipeNo, wd.LaserPowerCore, wd.MarkSpeed, wd.FocalLength, - wd.WeldingJigNo, wd.WeldingSpanTimeMilliseconds, wd.LaserPowerByLBAD, + strDate, strTime, report.LotId, report.CellId, + report.InnerCellInfo.RecipeNo, report.InnerCellInfo.LaserPowerCore, report.InnerCellInfo.MarkSpeed, report.InnerCellInfo.FocalLength, + report.JigNo, report.WeldingSpanTime.TotalMilliseconds.ToString(), wd.LaserPowerByLBAD, wd.TodayProduct, wd.TotalProduct); WeldingCommon.Utils.ExcelManagementUnit.AppendStringInCSV(strPath, strItem, strCsvData); - // 보고 완료: ReportTarget.ReportComplete=true 설정 + pendingSlot 클리어 + // 보고 완료: Complete.ReportComplete=true 설정 + pendingSlot 클리어 _CellScheduler.CompleteReport(); return SequenceAction.Ok(); @@ -1151,7 +1118,7 @@ namespace ILSOS_CCW_H52A.Sequences private string CheckCanWelded(SequenceContext context, string id, ICollection branches, SequenceActionResult param) { // ── 재시작 전 미완료 보고 우선 처리 ───────────────────────────────────────── - // SavePendingComplete()로 보존된 슬롯이 있으면 정상 파이프라인(ReportTarget)보다 우선. + // SavePendingComplete()로 보존된 슬롯이 있으면 정상 파이프라인(Complete)보다 우선. if (_CellScheduler.HasPendingComplete) { var p = _CellScheduler.PendingComplete; Log.I($"[PendingReport] 재시작 전 미완료 보고: LotId={p.LotId}, CellId={p.CellId}, JigNo={p.JigNo}"); @@ -1160,8 +1127,8 @@ namespace ILSOS_CCW_H52A.Sequences // ───────────────────────────────────────────────────────────────────────────── // 정상 보고 경로: - // - ReportTarget이 설정돼 있고 아직 보고 완료되지 않은 경우 - // - 첫번째, 두번째 반복은 SetReportTarget이 호출되지 않으므로 자연스럽게 통과 + // - Complete(Shift로 자동 승격)에 용접 완료된 셀이 있고 아직 보고 미완인 경우 + // - 예열 구간(Complete=null 또는 WeldComplete=false)은 자연스럽게 통과 if (_CellScheduler.HasReport) return SEQ_REPORT_CELL_RESULT; diff --git a/Machines/ILSOS_CCW_H52A/Sequences/SeqAutoRunRMOTF.cs b/Machines/ILSOS_CCW_H52A/Sequences/SeqAutoRunRMOTF.cs deleted file mode 100644 index d8fa028..0000000 --- a/Machines/ILSOS_CCW_H52A/Sequences/SeqAutoRunRMOTF.cs +++ /dev/null @@ -1,1218 +0,0 @@ -using Aurora; -using Aurora.Api; -using Aurora.Api.Manager; -using Aurora.View; -using AuroraCellTracker; -using AuroraIO; -using AuroraLaser; -using AuroraLaserScanner; -using AuroraLBAD.Service; -using CoreUnit.Common; -using CoreUnit.Control.UserControl.Canvas; -using CoreUnit.Scanner.UserControl.ScannerCanvas; -using DB; -using Hermes; -using ILSOS_CCW_H52A.Device; -using ILSOS_CCW_H52A.Models; -using ILSOS_CCW_H52A.RMS; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Windows; -using WeldingCommon; -using WeldingCommon.Alarm; -using WeldingCommon.Recipes; -using WeldingCommon.Sequences; -using WeldingCommon.Settings; -using WeldingCommon.Utils; -using static AuroraLBAD.Service.StreamLightLBAD; -using static ILSOS_CCW_H52A.Device.IOController_CCW_H52A; -using static ILSOS_CCW_H52A.Device.PLCControllerCCWH52A; -using static ILSOS_CCW_H52A.Device.ScannerListCCWH52A; - -namespace ILSOS_CCW_H52A.Sequences -{ - public class SeqAutoRunRMOTF - { - static readonly Logger Log = new Logger("SeqAutoRunRMOTF"); - - const string SEQ_ENTER = "SEQ_ENTER"; // inputParam 으로 받자. - const string SEQ_CHECK_INIT_CONDITION = "Check Init Condition"; // Check Init Condition - - const string SEQ_FORK_ENCODER_MONITOR = "Fork Encoder Monitor"; - const string SEQ_ENCODER_MONITOR = "Check Encoder Monitor"; - const string SEQ_JOIN_ENCODER_MONITOR = "Join Encoder Monitor"; - - // TODO: [장비구현필요] 실제 공정 추가 - const string SEQ_CHECK_LOAD_COMPLETE = "Check Load Complete"; - - const string SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ = "Set Sequence Param (UploadWeldingList Seq)"; - const string SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ = "Process (UploadWeldingList Seq)"; - const string SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ = "Get Sequence Result (UploadWeldingList Seq)"; - - public const string SEQ_CHECK_SCANNER_LIST_COMPLETE = "Check Scanner List Complete"; - const string SEQ_READY_SCANNER_LIST = "Ready ScannerList"; - - const string SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ = "Set Sequence Param (ReceiveCellInfo Seq)"; - const string SEQ_DO_ID_RECEIVE_CELL_INFO_SEQ = "Process (ReceiveCellInfo Seq)"; - const string SEQ_GET_PARAMS_RECEIVE_CELL_INFO_SEQ = "Get Sequence Result (ReceiveCellInfo Seq)"; - - const string SEQ_EXECUTE_WELDING = "Execute Welding"; - const string SEQ_REQUEST_UNLOAD_CELL = "Request Unload Cell"; - //const string SEQ_WAIT_LBAD_JUDGE = "Wait LBAD Judge"; - - const string SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ = "Set Sequence Param (ReportCellResult Seq)"; - const string SEQ_DO_ID_REPORT_CELL_RESULT_SEQ = "Process (ReportCellResult Seq)"; - const string SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ = "Get Sequence Result (ReportCellResult Seq)"; - - //const string SEQ_REPORT_CELLINFO_TO_PLC = "ReportCellInfoToPLC"; - const string SEQ_CHECK_CYCLE_STOP = "Check Cycle Stop"; - const string SEQ_CHECK_CAN_WELDED = "Check Can Welded"; - - const string SEQ_SAVE_RESULT_DATA = "Save Result Data"; - - const string SEQ_WRITE_COMPLETION_PLC_BIT = "Write Completion PLC Bit"; - const string SEQ_INIT_CONDITION_ERROR = "Init Condition Error"; - const string SEQ_COMPLETE = "SEQ_COMPLETE"; // 완료 - - static class ContextKey - { - public const string KEY_SEQUENCE_RESULT = "KEY_SEQUENCE_RESULT_SeqAutoRunCCWH52A"; - public const string KEY_SEQUENCE_START_TIME = "KEY_SEQUENCE_START_TIME_SeqAutoRunCCWH52A"; - public const string KEY_SEQUENCE_ERROR_CODE = "KEY_SEQUENCE_ERROR_CODE_SeqAutoRunCCWH52A"; - } - - const int PLC_TIMEOUT = 60; // sec, Timeout은 시퀀스 정지가 아니라 타임아웃 시간마다 로그만 남기도록 한다 - - private Scanner _Scanner; - private LaserDevice _Laser; - - private PLCControllerCCWH52A _PLC; - private IODevice _IO; - private StreamLightLBAD _StreamLightLBAD; - private static CellTracker _CellTracker; - - private SystemParameter _SystemParameter; - private ScannerCanvasUserCtrl _ScannerCanvasUserCtrl; //스캐너 동작관련 객체 선언 - - private string _LotId = "N/A"; - private string _CellId = "N/A"; - private int _ModelNo; - - private IRecipeManager _RecipeManager; - - private eListNo _WeldingScannerListNo; - - private List _SelectedDrawObjectList; - - private SeqAutoRunCCWH52A_InitParam _InitParam; - - private uint _TodayProduct; - private uint _TotalProduct; - - private double _LaserPowerByLBAD; - private int _CompletedJigNo; - private static bool isWeled; - - private bool _ModulationMode; - - private DateTime _AutoRunStartTime; - private DateTime _WeldingStartTime; - private TimeSpan _WeldingSpanTime; - private DateTime _WeldEndTime; - private TimeSpan _InterfaceSpanTime; - private DateTime _InterfaceStartTime; - - private double _CellMeasureCenterOffsetX; - private double _CellMeasureCenterOffsetY; - - // MOTF - private TimeSpan _WeldInterval; - - private int _LastScannerParamNo = -1; //마지막 작업한 스캔 변수값들이 현재 작업하려는 스캔 변수값과 같은지 판단함(같으면 설정작업을 skip함) - private int _EncoderOverflowCount = 0; - - private double _RotaryEncoderOffset = 0; - private int _WeldingJigNo = -1; - private int _WeldingCount = 0; - private int _RotaryJigCount = 16; - - private double _WeldingStartAngle; - - private bool isTheFirstListWrite; - private bool isTheSecondListWrite; - private bool isTheFirstListExecute; - private int _RecipeNo; - - private bool UsePlcShotThemAll { get; set; } = false; - private bool UsePlcPositionCompensation { get; set; } = false; - private string RecipeFileName { get; set; } = ""; - private enum InitErrorList - { - SUCCESS = 0, - LBAD_CLIENT_ACTIVATE_FAILED, - LBAD_SUB_ACTIVATE_FAILED, - LASER_INIT_ERROR, - PLC_AUTORUN_BIT_OFF, - MOTF_OFF, - PLC_ALARM, - } - public SequenceBuilder Builder() - { - var sb = new SequenceBuilder(1000, true); - - sb.AddAction(SEQ_ENTER, Sequence_Enter); - sb.AddDecision(SEQ_CHECK_INIT_CONDITION, CheckInitCondition); //분기 - - sb.AddFork(SEQ_FORK_ENCODER_MONITOR); - sb.AddAction(SEQ_ENCODER_MONITOR, EncoderMonitor); - sb.AddJoin(SEQ_JOIN_ENCODER_MONITOR); - - sb.AddAction(SEQ_CHECK_LOAD_COMPLETE, CheckLoadComplete); - - sb.AddAction(SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ, SetReceiveCellInfo_SeqParams); // Cell 정보를 받아와 입력한다. - sb.AddSubsequence(SEQ_DO_ID_RECEIVE_CELL_INFO_SEQ, SequenceManager.GetSeqBuilder_SeqReceiveCellInfo()); // cell 정보를 받아오는 Sub Seq 실행 - sb.AddAction(SEQ_GET_PARAMS_RECEIVE_CELL_INFO_SEQ, GetReceiveCellInfo_SeqResult); // Cell 정보를 가져온다 - - sb.AddAction(SEQ_CHECK_SCANNER_LIST_COMPLETE, CheckScannerListComplete); - sb.AddDecision(SEQ_READY_SCANNER_LIST, ReadyScannerList); - - sb.AddAction(SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ, SetUploadWeldingList_SeqParams); - sb.AddSubsequence(SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ, SequenceManager.GetSeqBuilder_SeqUploadWeldingList()); - sb.AddAction(SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ, GetUploadWeldingList_SeqResult); - - sb.AddAction(SEQ_EXECUTE_WELDING, ExecuteWelding); - sb.AddAction(SEQ_REQUEST_UNLOAD_CELL, RequestUnloadCell); - - sb.AddAction(SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ, SetReportCellResult_SeqParams); - sb.AddSubsequence(SEQ_DO_ID_REPORT_CELL_RESULT_SEQ, SequenceManager.GetSeqBuilder_SeqReportCellResult()); - sb.AddAction(SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ, GetReportCellResult_SeqResult); - - sb.AddDecision(SEQ_CHECK_CYCLE_STOP, CheckCycleStop); - sb.AddDecision(SEQ_CHECK_CAN_WELDED, CheckCanWelded); - - sb.AddAction(SEQ_SAVE_RESULT_DATA, SaveResultData); // 해당 공정의 정보를 기록 함. - sb.AddAction(SEQ_WRITE_COMPLETION_PLC_BIT, WriteCompletionPLCBit); // 정상적으로 종료 되면, complete bit write - sb.AddAction(SEQ_INIT_CONDITION_ERROR, InitConditionError); - sb.AddAction(SEQ_COMPLETE, Complete); - - sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_FORK_ENCODER_MONITOR] > sb[SEQ_CHECK_LOAD_COMPLETE] - > sb[SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ] > sb[SEQ_DO_ID_RECEIVE_CELL_INFO_SEQ] > sb[SEQ_GET_PARAMS_RECEIVE_CELL_INFO_SEQ] - > sb[SEQ_CHECK_SCANNER_LIST_COMPLETE] > sb[SEQ_READY_SCANNER_LIST] - > sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ] - > sb[SEQ_EXECUTE_WELDING] > sb[SEQ_REQUEST_UNLOAD_CELL] > sb[SEQ_CHECK_CAN_WELDED] - > sb[SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ] > sb[SEQ_DO_ID_REPORT_CELL_RESULT_SEQ] > sb[SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ] - > sb[SEQ_SAVE_RESULT_DATA] > sb[SEQ_CHECK_CYCLE_STOP] - > sb[SEQ_WRITE_COMPLETION_PLC_BIT] > sb[SEQ_JOIN_ENCODER_MONITOR] > sb[SEQ_COMPLETE]); - - sb.Flows(sb[SEQ_READY_SCANNER_LIST] > sb[SEQ_EXECUTE_WELDING]); - - sb.Flows(sb[SEQ_CHECK_CAN_WELDED] > sb[SEQ_CHECK_CYCLE_STOP]); // 용접을 하지 않은 Cell은 상위보고 하지 않는다. - sb.Flows(sb[SEQ_CHECK_CYCLE_STOP] > sb[SEQ_CHECK_LOAD_COMPLETE]); - - sb.Flows(sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_INIT_CONDITION_ERROR] > sb.Final); - sb.Flows(sb[SEQ_FORK_ENCODER_MONITOR] > sb[SEQ_ENCODER_MONITOR] > sb[SEQ_JOIN_ENCODER_MONITOR] > sb[SEQ_COMPLETE]); - - #region - //sb.Flows(sb[SEQ_FORK_ENCODER_MONITOR] > sb[SEQ_ENCODER_MONITOR]); - ////sb.Flows(sb[SEQ_FORK_ENCODER_MONITOR] > sb[SEQ_CHECK_LOAD_COMPLETE]); - //sb.Flows(sb[SEQ_JOIN_ENCODER_MONITOR] > sb[SEQ_COMPLETE]); - /// - //// 1. 시퀀스 시작 ~ 포크 - //sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_FORK_ENCODER_MONITOR]); - - //// 2. Fork 이후 메인 루트 - //sb.Flows(sb[SEQ_FORK_ENCODER_MONITOR] > sb[SEQ_CHECK_LOAD_COMPLETE]); - //sb.Flows(sb[SEQ_CHECK_LOAD_COMPLETE] > sb[SEQ_CHECK_SCANNER_LIST_COMPLETE]); - //sb.Flows(sb[SEQ_CHECK_SCANNER_LIST_COMPLETE] > sb[SEQ_READY_SCANNER_LIST]); - //sb.Flows(sb[SEQ_READY_SCANNER_LIST] > sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ]); - //sb.Flows(sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ]); - //sb.Flows(sb[SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ]); - //sb.Flows(sb[SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_EXECUTE_WELDING]); - //sb.Flows(sb[SEQ_EXECUTE_WELDING] > sb[SEQ_REQUEST_UNLOAD_CELL]); - //sb.Flows(sb[SEQ_REQUEST_UNLOAD_CELL] > sb[SEQ_CHECK_CYCLE_STOP]); - //sb.Flows(sb[SEQ_CHECK_CYCLE_STOP] > sb[SEQ_SAVE_RESULT_DATA]); - //sb.Flows(sb[SEQ_SAVE_RESULT_DATA] > sb[SEQ_WRITE_COMPLETION_PLC_BIT]); - //sb.Flows(sb[SEQ_WRITE_COMPLETION_PLC_BIT] > sb[SEQ_JOIN_ENCODER_MONITOR]); - - //// 3. Fork 이후 병렬 브랜치 - //sb.Flows(sb[SEQ_FORK_ENCODER_MONITOR] > sb[SEQ_ENCODER_MONITOR]); - //sb.Flows(sb[SEQ_ENCODER_MONITOR] > sb[SEQ_JOIN_ENCODER_MONITOR]); - - //// 4. Join 이후 Complete - //sb.Flows(sb[SEQ_JOIN_ENCODER_MONITOR] > sb[SEQ_COMPLETE]); - - //// 5. 에러 분기/종료 - //sb.Flows(sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_INIT_CONDITION_ERROR] > sb.Final); - - //// 6. 루프, 분기(선택적) - //sb.Flows(sb[SEQ_READY_SCANNER_LIST] > sb[SEQ_EXECUTE_WELDING]); - //sb.Flows(sb[SEQ_CHECK_CYCLE_STOP] > sb[SEQ_CHECK_LOAD_COMPLETE]); - #endregion - sb.OnStopped(OnStopped); - sb.OnForceError(OnForceError); - - sb.Draw("SeqAutoRunRMOTF.pdf"); - - return sb; - } - - private SequenceActionResult Sequence_Enter(SequenceContext context, string id, SequenceActionResult param) - { - Log.I("SeqAutoRunRMOTF Start"); - Status.SetWorkingPosition(eWorkingPosition.CHECKING_CONDITION); - - _InitParam = param.Param as SeqAutoRunCCWH52A_InitParam; - _RecipeManager = Application.Current.AuroraEnv().RecipeManager; - _SystemParameter = context.GetSetting(CommonSettingIds.SystemParameter); - - InitDev(context); - if (!CheckDeviceReady(context)) { - //Check Device - Log.E("The devices are not active."); - return SequenceAction.ForceStopByAlarm(AlarmCode.ALARM_SEQUENCE_AutoRun_DeviceNotReady); - } - if (InitSequenceVariable(context) == false) { - return SequenceAction.ForceStopByAlarm(AlarmCode.ALARM_SEQUENCE_AutoRun_InitVariableError); - } - Thread.Sleep(1); // 부하 방지 - return SequenceAction.Ok(); - } - - private bool InitSequenceVariable(SequenceContext context) - { - _AutoRunStartTime = DateTime.Now; - _TodayProduct = _SystemParameter.TodayProductCount; - _TotalProduct = _SystemParameter.TotalProductCount; - - var ActivateRecipeName = _RecipeManager.ActivatedRecipe(); - Log.I($"Current Activate Recipe, ID : {ActivateRecipeName.Id}, Name : {ActivateRecipeName.Name}"); - - var mainPage = WeldingRecipeManager.GetWeldingPage(); - _ScannerCanvasUserCtrl = mainPage.ScannerCanvasCtrlAutoPage; - - _WeldingScannerListNo = eListNo.LIST1; - - _CellMeasureCenterOffsetX = 0.0; - _CellMeasureCenterOffsetY = 0.0; - - var currentModelName = context.Recipes.ActivatedModelName(); - var modelItem = context.GetModel(currentModelName, CommonModelIds.EquipmentSpecificModel); - _ModelNo = modelItem.Model_No; - - return true; - } - - private void InitDev(SequenceContext context) - { - //Device Init - _Scanner = context.GetLaserScanner(); - _Laser = context.GetLaser(); - if (_InitParam.UseStream) { - _StreamLightLBAD = new StreamLightLBAD(); - _StreamLightLBAD._Client = context.GetStreamLightClient(); - _StreamLightLBAD._Sub = context.GetStreamLightSub(); - } - _CellTracker = context.GetCellTracker(); - _PLC = context.Devices[DeviceIds.PLCDevice] as PLCControllerCCWH52A; - _IO = context.GetIOUnit(); - } - - private bool CheckDeviceReady(SequenceContext context) - { - List deviceListToCheck = new List() { CommonDeviceIds.Scanner, CommonDeviceIds.Laser, CommonDeviceIds.PLCDevice, CommonDeviceIds.IODevice }; - - if (_InitParam.UseStream) { - deviceListToCheck.Add(CommonServiceIds.StreamLightLBADClient); - deviceListToCheck.Add(CommonServiceIds.StreamLightLBADSub); - } - - bool isAllDeviceActivated = true; - foreach (string item in deviceListToCheck) { - if (!context.Devices[item].IsActivated) { - isAllDeviceActivated = isAllDeviceActivated && false; - } - } - - return isAllDeviceActivated; - } - - private bool CheckCondition(SequenceContext context) - { - int InitializeCode = InitializeDeviceStatus(context); - if (InitializeCode == (int)InitErrorList.SUCCESS) - return true; - else - context.PutValue(ContextKey.KEY_SEQUENCE_ERROR_CODE, InitializeCode); - return false; - } - - private int InitializeDeviceStatus(SequenceContext context) - { - // PLC Interface AutoStatus Start - // Won : PC의 AutoStatus 가 True 되는 순간 Rotary가 돌기 시작한다. - // Rotary 돌기 시작 한 후 Encoder 값을 읽으면 안 되므로 정지상태에서 읽은 후 AutoStatus true 하도록 - // InitAutoRunBit 시점 변경 - //InitAutoRunBit(); - // LBAD Initialize - // LBAD 는 server 이기 때문에, 만약 끊어졌으면 다시 접속이 필요함 - if (_SystemParameter.BypassModeLBAD == false) { - if (!_StreamLightLBAD._Client.IsActivated) { - int ret = _StreamLightLBAD._Client.Activate(); - Thread.Sleep(500); - if (ret != E1.OK) { - Log.E($"StreamLightClient activate failed"); - return (int)InitErrorList.LBAD_CLIENT_ACTIVATE_FAILED; - } - } - - if (_StreamLightLBAD._Sub.IsActivated == false) { - int ret = _StreamLightLBAD._Sub.Activate(); - Thread.Sleep(500); - if (ret != E1.OK) { - Log.E($"StreamLightSub activate failed"); - return (int)InitErrorList.LBAD_SUB_ACTIVATE_FAILED; - } - } - _StreamLightLBAD.Initialize(); - if (_StreamLightLBAD.SendReadyStatus(eRequestData.Ready_On) == false) { - Log.I(string.Format($"[LBAD Interface]CheckReadyStatus null")); - //return false; - } - } - - // Laser Initialize - _Laser.PilotLaserOff(); - _Laser.LaserOn(); - Thread.Sleep(500); - if (!_Laser.GetLaserReady()) { - Log.E("ERROR Initialize Laser"); - return (int)InitErrorList.LASER_INIT_ERROR; - } - // Scanner Initialize - if (_Scanner.GetModulationMode()) { - _ModulationMode = true; - } else { - _ModulationMode = false; - } - - //// PLC Initialize AutoRun Bit 최소화 작업 진행 - if (_PLC.ReadBit((int)eBitInput.PLC_AUTO_STATUS).data == false) // AutoRun Bit가 OFF인 경우 - { - if (_PLC.ReadBit((int)eBitInput.PLC_AUTO_REQ).data == false) // AutoRun Request 상태 체크 - { - Log.E(string.Format("ERROR Initialize PLC, PLC Alarm ON")); // AutoRun Request와 AutoRun Bit 모두 OFF인 경우, PLC 측에서 Alarm 발생함. - return (int)InitErrorList.PLC_ALARM; - } else { - Log.E(string.Format("ERROR Initialize PLC, Bit Off PLC_AUTO_STATUS")); // AutoRun Request가 ON인데 AutoRun Bit 모두 OFF인 경우, PLC에서 AutoRun Bit를 켜지 않음. - return (int)InitErrorList.PLC_AUTORUN_BIT_OFF; - } - } - - // Marking On The Flying Off - if (_Scanner.Config.UseMarkingOnTheFly == false) { - Log.E("ERROR Config Setting : Scanner Marking on the fly (OFF)"); - return (int)InitErrorList.MOTF_OFF; - } - - // MOTF Set Scanner List - _Scanner.SelectCorrectionTable(2); - Log.I(string.Format("Normal, Select Laser Correction File")); - - // Aurora 내부에서 찾아야할 듯 함 - //UsePlcShotThemAll = Dao.SystemRecipe.PlcShotThemAll; - //UsePlcPositionCompensation = Dao.SystemRecipe.PlcPositionCompensationUse; - string[] strArr = Dao.SystemRecipe.WorkRecipeFile.Split('\\'); - RecipeFileName = strArr[strArr.Length - 1]; - - _LastScannerParamNo = -1; - - // 트럼프 TruDisk를 쓰기 위해서는 SetFirstPulseKiller를 사용해야 함. - - // Rotary는 시작 트리거 미사용 - _Scanner.SetControlMode(0); - UtilUnit.logUnit.SetLog(LogUnit.eLogType.DEBUG, MethodBase.GetCurrentMethod().Name, "[AutoRun] 외부 시작 트리거 DISABLE"); - - #region MOTF Absolute Encoder 기준으로 초기화 - // Set Rotate Center는 Ctrl명령, 처음 한번만 실행 - _Scanner.SetRotateCenter(_Scanner.Config.MarkingOnTheFlyRotateCenterX, _Scanner.Config.MarkingOnTheFlyRotateCenterY); - - _Scanner.InitFly2D(); // X, Y 엔코더 리셋 - _EncoderOverflowCount = 0; - - // 현재 정지상태의 Rotary 엔코더 값을 읽어와서 저장 - _RotaryEncoderOffset = GetRotaryCurrentPosition(); // m_abwRotaryEncoderOffset의 범위는 0 이상 360 미만 - - InitRotaryOnTheFlyWeldingCount(_RotaryEncoderOffset, _RotaryJigCount, out _WeldingCount, out _WeldingJigNo); - - Log.I(string.Format($"ScannerUnit.InitRotaryOnTheFlyWeldingCount : m_abwRotaryEncoderOffset({_RotaryEncoderOffset}), weldingCount({_WeldingCount}), weldingJigNo({_WeldingJigNo}), rotaryJigCount({_RotaryJigCount})")); - - // 용접 완료 대기 스캐너 List 리셋 - ResetInputScannerList(); - WaitingScannerList.Reset(); - CompleteScannerList.Reset(); - - isTheFirstListWrite = false; // 작업 시작 시 처음 2개의 List는 입력하고 시작한다 - isTheSecondListWrite = false; - isTheFirstListExecute = true; // 제일 첫 List는 ExecuteList 필요. 이후는 AutoChange - - _PLC.WriteBit(eBitOutput.PC_AUTO_STATUS, true); - Log.I(string.Format($"[PLCInterface]SET PC_AUTO_STATUS True")); - #endregion - - return (int)InitErrorList.SUCCESS; - } - - - private double GetRotaryCurrentPosition() - { - try { - //double finalValue = Convert.ToDouble(_plc.GetLongAIValue("PLC_CURRENT_POS_1") / 100000f); - double finalValue = Convert.ToDouble(_PLC.ReadDWord((int)eWordInput.PLC_CURRENT_POS_1).data / 100000f); - - finalValue += _Scanner.Config.RotaryEncoderOffset; - - if (360.0 <= finalValue) { - while (360.0 <= finalValue) { - finalValue -= 360.0; - } - } else if (finalValue < 0) { - while (finalValue < 0) { - finalValue += 360.0; - } - } - - return finalValue; - } catch { - return -9999.9999; - } - } - - /// - /// 현재 Rotary의 회전 각도에서, 현재 용접 카운트와 지그 번호를 계산. 추가로 Overflow 카운트도 초기화 - /// - /// Rotary 회전 Offset. 운전 시작 시 Rotary가 지그 1번 정중심에서부터 시작했을 경우가 0. 범위는 0이상 - /// Rotary 내 지그 갯수임. 장비 및 T/T에 따라서, 360도 당 지그의 개수는 다를 수 있으므로. - /// Rotary Welding Count. 30도 구간 하나가 지나갈 때마다 +1 - /// 현재 '용접 중' 구간에 들어가 있는 지그 번호 - public void InitRotaryOnTheFlyWeldingCount(double rotaryAngleOffset, int rotaryJigCount, out int weldingCount, out int weldingJigNo) - { - // 현재 로터리 엔코더 값을 기준으로 현재 카운트, 지그 번호를 확인 - double anglePerOneJig = 360 / (double)rotaryJigCount; //double로 바꿔서 계산해야 22가 아닌 22.5로 anglePerOneJig가 계산됨 25.08.02 - weldingCount = (int)((rotaryAngleOffset + anglePerOneJig / 2) / anglePerOneJig); // _WeldingCount = 0, 1, 2, ... - - weldingJigNo = (int)(weldingCount % rotaryJigCount) + 1; // _WeldingJigNo = 1, 2, ... , 12 - Log.I($"Angle Per One Jig : {anglePerOneJig}"); - } - - private string CheckInitCondition(SequenceContext context, string id, ICollection branches, SequenceActionResult param) - { - if (!CheckCondition(context)) { - //AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_AutoRun_CheckInitCondition); - Log.E("Condition is not in state to start sequence."); - context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, false); - return SEQ_INIT_CONDITION_ERROR; - } - - Status.EquipmentMode = eEquipmentMode.AUTO; - - var startTime = DateTime.Now; - context.PutValue(ContextKey.KEY_SEQUENCE_START_TIME, startTime); - Thread.Sleep(1); // 부하 방지 - Log.D("ReceiveCellInfo Sequence CheckInitCondition"); - return SEQ_FORK_ENCODER_MONITOR; - //return SEQ_CHECK_LOAD_COMPLETE; - } - - #region TODO: [장비구현필요] - // TODO: [장비구현필요] 공정 Node 구현 - - // 지그 상태 확인 - private SequenceActionResult CheckLoadComplete(SequenceContext context, string id, SequenceActionResult param) - { - Status.SetWorkingPosition(eWorkingPosition.LOADING_CELL); - - // MOTF WaitScannerLoadListEnable - // List가 실행 중이라면(ex : 엔코더 대기 상태 등), 반환값은 0, LoadList 할 수 없는 상태(List 실행 중이거나, 엔코더 대기 상태) - // LoadList가 0보다 크면 다음 시퀀스 진행해야 함 - WaitContinue: - var ret = context.RetryUntilSuccess(() => _Scanner.LoadList(_WeldingScannerListNo) > 0, int.MaxValue, 10, true); - if (ret == E2.TIMEOUT) { - Log.E("TIMEOUT_Scanner_LoadList : 600시간 Run"); - goto WaitContinue; - } - - Log.I($"LoadList function success : List {_WeldingScannerListNo}"); - Thread.Sleep(1); // 부하 방지 - return SequenceAction.Ok(); - } - - private SequenceActionResult CheckScannerListComplete(SequenceContext context, string id, SequenceActionResult param) - { - if (isTheFirstListWrite) // 작업 시작 시, 첫번째 리스트는 바로 쓰고, 바로 시작한다(ExecuteList). 다만 List 명령에 의해 Encoder가 들어올 때까지 대기. - { - isTheFirstListWrite = false; - Log.I("Write the 1st scanner list"); - - } else { - if (isTheSecondListWrite) // 두번째 리스트는 바로 쓰지만, 첫번째 리스트 실행이 완료되면 자동으로 이어서 실행된다(AutoChange) - { - isTheSecondListWrite = false; - Log.I("Write the 2nd scanner list"); - - } else { - isWeled = false; - // 첫번째나 두번째가 아니라면, 실제 리스트 실행이 끝난 것이기 때문에 완료 처리가 필요 - CompleteScannerList = InputScannerList[(int)_WeldingScannerListNo - 1]; - - if (!CheckCurrentEncoderAngle(CompleteScannerList.StartAngle)) { - // 에러 상황(현재 Rotary Encoder 값이 정상적인 스캐너 리스트 각도 범위를 벗어남) - Log.I("ERR_SCANNER_LIST_PROCESSING_TIMEOVER"); - - return SequenceAction.Error(); - - // WON : 2칸 전에 용접을 진행하지 않아 현재 Angle이 CompleteScannerList.StartAngle + 45 범위를 벗어난 경우라면 에러 상황이 아니므로 에러로 처리 할 필요가 없다 - // 위에 CheckCurrentEncoderAngle if문 조건 대신 아래 내용으로 테스트 해본 뒤에 적용 필요 - //if (!CheckCurrentEncoderAngle(CompleteScannerList.StartAngle)) { - // // 에러 상황(현재 Rotary Encoder 값이 정상적인 스캐너 리스트 각도 범위를 벗어남) - // if (CompleteScannerList.CanExist) { - // Log.I("ERR_SCANNER_LIST_PROCESSING_TIMEOVER"); - // return SequenceAction.Error(); - // } - // return SequenceAction.Ok(); - } else { - if (CompleteScannerList.CanExist) { - isWeled = true; - #region 용접 시간, 엔코더 측정/기록 - //_WeldInterval = DateTime.Now - _WeldEndTime; - //_WeldEndTime = DateTime.Now; - //double elapsedTime = _Scanner.GetTime(); - //_WeldingSpanTime = TimeSpan.FromSeconds(elapsedTime); // Encoder 대기 넘어간 후의, 실제 스캐너 리스트 실행 시간 - //_WeldingStartTime = _WeldEndTime.Subtract(_WeldingSpanTime); - - double elaspedTime = _Scanner.GetTime(); - - if (CompleteScannerList.WeldComplete) { - _WeldInterval = DateTime.Now - _WeldEndTime; - _WeldEndTime = DateTime.Now; - _WeldingStartTime = CompleteScannerList.WeldStartTime; - _WeldingSpanTime = TimeSpan.FromSeconds(elaspedTime); - _LotId = CompleteScannerList.LotId; - _CellId = CompleteScannerList.CellId; - - Log.I(string.Format("JigNo : {0}, Weld start : {1}, Weld End : {2}, WeldTime : {3}, interval : {4:F3}", - CompleteScannerList.JigNo, _WeldingStartTime.ToString("HH:mm:ss.fff"), _WeldEndTime.ToString("HH:mm:ss.fff"), _WeldingSpanTime.TotalMilliseconds, _WeldInterval.TotalSeconds)); - - if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + CompleteScannerList.JigNo - 1).data) { - _PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE_1 + CompleteScannerList.JigNo - 1, true); - Log.I(string.Format($"PC_WELD_COMPLETE_{CompleteScannerList.JigNo} -> true)")); - } - UpdateProductCount(context); - UpdateProductInfoForView(); - SaveCellAPD(); - } - - //if (_SystemParameter.BypassModeLBAD == false) { - // if (_StreamLightLBAD.SendWeldingStop() == false) { - // Log.I(string.Format($"[LBAD Interface]SendWeldingStop null")); - // //return null; - // } - //} - - UtilUnit.logUnit.SetLog(LogUnit.eLogType.PRODUCT, MethodBase.GetCurrentMethod().Name, "UPDATE_WELDING_TIME;" + _WeldingSpanTime.TotalMilliseconds); - UtilUnit.logUnit.SetLog(LogUnit.eLogType.PRODUCT, MethodBase.GetCurrentMethod().Name, "UPDATE_PRODUCT_COUNT;" + _WeldEndTime.ToString("yyyy-MM-dd HH:mm:ss")); - - double encoder0_0, encoder1_0, encoder0_1, encoder1_1; - _Scanner.ReadEncoder(out encoder0_0, out encoder1_0, out encoder0_1, out encoder1_1, true); - - double startEncoderCount = encoder0_0; - double endEncoderCount = encoder0_1; - double angularVelocity = (endEncoderCount - startEncoderCount) / elaspedTime; // 단위는 [degree/sec] - - Log.I(string.Format("Encoder start : {0:F4}, end : {1:F4}, vel : {2:F2}", startEncoderCount, endEncoderCount, angularVelocity)); - #endregion - #region 스캐너 리스트 Record 파일 기록 - if (_Scanner.Config.UseRecordSignal) { - String RecordFileName = _RecipeManager.ActivatedRecipe().Name + "_Jig#" + CompleteScannerList.JigNo.ToString(); - string DataFilePath = ProjectUtil.GetDataLogSetting().GetFilePath_ScannerRecordLog(RecordFileName, true); - _Scanner.SaveRecord(DataFilePath); - } - #endregion - } - } - } - } - return SequenceAction.Ok(); - } - - public bool CheckCurrentEncoderAngle(double startAngle) - { - double encoderX, currentAngle; - - _Scanner.GetEncoder(out encoderX, out currentAngle, true); - - if (0 < startAngle && currentAngle < 0) { - // Encoder 반전되는 순간이며, 이 때만 인터락 무시 - } else if (startAngle <= currentAngle) { - if (currentAngle < startAngle + 45)// 다음 리스트 구간이 끝나기 전까지는 완료가 되어야 한다 - { - Log.I(string.Format("Current encoder check OK, startAngle : {0}, currentAngle : {1})", startAngle, currentAngle)); - return true; - } else Log.W(string.Format("Current encoder check NG(Too late), startAngle : {0}, currentAngle : {1})", startAngle, currentAngle)); - } else Log.W(string.Format("Current encoder check NG(Too early), startAngle : {0}, currentAngle : {1})", startAngle, currentAngle)); - - return false; - } - - private string ReadyScannerList(SequenceContext context, string id, ICollection branches, SequenceActionResult param) - { - Status.SetWorkingPosition(eWorkingPosition.UPLOADING_WELD_LIST); - - //_SelectedDrawObjectList = _ScannerCanvasUserCtrl.Model.Layers[0].Objects; - - #region List 입력 시점의 엔코더 카운트 로그 기록 - double encoderX, encoderY; - - _Scanner.GetEncoder(out encoderX, out encoderY, true); - - UtilUnit.logUnit.SetLog(LogUnit.eLogType.SYSTEM, MethodBase.GetCurrentMethod().Name, string.Format("Encoder X, Y, Offset, Y-X+Offset : {0}, {1}, {2}, {3}", - encoderX.ToString("F5"), encoderY.ToString("F5"), _RotaryEncoderOffset.ToString("F5"), (encoderY - encoderX + _RotaryEncoderOffset).ToString("F5"))); - #endregion - - // 스캐너 위치 초기화 - _Scanner.Fly_Return(_Scanner.Config.MarkingOntheFlyParkingPositionX, _Scanner.Config.MarkingOntheFlyParkingPositionY); - - #region List 입력(엔코더 조건 만족 대기) - _WeldingCount++; - - double compensateEncoderReset = 0.015; // 엔코더 리셋 보상 각도 설정(70도/sec 기준 약 0.015도) - - WaitForEncoderNextRotarySection(_WeldingCount, _RotaryJigCount, _RotaryEncoderOffset, compensateEncoderReset, out _WeldingStartAngle); - - Log.I(string.Format("ScannerUnit.WaitForEncoderNextRotarySection : m_weldingCount({0}),m_abwRotaryEncoderOffset({1:F3}), compensateEncoderReset({2:F3}), overflowCount({3}), weldingStartAngle({4:F3})", - _WeldingCount, _RotaryEncoderOffset, compensateEncoderReset, _EncoderOverflowCount, _WeldingStartAngle)); - #endregion - - // 3개임으로 3으로 작성 - #region List 입력(용접 좌표 입력) - if (_WeldingJigNo == _RotaryJigCount) - _WeldingJigNo = 1; - else - _WeldingJigNo++; - - bool canExist; // 지그 용접 수행 여부 확인 - - if (UsePlcShotThemAll) { - canExist = true; - Log.I("Settings - PLC : Shot Them All Mode"); - } else - canExist = GetRotaryCanExist(_WeldingJigNo); - - Log.I("Can Exist : " + canExist.ToString() + ", JigNo " + _WeldingJigNo + " ,CountNo " + _WeldingCount + ", StartAngle(Y) : " + _WeldingStartAngle); - - if (canExist) { - #region 용접할 Objects 선택 - if (_WeldingJigNo - 1 < _ScannerCanvasUserCtrl.Model.Layers.Length) { - _SelectedDrawObjectList = _ScannerCanvasUserCtrl.Model.Layers[_WeldingJigNo - 1].Objects; - Log.I(string.Format("Page 불러오기 : [{0}])", _WeldingJigNo - 1)); - } else { - _SelectedDrawObjectList = _ScannerCanvasUserCtrl.Model.Layers[0].Objects; - Log.I(string.Format("Page 불러오기 : [0])")); - } - #endregion - // 입력한 Scanner List를 완료대기열에 추가 - // Won : GetProcessingWeldingData().WorkLotId 는 CellTrakcer로 부터 받은 상태의 LotId - // GetProcessingWeldingData().LotId 는 AutorunView에 표기할 용접이 완료 된 LotID - string LotId = Status.GetProcessingWeldingData().WorkLotId; // CellTracker로 부터 WorkLotID, WorkCellID 받는 구문 추가 후 해당 데이터로 입력 필요 - string CellId = Status.GetProcessingWeldingData().WorkCellId; - SetInputScannerList(_WeldingScannerListNo, DateTime.Now, _WeldingCount, _WeldingStartAngle, _WeldingJigNo, _RotaryJigCount, canExist, LotId, CellId); - _RecipeNo = _RecipeManager.ActivatedRecipe().Id; - - SetWeldingData(); - return SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ; - } else { - return SEQ_EXECUTE_WELDING; - } - #endregion - } - - private ScannerParam GetSelectedDrawObjectData(IDrawObject DrawObj) - { - if (DrawObj is Line lineItem) - return WeldingRecipeManager.GetScannerParam(lineItem.ScannerParamNo); - else if (DrawObj is Arc arcItem) - return WeldingRecipeManager.GetScannerParam(arcItem.ScannerParamNo); - else if (DrawObj is Group groupItem) - return WeldingRecipeManager.GetScannerParam(groupItem.ScannerParamNo); - - return null; - } - private void SetWeldingData() - { - ScannerParam laserParam = null; - laserParam = GetSelectedDrawObjectData(_SelectedDrawObjectList[0]); - - if (laserParam != null) { - // EDC 보내는 용도 - Status.GetProcessingWeldingData().LaserPowerCore = laserParam.LaserPower1.ToString(); - Status.GetProcessingWeldingData().LaserPowerRing = laserParam.LaserPower2.ToString(); - Status.GetProcessingWeldingData().MarkSpeed = laserParam.MarkSpeed.ToString(); - Status.GetProcessingWeldingData().FocalLength = (_PLC.ReadDWord((int)eWordInput.PLC_WELDING_FOCAL_LENGTH).data / 1000f).ToString(); - Status.GetProcessingWeldingData().WeldingJigNo = _WeldingJigNo.ToString(); - } - } - - public void WaitForEncoderNextRotarySection(int weldingCount, int rotaryJigCount, double rotaryAngleOffset, double encoderResetOffset, out double sectionStartAngle) - { - // 한 바퀴당 지그 숫자에 따른 변경 - double encoderAllowedMinDegree = Int32.MinValue / _Scanner.Config.MarkingOnTheFlyEncoderResolutionRotate * 360.0; - double encoderAllowedMaxDegree = Int32.MaxValue / _Scanner.Config.MarkingOnTheFlyEncoderResolutionRotate * 360.0; - - double anglePerOneJig = (double)(360 / (double)rotaryJigCount); - - // 아래는 지그 당 각도가 30도라는 가정하의 수식임. - // 1.1. 시작 각도 = (현재 지그 번호 * 30도) -15도 - 초기화 엔코더 값 - 엔코더 리셋 보상값 - // rotaryAngleOffset = x가 0도 이상 15도 미만일 때, weldingCount = 1부터 시작, sectionStartAngle = 15 - x에서 30씩 증가 - // rotaryAngleOffset = x가 15도 이상 45도 미만일 때, weldingCount = 2부터 시작, sectionStartAngle = 30 - x에서 30씩 증가 - // rotaryAngleOffset = x가 45도 이상 75도 미만일 때, weldingCount = 3부터 시작, sectionStartAngle = 30 - x에서 30씩 증가 - // rotaryAngleOffset = x가 315도 이상 345도 미만일 때, weldingCount = 12부터 시작, sectionStartAngle = 30 - x에서 30씩 증가 - // rotaryAngleOffset = x가 345도 이상 360도 미만일 때, weldingCount = 13부터 시작, sectionStartAngle = 30 - x에서 30씩 증가 - sectionStartAngle = weldingCount * anglePerOneJig - (anglePerOneJig / 2) - rotaryAngleOffset - encoderResetOffset - _EncoderOverflowCount * (encoderAllowedMaxDegree - encoderAllowedMinDegree); - - // 1.2. 계산된 시작각도가 이미 지나버렸으면 알람 발생 필요 - - // 1.3. Overflow가 나는 숫자라면, 보상할 것. - if (sectionStartAngle > encoderAllowedMaxDegree) { - sectionStartAngle -= encoderAllowedMaxDegree - encoderAllowedMinDegree; - _EncoderOverflowCount++; - } - - double sectionEndAngle = (encoderAllowedMaxDegree < sectionStartAngle + anglePerOneJig) ? encoderAllowedMaxDegree : sectionStartAngle + anglePerOneJig; - - _Scanner.WaitForEncoderRotateRange(encoderAllowedMinDegree, encoderAllowedMaxDegree, sectionStartAngle, sectionEndAngle); - } - - public bool GetRotaryCanExist(int jigNo) - { - #region 지그 16개 요청기록 로그 남기기, 빠져나간 캔에 대한 Complete Bit 초기화 - string result = ""; - - for (int i = 1; i <= _RotaryJigCount; i++) { - if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + i).data) - result += "1, "; - else { - result += "0, "; - - string outId = string.Format("PC_WELD_COMPLETE_{0}", i); - - if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + i).data) { - _PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE_1 + i, false); - Log.I(string.Format($"PC_WELD_COMPLETE_{1 + i} -> FALSE)")); - } - } - } - //UtilUnit.logUnit.SetLog(LogUnit.eLogType.DEBUG, MethodBase.GetCurrentMethod().Name, string.Format("PLC -> PC 용접 Cmd : ({0})", result)); - #endregion - - if (jigNo <= _RotaryJigCount) - //return m_rscPlc.GetDIStatus(string.Format("PLC_USE_WELD_JIG_{0}", jigNo)); - return _PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + (jigNo - 1)).data; - else - return false; - } - - private SequenceActionResult SetUploadWeldingList_SeqParams(SequenceContext context, string id, SequenceActionResult param) - { - //현재 시퀀스에서 LoadList를 해주기 때문에 Sub 시퀀스에 IncludeListStartEnd를 false로 넘겨줘야 함 - SeqUploadWeldingList_InitParam seqParams = new SeqUploadWeldingList_InitParam() { - NeedSetLaserTiming = _ModulationMode, - IncludeListStartEnd = false, - CellMeasureCenterOffsetX = _CellMeasureCenterOffsetX, - CellMeasureCenterOffsetY = _CellMeasureCenterOffsetY, - SelectedDrawObjectList = _SelectedDrawObjectList, - WeldingScannerListNo = _WeldingScannerListNo, - Rotation_Degree = 11.25, - }; - - return SequenceAction.Ok(seqParams); - } - - private SequenceActionResult GetUploadWeldingList_SeqResult(SequenceContext context, string id, SequenceActionResult param) - { - var resultOutParam = param.Param as SeqUploadWeldingList_OutParam; - if (resultOutParam.Success == false) { - //AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_UploadWeldingList_ResultFailed); - return SequenceAction.ForceStopByAlarm(AlarmCode.ALARM_SEQUENCE_UploadWeldingList_ResultFailed); - //return null; - } - - return SequenceAction.Ok(); - } - - private SequenceActionResult SetReceiveCellInfo_SeqParams(SequenceContext context, string id, SequenceActionResult param) - { - SeqReceiveCellInfo_InitParam seqParams = new SeqReceiveCellInfo_InitParam() { - }; - - return SequenceAction.Ok(seqParams); - } - - private SequenceActionResult GetReceiveCellInfo_SeqResult(SequenceContext context, string id, SequenceActionResult param) - { - var resultOutParam = param.Param as SeqReceiveCellInfo_OutParam; - if (resultOutParam.Success == false) { - return null; - } - return SequenceAction.Ok(); - } - - private SequenceActionResult ExecuteWelding(SequenceContext context, string id, SequenceActionResult param) - { - Status.SetWorkingPosition(eWorkingPosition.EXECUTING_WELD); - - // MOTF Welding - // List 닫기 - _Scanner.SetEndList(); - - #region List 실행(처음엔 ExecuteList, 다음부터 AutoChangeList, 이후 대상 리스트 교체 (1 <-> 2)) - if (isTheFirstListExecute) { - isTheFirstListExecute = false; - - _Scanner.ExecuteList(_WeldingScannerListNo); - Log.I(string.Format($"START Welding : ExecuteList_{_WeldingScannerListNo}")); - } else { - _Scanner.AutoChange(); - Log.I(string.Format($"Next upload list : uploadList_{_WeldingScannerListNo}")); - } - - _WeldingScannerListNo = (_WeldingScannerListNo != eListNo.LIST1) ? eListNo.LIST1 : eListNo.LIST2; - #endregion - - return SequenceAction.Ok(); - } - - private SequenceActionResult RequestUnloadCell(SequenceContext context, string id, SequenceActionResult param) - { - Status.SetWorkingPosition(eWorkingPosition.UNLOADING_CELL); - - return SequenceAction.Ok(); - } - private SequenceActionResult EncoderMonitor(SequenceContext context, string id, SequenceActionResult param) - { - int EncoderLogCount = 0; - double send_time_offset = 0.1; - string LotID = "", CellID = ""; - - while (!context.Stopped) { - double encoderX, currentAngle; - _Scanner.GetEncoder(out encoderX, out currentAngle, true); - double CurrentPosPLC = GetRotaryCurrentPosition(); - bool WeldingInPosition = encoderX > _Scanner.Config.MarkingRangeMinRotate + 11.25 - send_time_offset - 0.1 && encoderX < _Scanner.Config.MarkingRangeMinRotate + 11.25 - send_time_offset + 0.1; - - if (WeldingInPosition) { - if (InputScannerList[(int)_WeldingScannerListNo - 1].CanExist) { - Log.I($"Fork Before Min Rotate Encoder X : ({encoderX}), Encoder Y : ({currentAngle}), PLC Rotary : ({CurrentPosPLC}), List {_WeldingScannerListNo}, JigNo : ({InputScannerList[(int)_WeldingScannerListNo - 1].JigNo})"); - if (!_SystemParameter.BypassModeLBAD) { - if (InputScannerList[(int)_WeldingScannerListNo - 1].CheckSendCellinfo == false) { - LotID = InputScannerList[(int)_WeldingScannerListNo - 1].LotId; - CellID = InputScannerList[(int)_WeldingScannerListNo - 1].CellId; - if (currentAngle > InputScannerList[(int)_WeldingScannerListNo - 1].StartAngle) { - InputScannerList[(int)_WeldingScannerListNo - 1].CheckSendCellinfo = _StreamLightLBAD.SendCellInfo(LotID, CellID, _RecipeNo, _ModelNo, InputScannerList[(int)_WeldingScannerListNo - 1].JigNo); - - if (InputScannerList[(int)_WeldingScannerListNo - 1].CheckSendCellinfo == false) - Log.I($"[LBAD Interface]SendCellInfo null, LotID [{LotID}], CellID [{CellID}], JigNo [{InputScannerList[(int)_WeldingScannerListNo - 1].JigNo}]"); - else - Log.I($"[StreamLight]SendCellInfo LotID [{LotID}], CellID [{CellID}], JigNo [{InputScannerList[(int)_WeldingScannerListNo - 1].JigNo}]"); - } - } - } - } - } - - if (_IO._iOUnit.ReadDiBit(Convert.ToInt32(eADIAddress.LaserOn))) { - if (InputScannerList[(int)_WeldingScannerListNo - 1].WeldStartTime == DateTime.MinValue && InputScannerList[(int)_WeldingScannerListNo - 1].CanExist) { - InputScannerList[(int)_WeldingScannerListNo - 1].WeldStartTime = DateTime.Now; - InputScannerList[(int)_WeldingScannerListNo - 1].WeldComplete = true; - EncoderLogCount = 0; - Log.I($"Laser On, Welding Complete. JigNo : ({InputScannerList[(int)_WeldingScannerListNo - 1].JigNo})"); - } - - if (EncoderLogCount == 0) { - Log.I($"Fork Laser On Encoder X : ({encoderX}), Encoder Y : ({currentAngle}), PLC Rotary : ({CurrentPosPLC}), List {_WeldingScannerListNo}, JigNo : ({InputScannerList[(int)_WeldingScannerListNo - 1].JigNo})"); - } - EncoderLogCount = (EncoderLogCount + 1) % 7; - } - - for (int i = 0; i < _RotaryJigCount; i++) { - if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + i).data == false) { - _PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE_1 + i, false); - } - } - - _PLC.WriteDWord((int)eWordOutput.PC_CURRENT_POS, (int)((currentAngle + _RotaryEncoderOffset) % 360 * 100_000f)); - Thread.Sleep(1); // 부하 방지 - } - return SequenceAction.Ok(); - } - - private void UpdateProductCount(SequenceContext context) - { - if (_SystemParameter.LastResetTime < DateTime.Now.Date) { - _SystemParameter.LastResetTime = DateTime.Now.Date; - Log.I($"Today Count Reset. {_SystemParameter.TodayProductCount} -> 0"); - _SystemParameter.TodayProductCount = 0; - } - - _TodayProduct = _SystemParameter.TodayProductCount; - _TotalProduct = _SystemParameter.TotalProductCount; - if (_TodayProduct < uint.MaxValue) { - _TodayProduct++; - } - if (_TotalProduct < uint.MaxValue) { - _TotalProduct++; - } - _SystemParameter.TodayProductCount = _TodayProduct; - _SystemParameter.TotalProductCount = _TotalProduct; - } - - private void UpdateProductInfoForView() - { - Status.GetProcessingWeldingData().TotalProduct = _TotalProduct; - Status.GetProcessingWeldingData().TodayProduct = _TodayProduct; - - Status.GetProcessingWeldingData().AutoRunStartTime = _AutoRunStartTime; - - Status.GetProcessingWeldingData().WeldingStartTime = _WeldingStartTime; - Status.GetProcessingWeldingData().WeldingEndTime = _WeldEndTime; - Status.GetProcessingWeldingData().WeldingSpanTimeMilliseconds = _WeldingSpanTime.TotalMilliseconds.ToString(); - - // Status.GetProcessingWeldingData().LotId 는 Autorun View에 표기할 용접이 완료 된 LotId 이므로 WorkLotID 와의 구분 확인 - Status.GetProcessingWeldingData().LotId = _LotId; - Status.GetProcessingWeldingData().CellId = _CellId; - - Status.GetProcessingWeldingData().RecipeNo = _RecipeNo; - Status.GetProcessingWeldingData().LaserPowerByLBAD = _LaserPowerByLBAD.ToString(); - - Status.GetProcessingWeldingData().WeldingJigNo = _CompletedJigNo.ToString(); - - } - private SequenceActionResult SetReportCellResult_SeqParams(SequenceContext context, string id, SequenceActionResult param) - { - Status.SetWorkingPosition(eWorkingPosition.REPORTING_RESULT); - - SeqReportCellResult_InitParam seqParams = new SeqReportCellResult_InitParam() { - EDC_Interface = new EDC(), - }; - - return SequenceAction.Ok(seqParams); - } - - private SequenceActionResult GetReportCellResult_SeqResult(SequenceContext context, string id, SequenceActionResult param) - { - var resultOutParam = param.Param as SeqReportCellResult_OutParam; - if (resultOutParam.Success == false) { - return null; - } - - return SequenceAction.Ok(); - } - - private static string CheckCycleStop(SequenceContext context, string id, ICollection branches, SequenceActionResult param) - { - Status.SetWorkingPosition(eWorkingPosition.CHECKING_CYCLE); - - // TODO: 확인 필요, CybleStop 에 대한 내용, cycle stop 여부 가져오기 - //bCycleStop = GetCycleStopRequest(); - - // TODO: 한번만 돌도록 설정함, PLC 로 받으면 좋음. - //Jin : cycleStop 명령을 용접 프로그램에서 할 경우가 현재는 없음.. - // CheckCycleStop 노드와 Complete 노드 사이 다른 노드가 필요하다면 해당 노드를 CheckCycleStop 노드 위로 올리자 - bool cycleStop = false; - if (cycleStop) { - return SEQ_SAVE_RESULT_DATA; - } else { - return SEQ_CHECK_LOAD_COMPLETE; - } - } - // END ALL - #endregion - private static string CheckCanWelded(SequenceContext context, string id, ICollection branches, SequenceActionResult param) - { - if (isWeled) - return SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ; - else - return SEQ_CHECK_CYCLE_STOP; - } - - private void SaveCellAPD() - { - if (Status.GetProcessingWeldingData().APD.Count > 0) { - string directoryPath = "D:\\ILSOSConfig\\APD_History"; - string fileName = DateTime.Now.ToString("HH") + "_CellAPD"; - string fullPath = Path.Combine(directoryPath, Status.GetProcessingWeldingData().APD.First().Date.ToString("yyyy-MM-dd"), fileName); - Status.GetProcessingWeldingData().APD.CreateFiles(fullPath); - } - } - private SequenceActionResult SaveResultData(SequenceContext context, string id, SequenceActionResult param) - { - - context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, true); - return SequenceAction.Ok(); - } - - private SequenceActionResult WriteCompletionPLCBit(SequenceContext context, string id, SequenceActionResult param) - { - // 완료 비트 write 하는 Node 추가 필요. format 유지, ReceiveCellInfo 없음 - Log.D("AutoRun Sequence WriteCompletionPLCBit"); - - return SequenceAction.Ok(); - } - - private SequenceActionResult InitConditionError(SequenceContext context, string id, SequenceActionResult param) - { - context.TryGetValue(ContextKey.KEY_SEQUENCE_ERROR_CODE, out int InitializeCode); - switch (InitializeCode) { - case (int)InitErrorList.PLC_AUTORUN_BIT_OFF: - Log.D("AutoRun Sequence InitConditionError : PLC_AUTORUN_OFF"); - return SequenceAction.ForceStopByAlarm(AlarmCode.ALARM_SEQUENCE_AutoRun_CheckInitCondition_PLC_AUTORUN_OFF); - case (int)InitErrorList.LBAD_SUB_ACTIVATE_FAILED: - Log.D("AutoRun Sequence InitConditionError : LBAD_SUB_ERR"); - return SequenceAction.ForceStopByAlarm(AlarmCode.ALARM_SEQUENCE_AutoRun_CheckInitCondition_LBAD_SUB_ERR); - case (int)InitErrorList.LBAD_CLIENT_ACTIVATE_FAILED: - Log.D("AutoRun Sequence InitConditionError : LBAD_CLIENT_ERR"); - return SequenceAction.ForceStopByAlarm(AlarmCode.ALARM_SEQUENCE_AutoRun_CheckInitCondition_LBAD_CLIENT_ERR); - case (int)InitErrorList.LASER_INIT_ERROR: - Log.D("AutoRun Sequence InitConditionError : LASER_ERR"); - return SequenceAction.ForceStopByAlarm(AlarmCode.ALARM_SEQUENCE_AutoRun_CheckInitCondition_LASER_ERR); - case (int)InitErrorList.MOTF_OFF: - Log.D("AutoRun Sequence InitConditionError : MOTF_OFF"); - return SequenceAction.ForceStopByAlarm(AlarmCode.ALARM_SEQUENCE_AutoRun_CheckInitCondition_MOTF_OFF); - case (int)InitErrorList.PLC_ALARM: - Log.D("AutoRun Sequence InitConditionError : PLC_ALARM"); - return null; - default: - Log.D("AutoRun Sequence InitConditionError"); - return SequenceAction.ForceStopByAlarm(AlarmCode.ALARM_SEQUENCE_AutoRun_CheckInitCondition); - } - } - - private SequenceActionResult Complete(SequenceContext context, string id, SequenceActionResult param) - { - RestoreDeviceStatus(); - - context.Settings.Save(CommonSettingIds.SystemParameter, _SystemParameter, "SeqAutoRunCCWH52A"); - - context.TryGetValue(ContextKey.KEY_SEQUENCE_RESULT, out bool seqResult); - SeqAutoRunCCWH52A_OutParam result = new SeqAutoRunCCWH52A_OutParam() { Success = seqResult }; - - if (seqResult == false) { - //AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_AutoRun_ResultFailed); - } - Log.D("AutoRun Sequence Complete"); - Status.SetWorkingPosition(eWorkingPosition.DONE); - - return SequenceAction.Ok(result); - } - - private bool RestoreDeviceStatus() - { - //PLC All BIT OFF - for (int i = 0; i < _RotaryJigCount; i++) { - _PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE_1 + i, false); - } - _PLC.WriteBit((int)eBitOutput.PC_AUTO_STATUS, false); - //_PLC.WriteBit((int)eBitOutput.PC_RECIPE_PARAM_UPLOAD_COMPLETE, false); - Log.I(string.Format("[PLCInterface]PC All Bit Off")); - - //LBAD Ready Off - //_LBAD.SetReadybyAuto(false); - if (_SystemParameter.BypassModeLBAD == false) { - if (_StreamLightLBAD.SendReadyStatus(eRequestData.Ready_Off) == false) { - Log.I(string.Format($"[LBAD Interface]CheckReadyStatus null")); - } - } - - //Laser Off - _Laser.LaserOff(); - - //List 실행 종료 - _Scanner.StopExecution(); - - //Anlog 출력 0으로 변경, efunctiontype을 command로 변경해주면 list가 아니라 직접 변경됨 - _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.COMMAND); - _Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.COMMAND); - - //Scanner 원점 복귀 - _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); - - //Vision Correctiong 파일 변경 - _Scanner.SelectCorrectionTable(1); - - //Recipe를 기존에 Manual에서 작업하던 화면으로 rollback - WeldingRecipeManager.RollbackRecipe(); - - return true; - } - - private void OnForceError(SequenceContext context, string arg2) - { - context.Settings.Save(CommonSettingIds.SystemParameter, _SystemParameter, "SeqAutoRunCCWH52A"); - - OnSeqActionStop(); - - Log.I("SequenceAction Ok : OnForceError"); - } - - private void OnStopped(SequenceContext context) - { - context.Settings.Save(CommonSettingIds.SystemParameter, _SystemParameter, "SeqAutoRunCCWH52A"); - - OnSeqActionStop(); - - Log.I("SequenceAction Ok : OnStopped"); - } - - private void OnSeqActionStop() - { - Status.EquipmentMode = eEquipmentMode.MANUAL; - - //PLC All BIT OFF - for (int i = 0; i < _RotaryJigCount; i++) - _PLC.WriteBit(eBitOutput.PC_WELD_COMPLETE_1 + i, false); - _PLC.WriteBit(eBitOutput.PC_AUTO_STATUS, false); - Log.I("[PLCInterface]PC All Bit Off"); - - //LBAD Ready Off - //_LBAD.SetReadybyAuto(false); - if (_SystemParameter.BypassModeLBAD == false) { - if (_StreamLightLBAD.SendReadyStatus(eRequestData.Ready_Off) == false) { - Log.I(string.Format($"[LBAD Interface]CheckReadyStatus null")); - } - } - - //Laser Off - _Laser.LaserOff(); - - //List 실행 종료 - _Scanner.StopExecution(); - - //Anlog 출력 0으로 변경, efunctiontype을 command로 변경해주면 list가 아니라 직접 변경됨 - _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.COMMAND); - _Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.COMMAND); - - //Scanner 원점 복귀 - _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); - - //Vision Correctiong 파일 변경 - _Scanner.SelectCorrectionTable(1); - - //Recipe를 기존에 Manual에서 작업하던 화면으로 rollback - WeldingRecipeManager.RollbackRecipe(); - } - } -}