163 lines
11 KiB
Markdown
163 lines
11 KiB
Markdown
# 작업일지 — 2026-07-23
|
|
|
|
## 1. Recipe Laser Shot — Laser Ready / Guide Beam IO 번호 확인 및 상시 ON 레이저 대응
|
|
|
|
### 배경
|
|
현장 레이저가 기존과 달라 배선을 다른 곳에 물렸고, **레이저 컨트롤러를 상시 ON** 상태로 둔 채 그 값을 읽어
|
|
**TRUE로 유지돼야 레시피 출사 시퀀스가 동작**하는 구조로 가야 함.
|
|
Recipe의 Laser Shot 구간에서 Laser Ready 버튼 / Guide Beam 버튼이 물린 **IO 번호 확인** 요청.
|
|
|
|
> **현재 프로그램 SOURCE는 수정하지 않음** — 분석 및 수정안(DIFF)만 기록.
|
|
|
|
### 확인 결과 — 현재 사용 중인 IO 번호
|
|
| 항목 | 방향/번호 | enum 의미 | 소스 위치 |
|
|
|---|---|---|---|
|
|
| Laser Ready 판정(모니터링) | **DI 11 && DI 15** | `CoreLaser_Laser_Output_State` / `RingLaser_Laser_Output_State` | `UCScannerObjectTeachingControlBoxViewModel.cs:271` |
|
|
| Laser Ready 버튼(토글 출력) | **DO 9, DO 13** | `CoreLaser_Control` / `RingLaser_Control` | 같은 파일 `:552~567` |
|
|
| Guide Beam 상태 표시 | **DO 17 (읽기)** | `EX_Red_Control` | 같은 파일 `:270` |
|
|
| Guide Beam 버튼(토글) | **DO 17 (쓰기)** | `EX_Red_Control` | 같은 파일 `:534~542` |
|
|
| 출사(TeachingRun) 게이트 | `IsLaserReady == false` → 차단 | — | 같은 파일 `:415~418` |
|
|
|
|
- Guide Beam은 DI가 없어 **DO 17 명령 비트를 되읽어 표시**(실제 빔 출력 피드백 아님).
|
|
- Laser Ready 판정 IO 변천: `DI 9` → `DI 12 && DI 24`(260617) → `DI 11 && DI 15`(260618, 현재).
|
|
|
|
### 현재 구조가 상시 ON 레이저와 안 맞는 이유
|
|
- DO9/DO13 토글은 더 이상 Ready 성립 조건이 아님(안 눌러도 Ready여야 하고, 눌러도 무의미).
|
|
- 판정은 **새로 물린 DI를 상시 읽어 TRUE 유지**하는 형태여야 함.
|
|
- 변경 포인트는 **271행 판정식(필수)** + **버튼 의미 재정의(선택)** 두 곳뿐.
|
|
|
|
### 작성한 수정안 (미적용)
|
|
- 판정 DI를 파일 상단 상수(`DI_LASER_READY_MAIN` / `DI_LASER_READY_SUB`)로 추출 → 현장 번호 확정 시 상수만 교체.
|
|
`SUB < 0` 이면 단일 DI 판정으로 자동 동작.
|
|
- 점검용 `FORCE_LASER_READY`(기본 false, true 커밋 금지) 추가.
|
|
- Laser Ready 버튼: DO9/13 쓰기 차단 + 현재 DI 상태 토스트 안내(구 레이저 복귀 대비 주석 보존).
|
|
- 출사 게이트(`PerformCmdRunTeachingRun`)는 변경 없음 — `IsLaserReady`가 TRUE 유지되면 자동 통과.
|
|
- (별건) `LaserIOControl.cs` `RingLaser_Control_Status = 23` → 실배선 기준 `24` 정정 권장.
|
|
|
|
### 주의 — DI/DO 실제 의미
|
|
인덱스의 실제 의미는 enum이 아니라 **런타임 로드되는 `DI.csv`/`DO.csv` 맵**이 결정한다
|
|
(Setting → Device(IODevice) Config의 `IOInterfaceMapDI/DO`, 소스 하드코딩 없음).
|
|
기본 `DI.csv`는 12=START SWITCH, 24=FAN 8 ALARM, 25=LASER Ready 로 **enum과 불일치 가능** → 번호 확정 시 CSV 대조 필수.
|
|
|
|
### 잔여·후속 작업
|
|
- [ ] 현장 신규 배선 **Ready DI 번호 확정**(단일인지 Core/Ring 2개 AND인지 포함)
|
|
- [ ] 로드 중인 `DI.csv`에서 해당 번호 라벨 확인
|
|
- [ ] 판정부 적용 + 상수값 교체 → Recipe 화면에서 컨트롤러 ON만으로 Ready=TRUE 확인
|
|
- [ ] TeachingRun(출사)이 버튼 조작 없이 진입되는지 확인
|
|
- [ ] Guide Beam은 여전히 명령 비트 되읽기 — 신규 레이저에 가이드빔 제어선 별도 존재 시 DO 번호 재확인
|
|
(정식 경로 TruPulse `ExtPilotOnOff` 미구현)
|
|
|
|
**상세 분석서:** `docs/분석/2026/07/23/Laser_Shot_IO_LaserReady_GuideBeam_분석.md`
|
|
|
|
---
|
|
|
|
## 2. 시퀀스 측 레이저(IO) 인터락 추가 분석 — `SeqComponentTeachingRun`
|
|
|
|
Manual 출사를 `SeqComponentTeachingRun` 으로 돌릴 예정이므로, 시퀀스 안의 레이저 Ready 확인부까지 확인.
|
|
**소스는 여전히 미수정(분석만).**
|
|
|
|
### 확인 결과 — Ready 를 보는 곳은 3계층, 그중 실효는 1개뿐
|
|
| 계층 | 위치 | 판정 | 효력 |
|
|
|---|---|---|---|
|
|
| ① 화면 게이트 | ViewModel `:415` ← `:271` `DI11 && DI15` | IO 기반 | **유일한 실동작 IO 인터락**(버튼 클릭 시점 1회) |
|
|
| ② 시퀀스 진입 | `SeqComponentTeachingRun.cs:473` `_Laser.GetLaserReady` | Aurora Laser 디바이스(**IO 아님**) | 결선과 무관 |
|
|
| ③ 출사 직전 | 같은 파일 `:561` → `LaserReadyResponse()` `:658` | `return true;` 스텁 | **인터락 없음** |
|
|
|
|
→ **시퀀스 내부에는 IO(DI) 기반 Ready 확인이 없다.** 실동작 인터락은 Head Theta(`:572~613`)뿐.
|
|
|
|
### "Laser Ready" 정의가 3벌로 갈려 있음
|
|
- ViewModel `:271` = **DI 11 && DI 15**(`Laser_Output_State`)
|
|
- `LaserIOControl.cs:77` = **DI 9 && DI 13**(`Laser_Ready`)
|
|
- 시퀀스 `:473` = 레이저 디바이스 호출(IO 미사용)
|
|
|
|
### 부수 발견
|
|
- `LaserIOControl` 은 PTOP 에서 dead — IODevice 는 `PAIX_PTOP` 등록(`EquipmentSetup.cs:153`),
|
|
`SeqTestRun.cs:469` 의 `as LaserIOControl` 는 항상 null. **단 `SeqTestRun` 은 미사용 파일(확인 완료)** → 실동작 리스크 없음.
|
|
- **Auto 경로엔 레이저 Ready 인터락 자체 없음** — `SeqAutoRunPTOP.cs:589` 는 no-op 이고 호출처도 없음.
|
|
- `ePrismaticDIAddress/DOAddress` enum 이 `PAIX_PTOP.cs` / `LaserIOControl.cs` **2벌 중복**.
|
|
|
|
### 수정 방향(미적용) — 판정 1곳 + 호출 3곳
|
|
1. 공용 게이트 `WeldingCommon/Devices/Laser/LaserReadyGate.cs` 신설(상수 MAIN/SUB/FORCE, `IsReady(IODevice)` fail-closed)
|
|
— 구식 csproj 라 `<Compile Include>` 수동 추가 필요
|
|
2. ViewModel `:271` → 게이트 호출
|
|
3. 시퀀스 `:473` → `_Laser.GetLaserReady` 대신 게이트
|
|
4. 시퀀스 `:658 LaserReadyResponse()` → 게이트 (출사 직전 재확인 부활)
|
|
5. `LaserIOControl.GetLaserReady()` 도 게이트로 위임
|
|
6. Laser Ready 버튼(DO9/13) 쓰기 차단 + DI 상태 토스트
|
|
|
|
**리스크:** 4번은 "항상 통과 → 미충족 시 차단"으로 바뀌므로 **Ready DI 번호 확정 후 마지막에** 적용.
|
|
Auto 경로 게이트 추가는 양산 정지 리스크가 새로 생기므로 현장 합의 후 별도 결정.
|
|
|
|
**상세:** 같은 분석서 §6~§9
|
|
|
|
---
|
|
|
|
## 3. 아키텍처 검토 — IO 직접 제어 vs Laser 추상화 계층 (학습용)
|
|
|
|
**소스 수정 없음. 개념 정리 + 다음 프로젝트 방향성 기록.**
|
|
|
|
### 논의
|
|
- **차장님 의견:** 추상화 레벨이 `Laser` 클래스이므로, **디바이스 등록 시점에 IO 보드를 Laser 에 물리고 IO 주소/비트 맵도 함께 등록**해 한 곳에서 관리했어야 함.
|
|
- **PTOP 현실:** IO 는 `IODevice` 로 따로 등록 → 화면·시퀀스가 address 를 직접 읽어 개별 제어.
|
|
- **결론(받은 답변):** IO Device 는 IO Device 대로 쓰되 **Laser Device 가 IO Device 에 의존적으로 동작**하는 게 정석. **이력을 모르면 추적이 어려울 뿐, 사용에는 지장 없음.**
|
|
|
|
### 확인한 사실
|
|
- Aurora 에 **IO형 레이저 구현이 이미 존재** — `Laser.cs:90~103` 의 `eLaserType.IPG_YLS / Coherent_Arm_IO / Trumpf_IO` 가 `DeviceManager["IO_Board"]` 를 꺼내 `ILaser` 구현체에 **주입**.
|
|
- `LaserTrumpf_IO` 는 `LaserOn/Off`, `GetLaserReady`, `PilotLaser`, 300ms 상태 폴링·램프 갱신까지 **전부 DI/DO 로 구현**돼 있음 → 지금 ViewModel 이 손으로 하는 일이 이미 들어있음.
|
|
- **단, 계층을 옮겨도 "매번 소스 수정"은 안 없어짐** — `LaserTrumpf_IO` 도 핀이 `ePTDIAddress` enum 하드코딩.
|
|
→ 문제는 **(A) 제어 경로 분산** 과 **(B) 핀 번호 하드코딩** 2개이며 서로 독립.
|
|
|
|
### (B) 해결 수단 — 이미 사용 가능
|
|
- **옵션 1(추천, 재빌드 0):** `IOUnit.cs:367 GetDiIndex(string id)` / `:380 GetDoIndex` 로 **`DI.csv` 라벨 조회** → 배선 변경 시 CSV 한 줄만 수정.
|
|
- **옵션 2:** `LaserInterlockSetting` 에 DI 번호 필드 추가 → 세팅 화면에서 변경(재빌드 없음).
|
|
- **옵션 3(중장기):** `LaserConfig` 확장 + IO형 일원화 — 공용 `AuroraLaser` 수정이라 타 장비 회귀 리스크.
|
|
|
|
### 다음 방향성
|
|
즉효로 옵션 1/2 + 판정 게이트 1곳 수렴 → 안정화 후 게이트 내부를 `_Laser.GetLaserReady()` 위임으로 교체해 Laser 계층에 흡수.
|
|
신규 프로젝트는 **처음부터 `eLaserType.*_IO` 등록 + 핀 맵 Config/CSV 관리**.
|
|
|
|
### 숙제
|
|
- `CommonDeviceIds.IODevice` 실제 값이 `"IO_Board"` 인지 (`Laser.cs` 가 문자열 하드코딩 조회 → 다르면 IO형 전환 시 NRE)
|
|
- PTOP 현재 `LaserConfig.Type` 설정값 / `Trumpf_IO` 핀 배치와 실배선 일치 여부
|
|
- `DI.csv` 에 신규 Ready 신호가 이름으로 등재됐는지(옵션 1 가능 여부)
|
|
- `LaserTrumpf_IO.GetLaserReady()` 는 시뮬에서 **false** 반환(`:273`) → 개발 PC 출사 막힘, 전환 시 정책 확인
|
|
|
|
**상세:** 같은 분석서 §10~§17
|
|
|
|
---
|
|
|
|
## 4. 이설·다현장 대응 관점 — "왜 설정화인가"
|
|
|
|
**질문:** A공장에 맞춰 놓아도 B공장으로 이설하면 바뀌는 부분이 있는데, 소스 수정으로 대응하는 게 맞나?
|
|
**답:** 맞지 않다. 단 "전부 설정화"도 아니고 **값의 종속성으로 3계층 분리**가 먼저.
|
|
|
|
| 계층 | 내용 | 위치 | 이설 시 |
|
|
|---|---|---|---|
|
|
| ① 설비 고유·불변 | 시퀀스 흐름, 안전 판정 **알고리즘**, PLC 규약 | 코드 | 안 바뀜 |
|
|
| ② 호기·현장 가변 | **IO 핀 매핑**, PLC IP/국번, 원점·오프셋, 경로, 타임아웃 | 설정(CSV/json) | **여기만 교체** |
|
|
| ③ 생산 가변 | 파워·속도·좌표·페이지 | 레시피/모델 | 품종별 |
|
|
|
|
- **현 문제:** ②인 Laser Ready DI 가 ①(코드)에 있음 → 레이저 교체만으로 재빌드. 실제 이번 건에서 `DI9 → DI12&24 → DI11&15` **소스 3회 수정.**
|
|
- **Aurora 는 ② 자리를 이미 제공** — `IOUnitConfig.IOInterfaceMapDI/DO`, `IODevice.cs:252` CSV 로드, `IOUnit.cs:367 GetDiIndex(string)`.
|
|
**`DI.csv` 가 저장소에 없다는 것 자체가 "현장 데이터로 관리하라"는 설계 방증.**
|
|
- **권장:** 소스 / **현장 프로파일**(DI·DO CSV, DeviceConfig, Setting json, 보정파일) 분리 → 이설 시 프로파일만 교체.
|
|
단 **① 기동 시 매핑 검증+로그**(미등재 `-1` 이면 fail-closed·알람), **② 프로파일 형상관리(공장/호기별 백업)** 를 반드시 같이 넣을 것.
|
|
- **한계선:** 인터락 **판정 로직 자체**는 코드에 유지(현장이 바꿀 수 있는 건 "어느 핀인가"까지). 설정 변경은 권한 제한 + 이력 로그.
|
|
- **진행 순서:** 게이트 1곳 수렴 → CSV 라벨 조회 → (대체: Setting 노출) → 기동 검증·로그 → 안정화 후 Laser 계층 위임.
|
|
|
|
**상세:** 같은 분석서 §18~§23
|
|
|
|
---
|
|
|
|
## 5. 학습노트 (읽기용 정리본)
|
|
|
|
소스를 열지 않고도 흐름이 잡히도록 **핵심 코드를 옮겨 담은 정리본**을 별도 작성.
|
|
|
|
**`docs/분석/2026/07/23/레이저제어_구조_학습노트.md`**
|
|
|
|
- §0 30초 요약 → §1 Aurora 레이저 계층도 → **§2 코드 읽는 순서(①~⑥)**
|
|
- §3 `LaserTrumpf_IO` 가 DI/DO 로 하는 일(코드 발췌) → §4 구현체가 갈리는 지점(`Laser.cs:60~103`)
|
|
- §5 PTOP 실제 등록/화면 코드 → §6 시퀀스 Ready 3계층 + 정의 3벌 표
|
|
- §7 문제는 두 개(A 경로 분산 / B 핀 하드코딩, 서로 독립) → §8 `IOUnit.GetDiIndex` 로 이름 조회
|
|
- §9 이설 관점 3계층 + 현장 프로파일 → §10 결론 3줄 → **§11 셀프 체크 5문항** → §12 숙제
|