Compare commits
2 Commits
5799872867
...
2ef276e093
| Author | SHA1 | Date | |
|---|---|---|---|
| 2ef276e093 | |||
| 18ca9bc3f4 |
@ -698,6 +698,22 @@ namespace ILSOS_PrismaticRD_PTOP.Sequences
|
|||||||
// 1. PLC_PAGE_CHANGE_REQ (bit 8) ON 대기
|
// 1. PLC_PAGE_CHANGE_REQ (bit 8) ON 대기
|
||||||
var interfaceStartTime = DateTime.Now;
|
var interfaceStartTime = DateTime.Now;
|
||||||
|
|
||||||
|
#region [진단계측 2026-08-26] page5→6 REQ 미발행 추적 (원복: 이 region + 아래 2개 삽입부 + 헬퍼 2개 삭제)
|
||||||
|
// 배경: 2026-08-26 로그에서 레시피 23/24 의 page 5 Resume 후 PLC_PAGE_CHANGE_REQ 가 오지 않아 교착.
|
||||||
|
// 레시피 21/22 는 같은 5→6 전환이 2.4~3.1초 만에 성공한다(그 구간만 REQ 가 OFF 로 떨어진다).
|
||||||
|
// 기존 로그는 "TIMEOUT..." 한 줄뿐이라 대기 중 PLC 워드/비트가 어떻게 움직이는지 알 수 없었다.
|
||||||
|
// 특히 PLC_PAGE_NO 가 6 으로 올라갔는데 REQ 만 안 오는지, 5 에서 멈춘 건지 구분이 안 된다.
|
||||||
|
// · PAGE:6 + REQ:0 → PLC 가 페이지는 올렸으나 REQ 발행 조건 미충족
|
||||||
|
// · PAGE:5 + REQ:0 → PLC 스텝이 page 5 에서 아예 진행하지 않음
|
||||||
|
// 방식: REQ 폴링(10ms)은 그대로 두고, 전체 스냅샷은 1초 주기로만 뜬다(MC 개별읽기 부하 억제).
|
||||||
|
// 값이 바뀔 때만 남기므로 정상 통과(0~3초) 구간에서는 1~2줄이고 로그 폭주가 없다.
|
||||||
|
// 분석: docs/분석/2026/08/26/Page5_Page6_REQ_미발행_PLC문의_260826.md
|
||||||
|
var diagWaitStart = DateTime.Now;
|
||||||
|
var diagNextPoll = DateTime.Now;
|
||||||
|
string diagLastSnapshot = null;
|
||||||
|
Log.W($"[진단계측][CheckPageNo] 대기 진입 {BuildHandshakeSnapshot()}");
|
||||||
|
#endregion
|
||||||
|
|
||||||
while (!context.Stopped)
|
while (!context.Stopped)
|
||||||
{
|
{
|
||||||
//plc
|
//plc
|
||||||
@ -727,18 +743,87 @@ namespace ILSOS_PrismaticRD_PTOP.Sequences
|
|||||||
|
|
||||||
if (DateTime.Now.Subtract(interfaceStartTime).TotalSeconds > PLC_TIMEOUT)
|
if (DateTime.Now.Subtract(interfaceStartTime).TotalSeconds > PLC_TIMEOUT)
|
||||||
{
|
{
|
||||||
Log.W("[CheckPageNo] Waiting for PLC_PAGE_CHANGE_REQ -> TIMEOUT...");
|
// [진단계측 2026-08-26] 기존 한 줄에 스냅샷을 붙인다. 원복 시 뒤쪽 보간만 지우면 된다.
|
||||||
|
Log.W($"[CheckPageNo] Waiting for PLC_PAGE_CHANGE_REQ -> TIMEOUT... " +
|
||||||
|
$"(누적 {DateTime.Now.Subtract(diagWaitStart).TotalSeconds:F0}s) {BuildHandshakeSnapshot()}");
|
||||||
interfaceStartTime = DateTime.Now;
|
interfaceStartTime = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region [진단계측 2026-08-26] 1초 주기 변화 감지 (원복: 이 region 삭제)
|
||||||
|
if (DateTime.Now >= diagNextPoll)
|
||||||
|
{
|
||||||
|
diagNextPoll = DateTime.Now.AddSeconds(1);
|
||||||
|
|
||||||
|
var snapshot = BuildHandshakeSnapshot();
|
||||||
|
if (snapshot != diagLastSnapshot)
|
||||||
|
{
|
||||||
|
Log.W($"[진단계측][CheckPageNo] 변화 " +
|
||||||
|
$"(대기 {DateTime.Now.Subtract(diagWaitStart).TotalSeconds:F1}s) {snapshot}");
|
||||||
|
diagLastSnapshot = snapshot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
Thread.Sleep(10);
|
Thread.Sleep(10);
|
||||||
}
|
}
|
||||||
if (context.Stopped) return null;
|
if (context.Stopped) return null;
|
||||||
|
|
||||||
|
// [진단계측 2026-08-26] REQ 수신 시점 확정값. 21/22(성공) 대비 23/24(실패) 비교의 기준선이 된다.
|
||||||
|
Log.W($"[진단계측][CheckPageNo] REQ 수신 " +
|
||||||
|
$"(대기 {DateTime.Now.Subtract(diagWaitStart).TotalSeconds:F2}s) {BuildHandshakeSnapshot()}");
|
||||||
|
|
||||||
Log.I($"[CheckPageNo] PLC_PAGE_CHANGE_REQ ON 감지 → CheckPageNoComp 이동");
|
Log.I($"[CheckPageNo] PLC_PAGE_CHANGE_REQ ON 감지 → CheckPageNoComp 이동");
|
||||||
return SequenceAction.Ok();
|
return SequenceAction.Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region [진단계측 2026-08-26] 핸드셰이크 스냅샷 헬퍼 (원복: 이 region 통째로 삭제)
|
||||||
|
// PLC 입력 / PC 출력 되읽기를 한 줄로 만든다. 개별 MC 읽기 16회라 호출 주기는 1초 이상으로 유지할 것.
|
||||||
|
// 읽기 실패는 값 대신 E 로 표기해 "0 인지 못 읽은 건지"를 구분한다.
|
||||||
|
private string BuildHandshakeSnapshot()
|
||||||
|
{
|
||||||
|
if (_PLC == null) return "PLC=null";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var req = _PLC.ReadBit(eBitInput.PLC_PAGE_CHANGE_REQ);
|
||||||
|
var plcAuto = _PLC.ReadBit(eBitInput.PLC_AUTO_STATUS);
|
||||||
|
var plcAReq = _PLC.ReadBit(eBitInput.PLC_AUTO_REQ);
|
||||||
|
var bit15 = _PLC.ReadBit(eBitInput.PLC_WELD_READY_REQ);
|
||||||
|
var trigReq = _PLC.ReadBit(eBitInput.PLC_WELD_TRIGGER_REQ);
|
||||||
|
var cmpAck = _PLC.ReadBit(eBitInput.PLC_WELD_COMPLETE_ACK);
|
||||||
|
var plcPage = _PLC.ReadWord(eWordInput.PLC_PAGE_NO);
|
||||||
|
var plcRcp = _PLC.ReadWord(eWordInput.PLC_RECIPE_NO);
|
||||||
|
var theta = _PLC.ReadWord(eWordInput.HEAD_THETA_POSITION);
|
||||||
|
|
||||||
|
var pcAuto = _PLC.ReadOutBit(eBitOutput.PC_AUTO_STATUS);
|
||||||
|
var pcAck = _PLC.ReadOutBit(eBitOutput.PC_WELD_READY_ACK);
|
||||||
|
var pcPgCmp = _PLC.ReadOutBit(eBitOutput.PC_PAGE_CHANGE_COMPLETE);
|
||||||
|
var pcWldCmp = _PLC.ReadOutBit(eBitOutput.PC_WELD_COMPLETE);
|
||||||
|
var pcBusy = _PLC.ReadOutBit(eBitOutput.PC_WELD_BUSY);
|
||||||
|
var pcPage = _PLC.ReadOutWord(eWordOutput.PC_PAGE_NO);
|
||||||
|
var pcRcp = _PLC.ReadOutWord(eWordOutput.PC_RECIPE_NO);
|
||||||
|
|
||||||
|
return $"PLC[REQ:{DiagBit(req)} PAGE:{DiagWord(plcPage)} RCP:{DiagWord(plcRcp)} " +
|
||||||
|
$"AUTO:{DiagBit(plcAuto)} AUTO_REQ:{DiagBit(plcAReq)} bit15:{DiagBit(bit15)} " +
|
||||||
|
$"TRIG_REQ:{DiagBit(trigReq)} CMP_ACK:{DiagBit(cmpAck)} THETA:{DiagWord(theta)}] " +
|
||||||
|
$"PC[AUTO:{DiagBit(pcAuto)} READY_ACK:{DiagBit(pcAck)} PAGE_CMP:{DiagBit(pcPgCmp)} " +
|
||||||
|
$"WELD_CMP:{DiagBit(pcWldCmp)} BUSY:{DiagBit(pcBusy)} " +
|
||||||
|
$"PAGE:{DiagWord(pcPage)} RCP:{DiagWord(pcRcp)}] " +
|
||||||
|
$"ResumeMode:{(ResumeMode ? "1" : "0")}";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return $"스냅샷 실패({ex.GetType().Name}: {ex.Message})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string DiagBit((int err, bool data) read)
|
||||||
|
=> read.err == Hermes.E1.OK ? (read.data ? "1" : "0") : "E";
|
||||||
|
|
||||||
|
private static string DiagWord((int err, short data) read)
|
||||||
|
=> read.err == Hermes.E1.OK ? read.data.ToString() : "E";
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region 260806 구버전 보존 — CheckPageNoComp (원복: 아래 블록 주석을 풀고 뒤의 260806 신규 region을 제거)
|
#region 260806 구버전 보존 — CheckPageNoComp (원복: 아래 블록 주석을 풀고 뒤의 260806 신규 region을 제거)
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -174,6 +174,8 @@ namespace WeldingCommon.Views
|
|||||||
private WinSequenceDiagram _WinSequenceDiagramScoutFlyingVision;
|
private WinSequenceDiagram _WinSequenceDiagramScoutFlyingVision;
|
||||||
private WinSequenceDiagram _WinSequenceDiagramTeachingRun;
|
private WinSequenceDiagram _WinSequenceDiagramTeachingRun;
|
||||||
private WinSequenceDiagram _WinSequenceDiagramComponentTeachingRun;
|
private WinSequenceDiagram _WinSequenceDiagramComponentTeachingRun;
|
||||||
|
// 260826 현재 미사용 — PerformCmdLaserReadyCheck 가 DO 되읽기 방식으로 바뀌었다.
|
||||||
|
// 해당 메서드의 "260824/260826 이전 원본" 주석 블록이 이 필드를 참조하므로 원복 대비로 남겨둔다.
|
||||||
public bool toggleIO = true;
|
public bool toggleIO = true;
|
||||||
public UCScannerObjectTeachingControlBoxViewModel(IAuroraEnvironment aurora)
|
public UCScannerObjectTeachingControlBoxViewModel(IAuroraEnvironment aurora)
|
||||||
{
|
{
|
||||||
@ -633,18 +635,31 @@ namespace WeldingCommon.Views
|
|||||||
//}
|
//}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
// 260824 본 레이저 단일 발진기 — 제어권(REMOTE) 1발 토글
|
#region 260826 이전 원본 (toggleIO 필드 토글 — 원복 시 이 블록을 살리고 아래 2줄을 제거)
|
||||||
|
//// 260824 본 레이저 단일 발진기 — 제어권(REMOTE) 1발 토글
|
||||||
|
//// ※ AC_KEY(DO 8)는 전원 투입 계층이라 여기서 건드리지 않는다(반 하드와이어 여부 미확정, Q3).
|
||||||
|
//if (toggleIO)
|
||||||
|
//{
|
||||||
|
// _IODevice._iOUnit.WriteDoBit((int)ePrismaticDOAddress.Laser_REMOTE, true);
|
||||||
|
// toggleIO = false;
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// _IODevice._iOUnit.WriteDoBit((int)ePrismaticDOAddress.Laser_REMOTE, false);
|
||||||
|
// toggleIO = true;
|
||||||
|
//}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
// 260826 현재 DO 를 읽어 반전하는 방식으로 전환 (바로 위 PerformCmdLaserGuideBeam :607-608 과 동일 패턴).
|
||||||
|
// 기존 toggleIO 는 "다음에 쓸 값"을 VM 이 기억하는 방식이라 실제 DO 와 어긋났다.
|
||||||
|
// SeqAutoRunPTOP 가 같은 DO 를 쓰면서 toggleIO 를 갱신하지 않기 때문 —
|
||||||
|
// :1220 용접시작 true / :1243 용접종료 false / :1701 정지 false
|
||||||
|
// 어긋나면 버튼을 눌러도 같은 값을 다시 써서 아무 변화가 없다(= 두 번 눌러야 반응. 현장 확인 260826).
|
||||||
|
// 현재 DO 를 읽어 반전하면 누가 중간에 건드려도 1회 입력에 TRUE/FALSE 가 정확히 기록되고,
|
||||||
|
// 표시(OnMonitoring 의 IsLaserReady = ReadDO(Laser_REMOTE))와도 1:1 로 맞는다.
|
||||||
// ※ AC_KEY(DO 8)는 전원 투입 계층이라 여기서 건드리지 않는다(반 하드와이어 여부 미확정, Q3).
|
// ※ AC_KEY(DO 8)는 전원 투입 계층이라 여기서 건드리지 않는다(반 하드와이어 여부 미확정, Q3).
|
||||||
if (toggleIO)
|
bool curRemote = _IODevice.ReadDO((int)ePrismaticDOAddress.Laser_REMOTE);
|
||||||
{
|
_IODevice._iOUnit.WriteDoBit((int)ePrismaticDOAddress.Laser_REMOTE, !curRemote);
|
||||||
_IODevice._iOUnit.WriteDoBit((int)ePrismaticDOAddress.Laser_REMOTE, true);
|
|
||||||
toggleIO = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_IODevice._iOUnit.WriteDoBit((int)ePrismaticDOAddress.Laser_REMOTE, false);
|
|
||||||
toggleIO = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PerformCmdToggleScannerCamView(object obj)
|
private void PerformCmdToggleScannerCamView(object obj)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user