# 분석 — bit15 Resume 핸드셰이크 교착 - **작성일**: 2026-08-05 - **근거 로그**: `docs/Aurora_20260805.log` (현장 PC, CP949) - **대상**: `SeqAutoRunPTOP.cs` / `UCMainAutoRunViewModel.cs` - **증상**: [AutoRun Resume]를 눌러도 PLC bit15(`PLC_WELD_READY_REQ`)가 안 내려가고 진행이 멈춤. 모니터링에서 PC 15번 비트를 수동으로 살리면 진행됨 --- ## 1. 근본 원인 — Resume 스킵 분기가 죽어 있다 ★ `Builder()`에 Resume 시 핸드셰이크를 건너뛰는 경로가 **선언되어 있다**: ```csharp // SeqAutoRunPTOP.cs:224 sb.Flows(sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ]); // 260621: Resume 시 핸드셰이크 스킵 ``` 그런데 **그 분기를 선택하는 코드가 없다**: ```csharp // SeqAutoRunPTOP.cs:322-337 CheckInitCondition (Decision 노드) private string CheckInitCondition(...) { Log.I($"[CheckInitCondition] 초기 조건 확인 중"); Status.SetWorkingPosition(eWorkingPosition.CHECKING_CONDITION); Thread.Sleep(5); Log.I($"[CheckInitCondition] 조건 확인 완료 → CheckPageNo 이동"); return SEQ_CHECK_PAGENO; // ← 무조건. ResumeMode 를 보지 않는다 } ``` `ResumeMode` 참조처는 **`CheckCycleStop`(`:883`) 하나뿐**이고, **흐름 분기에는 전혀 쓰이지 않는다.** → 길(`sb.Flows`)은 깔려 있는데 그 길로 가라고 말하는 코드가 없어서, **Resume이든 일반 시작이든 똑같이 `CheckPageNo`로 가서 PLC의 `PAGE_CHANGE_REQ`를 기다린다.** ### 교착 구조 ``` PC : PLC 가 PAGE_CHANGE_REQ(M70508) 줄 때까지 대기 (CheckPageNo) PLC : PC 가 용접 완료(또는 다른 조건) 줄 때까지 bit15 유지 → 서로 기다림 ``` - **평소**: PLC가 마침 `PAGE_CHANGE_REQ`를 줌 → 진행 → 정상으로 보였음 - **18:36**: PLC가 안 줌 → PC 무한 대기 → TIMEOUT 2회 → Resume 연타 ### 18:36:05 실측 (레시피 31) ``` 18:36:05.828 AutoRun Resume Clicked! 18:36:05.853 sequence started - 'SeqAutoRunPTOP' 18:36:05.854 [Bit15] AutoRun Resume → PC_WELD_READY_ACK ON 18:36:05.855 [Sequence_Enter] 레시피 [31], Top_Frame_Welding 활성화 18:36:05.866 [CheckPageNo] PLC_PAGE_CHANGE_REQ 신호 대기 중... ← 정체 18:37:05.874 W [CheckPageNo] Waiting for PLC_PAGE_CHANGE_REQ -> TIMEOUT... 18:38:05.880 W [CheckPageNo] Waiting for PLC_PAGE_CHANGE_REQ -> TIMEOUT... ``` 이 상태에서 Resume을 7회 연타 → 전부 `ERROR: sequence is not ready - Running`. --- ## 2. 검토했으나 주원인이 아닌 것 | 가설 | 판정 | |---|---| | PC가 ACK를 안 보냈다 | **아니다.** 클릭 46회 = `PC_WELD_READY_ACK ON` 46회 | | 1초 펄스가 짧아 PLC가 놓친다 | **근거 부족.** 46회 중 45회는 버튼으로 정상 진행 | | 수동/버튼 차이가 레벨 vs 펄스 | **근거 부족.** 위와 같은 이유 | > 초기 분석에서 펄스 가설을 원인으로 제시했으나 **철회한다.** 버튼으로 대부분 정상 동작했다. --- ## 3. 부수 결함 (교착 상태에서 증상을 악화시킴) ### 3-1. `ResumeMode`가 안 풀린다 `CheckCycleStop`(`:883-887`)이 **하루 종일 실행 0회**라, 그 안의 두 줄이 한 번도 안 돌았다: ```csharp if (ResumeMode) { WriteBit(PC_WELD_READY_ACK, false); ResumeMode = false; } ``` 해제 경로가 `OnAutoRunStartRequest:301`(일반 시작)뿐이라, `OnAutoRunResume`의 `if (!ResumeMode)` 가드(`:264`)가 무력화 → 연타가 전부 통과. ### 3-2. `OnAutoRunResume`에 Running 체크 없음 + 거짓 성공 로그 ```csharp :270 WriteBit(PC_WELD_READY_ACK, true); ← ACK 는 나감 :283 RunSequenceAutoRun(); ← Start 실패해도 반환값 확인 안 함 :284 Log.I("... Auto 재개(정상 핸드셰이크)"); ← 무조건 찍힘 ``` `OnAutoRunStartRequest`는 `ApproveAutorunByUserOrAuto():411`에서 Running을 체크하는데 여기엔 없다. ### 3-3. 타이머 중첩으로 ACK 펄스 축소 클릭마다 새 `DispatcherTimer` 생성, 기존 취소 없음(`:272-279`). 18:38:24~26 실측 — 의도 1초가 **161ms**로 축소. **연타할 때만 발생**하므로 부차적. ### 3-4. 로그 태그 함정 `[ExecuteWelding] 각도 offset 적용…`은 ExecuteWelding 노드가 아니다. `SetUploadWeldingList_SeqParams:651`의 `LaserAngleOffsetSelector.Select(…, "ExecuteWelding")` 호출자 태그 하드코딩. 이 로그로 "용접까지 갔다"고 읽으면 안 된다 (`rules.md` #1). --- ## 4. 로그 통계 (하루 전체) | 패턴 | 건수 | |---|---| | `AutoRun Resume Clicked!` / `PC_WELD_READY_ACK ON` / `OFF` | 46 / 46 / 46 | | `GetUploadWeldingList_SeqResult` | 82 | | `WeldingStartReadBit` · `WaitWeldingStart` · `WriteWeldComplete` · `CheckCycleStop` | **전부 0** | | `OnStopped` | 84 | | `ERROR: sequence is not ready - Running` | 9 | **모든 사이클이 「업로드 완료 → 즉시 OnStopped」로 끝났다.** AutoRun 시퀀스가 용접 단계에 진입한 적이 없고, 출사는 전부 Manual 수동이었다. `[CheckPageNoComp] List` 30건은 전부 3값 일치(`1/1/1`, `2/2/2`, …) — 페이지 읽기 자체는 안정적. ### 페이지 정체 구간 (16:56~17:40, 레시피 21) `List 1/1/1`이 16:56:50 / 17:04:31 / 17:23:05 / 17:34:49 — **44분간 페이지 1을 4회 반복**. 17:40:21 Resume(ACK) 직후 `List 2/2/2`로 진행. 이후 페이지마다 Resume 필요. --- ## 5. PLC 제어팀 질문 목록 (2026-08-06) ### A. Resume 시나리오 — 최우선 1. **작업자가 수동 가접을 끝내고 Resume 하면, PLC는 그다음에 무엇을 줍니까?** - `PAGE_CHANGE_REQ`(M70508)를 **다시 줍니까?** 아니면 이미 준 것으로 간주합니까? - → PC는 지금 **무조건 `PAGE_CHANGE_REQ`를 기다립니다.** 안 주시면 교착입니다. 2. **Resume 때 PC가 핸드셰이크(Page/Recipe 확인)를 건너뛰고 바로 용접해도 됩니까?** - → 260621 설계 의도가 이것인데 **코드가 빠져 있습니다.** 이대로 살릴지 결정 필요. 3. **`M70515`(bit15)를 내리는 조건 전부**를 알려주십시오. ACK 수신만입니까? - → 근거: 18:36:16에 977ms 정상 ACK 펄스를 받고도 유지됐습니다. 4. bit15가 ON인 동안 `PAGE_CHANGE_REQ`를 **안 주는 게 맞습니까?** ### B. 용접 트리거 5. **`M70516`(PLC_WELD_TRIGGER_REQ)를 실제로 주신 적이 있습니까?** - → PC 로그상 `WeldingStartReadBit`·`WaitWeldingStart`가 **하루 종일 0건**입니다. 6. 가접(bit15) 운용 최종 시나리오 — **자동 재개**입니까 **작업자 버튼**입니까? 현재는 매 페이지 [AutoRun Resume]를 눌러야 넘어갑니다. ### C. 페이지 / 워드 7. **PLC가 페이지 번호(D70501)를 올리는 조건**은 무엇입니까? ACK 수신입니까? - → 근거: 4사이클 페이지 1 고정 → ACK 1회 → 즉시 페이지 2. 8. **정지 시 PC측 에코 워드(`PC_PAGE_NO`/`PC_RECIPE_NO`)를 0으로 지워도 됩니까?** 현재는 지우지 않고 유지합니다. PLC가 0을 "무효"로 봅니까 "0번"으로 봅니까? 9. **`M70008`(PC_PAGE_CHANGE_COMPLETE)를 실제로 감시하십니까?** `M70009`(PC_RECIPE_CHANGE_COMPLETE)는 미사용이 맞습니까? ### D. ACK 신호 특성 (보조) 10. `M70015`(ACK)를 **레벨로 보십니까 엣지로 보십니까?** 최소 유지 시간은요? - → 현재 PC는 1초 펄스. 주원인은 아니나 연타 시 161ms까지 줄어듭니다. ### E. 함께 대조할 주소 | PC 심볼 | 주소 | 방향 | |---|---|---| | `PLC_WELD_READY_REQ` / `PC_WELD_READY_ACK` | M70515 / M70015 | PLC→PC / PC→PLC | | `PLC_PAGE_CHANGE_REQ` / `PC_PAGE_CHANGE_COMPLETE` | M70508 / M70008 | PLC→PC / PC→PLC | | `PLC_WELD_TRIGGER_REQ` | M70516 | PLC→PC | | `PLC_PAGE_NO` / `PLC_RECIPE_NO` | D70501 / D70502 | PLC→PC | | `PC_PAGE_NO` / `PC_RECIPE_NO` | D70001 / D70002 | PC→PLC | > 주소는 `Device/PLC/PLCController.Address.cs` **주석 기준**이며 enum은 offset 표기다. > 실제 디바이스 번호는 **미검증** — 현장 맵과 직접 대조할 것. --- ## 6. PC측 수정 후보 (미적용) | # | 내용 | PLC 협의 | |---|---|---| | **1** | `CheckInitCondition`이 `ResumeMode`일 때 `SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ` 반환 | **필요** (질문 1·2) | | 2 | `OnAutoRunResume`에 `RunState == Running` 체크 + 실패 시 `Log.E`·토스트 | 불필요 | | 3 | 타이머를 필드 1개로 두고 재클릭 시 `Stop()` 후 재시작 | 불필요 | | 4 | `[ExecuteWelding]` 호출자 태그를 실제 호출부 이름으로 수정 | 불필요 | | 5 | `ResumeMode` 해제 경로 보강 | 질문 6 결과에 따름 | **1번이 본질.** `sb.Flows`는 이미 있으므로 Decision 반환값만 추가하면 된다: ```csharp if (ResumeMode) { Log.I("[CheckInitCondition] ResumeMode → 핸드셰이크 스킵, 업로드로 직행"); return SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ; } return SEQ_CHECK_PAGENO; ``` 2~4는 PLC 프로토콜을 건드리지 않으므로 선반영 가능. --- ## 관련 문서 - [작업지시서_PTOP_PLC핸드셰이크_260805.md](./작업지시서_PTOP_PLC핸드셰이크_260805.md) — 읽기 검증(err 체크) 작업지시 - [harness-ptop.md](./harness-ptop.md) · [../rules.md](../rules.md)