diff --git a/Doc/인수인계/260916_자동운전_전환_사전점검.md b/Doc/인수인계/260916_자동운전_전환_사전점검.md new file mode 100644 index 0000000..9fdd059 --- /dev/null +++ b/Doc/인수인계/260916_자동운전_전환_사전점검.md @@ -0,0 +1,336 @@ +# 자동운전 전환 사전 점검 — 레시피/페이지 이동 및 출사 경로 분석 + +- 작성일: 2026-09-16 +- 대상: `SeqAutoRunPTOP` (Machines/ILSOS_PrismaticRD_PTOP/Sequences/SeqAutoRunPTOP.cs) +- 배경: 현장에서 현재 **수동 출사**로 운영 중. PLC 비트 조건에 따른 **자동 운전**으로 전환했을 때 + 시퀀스가 레시피/페이지를 스스로 이동해 정상 출사하는지 확인 요청. +- 방법: **정적 분석 전용. 소스 무수정, 런타임 검증 미실시.** + 런타임으로 확인한 항목은 하나도 없으며, 모든 판정은 코드 경로 추적 결과다. + +--- + +## 1. 결론 요약 + +**출사 자체는 간다.** 레시피 전환 → 페이지 전환 → 레이어 선택 → 리스트 업로드 → 발진까지 +경로가 끊긴 곳은 없고, 260806~260818 에 들어간 에코 수렴 로직이 레시피/페이지 정합성을 +노드 통과 조건으로 잡아주고 있다. + +**다만 사이클 종결부가 통째로 실행되지 않는다.** 용접은 되는데 파형 저장·생산 카운트·출력비트 +리셋이 영구히 빠진다. 그리고 **자동 경로에는 Door 인터락이 없고, 중알람이 자동운전을 멈추지 못한다.** + +| 등급 | 항목 | 영향 | +|---|---|---| +| 치명 | 사이클 종결부 3노드 영구 미실행 | 파형 미저장 · 생산카운트 미증가 · 출력비트 미리셋 | +| 높음 | 자동 경로에 Door 인터락 없음 | 문 열림 상태에서도 PC는 출사를 막지 않음 | +| 높음 | 중알람이 자동운전을 정지시키지 못함 | 정지 대상 시퀀스 ID 불일치 | +| 중 | REQ/TRIGGER 가 레벨 판정(엣지 아님) | 이론상 같은 페이지 재출사 가능 | +| 중 | 빈 페이지 만나면 자동운전 정지 | 객체 0개 레이어에서 시퀀스 중단 | +| 중 | bit15 Resume 핸드셰이크 스킵 미구현 | Resume 후 PLC 새 REQ 없으면 교착 | +| 낮음 | 디버그 토스트가 매 사이클 표시 | 운전 중 화면 노이즈 | +| 낮음 | 진단계측 로그 잔존 | MC 개별읽기 16회/초, 로그 증가 | + +--- + +## 2. 자동 사이클 흐름 (실제 코드 경로) + +`Builder()` 의 Flows 정의 기준 (SeqAutoRunPTOP.cs:211-253). + +``` +Init + → Sequence_Enter :293 PC_AUTO_STATUS=ON, 레시피 핸들 확보 + → CheckInitCondition :350 ★ 항상 RESYNC 로만 분기 (아래 6-C) + → ResyncRecipePage :598 재기동 시 PLC 워드로 Recipe/Page 선(先) 확정 + → CheckPageNo :689 PLC_PAGE_CHANGE_REQ(0x08) ON 대기 ◄── 사이클 진입점 + → CheckRecipeNoComp :475 Recipe 수렴: 읽기→ActivateRecipe→Layers reload→에코→되읽기 확인 + → CheckPageNoComp :953 Page 수렴: 읽기→_CurrentPageNo 갱신→에코→되읽기 확인 + + Recipe/Page 동시 최종확인 (어긋나면 Recipe부터 재확정) + → SetUploadWeldingList_Params :1095 Layers[_CurrentPageNo] 의 객체를 용접 대상으로 선택 + → (SeqUploadWeldingList) :181 RTC 리스트 생성 (서브시퀀스) + → GetUploadWeldingList_Result :1159 + → WeldingStartReadBit :1181 PLC_WELD_TRIGGER_REQ ON 대기 + → PreScoutCheck :1412 M70509 ON 이면 Scout 실행, OFF 면 스킵 + → WaitWeldingStart :1221 PC_WELD_TRIGGER_ACK=ON, PC_WELD_COMPLETE=OFF + → ExecuteWelding :1244 HeadTheta 인터락 → Gate ON → ExecuteList → Gate OFF + → PostScoutCheck :1430 + → WriteWeldComplete :1464 PC_WELD_TRIGGER_ACK=OFF, PC_WELD_COMPLETE=ON + → CheckCycleStop :1379 ★ 무조건 CheckPageNo 로 회귀 + ┊ + ┊ (아래 3노드는 도달하지 않음) + ┄ SaveResultData :1478 + ┄ WriteCompletionPLCBit :1512 + ┄ Complete :1530 +``` + +--- + +## 3. 정상 동작이 확인된 부분 + +### 3-1. 레시피 이동 +`CheckRecipeNoComp` (:475-579) 가 **워드만 맞추고 끝내지 않는다.** +`PLC_RECIPE_NO` 읽기 → 등록 레시피 조회 → `ActivateRecipe` → `WaitRecipeActivated` 로 반영 대기 +→ `RecipeHelper.OnActiveReloaded()` 를 **UI 스레드에서 동기 호출**해 `Model.Layers` 갱신 보장 +→ `PC_RECIPE_NO` 에코 → 되읽기로 수렴 확인(:565-567) 후에만 다음 노드로 간다. + +미등록 레시피나 0 이면 **에코하지 않고 재시도**(:516-533)한다. 에코가 안 나가면 PLC 게이트가 +열리지 않으므로 잘못된 레시피로 출사가 나갈 수 없다. 설계가 맞다. + +### 3-2. 페이지 이동 +`CheckPageNoComp` (:953-1086) 도 같은 구조다. 추가로 두 가지가 좋다. + +- 페이지 상한을 **활성 레시피의 레이어 수로 가변 검증**(:998). 하드코딩이 없어 레시피별 2~5페이지에 대응한다. +- **Recipe/Page 동시 최종확인**(:1035-1057). Page 수렴 중 PLC가 Recipe를 바꿔버린 260812 케이스를 + 잡기 위해, Page 확정 후 두 워드를 다시 읽어 둘 다 일치할 때만 통과한다. 어긋나면 Recipe부터 재확정한다. + +### 3-3. 페이지 → 실제 용접 레이어 연결 +`_CurrentPageNo = p - 1` (:1009) 로 1-base→0-base 변환 후, +`SetUploadWeldingList_SeqParams` 가 `Model.Layers[_CurrentPageNo]` 의 객체를 선택한다(:1110-1111). +Layers 접근을 UI 스레드로 직렬화(:1105)해 레시피 reload 와의 race 를 막아뒀다. 정합한다. + +### 3-4. 출사 게이트 +`ExecuteWelding` (:1244-1377): HeadTheta 인터락 판정 → `Laser_REMOTE` DO ON → 15ms 대기 → +`ExecuteList` → `WaitForListTaskCompleted` → `Laser_REMOTE` OFF → `JumpAbs(0,0)` 원점 복귀. +게이트 ON/OFF 짝이 맞고, 정지 시에도 `OnSeqActionStop` (:1786) 에서 OFF 를 보장한다. + +> **정정**: `WaitForListTaskCompleted(1000)` 의 인자 단위는 **초**다 +> (`ScannerUnit.cs:1095` `public void WaitForListTaskCompleted(int timeOut) //단위는 초`). +> 즉 1000초로, 긴 용접이 조기 절단될 위험은 없다. 이전에 "1초 하드코딩"으로 기록해 둔 메모가 있다면 잘못이다. +> 다만 초과 시 `throw`(:1104) 하며 `ExecuteWelding` 에 try/catch 가 없다. + +--- + +## 4. 치명 — 사이클 종결부 3노드 영구 미실행 + +### 근거 +```csharp +// SeqAutoRunPTOP.cs:1379-1394 +private string CheckCycleStop(...) +{ + if (ResumeMode) { ... } + Log.I($"[CheckCycleStop] 사이클 계속 진행 → CheckPageNo 이동"); + return SEQ_CHECK_PAGENO; // ← 분기 조건 없음. 무조건 이 한 줄. +} +``` +`SEQ_SAVE_RESULT_DATA` / `SEQ_WRITE_COMPLETION_PLC_BIT` / `SEQ_COMPLETE` 로 가는 경로는 +Flows 상 존재하지만(:242-244) 실행 시 선택되지 않는다. + +### 자동 전환 시 실제로 빠지는 것 + +| 미실행 | 위치 | 결과 | +|---|---|---| +| `SaveScannerRecordFileForamt()` | :1484 → :1497 | **스캐너 파형(`SaveRecord("AutoRunTDC")`) 이 한 번도 저장되지 않음** | +| 생산 카운트 증가 | :1541-1542 | Total/Today 생산수량이 자동운전에서 절대 늘지 않음 | +| `RestoreDeviceStatus()` | :1518 → :1564 | PC 출력비트 일괄 리셋 미수행 | +| `KEY_SEQUENCE_RESULT` 기록 | :1487 | 사이클 성공 여부가 남지 않음 | + +### 가장 주의할 부수효과 — `PC_PAGE_CHANGE_COMPLETE` 가 계속 ON +`CheckPageNoComp` 가 매 사이클 이 비트를 true 로 쓴다(:1076). 이 비트를 false 로 내리는 곳은 +`RestoreDeviceStatus`(:1568) 와 `OnSeqActionStop`(:1723) 둘뿐인데, 전자는 도달하지 않는다. +→ **자동운전 중에는 첫 페이지 전환 이후 계속 ON 상태로 latch 된다.** + +소스 주석(:1069, :1742)은 "PLC 는 이 비트를 보지 않는다(260806 확인)"라고 기록하고 있다. +그 전제가 맞으면 무해하고, 틀리면 2번째 페이지부터 PLC 가 전환 완료를 인지하지 못한다. +**→ PLC 확인 항목 Q1.** + +--- + +## 5. 높음 — 안전/정지 계통 + +### 5-A. 자동 경로에 Door 인터락이 없다 +`AlarmManager.IsDoorOpen()` 호출처를 전수 조사한 결과 **수동 경로 2곳뿐**이다. + +- `SeqComponentTeachingRun.cs:285` (시퀀스 진입 전) +- `SeqComponentTeachingRun.cs:624` (출사 직전 최종 게이트) +- `UCScannerLaserControlViewModel.cs:295/387/516` (메뉴얼 직접 출사) + +`SeqAutoRunPTOP.cs` 전체에 `IsDoorOpen` / `Door` 검사가 **0건**이다. `ExecuteWelding`(:1244-1377) +어디에도 없다. 즉 **자동 운전 중 문이 열려도 PC 는 출사를 막지 않는다.** + +260902 Door 인터락 작업(ISSUE-260902-01)은 수동 출사 경로만 대상이었으므로 이는 누락이 아니라 +범위 밖이었던 것이다. 다만 자동 전환 시에는 차단 책임이 **전적으로 PLC/하드와이어**에 있다. +**→ PLC 확인 항목 Q2.** + +### 5-B. 중알람이 자동운전을 멈추지 못한다 (ISSUE-260828-02, 현재 소스에서 재확인) +```csharp +// Alarm/AlarmManager_PTOP.cs:25-27 +if (alarm.Level == AlarmLevel.H) { + StopSequence(SequenceIds.SeqAutoRun); // ← 구 Prismatic 시퀀스 +} +``` +실제 운전 중인 것은 `SeqAutoRunPTOP` 다(`UCMainAutoRunViewModel.cs:101, 365`). +등록도 두 ID 가 따로 되어 있다(`EquipmentSetup.cs:218` vs `:225`). +→ **H 레벨 중알람이 떠도 자동운전은 계속 돈다.** 식별자 1개 교체로 해결되는 사안이지만 미수정 상태다. + +추가로 `ExecuteWelding` 에 알람 검사 자체가 없어, 알람 상태에서도 발진 경로가 열려 있다. + +### 5-C. 참고 — 수동 정지는 정상 +`OnStopSequenceAutoRun`(:449-467) 은 `_SeqAutoRunPTOP.Stop()` 을 정확히 호출하고, +`OnSeqActionStop` 에서 PC 출력비트 OFF + `Laser_REMOTE` OFF 까지 수행한다. 이쪽은 문제없다. + +--- + +## 6. 중 — 동작 정합성 + +### 6-A. REQ / TRIGGER 가 레벨 판정이다 (엣지 아님) +```csharp +// CheckPageNo :726 +if (_PLC.ReadBit(eBitInput.PLC_PAGE_CHANGE_REQ).data) { ... break; } +// WeldingStartReadBit :1195 +if (_PLC.ReadBit(eBitInput.PLC_WELD_TRIGGER_REQ).data) { ... break; } +``` +두 대기 노드 모두 "ON 이면 통과"이지 상승엣지를 보지 않는다. +`CheckCycleStop` 이 `CheckPageNo` 로 루프백할 때 PLC 가 아직 REQ 를 내리지 않았다면 +**같은 페이지를 다시 읽어 에코하고, TRIGGER_REQ 도 ON 상태면 같은 페이지를 한 번 더 용접한다.** + +실제로는 260826 진단계측에서 "성공 구간에는 REQ 가 OFF 로 떨어진다"고 관찰된 바 있어 +PLC 가 비트를 내려주고 있는 것으로 보인다. 즉 **현재 안전은 PLC 타이밍에 의존**하고 있고, +PC 쪽에는 중복 방지 장치가 없다. **→ PLC 확인 항목 Q3.** + +### 6-B. 빈 페이지를 만나면 자동운전이 멈춘다 +```csharp +// SetUploadWeldingList_SeqParams :1122-1126 +if (_SelectedObjectList == null || _SelectedObjectList.Count() == 0) { + Log.E("[SetUploadWeldingList] No welding objects found! Sequence will fail."); + return null; // ← 시퀀스 중단 +} +``` +객체가 하나도 없는 레이어를 PLC 가 지정하면 그 자리에서 자동운전이 끝난다(재시작 필요). +전환 전에 **운용 대상 레시피 전 페이지의 객체 수가 0 이 아닌지** 확인해 두는 편이 안전하다. + +### 6-C. bit15 Resume 핸드셰이크 스킵이 미구현 (ISSUE-260805-01, 재확인) +```csharp +// CheckInitCondition :350-365 — 분기 조건 없이 +return SEQ_RESYNC_RECIPE_PAGE; +``` +Builder 에 정의된 Resume 스킵 경로 +`sb.Flows(sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ]); // :252` +는 **선택되지 않는 dead code** 다. + +`ResumeMode=true` 여도 `ResyncRecipePage`(:600) 에서 재동기만 건너뛸 뿐, 결국 `CheckPageNo` 의 +**PLC 새 REQ 대기로 들어간다.** PLC 가 Resume 후 REQ 를 다시 주지 않으면 교착이다. +자동 전환 후 bit15(가변 용접) 운용을 함께 쓸 계획이면 이 항목이 먼저 정리돼야 한다. + +### 6-D. 참고 — HeadTheta 인터락은 체크박스 의존 +`ExecuteWelding :1253` 의 `thetaSetting.HeadThetaInterlockEnabled` 가 꺼져 있으면 +각도 판정 전체가 스킵된다. 자동 전환 전 설정값 확인 필요(fail-closed 는 활성화된 경우에만 적용). + +--- + +## 7. 낮음 — 운전 품질 + +### 7-A. 디버그 토스트가 매 사이클 뜬다 +- `Sequence_Enter :298` — `MessageUtil.ShowToast("Sequence_Enter")` (기동 시 1회) +- `WeldingStartReadBit :1200` — `MessageUtil.ShowToast("PLC_WELD_TRIGGER_REQ : ON")` **(매 사이클)** + +둘 다 `// 디버그 끝내고 삭제` 주석이 달린 채 살아 있다. 연속 자동운전 시 화면에 계속 뜬다. + +### 7-B. 진단계측 로그 잔존 +`CheckPageNo` 의 `[진단계측 2026-08-26]` region(:701-715, :752-765)이 **1초 주기로 +`BuildHandshakeSnapshot()`** 을 호출한다. 이 헬퍼는 **MC 개별읽기 16회**(:788-804)다. +page 대기가 길어지는 구간에서 PLC 통신 부하와 로그량이 함께 늘어난다. +원복 표기가 주석에 있으니 자동 안정화 후 제거 대상. + +### 7-C. 정지 시 레시피 롤백 +`OnStopSequenceAutoRun :462` 에서 `RecipeHelper.RollbackRecipe()` 를 호출한다. +자동 정지 후 활성 레시피가 직전 선택 레시피로 되돌아가므로, 정지 직후 화면 레시피가 +PLC 지시와 달라 보일 수 있다. 동작 자체는 의도된 것으로 보이나 현장 혼선 여지가 있어 기록해 둔다. + +--- + +## 8. PLC 확인 요청 항목 + +| # | 질문 | 왜 필요한가 | +|---|---|---| +| Q1 | `PC_PAGE_CHANGE_COMPLETE`(M70008)를 PLC 가 보는가? 본다면 엣지인가 레벨인가? | 자동운전 중 이 비트가 계속 ON 으로 latch 된다(4장). 엣지를 본다면 2페이지째부터 전환 인지 실패 | +| Q2 | 자동 운전 중 Door Open 시 레이저 차단은 PLC/하드와이어에서 보장되는가? | PC 측 자동 경로에 Door 검사가 전혀 없다(5-A) | +| Q3 | `PLC_PAGE_CHANGE_REQ` / `PLC_WELD_TRIGGER_REQ` 는 PC 응답 수신 후 반드시 OFF 로 내리는가? | PC 가 레벨 판정이라 OFF 가 보장돼야 중복 출사가 없다(6-A) | +| Q4 | bit15 Resume 후 PLC 가 새 PAGE_CHANGE_REQ 를 재발행하는가? | 재발행이 없으면 Resume 교착(6-C) | + +--- + +## 9. 자동 전환 전 권고 순서 + +1. **Q1~Q4 를 PLC 측과 먼저 정리.** 특히 Q2(Door)는 안전 항목이라 선행돼야 한다. +2. **운용 레시피 전 페이지의 객체 수 확인** — 빈 레이어가 있으면 그 페이지에서 멈춘다(6-B). +3. **HeadTheta 인터락 체크박스 상태 확인**(6-D). +4. **첫 전환은 1사이클 단위로** — `[CheckCycleStop] 사이클 계속 진행` 로그가 뜨는 것을 확인하고, + 그 뒤로 `[SaveResultData]` / `[Complete]` 가 **안 뜨는 것이 현재 정상**임을 인지한 상태로 관찰. +5. 파형 데이터와 생산 카운트가 필요하면 **4장 종결부 문제를 먼저 조치**해야 한다(현재 ISSUE-260828-01 보류 중). +6. bit15 가변 용접을 병행할 계획이면 **6-C 선행**. + +--- + +## 10. 로그로 보는 판정 기준 + +정상 1사이클이면 이 순서로 찍힌다. + +``` +[CheckPageNo] PLC_PAGE_CHANGE_REQ 신호 대기 중... +---> [CheckPageNo] Check OK -> PLC_PAGE_CHANGE_REQ : ON +[CheckRecipeNoComp] PLC_RECIPE_NO 수렴 시작 +---> [CheckRecipeNoComp] 수렴 완료 (N회차) - PC_RECIPE_NO: [xx] +[CheckPageNoComp] PLC_PAGE_NO 수렴 시작 +---> [CheckPageNoComp] 수렴 완료 (N회차) - PC_PAGE_NO: [x], PC_Index: [x-1] +---> [CheckPageNoComp] Recipe/Page 최종 확인 완료 (1회차) +[SetUploadWeldingList] Selected PageNo [x-1] → Layer Name: [...], Object Count: [N] +---> [WeldingStartReadBit] PLC_WELD_TRIGGER_REQ ON 감지 +[ExecuteWelding] Laser Gate ON (REMOTE) +[ExecuteWelding] WaitForListTaskCompleted 완료 +[ExecuteWelding] Laser Gate OFF (REMOTE) +[WriteWeldComplete] 용접완료 송신 - COMPLETE=true +[CheckCycleStop] 사이클 계속 진행 → CheckPageNo 이동 +``` + +주의해서 볼 로그: + +| 로그 | 의미 | +|---|---| +| `[CheckPageNoComp] 최종 확인 불일치` 반복 | PLC 가 확정 후 Recipe/Page 를 계속 바꾸는 중 (260812 패턴) | +| `[CheckRecipeNoComp] 미수렴` 반복 | 에코가 PLC 에 반영되지 않음 — 통신 또는 워드 맵 확인 | +| `Invalid PageNo: N (활성 Recipe 페이지 수: M)` | PLC 지시 페이지가 레시피 레이어 수를 초과 | +| `No welding objects found!` | 빈 페이지 — 여기서 자동운전 종료(6-B) | +| `[진단계측][CheckPageNo] 변화` 가 길게 이어짐 | REQ 대기 교착 — 스냅샷의 PAGE/REQ 값으로 PLC 스텝 확인 | +| `Object Count: [0]` | 빈 레이어 경고 신호 | + +--- + +## 11. 근거 위치 정리 + +| 항목 | 파일:라인 | +|---|---| +| 노드 등록 / Flows | SeqAutoRunPTOP.cs:172-253 | +| CheckInitCondition 무조건 분기 | SeqAutoRunPTOP.cs:350-365 | +| CheckRecipeNoComp (에코 수렴형) | SeqAutoRunPTOP.cs:475-579 | +| ResyncRecipePage | SeqAutoRunPTOP.cs:598-668 | +| CheckPageNo (REQ 레벨 대기) | SeqAutoRunPTOP.cs:689-777 | +| 진단계측 스냅샷 헬퍼 | SeqAutoRunPTOP.cs:779-825 | +| CheckPageNoComp (수렴 + 동시 최종확인) | SeqAutoRunPTOP.cs:953-1086 | +| 페이지 → 레이어 선택 | SeqAutoRunPTOP.cs:1095-1126 | +| WeldingStartReadBit (TRIGGER 레벨 대기) | SeqAutoRunPTOP.cs:1181-1218 | +| ExecuteWelding (HeadTheta + Gate) | SeqAutoRunPTOP.cs:1244-1377 | +| CheckCycleStop 무조건 루프백 | SeqAutoRunPTOP.cs:1379-1394 | +| 미도달 3노드 | SeqAutoRunPTOP.cs:1478-1562 | +| RestoreDeviceStatus | SeqAutoRunPTOP.cs:1564-1580 | +| OnSeqActionStop | SeqAutoRunPTOP.cs:1713-1800 | +| 중알람 정지 대상 ID | Alarm/AlarmManager_PTOP.cs:20-28 | +| 시퀀스 등록 (SeqAutoRun vs PTOP) | EquipmentSetup.cs:218, 225 | +| AutoRun 시작/정지/Resume | Views/Main/UCMainAutoRunViewModel.cs:242-342, 449-467 | +| PLC_AUTO_REQ 상승엣지 → 시작 이벤트 | Devices/PLC/PLCController.Config.cs:125-131 | +| WaitForListTaskCompleted 단위(초) | LASA/GUI/Scanner/ScannerUnit.cs:1095-1107 | +| Door 인터락 (수동 경로에만 존재) | SeqComponentTeachingRun.cs:285, 624 | + +--- + +## 12. 관련 이슈 + +| 이슈번호 | 관계 | +|---|---| +| ISSUE-260828-01 | 본 문서 4장과 동일 건 (종결부 3노드). 현재 보류 | +| ISSUE-260828-02 | 본 문서 5-B 와 동일 건 (중알람 정지 ID). 현재 OPEN | +| ISSUE-260805-01 | 본 문서 6-C 와 동일 건 (bit15 Resume). 현재 OPEN | +| ISSUE-260820-01 | 6-A 와 인접 (REQ 선행 / 지연). PLC 회신 대기 | +| ISSUE-260826-01 | 6-A·6-C 와 인접 (page5→6 REQ 미발행). PLC 문의 발송 | +| ISSUE-260902-01 | 5-A 의 배경 (Door 인터락은 수동 경로 한정 적용) | + +--- + +*본 문서는 정적 분석 결과이며 소스를 수정하지 않았다. 런타임 검증은 수행하지 않았다.*