LGES-OC5-PtoP-Welder/docs/작업지시서_ScoutNormal_수동출사_파일명태그_260807.md
NohDoyeon241104 b7437a00f7 feat: 수동 Scout 이미지 파일명에 레시피/페이지 번호 태그 추가
레시피 티칭 화면 Scout 출사 시 SaveTag를 normal_{recipeId}_{pageNo}로 주입해 1_HHmmss_normal_23_5.PNG 형태로 저장. 공통 시퀀스 SeqScoutNormal은 무수정(기존 SaveTag 확장점 사용). 페이지 번호는 1-base로 AutoRun의 auto_{recipe}_{page}_pre/post와 숫자 정합. 원복 마커: #region 260807. 현장 검증 완료.
2026-08-07 10:39:42 +09:00

155 lines
7.5 KiB
Markdown

# 작업지시서 — 수동 Scout 출사 이미지 파일명에 `normal_{recipeId}_{pageNo}` 태그 부착
- **작성일**: 2026-08-07
- **대상**: `WeldingComponents/WeldingCommon/Views/Recipes/UCScannerObjectTeachingControlBoxViewModel.cs`
- **상태**: **완료 (2026-08-07)** — 소스 반영 · 빌드 · **현장 검증 완료**(수동 Scout 파일명에 레시피/페이지 번호 정상 반영 확인). 태그 형식 §5 A안
- **원복 마커**: `#region 260807 이전 원본` / `#region 260807: 레시피/페이지 번호 반영 SaveTag 변경`
- **승인 구분**: `WeldingComponents` 수정이므로 **사전 승인 필수** (architecture.md §1)
---
## 1. 배경
AutoRun 자동 사이클에서 찍은 Scout 이미지는 `_auto_{recipe}_{page}_{pre|post}` 태그가 붙지만,
**레시피 티칭 화면에서 수동으로 찍은 Scout 이미지는 태그 없이** `1_{HHmmss}.PNG` 로만 저장된다.
현장에서 나중에 파일만 봤을 때 어떤 레시피·페이지를 찍은 것인지 구분이 안 된다.
### 왜 이런 차이가 나는가 (코드 근거)
`SaveTag` 를 세팅하는 곳은 저장소 전체에서 2곳뿐이다.
| 위치 | SaveTag | 결과 파일명 |
|---|---|---|
| `SeqAutoRunPTOP.cs:1153` (pre) | `auto_{recipeNo}_{pageNo}_pre` | `1_143052_auto_23_5_pre.PNG` |
| `SeqAutoRunPTOP.cs:1179` (post) | `auto_{recipeNo}_{pageNo}_post` | `1_143052_auto_23_5_post.PNG` |
| `UCScannerObjectTeachingControlBoxViewModel.cs:302` (수동) | **미설정** | `1_143052.PNG` |
| `UCTestSequenceViewModel.cs:361` (테스트 화면) | **미설정** | `1_143052.PNG` |
미설정 시 기본값은 빈 문자열이다 — `SeqScoutNormal.cs:397` `public string SaveTag { get; set; } = "";`
---
## 2. 목표 결과
```
변경 전 : 1_143052.PNG
변경 후 : 1_143052_normal_23_5.PNG
└ recipeId └ pageNo
```
저장 경로는 **변경 없음** — `D:\ILSOSConfig\ILSOS_PrismaticRD_PTOP\_vision\FieldScanImage\{yyyy_M_d}\`
> pre/post 구분은 하지 않는다. 수동 출사는 용접 전/후 개념이 시퀀스에 없다.
> `normal_` 접두어로 AutoRun 산출물(`auto_`)과 구분된다.
---
## 3. 변경 범위 — 파일 1개, 블록 1개
**공통 시퀀스 `SeqScoutNormal.cs` 는 수정하지 않는다.**
파일명 조립 로직(`SeqScoutNormal.cs:304`)이 이미 태그 유무를 분기하고 있어 확장점이 열려 있다.
```csharp
// SeqScoutNormal.cs:304 — 수정 대상 아님. 이미 이렇게 되어 있음
string fileName = string.IsNullOrEmpty(_InitParam.SaveTag) ? $"{baseName}.PNG" : $"{baseName}_{_InitParam.SaveTag}.PNG";
```
### 변경 위치: `UCScannerObjectTeachingControlBoxViewModel.cs:301-307`
**변경 전**
```csharp
var scoutSeqParams = new ScoutSeqParams(VisionRecipeManager.GetFovInfos()[0], eDisplayType.Machine_B);
var param = new SeqScoutNormal_InitParam() {
IsRealTimeScout = false,
ScoutSeqParams = scoutSeqParams,
// [추가 2026-06-19] 현재 표시 중인 페이지의 스카우트 필드를 사용하도록 명시 주입
PageIndex = CommonHelper.GetMainPage().GetCurrentPageIndex(),
};
```
**변경 후** (→ 표시 줄만 신규/변경)
```csharp
var scoutSeqParams = new ScoutSeqParams(VisionRecipeManager.GetFovInfos()[0], eDisplayType.Machine_B);
→ int pageIndex = CommonHelper.GetMainPage().GetCurrentPageIndex(); // 0-base
→ int recipeId = _Aurora.RecipeManager.ActivatedRecipe()?.Id ?? 0; // 미활성 시 0
var param = new SeqScoutNormal_InitParam() {
IsRealTimeScout = false,
ScoutSeqParams = scoutSeqParams,
// [추가 2026-06-19] 현재 표시 중인 페이지의 스카우트 필드를 사용하도록 명시 주입
→ PageIndex = pageIndex,
→ // [추가 2026-08-07] 수동 출사 이미지 파일명 태그 — {기존}_normal_{recipeId}_{pageNo}.PNG
→ SaveTag = $"normal_{recipeId}_{pageIndex + 1}",
};
```
---
## 4. 값 소스 (검증 완료)
| 값 | 소스 | 근거 | 비고 |
|---|---|---|---|
| `recipeId` | `_Aurora.RecipeManager.ActivatedRecipe()?.Id` | 선례 `SeqAutoRunPTOP.cs:465-466` | `_Aurora` 는 이미 이 클래스 필드(`:50`), 생성자에서 주입(`:154`) — 신규 의존성 없음 |
| `pageIndex` | `CommonHelper.GetMainPage().GetCurrentPageIndex()` | `MainPage.cs:526-534` | **0-base** (콤보박스 SelectedIndex, 음수면 ActiveLayer.No 폴백) |
| 파일명의 `pageNo` | `pageIndex + 1` | — | **§5 확인 필요** |
### AutoRun 태그와의 의미 차이 (설계상 의도된 차이)
| | AutoRun 태그 | 수동 태그 |
|---|---|---|
| 레시피 출처 | PLC 워드 `PLC_RECIPE_NO` (`plcRecipeNo`) | **PC 활성 레시피** |
| 페이지 출처 | PLC 워드 `PLC_PAGE_NO` (`plcPageNo`, 1-base) | **화면 선택 페이지** |
수동 출사 시점에는 PLC 워드가 현재 화면과 무관할 수 있으므로 PC 기준이 맞다.
정상 사이클에서는 `CheckRecipeNoComp` 수렴 후 두 값이 일치한다 (`SeqAutoRunPTOP.cs:457-545`).
---
## 5. 페이지 번호 base — **A안 확정 (2026-08-07)**
`GetCurrentPageIndex()` 는 **0-base**, AutoRun 태그의 `plcPageNo` 는 **1-base** (`SeqAutoRunPTOP.cs:141`).
| 안 | 파일명 (화면에서 5페이지 선택 시) | 결과 |
|---|---|---|
| **A. `pageIndex + 1`** ← **확정** | `..._normal_23_5.PNG` | AutoRun `..._auto_23_5_pre.PNG` 와 **같은 숫자** — 대조 가능 |
| B. `pageIndex` 그대로 | `..._normal_23_4.PNG` | 같은 페이지인데 숫자가 1 작음 — 혼동 |
확정 태그 식: `$"normal_{recipeId}_{pageIndex + 1}"`
→ 화면 표시 페이지 번호와 파일명 숫자가 일치하고, AutoRun 산출물과 직접 대조된다.
---
## 6. 영향 범위
- **동작 변경**: 레시피 티칭 화면 Scout 버튼으로 찍은 이미지의 **파일명만** 바뀐다.
- **경로·포맷·저장 로직**: 변경 없음. `SeqScoutNormal.cs:305-310` 그대로.
- **Teaching 화면 표시**: 영향 없음. 저장 직후 `_SystemParameter.ScannerFieldImageFile` 에 전체 경로를 넣고
설정 저장으로 화면이 갱신되는 구조라(`SeqScoutNormal.cs:307`, `:312-313`) 파일명에 무관하다.
- **AutoRun 경로**: 무영향. `SeqAutoRunPTOP.cs` 무수정.
- **`UCTestSequenceViewModel.cs:361`(테스트 시퀀스 화면)**: **이번 범위에 포함하지 않음.** 태그 없이 유지.
### 기존 파일과의 호환
기존에 쌓인 `1_{HHmmss}.PNG` 파일은 그대로 남는다. 파일명 규칙이 날짜 폴더 단위로 섞이지만
접미어 유무로 신/구 구분이 가능하다.
---
## 7. 검증 방법
1. 빌드: `ILSOS_All.sln` / `Release|x64` → `Machines/_out_prismatic_rd_ptop/x64-Release/`
2. 레시피 활성화 후 레시피 티칭 화면에서 페이지 선택 → Scout 버튼 실행
3. `D:\ILSOSConfig\ILSOS_PrismaticRD_PTOP\_vision\FieldScanImage\{오늘날짜}\` 확인
- 기대: `1_{HHmmss}_normal_{활성레시피ID}_{선택페이지}.PNG`
4. 레시피 미활성 상태에서도 실행 → `normal_0_{페이지}` 로 저장되고 **예외가 나지 않는지** 확인
5. AutoRun 1사이클 실행 → `_auto_..._pre` / `_auto_..._post` 가 **종전대로** 나오는지 회귀 확인
> 5번은 M70516(WELD_TRIGGER_REQ)이 실제로 ON 되어야 검증된다. 2026-08-05 로그에서는 이 비트가
> 한 번도 감지되지 않아 AutoRun Scout 노드에 도달하지 못했다 (`Check OK -> PLC_WELD_TRIGGER_REQ` 0건).
---
## 8. 롤백
변경 블록에 `[추가 2026-08-07]` 주석 마커를 남긴다. 원복 시 해당 마커 줄과 `SaveTag` 줄,
지역변수 2줄을 제거하고 `PageIndex` 를 원래 인라인 호출로 되돌리면 된다.