- 분석_bit15_Resume_핸드셰이크_260805.md - 작업지시서_PTOP_PLC핸드셰이크_260805.md - 분석_HeavyAlarm_비트_동작_260810.md - 작업일지 2026_08_06.md
10 KiB
작업지시서 — PTOP AutoRun PLC 핸드셰이크 읽기 검증
- 작성일: 2026-08-05
- 대상:
Machines/ILSOS_PrismaticRD_PTOP/Sequences/SeqAutoRunPTOP.cs - 증상: AutoRun 중 간헐적으로 Recipe No / Page No 를 PLC에서 받고도 제대로 읽어오지 못함
- 상태: 아래 §3만 소스 반영. §4는 미반영 — 작업 대기
1. 배경
정지(STOP) 시 BIT는 초기화하는데 WORD(Page·Recipe No)는 초기화하지 않는다는 점 때문에 WORD 0 초기화를 추가하려 했으나, 분석 결과 증상과 방향이 반대임이 확인됐다.
| 방향 | 증상과의 관계 | |
|---|---|---|
| WORD 0 초기화 | PC → PLC (쓰기) | 무관 |
| 실제 증상 | PLC → PC (읽기) | 여기가 원인 |
정지 시 WORD를 지울 필요가 없는 이유(코드 근거):
- 재진입 시
CheckRecipeNoComp/CheckPageNoComp가 어차피 워드를 재에코한다 (:395,:429,:563). - PLC가 보는 핸드셰이크 게이트는 워드가 아니라
PC_PAGE_CHANGE_COMPLETE(0x08) 비트이고 (PLCController.Address.cs:63), 그 비트는 정지 시 이미 false로 내려간다 (:1206). - bit15 Resume(Manual 수동 출사 후 이어하기)은 직전 Recipe/Page 에코가 남아 있어야 한다
(
UCMainAutoRunViewModel.cs:226).
2. 확인된 사실 (코드 근거)
2-1. ReadWord 의 에러 코드를 아무도 검사하지 않는다 ★ 최우선
// Device/PLC/PLCController.Logic.cs:16
public (int err, short data) ReadWord(eWordInput address) => base.ReadWord((ushort)address, ePLCDevice.D);
SeqAutoRunPTOP.cs 에서 .err 참조 0건. 전 호출부가 .data 만 꺼낸다.
| 위치 | 호출 |
|---|---|
:349 |
plcRecipeNo = _PLC.ReadWord(PLC_RECIPE_NO).data; |
:376 |
plcRecipeNo = _PLC.ReadWord(PLC_RECIPE_NO).data; (재폴링) |
:508 |
plcPageNoList.Add(_PLC.ReadWord(PLC_PAGE_NO).data); |
:571 |
curPlcPageNo = _PLC.ReadWord(PLC_PAGE_NO).data; (ACK 검증) |
:763 |
thetaRaw = _PLC.ReadWord(HEAD_THETA_POSITION).data; |
프레임워크 자신은 검사한다 —
WeldingCommon/Devices/PLC/PLCController.Logic.cs:30if (readValue.err != E1.OK) { Log.E("RMS Parameter Read Fail"); return E2.CANCELLED; }같은 코드베이스에 확립된 패턴인데 이 시퀀스만 따르지 않는다.
[추론] 읽기 실패 시 data 가 default(short) = 0 으로 오는 것으로 보이나 미검증
(Melsec 드라이버까지 확인 필요). 다만 아래 2-2·2-3은 0이 올 때 증상과 정확히 일치한다.
2-2. 레시피는 1회만 읽고, 실패값 0이 "전환 의사 없음"으로 흡수된다
:348 // Recipe No 1회 읽기 (Page Change bit와 함께 래치되어 안정적이라고 가정 → 노이즈 검증 생략)
:349 plcRecipeNo = _PLC.ReadWord(PLC_RECIPE_NO).data;
:353 if (plcRecipeNo == 0) → "레시피 전환 생략, 현 Recipe 유지"
:356 return SequenceAction.Ok(); ← 알람도 정지도 없음, 에코도 안 함
주석의 "가정"이 깨지는 것이 지금 증상이다. 통신 실패 0과 PLC가 준 0이 구분되지 않아
이전 레시피 그대로 용접하는 경로가 열려 있다 (rules.md #1 — 주석 맹신 금지 사례).
읽기 순서상 레시피가 가장 먼저, 지연 없이 읽힌다:
CheckPageNo:457 PLC_PAGE_CHANGE_REQ ON 감지 → 즉시 break
↓ 지연 없음
CheckRecipeNoComp:349 ReadWord(PLC_RECIPE_NO) ← 1회, 무검증 ★ 가장 취약
↓
CheckPageNoComp:508 ReadWord(PLC_PAGE_NO) ×3 (200ms 간격)
PLC가 REQ 비트를 먼저 올리고 워드를 몇 스캔 뒤에 쓴다면 레시피만 stale/0 을 읽는다. 페이지는 600ms를 버니 살아남는다 — "레시피 번호를 못 읽어온다"와 부합.
2-3. "3회 연속 검증" 이 실제로는 검증이 아니다
:492 Log.I("PLC 페이지 번호 읽기 시작 (3회 연속 검증)")
:508 3개를 plcPageNoList 에 수집
:551 Log.E($"List {[0]}/{[1]}/{[2]}") ← 로그로 찍기만 함
:532 범위 검사는 plcPageNo(= 마지막 값) 하나만
세 값을 서로 비교하는 코드가 없다. 2, 0, 3 으로 읽혀도 마지막 3 이 범위 안이면 통과한다.
즉 반복만 있고 일치 확인이 없어 반복의 효과를 얻지 못한 채 600ms만 소비한다.
3. 이번에 반영한 것 (소스 수정 완료)
3-1. OnSeqActionStop() — 워드 0 초기화 제거, 정지 모드만 로그
SeqAutoRunPTOP.cs #region 260805
if (!ResumeMode) Log.I("일반 정지 (ResumeMode=false) → 에코 워드 보존, 0 초기화 안 함 (…)");
else Log.I("Resume 정지 (ResumeMode=true, bit15 Manual 전환) → 에코 워드 반드시 보존 (…)");
- PLC 동작 영향 0 — 워드를 쓰지 않는다. 260621 협의 동작 그대로.
- 로그 값은 캐시 필드(
plcPageNo/plcRecipeNo)다. 정지(특히OnForceError경로)에서 PLC를 다시 읽지 않기 위함. - 0 초기화가 필요하다고 판단되면 PLC 담당 확인 후
!ResumeMode쪽에만WriteWord를 넣는다.
3-2. CheckPageNoComp — return null 제거, 대기 + 토스트
invalidPageWait++;
Log.E($"Invalid PageNo received: {plcPageNo} (활성 Recipe 페이지 수: {recipePageCount}) — 대기 {invalidPageWait}회차");
if (invalidPageWait == 1 || invalidPageWait % TOAST_EVERY == 0)
MessageUtil.ShowErrorToast($"PLC Page No 이상: {plcPageNo}\n모니터링 확인해주세요.");
plcPageNoList.Clear(); checknum = 0; Thread.Sleep(3000); continue;
- 종전
return null은 Aurora 시퀀스 중단이었다 (docs/Aurora에이전트레퍼런스모음/02_patterns/sequence-builder.md:36—null 중단). 일시적 오독 한 번에 AutoRun이 죽고 재시작이 필요했다. - 이제 중단하지 않고 이 노드에서 대기·재수집한다. 작업자가 토스트를 보고 모니터링에서 값을 확인·조치하면 다음 회차에 정상값을 읽어 AutoRun 재시작 없이 이어간다.
recipePageCount는 매 회차 활성 Recipe 의Model.Layers.Count()로 다시 구한다 (:531). Recipe마다 페이지 수가 다르고, 레시피 반영이 늦으면 이 값도 늦게 맞으므로 재시도가 그 지연을 흡수한다.- 토스트는 첫 회차 + 이후 10회마다(약 30초 간격). 폭주 방지.
- 탈출 경로는
while (!context.Stopped)— Stop 버튼 정상 동작.
⚠ 상한이 없으므로 조건이 해소되지 않으면 무기한 대기한다. 의도된 동작이다 (작업자 개입 전제). 상한이 필요해지면
invalidPageWait로 쉽게 추가할 수 있다.
4. 작업 지시 (미반영 — 대기)
우선순위 순. 1번만 해도 원인 규명이 된다.
[P1] ReadWord err 체크 래퍼 도입
using Hermes;추가 (E1.OK). 같은 폴더의SeqStreamTest.cs등이 이미 사용.- 헬퍼 예:
private (bool ok, short data) ReadWordChecked(eWordInput addr, string caller, int retry, int delayMs)err == E1.OK확인 → 실패 시 재시도 → 최종 실패면ok=false- 재시도 후 성공한 경우도
Log.W로 남길 것 — "간헐적 삐끗"이 로그에 잡히는 지점
- 적용: §2-1 표의 5개 호출부
- 원칙: 시퀀스 흐름은 바꾸지 않는다. 현장 가동 중이므로 로그·토스트로만 구분한다.
로그로 갈려야 하는 4가지:
| 로그 | 의미 |
|---|---|
읽기 재시도 N회 후 성공 |
간헐적 통신 삐끗 ← 현 증상 후보 |
ReadWord 최종 실패 |
지속 통신 장애 |
PLC_RECIPE_NO: [0] ※읽기실패값 |
0이 통신 실패였음 |
PLC_RECIPE_NO: [0] (경고 없음) |
PLC가 진짜 0을 준 것 |
[P2] 레시피 다중 읽기 + 일치 검증
CheckRecipeNoComp:349 를 페이지와 대칭으로. §2-2의 settle race 흡수용.
단, P1 로그로 원인을 확정한 뒤 판단할 것 — 불필요하면 사이클 타임만 늘어난다.
[P3] 3회 수집을 실제 일치 검증으로 + 조기 종료
// 같은 값 2회 연속 → 안정으로 보고 조기 종료 (정상 시 600ms → 400ms)
if (checknum >= 2 && plcPageNoList[checknum-1] == plcPageNoList[checknum-2]) break;
// 3회 다 읽었는데 흔들리면 → 마지막 값을 믿지 말고 재수집
if (checknum > 2 && plcPageNoList.Distinct().Count() > 1) { 재수집 }
⚠ 범위 검사가 if (checknum > 2) 블록 안에 있으므로(:532), 조기 종료를 넣으려면
그 검사를 블록 밖으로 빼는 구조 변경이 필요하다.
[P4] ReadBit err 체크
:457, :695, :902, :928, :1148. 전부 대기 루프 안이라 실패해도 다음 폴링에서
재시도된다 — 위험도 낮음. 여력 있을 때.
5. PLC 협의 / 미확인 사항
| 항목 | 내용 |
|---|---|
| REQ 비트 ↔ 워드 타이밍 | PLC가 PAGE_CHANGE_REQ(M70508)와 워드(D70501/D70502)를 같은 스캔에 쓰는가, 비트를 먼저 올리는가. 비트가 먼저면 P2 필수, 동시면 P1만으로 충분 |
| 읽기 실패 시 반환값 | [추론] data=0 으로 보이나 미검증. Melsec 드라이버 확인 필요 |
| 정지 시 에코 워드 0 초기화 | PLC가 PC측 에코 워드 0을 "무효"로 보는지 "0번"으로 보는지. 현재 미결 → 그래서 3-1에서 쓰지 않음 |
| 현장 로그 | PLC_RECIPE_NO: [0] / Invalid PageNo received: 0 이 남아 있는지. 있으면 §2 분석이 즉시 확정된다 |
6. 검증 방법
- 빌드
msbuild Machines/ILSOS_PrismaticRD_PTOP/ILSOS_PrismaticRD_PTOP.csproj /p:Configuration=Debug /p:Platform=x64 /v:m /nologo - 3-1 확인 — AutoRun 정지 후 로그에
일반 정지 (ResumeMode=false)또는Resume 정지 (ResumeMode=true…)중 하나가 찍히는지. PLC 모니터에서 D70001/D70002가 이전 값을 유지하는지. - 3-2 확인 — 범위 밖 PageNo 유입 시 AutoRun이 죽지 않고 토스트가 뜨는지. 모니터링에서 값 조치 후 재시작 없이 이어지는지. Stop 버튼이 대기 중에도 듣는지.
관련 문서
- bit15 Resume 정체 분석 + PLC 질문 목록: 분석_bit15_Resume_핸드셰이크_260805.md
- 하네스:
harness-ptop.md - 협업 규칙:
../rules.md— 특히 #1(주석 맹신 금지), #2(수정 승인), #15·#16(추론 표기) - Aurora 시퀀스 규칙:
docs/Aurora에이전트레퍼런스모음/02_patterns/sequence-builder.md