Merge origin/field/ptop-1st: 충돌 4파일 원격 최신(4f03a0a) 기준 통일

용접 전/후 Scout 기능이 원격(4f03a0a, M70509 기반)에서 재작업되어
로컬 Scout 구현(SEQ_PRE_SCOUT_*, M70009/M70010)과 충돌.
가장 최근 커밋 4f03a0a 기준으로 아래 4파일 전부 원격 버전 채택:
- Doc/ILSOSConfig/PLC_DeviceMap_Bit_Input_M_Device.csv
- Machines/ILSOS_PrismaticRD_PTOP/Device/PLC/PLCController.Address.cs
- Machines/ILSOS_PrismaticRD_PTOP/Sequences/SeqAutoRunPTOP.cs
- WeldingComponents/WeldingCommon/Sequences/Main/SeqScoutNormal.cs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
노도연 2026-06-22 16:26:07 +09:00
commit 688b0fc463
4 changed files with 82 additions and 135 deletions

View File

@ -8,8 +8,8 @@ M70505,Heavy_ALStatus,Heavy_ALStatus
M70506,Door Interlok,Door Interlok M70506,Door Interlok,Door Interlok
M70507,EMO Status,EMO Status M70507,EMO Status,EMO Status
M70508,Page_CHGRequest,Page_CHGRequest M70508,Page_CHGRequest,Page_CHGRequest
M70509,PreWeld Scout Request,용접 전 Scout Request M70509,Scout Enable,Scout Enable(상시 ON 시 용접 전/후 Scout)
M70510,PostWeld Scout Request,용접 후 Scout Request M70510,,
M70511,, M70511,,
M70512,, M70512,,
M70513,, M70513,,

1 Device No Comment ENG Comment KOR
8 M70506 Door Interlok Door Interlok
9 M70507 EMO Status EMO Status
10 M70508 Page_CHGRequest Page_CHGRequest
11 M70509 PreWeld Scout Request Scout Enable 용접 전 Scout Request Scout Enable(상시 ON 시 용접 전/후 Scout)
12 M70510 PostWeld Scout Request 용접 후 Scout Request
13 M70511
14 M70512
15 M70513

View File

@ -22,12 +22,10 @@ namespace ILSOS_PrismaticRD_PTOP.Device
PLC_EMO_STATUS = 0x07, PLC_EMO_STATUS = 0x07,
PLC_PAGE_CHANGE_REQ = 0x08, PLC_PAGE_CHANGE_REQ = 0x08,
// 260622: M70509 = 용접 전 Scout Request (구 PLC_RECIPE_CHANGE_REQ/RMS_USED, 모두 미사용 → 재정의) // 260622: M70509 = Scout Enable 플래그 (PLC가 상시 ON 유지 시 용접 전/후 Scout 수행)
// Recipe 전환은 PAGE_CHANGE_REQ 트리거 + PLC_RECIPE_NO 워드로 처리하므로 이 bit는 Scout가 사용. // 구 PLC_RECIPE_CHANGE_REQ/RMS_USED 모두 미사용 → 재정의. Recipe 전환은 PAGE_CHANGE_REQ + RECIPE_NO 워드로 처리.
PLC_PRE_WELD_SCOUT_REQ = 0x09, PLC_SCOUT_ENABLE = 0x09,
// 260622: M70510 = 용접 후 Scout Request (신규) // 0x0A ~ 0x0E
PLC_POST_WELD_SCOUT_REQ = 0x0A,
// 0x0B ~ 0x0E
// 260621: M70515 확정 = Weld_01 Ready (가변용접 시 PLC ON → Recipe/Page 확인 팝업 + Resume 트리거) // 260621: M70515 확정 = Weld_01 Ready (가변용접 시 PLC ON → Recipe/Page 확인 팝업 + Resume 트리거)
PLC_WELD_READY_REQ = 0x0F, PLC_WELD_READY_REQ = 0x0F,
PLC_WELD_TRIGGER_REQ = 0x10, // M70516 (구 Ready) PLC_WELD_TRIGGER_REQ = 0x10, // M70516 (구 Ready)
@ -63,11 +61,9 @@ namespace ILSOS_PrismaticRD_PTOP.Device
PC_DOOR_INTERLOCK = 0x06, PC_DOOR_INTERLOCK = 0x06,
PC_EMO_STATUS = 0x07, PC_EMO_STATUS = 0x07,
PC_PAGE_CHANGE_COMPLETE = 0x08, PC_PAGE_CHANGE_COMPLETE = 0x08,
// 260622: M70009 = 용접 전 Scout Complete (구 PC_RECIPE_CHANGE_COMPLETE, PLC 미감시 → 재정의) // 260618: M70009 Recipe 변경 완료 응답 (구 PC_EMPTY01, 미사용 → 재정의)
PC_PRE_WELD_SCOUT_COMPLETE = 0x09, PC_RECIPE_CHANGE_COMPLETE = 0x09,
// 260622: M70010 = 용접 후 Scout Complete (신규) // 0x0A ~ 0x0E
PC_POST_WELD_SCOUT_COMPLETE = 0x0A,
// 0x0B ~ 0x0E
// 260621: M70015 확정 = Weld_01 ReadyACK (Resume ACK/run 신호) // 260621: M70015 확정 = Weld_01 ReadyACK (Resume ACK/run 신호)
PC_WELD_READY_ACK = 0x0F, PC_WELD_READY_ACK = 0x0F,
PC_WELD_TRIGGER_ACK = 0x10, // M70016 (구 ReadyACK) PC_WELD_TRIGGER_ACK = 0x10, // M70016 (구 ReadyACK)

View File

@ -76,22 +76,21 @@ namespace ILSOS_PrismaticRD_PTOP.Sequences
const string SEQ_WRITE_COMPLETION_PLC_BIT = "[SeqAutoRunPTOP] Write Completion PLC Bit"; const string SEQ_WRITE_COMPLETION_PLC_BIT = "[SeqAutoRunPTOP] Write Completion PLC Bit";
const string SEQ_COMPLETE = "[SeqAutoRunPTOP] SEQ_COMPLETE"; // 완료 const string SEQ_COMPLETE = "[SeqAutoRunPTOP] SEQ_COMPLETE"; // 완료
#region 260622: 용접 전/후 Scout 핸드셰이크 노드 #region 260622: M70509(Scout Enable) 기반 용접 전/후 Scout
// 용접 전 Scout: 페이지 확정 후 ~ 용접 전. PLC_PRE_WELD_SCOUT_REQ(M70509) 대기 → Scout(이미지 저장) // 용접 전: M70516(Weld Trigger) 감지 후 M70509 ON이면 scout(pre) → 0.1s → 용접
// → PC_PRE_WELD_SCOUT_COMPLETE(M70009) ON const string SEQ_PRE_SCOUT_CHECK = "[SeqAutoRunPTOP] Pre-Weld Scout Check"; // 분기: M70509 ON/OFF
const string SEQ_PRE_SCOUT_CHECK = "[SeqAutoRunPTOP] Pre-Weld Scout Check"; // 분기: Req 대기 / 스킵
const string SEQ_PRE_SCOUT_SET_PARAMS = "[SeqAutoRunPTOP] Pre-Weld Scout SetParams"; const string SEQ_PRE_SCOUT_SET_PARAMS = "[SeqAutoRunPTOP] Pre-Weld Scout SetParams";
const string SEQ_PRE_SCOUT_RUN = "[SeqAutoRunPTOP] Pre-Weld Scout Run"; // SeqScoutNormal 서브시퀀스 const string SEQ_PRE_SCOUT_RUN = "[SeqAutoRunPTOP] Pre-Weld Scout Run"; // SeqScoutNormal 서브시퀀스
const string SEQ_PRE_SCOUT_DONE = "[SeqAutoRunPTOP] Pre-Weld Scout Done"; const string SEQ_PRE_SCOUT_DONE = "[SeqAutoRunPTOP] Pre-Weld Scout Done"; // 0.1s 후 진행
// 용접 후 Scout: ExecuteWelding(완료) 후. PLC_POST_WELD_SCOUT_REQ(M70510) 대기 → Scout // 용접 후: 발진 완료 후 완료비트 송신 전 M70509 ON이면 scout(post) → 0.1s → 완료비트
// → PC_POST_WELD_SCOUT_COMPLETE(M70010) ON
const string SEQ_POST_SCOUT_CHECK = "[SeqAutoRunPTOP] Post-Weld Scout Check"; const string SEQ_POST_SCOUT_CHECK = "[SeqAutoRunPTOP] Post-Weld Scout Check";
const string SEQ_POST_SCOUT_SET_PARAMS = "[SeqAutoRunPTOP] Post-Weld Scout SetParams"; const string SEQ_POST_SCOUT_SET_PARAMS = "[SeqAutoRunPTOP] Post-Weld Scout SetParams";
const string SEQ_POST_SCOUT_RUN = "[SeqAutoRunPTOP] Post-Weld Scout Run"; const string SEQ_POST_SCOUT_RUN = "[SeqAutoRunPTOP] Post-Weld Scout Run";
const string SEQ_POST_SCOUT_DONE = "[SeqAutoRunPTOP] Post-Weld Scout Done"; const string SEQ_POST_SCOUT_DONE = "[SeqAutoRunPTOP] Post-Weld Scout Done"; // 0.1s 후 진행
// 용접 완료 비트 송신(post-scout 분기 뒤로 분리): TriggerACK off / BUSY off / COMPLETE on
const string SEQ_WRITE_WELD_COMPLETE = "[SeqAutoRunPTOP] Write Weld Complete";
// Scout 라이브 활성 플래그. PLC 미준비 시 false로 두면 Scout 노드는 즉시 통과(기존 사이클 영향 없음). private const int SCOUT_PROCEED_DELAY_MS = 100; // scout 완료 후 진행 지연(0.1초)
private const bool SCOUT_ENABLED = true;
#endregion #endregion
public enum ePrismaticDOAddress public enum ePrismaticDOAddress
@ -156,22 +155,24 @@ namespace ILSOS_PrismaticRD_PTOP.Sequences
sb.AddAction(SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ, GetUploadWeldingList_SeqResult); sb.AddAction(SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ, GetUploadWeldingList_SeqResult);
#endregion #endregion
// 260622: 용접 전 Scout 핸드셰이크 (페이지 확정 후 ~ 용접 전) // 260513 plc
sb.AddAction(SEQ_CHECK_WELDING_START_READ_BIT, WeldingStartReadBit);
// 260622: 용접 전 Scout (M70509 ON 시)
sb.AddDecision(SEQ_PRE_SCOUT_CHECK, PreScoutCheck); sb.AddDecision(SEQ_PRE_SCOUT_CHECK, PreScoutCheck);
sb.AddAction(SEQ_PRE_SCOUT_SET_PARAMS, PreScoutSetParams); sb.AddAction(SEQ_PRE_SCOUT_SET_PARAMS, PreScoutSetParams);
sb.AddSubsequence(SEQ_PRE_SCOUT_RUN, SequenceManager.GetSeqBuilder_SeqScoutNormal()); sb.AddSubsequence(SEQ_PRE_SCOUT_RUN, SequenceManager.GetSeqBuilder_SeqScoutNormal());
sb.AddAction(SEQ_PRE_SCOUT_DONE, PreScoutDone); sb.AddAction(SEQ_PRE_SCOUT_DONE, PreScoutDone);
// 260513 plc
sb.AddAction(SEQ_CHECK_WELDING_START_READ_BIT, WeldingStartReadBit);
sb.AddAction(SEQ_WAIT_WELDING_START, WaitWeldingStart); sb.AddAction(SEQ_WAIT_WELDING_START, WaitWeldingStart);
sb.AddAction(SEQ_EXECUTE_WELDING, ExecuteWelding); sb.AddAction(SEQ_EXECUTE_WELDING, ExecuteWelding);
// 260622: 용접 후 Scout 핸드셰이크 (ExecuteWelding 완료 후) // 260622: 용접 후 Scout (M70509 ON 시) → 완료비트 송신
sb.AddDecision(SEQ_POST_SCOUT_CHECK, PostScoutCheck); sb.AddDecision(SEQ_POST_SCOUT_CHECK, PostScoutCheck);
sb.AddAction(SEQ_POST_SCOUT_SET_PARAMS, PostScoutSetParams); sb.AddAction(SEQ_POST_SCOUT_SET_PARAMS, PostScoutSetParams);
sb.AddSubsequence(SEQ_POST_SCOUT_RUN, SequenceManager.GetSeqBuilder_SeqScoutNormal()); sb.AddSubsequence(SEQ_POST_SCOUT_RUN, SequenceManager.GetSeqBuilder_SeqScoutNormal());
sb.AddAction(SEQ_POST_SCOUT_DONE, PostScoutDone); sb.AddAction(SEQ_POST_SCOUT_DONE, PostScoutDone);
sb.AddAction(SEQ_WRITE_WELD_COMPLETE, WriteWeldComplete);
sb.AddDecision(SEQ_CHECK_CYCLE_STOP, CheckCycleStop); // 체크페이지 sb.AddDecision(SEQ_CHECK_CYCLE_STOP, CheckCycleStop); // 체크페이지
@ -187,23 +188,26 @@ namespace ILSOS_PrismaticRD_PTOP.Sequences
> sb[SEQ_CHECK_RECIPENO_COMPLETE] // Recipe 먼저 확정/전환 > sb[SEQ_CHECK_RECIPENO_COMPLETE] // Recipe 먼저 확정/전환
> sb[SEQ_CHECK_PAGENO_COMPLETE] // 그다음 Page 확정 > sb[SEQ_CHECK_PAGENO_COMPLETE] // 그다음 Page 확정
> sb[SEQ_PRE_SCOUT_CHECK] // 260622: 용접 전 Scout Req 대기(분기) #region TeachingRun 시퀸스의 중간 용접리스트 생성 구간
> sb[SEQ_PRE_SCOUT_SET_PARAMS] // Scout 파라미터(PreWeld)
> sb[SEQ_PRE_SCOUT_RUN] // SeqScoutNormal (캡처+저장)
> sb[SEQ_PRE_SCOUT_DONE] // Complete bit(M70009) ON
> sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ] // 1 파라미터 세팅 - TeachingRun 노드 참고 > sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ] // 1 파라미터 세팅 - TeachingRun 노드 참고
> sb[SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ] // 2 리스트 업로드 (서브시퀀스) - TeachingRun 노드 참고 > sb[SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ] // 2 리스트 업로드 (서브시퀀스) - TeachingRun 노드 참고
> sb[SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ] // 3 업로드 결과 확인 - TeachingRun 노드 참고 > sb[SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ] // 3 업로드 결과 확인 - TeachingRun 노드 참고
#endregion
> sb[SEQ_CHECK_WELDING_START_READ_BIT] // while read bit (M70516 대기)
> sb[SEQ_PRE_SCOUT_CHECK] // 260622: M70509 ON → pre scout
> sb[SEQ_PRE_SCOUT_SET_PARAMS]
> sb[SEQ_PRE_SCOUT_RUN]
> sb[SEQ_PRE_SCOUT_DONE] // 0.1s 후 용접
> sb[SEQ_CHECK_WELDING_START_READ_BIT] // while read bit
> sb[SEQ_WAIT_WELDING_START] // 4 업로드 완료 PLC 완료 신호 및 BUSY 신호로 변경 > sb[SEQ_WAIT_WELDING_START] // 4 업로드 완료 PLC 완료 신호 및 BUSY 신호로 변경
> sb[SEQ_EXECUTE_WELDING] // 5 Scanner 실행 (실제 용접) > sb[SEQ_EXECUTE_WELDING] // 5 Scanner 실행 (실제 용접, 완료비트는 보류)
> sb[SEQ_POST_SCOUT_CHECK] // 260622: 용접 후 Scout Req 대기(분기) > sb[SEQ_POST_SCOUT_CHECK] // 260622: M70509 ON → post scout
> sb[SEQ_POST_SCOUT_SET_PARAMS] // Scout 파라미터(PostWeld) > sb[SEQ_POST_SCOUT_SET_PARAMS]
> sb[SEQ_POST_SCOUT_RUN] // SeqScoutNormal (캡처+저장) > sb[SEQ_POST_SCOUT_RUN]
> sb[SEQ_POST_SCOUT_DONE] // Complete bit(M70010) ON > sb[SEQ_POST_SCOUT_DONE] // 0.1s 후 완료비트
> sb[SEQ_WRITE_WELD_COMPLETE] // 용접 완료 비트 송신 → 다음 시퀀스
> sb[SEQ_CHECK_CYCLE_STOP] > sb[SEQ_CHECK_CYCLE_STOP]
@ -212,9 +216,9 @@ namespace ILSOS_PrismaticRD_PTOP.Sequences
> sb[SEQ_COMPLETE] // 다시 enter로 올리기 > sb[SEQ_COMPLETE] // 다시 enter로 올리기
> sb.Final); > sb.Final);
// 260622: Scout 스킵 분기 (SCOUT_ENABLED=false 또는 Req 미수신 시 우회) // 260622: Scout 스킵 분기 (M70509 OFF → 기존과 동일하게 용접만)
sb.Flows(sb[SEQ_PRE_SCOUT_CHECK] > sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ]); sb.Flows(sb[SEQ_PRE_SCOUT_CHECK] > sb[SEQ_WAIT_WELDING_START]);
sb.Flows(sb[SEQ_POST_SCOUT_CHECK] > sb[SEQ_CHECK_CYCLE_STOP]); sb.Flows(sb[SEQ_POST_SCOUT_CHECK] > sb[SEQ_WRITE_WELD_COMPLETE]);
sb.Flows(sb[SEQ_CHECK_CYCLE_STOP] > sb[SEQ_CHECK_PAGENO]); // 루프백: 매 사이클 Page Change bit(0x08) 대기부터 재확인 sb.Flows(sb[SEQ_CHECK_CYCLE_STOP] > sb[SEQ_CHECK_PAGENO]); // 루프백: 매 사이클 Page Change bit(0x08) 대기부터 재확인
sb.Flows(sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ]); // 260621: Resume 시 핸드셰이크 스킵 sb.Flows(sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ]); // 260621: Resume 시 핸드셰이크 스킵
@ -832,21 +836,10 @@ namespace ILSOS_PrismaticRD_PTOP.Sequences
Log.D(string.Format($"[ExecuteWelding] Change SelectCorrectionTable Time : {_WeldingSpanTime.TotalMilliseconds}")); Log.D(string.Format($"[ExecuteWelding] Change SelectCorrectionTable Time : {_WeldingSpanTime.TotalMilliseconds}"));
Thread.Sleep(500); Thread.Sleep(500);
// 양극(P) 미사용 → 모든 페이지 음극 완료 비트로 응답
_PLC.WriteBit((int)eBitOutput.PC_WELD_TRIGGER_ACK, false);
Log.I($"[ExecuteWelding] 용접완료 송신 - READY_ACK=false (PageNo:{plcPageNo})");
Thread.Sleep(50);
_PLC.WriteBit((int)eBitOutput.PC_WELD_BUSY, false);
Log.I($"[ExecuteWelding] 용접완료 송신 - BUSY=false (PageNo:{plcPageNo})");
Thread.Sleep(50);
_PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE, true);
Log.I($"[ExecuteWelding] 용접완료 송신 - COMPLETE=true (PageNo:{plcPageNo})");
Thread.Sleep(5);
Status.SetWorkingPosition(eWorkingPosition.UNLOADING_CELL);
#endregion #endregion
Log.I($"[ExecuteWelding] 완료 → CheckCycleStop 이동"); // 260622: 완료비트(TriggerACK off/BUSY off/COMPLETE on) 송신은 post-scout(M70509) 분기 뒤로 분리 → WriteWeldComplete 노드
Log.I($"[ExecuteWelding] 발진 완료 (완료비트 송신 보류) → PostScoutCheck 이동");
return SequenceAction.Ok(); return SequenceAction.Ok();
} }
@ -867,48 +860,10 @@ namespace ILSOS_PrismaticRD_PTOP.Sequences
return SEQ_CHECK_PAGENO; return SEQ_CHECK_PAGENO;
} }
#region 260622: 용접 전/후 Scout 핸드셰이크 #region 260622: M70509(Scout Enable) 기반 용접 전/후 Scout
// ── 재사용 헬퍼 ───────────────────────────────────────────── // 이미지 파일명 접미어: auto_{recipeNo}_{pageNo}_{pre|post} → 최종 {기존}_auto_{recipeNo}_{pageNo}_{phase}.PNG
// Scout Request 비트(PLC→PC) 대기. SCOUT_ENABLED=false면 즉시 false 반환(스킵).
// 반환: true=Req 수신(Scout 진행) / false=스킵(또는 정지)
private bool WaitScoutRequestBit(SequenceContext context, eBitInput reqBit, string phase)
{
if (!SCOUT_ENABLED)
{
Log.I($"[{phase}Scout] SCOUT_ENABLED=false → Scout 스킵");
return false;
}
Log.I($"[{phase}Scout] {reqBit} 대기 중...");
var t0 = DateTime.Now;
while (!context.Stopped)
{
if (_PLC == null)
{
Log.E($"[{phase}Scout] _PLC instance is null! Scout 스킵");
return false;
}
if (_PLC.ReadBit(reqBit).data)
{
Log.I($"---> [{phase}Scout] {reqBit} ON 감지");
return true;
}
if (DateTime.Now.Subtract(t0).TotalSeconds > PLC_TIMEOUT)
{
Log.W($"[{phase}Scout] {reqBit} 대기 TIMEOUT...");
t0 = DateTime.Now;
}
Thread.Sleep(10);
}
return false; // 정지
}
// 이미지 파일명 접미어: auto_{recipeNo}_{pageNo}_{pre|post}
// 최종 파일명 = {기존파일명}_auto_{recipeNo}_{pageNo}_{phase}.PNG (디렉터리는 기존 날짜 폴더 유지)
// recipeNo=PLC Recipe No(CheckRecipeNoComp에서 확정), pageNo=PLC Page No(1-base, CheckPageNoComp에서 확정)
private string ScoutSaveTag(string phase) => $"auto_{plcRecipeNo}_{plcPageNo}_{phase}"; private string ScoutSaveTag(string phase) => $"auto_{plcRecipeNo}_{plcPageNo}_{phase}";
// SeqScoutNormal 서브시퀀스 파라미터 구성. saveTag로 저장 파일명 접미어 분기(용접 전/후).
private SeqScoutNormal_InitParam BuildScoutParams(string saveTag) private SeqScoutNormal_InitParam BuildScoutParams(string saveTag)
{ {
return new SeqScoutNormal_InitParam() return new SeqScoutNormal_InitParam()
@ -920,25 +875,13 @@ namespace ILSOS_PrismaticRD_PTOP.Sequences
}; };
} }
// Scout Complete 비트(PC→PLC) 고정 펄스: ON → SCOUT_COMPLETE_PULSE_MS 유지 → OFF. // ── 용접 전 Scout (M70516 감지 후) ──────────────────────────
// (CheckCycleStop이 항상 CheckPageNo로 루프백 → WriteCompletionPLCBit 미도달이므로 여기서 직접 OFF까지 처리)
private const int SCOUT_COMPLETE_PULSE_MS = 400;
private void PulseScoutCompleteBit(eBitOutput completeBit, string phase)
{
_PLC.WriteBit((int)completeBit, true);
Log.I($"[{phase}Scout] {completeBit} = true (펄스 {SCOUT_COMPLETE_PULSE_MS}ms)");
Thread.Sleep(SCOUT_COMPLETE_PULSE_MS);
_PLC.WriteBit((int)completeBit, false);
Log.I($"[{phase}Scout] {completeBit} = false (펄스 종료)");
}
// ── 용접 전 Scout ───────────────────────────────────────────
private string PreScoutCheck(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param) private string PreScoutCheck(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
{ {
bool need = WaitScoutRequestBit(context, eBitInput.PLC_PRE_WELD_SCOUT_REQ, "Pre"); bool scout = _PLC.ReadBit(eBitInput.PLC_SCOUT_ENABLE).data; // M70509
if (context.Stopped) return null; Log.I($"[PreScoutCheck] M70509(Scout Enable) = {scout}");
// Req 수신 → Scout 진행 / 아니면 업로드 단계로 스킵 // M70509 ON → pre scout / OFF → 기존과 동일하게 바로 용접
return need ? SEQ_PRE_SCOUT_SET_PARAMS : SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ; return scout ? SEQ_PRE_SCOUT_SET_PARAMS : SEQ_WAIT_WELDING_START;
} }
private SequenceActionResult PreScoutSetParams(SequenceContext context, string id, SequenceActionResult param) private SequenceActionResult PreScoutSetParams(SequenceContext context, string id, SequenceActionResult param)
{ {
@ -953,17 +896,18 @@ namespace ILSOS_PrismaticRD_PTOP.Sequences
Log.E("[PreScout] Scout 실패 → 시퀀스 중단"); Log.E("[PreScout] Scout 실패 → 시퀀스 중단");
return null; return null;
} }
PulseScoutCompleteBit(eBitOutput.PC_PRE_WELD_SCOUT_COMPLETE, "Pre"); Thread.Sleep(SCOUT_PROCEED_DELAY_MS); // 0.1초 후 용접 진행
Log.I("[PreScout] 완료 → UploadWeldingList 이동"); Log.I($"[PreScout] 완료 → {SCOUT_PROCEED_DELAY_MS}ms 후 WaitWeldingStart 이동");
return SequenceAction.Ok(); return SequenceAction.Ok();
} }
// ── 용접 후 Scout ─────────────────────────────────────────── // ── 용접 후 Scout (완료비트 송신 전) ────────────────────────
private string PostScoutCheck(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param) private string PostScoutCheck(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
{ {
bool need = WaitScoutRequestBit(context, eBitInput.PLC_POST_WELD_SCOUT_REQ, "Post"); bool scout = _PLC.ReadBit(eBitInput.PLC_SCOUT_ENABLE).data; // M70509
if (context.Stopped) return null; Log.I($"[PostScoutCheck] M70509(Scout Enable) = {scout}");
return need ? SEQ_POST_SCOUT_SET_PARAMS : SEQ_CHECK_CYCLE_STOP; // M70509 ON → post scout / OFF → 바로 완료비트 송신
return scout ? SEQ_POST_SCOUT_SET_PARAMS : SEQ_WRITE_WELD_COMPLETE;
} }
private SequenceActionResult PostScoutSetParams(SequenceContext context, string id, SequenceActionResult param) private SequenceActionResult PostScoutSetParams(SequenceContext context, string id, SequenceActionResult param)
{ {
@ -978,8 +922,25 @@ namespace ILSOS_PrismaticRD_PTOP.Sequences
Log.E("[PostScout] Scout 실패 → 시퀀스 중단"); Log.E("[PostScout] Scout 실패 → 시퀀스 중단");
return null; return null;
} }
PulseScoutCompleteBit(eBitOutput.PC_POST_WELD_SCOUT_COMPLETE, "Post"); Thread.Sleep(SCOUT_PROCEED_DELAY_MS); // 0.1초 후 완료비트 송신
Log.I("[PostScout] 완료 → CheckCycleStop 이동"); Log.I($"[PostScout] 완료 → {SCOUT_PROCEED_DELAY_MS}ms 후 WriteWeldComplete 이동");
return SequenceAction.Ok();
}
// 용접 완료 비트 송신(post-scout 분기 뒤로 분리). 음극 비트로 응답(양극 P 미사용).
private SequenceActionResult WriteWeldComplete(SequenceContext context, string id, SequenceActionResult param)
{
_PLC.WriteBit((int)eBitOutput.PC_WELD_TRIGGER_ACK, false);
Log.I($"[WriteWeldComplete] 용접완료 송신 - READY_ACK=false (PageNo:{plcPageNo})");
Thread.Sleep(50);
_PLC.WriteBit((int)eBitOutput.PC_WELD_BUSY, false);
Log.I($"[WriteWeldComplete] 용접완료 송신 - BUSY=false (PageNo:{plcPageNo})");
Thread.Sleep(50);
_PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE, true);
Log.I($"[WriteWeldComplete] 용접완료 송신 - COMPLETE=true (PageNo:{plcPageNo})");
Thread.Sleep(5);
Status.SetWorkingPosition(eWorkingPosition.UNLOADING_CELL);
Log.I($"[WriteWeldComplete] 완료 → CheckCycleStop 이동");
return SequenceAction.Ok(); return SequenceAction.Ok();
} }
#endregion #endregion
@ -1078,13 +1039,9 @@ namespace ILSOS_PrismaticRD_PTOP.Sequences
_PLC.WriteBit((int)eCommonBitOutput.PC_WELD_TRIGGER_ACK, false); // 용접 준비 false _PLC.WriteBit((int)eCommonBitOutput.PC_WELD_TRIGGER_ACK, false); // 용접 준비 false
_PLC.WriteBit((int)eCommonBitOutput.PC_WELD_BUSY, false); // 동작 중 false _PLC.WriteBit((int)eCommonBitOutput.PC_WELD_BUSY, false); // 동작 중 false
_PLC.WriteBit((int)eCommonBitOutput.PC_WELD_COMPLETE, false); // 용접 완료 false _PLC.WriteBit((int)eCommonBitOutput.PC_WELD_COMPLETE, false); // 용접 완료 false
Log.I(string.Format("[PLCInterface]PC Anod Bit Off")); Log.I(string.Format("[PLCInterface]PC Anod Bit Off"));
// 260622: Scout Complete 비트(M70009/M70010) 사이클 종료 시 리셋
_PLC.WriteBit((int)eBitOutput.PC_PRE_WELD_SCOUT_COMPLETE, false);
_PLC.WriteBit((int)eBitOutput.PC_POST_WELD_SCOUT_COMPLETE, false);
// 양극(P) 미사용 — 양극 용접 비트 리셋 제거 // 양극(P) 미사용 — 양극 용접 비트 리셋 제거
//Thread.Sleep(1000); // 추후 제거 //Thread.Sleep(1000); // 추후 제거
@ -1231,10 +1188,6 @@ namespace ILSOS_PrismaticRD_PTOP.Sequences
_PLC.WriteBit((int)eBitOutput.PC_PAGE_CHANGE_COMPLETE, false); _PLC.WriteBit((int)eBitOutput.PC_PAGE_CHANGE_COMPLETE, false);
Log.I("[OnSeqActionStop] PLC IO Output PAGECHANGE Init"); Log.I("[OnSeqActionStop] PLC IO Output PAGECHANGE Init");
// 260622: Scout Complete 비트(M70009/M70010) 정지 시 리셋
_PLC.WriteBit((int)eBitOutput.PC_PRE_WELD_SCOUT_COMPLETE, false);
_PLC.WriteBit((int)eBitOutput.PC_POST_WELD_SCOUT_COMPLETE, false);
// 260512 워드 // 260512 워드
// 260621: 에코 워드(PC_PAGE_NO/PC_RECIPE_NO)는 정지 시 0으로 지우지 않음 — PLC가 정합 확인에 쓰는 // 260621: 에코 워드(PC_PAGE_NO/PC_RECIPE_NO)는 정지 시 0으로 지우지 않음 — PLC가 정합 확인에 쓰는
// 마지막 핸드셰이크 값을 보존(다음 사이클에 어차피 재에코). 기존 0 초기화 2줄 제거. // 마지막 핸드셰이크 값을 보존(다음 사이클에 어차피 재에코). 기존 0 초기화 2줄 제거.

View File

@ -296,13 +296,12 @@ namespace WeldingCommon.Sequences
//4.스캐너 필드 이미지 파일 저장 //4.스캐너 필드 이미지 파일 저장
// TODO: Path 설정하는 것 따로 만들어서 넣기. 여기저기 흩어져 있음... // TODO: Path 설정하는 것 따로 만들어서 넣기. 여기저기 흩어져 있음...
// 디렉터리는 기존 그대로(날짜 폴더). SaveTag 가 있으면 기존 파일명 뒤에 '_접미어'로 붙임. // 디렉터리는 기존 그대로(날짜 폴더). SaveTag 가 있으면 기존 파일명 뒤에 '_접미어' 추가.
// 기존: {_ScoutNo+1}_{HHmmss}.PNG // 기존: {_ScoutNo+1}_{HHmmss}.PNG
// SaveTag 적용: {_ScoutNo+1}_{HHmmss}_{SaveTag}.PNG (예: 1_143052_auto_11_2_pre.PNG) // SaveTag 적용: {_ScoutNo+1}_{HHmmss}_{SaveTag}.PNG (예: 1_143052_auto_11_2_pre.PNG)
string dateDir = $"{DateTime.Now.Year}_{DateTime.Now.Month}_{DateTime.Now.Day}"; string dateDir = $"{DateTime.Now.Year}_{DateTime.Now.Month}_{DateTime.Now.Day}";
string saveTag = _InitParam.SaveTag;
string baseName = $"{_ScoutNo + 1}_{DateTime.Now.ToString("HHmmss")}"; string baseName = $"{_ScoutNo + 1}_{DateTime.Now.ToString("HHmmss")}";
string fileName = string.IsNullOrEmpty(saveTag) ? $"{baseName}.PNG" : $"{baseName}_{saveTag}.PNG"; string fileName = string.IsNullOrEmpty(_InitParam.SaveTag) ? $"{baseName}.PNG" : $"{baseName}_{_InitParam.SaveTag}.PNG";
string fieldScanImageFile = Path.Combine(ConfigurationManager.AppSettings.Get("DATA_PATH"), "_vision", "FieldScanImage", string fieldScanImageFile = Path.Combine(ConfigurationManager.AppSettings.Get("DATA_PATH"), "_vision", "FieldScanImage",
dateDir, fileName); dateDir, fileName);
_SystemParameter.ScannerFieldImageFile = fieldScanImageFile; _SystemParameter.ScannerFieldImageFile = fieldScanImageFile;
@ -393,9 +392,8 @@ namespace WeldingCommon.Sequences
// 변경: 호출부가 "현재 처리/표시 중인 페이지 번호"를 명시 주입. // 변경: 호출부가 "현재 처리/표시 중인 페이지 번호"를 명시 주입.
public int PageIndex { get; set; } = 0; public int PageIndex { get; set; } = 0;
// [추가 2026-06-22] 파일명 접미어. 호출부가 같은 SeqScoutNormal을 단계별로 호출하며 파일명을 분기하기 위함. // [추가 2026-06-22] 파일명 접미어. 디렉터리는 기존 날짜 폴더 그대로, 비면(기본) 기존 파일명 유지(하위호환).
// 디렉터리는 기존 날짜 폴더 그대로. 비어있으면(기본) 기존 파일명 그대로 유지(하위호환). // 적용 시: {기존파일명}_{SaveTag}.PNG (호출부에서 예: "auto_{recipeNo}_{pageNo}_pre" 전달)
// 적용 시 파일명: {기존파일명}_{SaveTag}.PNG (호출부에서 예: "auto_{recipeNo}_{pageNo}_pre" 전달)
public string SaveTag { get; set; } = ""; public string SaveTag { get; set; } = "";
} }