From ec2af6ac1f1e6de917232b251b57cc236af5ff54 Mon Sep 17 00:00:00 2001 From: backuppc Date: Wed, 4 Feb 2026 15:26:22 +0900 Subject: [PATCH] chore: commit all remaining changes --- .../AGVNavigationCore/Models/VirtualAGV.cs | 3 + .../EnigProtocol/enigprotocol/Commands.cs | 6 +- ...lock.통신 프로토콜_AGV_V350_LF_25.01.10_r2.xlsx# | 1 - HMI/Project/Device/Xbee.cs | 45 ++++++- HMI/Project/StateMachine/Step/_SM_RUN.cs | 10 +- .../StateMachine/Step/_SM_RUN_BUFFER_IN.cs | 31 +---- .../StateMachine/Step/_SM_RUN_BUFFER_OUT.cs | 103 +++++++-------- HMI/Project/StateMachine/Step/_SM_RUN_EXIT.cs | 119 ++++++++++++++---- HMI/Project/StateMachine/Step/_Util.cs | 15 ++- HMI/Project/StateMachine/_AGV.cs | 8 ++ HMI/Project/StateMachine/_Loop.cs | 7 ++ HMI/Project/StateMachine/_SPS.cs | 13 +- HMI/Project/StateMachine/_Xbee.cs | 14 ++- HMI/Project/ViewForm/fAuto.Designer.cs | 92 +++++++------- HMI/Project/ViewForm/fAuto.cs | 82 +++++++----- HMI/Project/fMain.cs | 106 +++++++++------- HMI/SubProject/CommData/Enum.cs | 1 + 17 files changed, 414 insertions(+), 242 deletions(-) delete mode 100644 Document/통신프로토콜/.~lock.통신 프로토콜_AGV_V350_LF_25.01.10_r2.xlsx# diff --git a/AGVLogic/AGVNavigationCore/Models/VirtualAGV.cs b/AGVLogic/AGVNavigationCore/Models/VirtualAGV.cs index f262031..c641820 100644 --- a/AGVLogic/AGVNavigationCore/Models/VirtualAGV.cs +++ b/AGVLogic/AGVNavigationCore/Models/VirtualAGV.cs @@ -363,6 +363,9 @@ namespace AGVNavigationCore.Models } else { + //움직이지 않는다면 움직이게하고, 움직인다면 마크스탑하낟.i + + //도킹노드라면 markstop 을 나머지는 바로 스탑한다. eAGVCommandReason reason = eAGVCommandReason.MarkStop; if (_targetnode.StationType == StationType.Normal || _targetnode.StationType == StationType.Limit) diff --git a/AGVLogic/EnigProtocol/enigprotocol/Commands.cs b/AGVLogic/EnigProtocol/enigprotocol/Commands.cs index f443fd4..3377d38 100644 --- a/AGVLogic/EnigProtocol/enigprotocol/Commands.cs +++ b/AGVLogic/EnigProtocol/enigprotocol/Commands.cs @@ -38,6 +38,7 @@ namespace ENIGProtocol Error = 1, Arrived = 2, ReadRFID = 3, + ActionComplete=4, Status = 9, } @@ -56,7 +57,7 @@ namespace ENIGProtocol // Operational Errors CART_EXIST, MARK_TIMEOUT, - MARK_SENSOR_FAIL, + MARK_SENSOR_FAIL, LIFT_ERROR, AGV_SPEED_SET_FAIL, AGV_RUN_FAIL, @@ -69,6 +70,9 @@ namespace ENIGProtocol CHARGE_RETRY_OVER, MAGNET_ON_ERROR, MAGNET_OF_ERROR, + BUFFER_NOT_COMPLETE, + MARK_STOP_FAIL, + LIDAR_STOP, } public static class AGVUtility diff --git a/Document/통신프로토콜/.~lock.통신 프로토콜_AGV_V350_LF_25.01.10_r2.xlsx# b/Document/통신프로토콜/.~lock.통신 프로토콜_AGV_V350_LF_25.01.10_r2.xlsx# deleted file mode 100644 index e184792..0000000 --- a/Document/통신프로토콜/.~lock.통신 프로토콜_AGV_V350_LF_25.01.10_r2.xlsx# +++ /dev/null @@ -1 +0,0 @@ -,BACKUPPC/1,backuppc,29.01.2026 14:26,file:///C:/Users/1/AppData/Roaming/LibreOffice/4; \ No newline at end of file diff --git a/HMI/Project/Device/Xbee.cs b/HMI/Project/Device/Xbee.cs index 33e8fb9..9361ea8 100644 --- a/HMI/Project/Device/Xbee.cs +++ b/HMI/Project/Device/Xbee.cs @@ -82,7 +82,7 @@ namespace Project.Device proto.OnMessage -= Proto_OnMessage; } - + public int senderrcnt = 0; /// /// 지그비장치에 데이터를 전송합니다 /// @@ -93,10 +93,12 @@ namespace Project.Device try { this.Write(data, 0, data.Length); + senderrcnt = 0; return true; } catch (Exception ex) { + senderrcnt += 1; ErrorMessage = ex.Message; return false; } @@ -119,6 +121,7 @@ namespace Project.Device try { base.Open(); + senderrcnt = 0; return IsOpen; } catch (Exception ex) @@ -150,6 +153,7 @@ namespace Project.Device var buffer = new byte[dev.BytesToRead]; dev.Read(buffer, 0, buffer.Length); proto.ProcessReceivedData(buffer); + VAR.TIME[eVarTime.LastRecv_XBE] = DateTime.Now; } /// @@ -168,6 +172,39 @@ namespace Project.Device PUB.logxbee.AddE($"Send SendMoveComplete [X] : {packet.Length} {packet.HexString()} {PUB.XBE.ErrorMessage}"); } + StateMachine.ERunStep lastactioncmd = StateMachine.ERunStep.READY; + DateTime lastactioncmdtime = DateTime.Now; + + /// + /// 특정행동이 완료되었을때 전달함 + /// + /// + public void SendActionComplete(StateMachine.ERunStep actionCmd) + { + if (lastactioncmd == actionCmd) + { + var ts = DateTime.Now - lastactioncmdtime; + if(ts.TotalSeconds < 2) + { + return; + } + } + + var id = PUB.setting.XBE_ID; + byte cmd = (byte)ENIGProtocol.AGVCommandEH.ActionComplete; + var packet = proto.CreatePacket(id, cmd, null); + if (Send(packet)) + PUB.logxbee.AddI($"SendActionComplete [O] : {packet.Length} {packet.HexString()}"); + else + PUB.logxbee.AddE($"SendActionComplete [X] : {packet.Length} {packet.HexString()} {PUB.XBE.ErrorMessage}"); + + //최종액션저장 + lastactioncmd = actionCmd; + lastactioncmdtime = DateTime.Now; + } + + + /// /// 신규 RFID태그값이 읽혔다면 이명령을 통해서 전송한다 /// @@ -254,7 +291,7 @@ namespace Project.Device value = 0; // stop data.Add(value); - + //나르미오류코드전송필요 260202 //agv\structure\errorflag.cs 파일의 public enum eflag 에 내용있음 data.AddRange(BitConverter.GetBytes(PUB.AGV.error.Value)); @@ -311,6 +348,10 @@ namespace Project.Device // ErrorCode [New RunStepErrorCode] value = (byte)PUB.Result.RunStepErrorCode; + + //라이다로인해 멈춘경우 오류코드 추가 260204 + if (value == 0 && PUB.AGV.system1.stop_by_front_detect) + value = (byte)ENIGProtocol.AGVErrorCode.LIDAR_STOP; data.Add(value); // LastTag diff --git a/HMI/Project/StateMachine/Step/_SM_RUN.cs b/HMI/Project/StateMachine/Step/_SM_RUN.cs index 8ac2e48..80df2e6 100644 --- a/HMI/Project/StateMachine/Step/_SM_RUN.cs +++ b/HMI/Project/StateMachine/Step/_SM_RUN.cs @@ -104,6 +104,7 @@ namespace Project case ERunStep.GOHOME: if (_SM_RUN_GOTO_HOME(runStepisFirst, PUB.sm.GetRunSteptime) == true) { + PUB.XBE.SendActionComplete(PUB.sm.RunStep); PUB.log.Add($"홈 이동이 완료되어 준비상태로 전환합니다"); PUB.sm.SetNewRunStep(ERunStep.READY); } @@ -156,7 +157,7 @@ namespace Project PUB.log.Add($"정의되지 않은 스테이션 입니다({target.StationType}) "); break; } - + PUB.XBE.SendActionComplete(PUB.sm.RunStep); PUB._virtualAGV.Turn = AGVNavigationCore.Models.AGVTurn.None; PUB.sm.SetNewRunStep(ERunStep.READY); } @@ -187,6 +188,7 @@ namespace Project } else if (_SM_RUN_CHARGE_GO(runStepisFirst, PUB.sm.GetRunSteptime)) { + PUB.XBE.SendActionComplete(PUB.sm.RunStep); PUB.Speak(Lang.충전을시작합니다); PUB.sm.SetNewRunStep(ERunStep.CHARGECHECK); return; @@ -202,6 +204,7 @@ namespace Project else if (_SM_RUN_CHARGE_CHECK(runStepisFirst, PUB.sm.GetRunSteptime)) { //충전상태가 활성화되었으므로 대기상태로 전환한다 + PUB.XBE.SendActionComplete(PUB.sm.RunStep); PUB.sm.SetNewRunStep(ERunStep.READY); PUB.log.AddAT("충전상태 확인 완료로 인해 대기 합니다"); } @@ -218,6 +221,7 @@ namespace Project //충전 상태가 OFF되어야 동작하게한다 if (_SM_RUN_CHARGE_GOFF(isFirst, stepTime) == true) { + PUB.XBE.SendActionComplete(PUB.sm.RunStep); //충전상태가 활성화되었으므로 대기상태로 전환한다 PUB.sm.ClearRunStep(); @@ -233,6 +237,7 @@ namespace Project case ERunStep.LOADER_IN: //로더도킹 if (_SM_RUN_ENTER(runStepisFirst, PUB.sm.GetRunSteptime)) { + PUB.XBE.SendActionComplete(PUB.sm.RunStep); PUB.Speak(Lang.버퍼도킹이완료되었습니다); //도킹완료상태를 업데이트한다. @@ -248,6 +253,7 @@ namespace Project case ERunStep.LOADER_OUT: //로더아웃 if (_SM_RUN_EXIT(runStepisFirst, PUB.sm.GetRunSteptime)) { + PUB.XBE.SendActionComplete(PUB.sm.RunStep); PUB.Speak(Lang.버퍼도킹해제완료); //도킹완료상태를 업데이트한다. @@ -262,6 +268,7 @@ namespace Project case ERunStep.BUFFER_OUT: //버퍼아웃 if (_SM_RUN_BUFFER_OUT(runStepisFirst, PUB.sm.GetRunSteptime)) { + PUB.XBE.SendActionComplete(PUB.sm.RunStep); PUB.Speak(Lang.버퍼도킹해제완료); //도킹완료상태를 업데이트한다. @@ -277,6 +284,7 @@ namespace Project case ERunStep.BUFFER_IN: //버퍼도킹 if (_SM_RUN_BUFFER_IN(runStepisFirst, PUB.sm.GetRunSteptime)) { + PUB.XBE.SendActionComplete(PUB.sm.RunStep); PUB.Speak(Lang.버퍼도킹이완료되었습니다); //도킹완료상태를 업데이트한다. diff --git a/HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_IN.cs b/HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_IN.cs index 72701bd..d609316 100644 --- a/HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_IN.cs +++ b/HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_IN.cs @@ -79,34 +79,15 @@ namespace Project if (PUB._virtualAGV.Turn == AGVNavigationCore.Models.AGVTurn.L90) { PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] 이미 Left Turn 완료 상태입니다. 턴 명령을 건너뜁니다."); - PUB.sm.UpdateRunStepSeq(); } else { - //하드웨어 상태 확인 - //var turnState = PUB.AGV.TurnInformation?.StateNew ?? arDev.eNarumiTurn.None; - - //if (turnState == arDev.eNarumiTurn.Left || turnState == arDev.eNarumiTurn.LeftIng) - //{ - // //이미 좌회전 중이거나 완료된 하드웨어 상태 - // PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] 하드웨어 좌회전 상태 확인됨({turnState}). 명령을 건너뜁니다."); - // PUB.sm.UpdateRunStepSeq(); - //} - //else if (turnState == arDev.eNarumiTurn.Right || turnState == arDev.eNarumiTurn.RightIng) - //{ - // //비정상 상태 (우회전 중?) - // SetRunStepError(ENIGProtocol.AGVErrorCode.TURN_FAIL, $"[{funcname}-{PUB.sm.RunStepSeq}] 턴 방향 불일치(Current:{turnState}). 우회전 상태에서 좌회전을 시도할 수 없습니다."); - //} - //else - //{ - //정상 (None) -> 턴 명령 실행 PUB.AGV.AGVMoveLeft180Turn(); PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] AGV Left Turn"); VAR.TIME.Update(eVarTime.LastTurnCommandTime); - PUB.sm.UpdateRunStepSeq(); - //} + PUB._mapCanvas.SetAlertMessage($"턴 실행"); } - PUB._mapCanvas.SetAlertMessage($"턴 진행 중"); + PUB.sm.UpdateRunStepSeq(); return false; } else if (PUB.sm.RunStepSeq == idx++) @@ -155,7 +136,7 @@ namespace Project //리프트 센서 확인 if (PUB.AGV.signal1.lift_down == false) { - VAR.I32[eVarInt32.RetryLift] = 0; + VAR.I32[eVarInt32.RetryLift] += 1; var rlt = PUB.AGV.LiftControl(arDev.Narumi.LiftCommand.DN); PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] 리프트 하강 실행:{rlt}"); } @@ -191,20 +172,20 @@ namespace Project } else if (PUB.sm.RunStepSeq == idx++) { - if(PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOffEnter) + if (PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOffEnter) { VAR.I32[eVarInt32.RetryManget] += 1; PUB.AGV.LiftControl(arDev.Narumi.LiftCommand.ON); PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] 마그넷ON"); } - + PUB.sm.UpdateRunStepSeq(); return false; } else if (PUB.sm.RunStepSeq == idx++) { //마그넷센서가 들어오는지 5초간 확인한다. - if (PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOffEnter && + if (PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOffEnter && PUB.AGV.signal1.magnet_on == false) { if (seqtime.TotalSeconds > 5) diff --git a/HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_OUT.cs b/HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_OUT.cs index fae9f1c..57a3eac 100644 --- a/HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_OUT.cs +++ b/HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_OUT.cs @@ -41,6 +41,17 @@ namespace Project return false; } else if (PUB.sm.RunStepSeq == idx++) + { + //회전이없다면 오류처리한다. + if(PUB._virtualAGV.Turn != AGVNavigationCore.Models.AGVTurn.L90) + { + SetRunStepError(ENIGProtocol.AGVErrorCode.BUFFER_NOT_COMPLETE, $"[{funcname}-{PUB.sm.RunStepSeq}] 버퍼에서 나오려면 버퍼진입작업이 완료되어있어야 합니다"); + return false; + } + PUB.sm.UpdateRunStepSeq(); + return false; + } + else if (PUB.sm.RunStepSeq == idx++) { arDev.Narumi.LiftCommand lift = PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOnExit ? arDev.Narumi.LiftCommand.UP : arDev.Narumi.LiftCommand.DN; PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] 리프트제어 {lift}"); @@ -57,7 +68,7 @@ namespace Project { if (seqtime.TotalSeconds > 20) { - if(VAR.I32[eVarInt32.RetryLift] < 3) + if (VAR.I32[eVarInt32.RetryLift] < 3) { PUB.log.AddAT($"[{funcname}-{PUB.sm.RunStepSeq}] 리프트가 완료되지 않아 재시도 합니다"); PUB.sm.UpdateRunStepSeq(-1); @@ -73,10 +84,10 @@ namespace Project PUB.sm.UpdateRunStepSeq(); return false; } - + else if (PUB.sm.RunStepSeq == idx++) { - if (PUB.AGV.signal1.mark_sensor == false) + //if (PUB.AGV.signal1.mark_sensor == false) { //빈 상태로 아웃해야한다. if (SpeedSetRetry) @@ -112,7 +123,7 @@ namespace Project else if (PUB.sm.RunStepSeq == idx++) { //전진이동 - if (PUB.AGV.signal1.mark_sensor == false) + //if (PUB.AGV.signal1.mark_sensor == false) { VAR.I32[eVarInt32.RetryMove] += 1; PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] AGV 전진 구동 시작"); @@ -124,13 +135,13 @@ namespace Project else if (PUB.sm.RunStepSeq == idx++) { //AGV구동을 확인하고 마크스탑을 설정한다. - if (PUB.AGV.signal1.mark_sensor == false) + //if (PUB.AGV.signal1.mark_sensor == false) { if (PUB.AGV.system1.agv_run == false) { if (seqtime.TotalSeconds > 3) { - if(VAR.I32[eVarInt32.RetryMove] < 3) + if (VAR.I32[eVarInt32.RetryMove] < 3) { //재시도를 하게한다. PUB.sm.UpdateRunStepSeq(-1); @@ -141,7 +152,7 @@ namespace Project SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_RUN_FAIL); VAR.I32[eVarInt32.RetryMove] = 0; } - + } return false; } @@ -161,14 +172,14 @@ namespace Project } else if (PUB.sm.RunStepSeq == idx++) { - if (PUB.AGV.signal1.mark_sensor == false) + //if (PUB.AGV.signal1.mark_sensor == false) { //마크스탑신호가 3초이내로 들어와야 한다 if (PUB.AGV.data.Speed != 'S') { if (seqtime.TotalSeconds > 3) { - if(VAR.I32[eVarInt32.RetryMarkStop] < 3) + if (VAR.I32[eVarInt32.RetryMarkStop] < 3) { PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] MarkStop 재시도"); PUB.sm.UpdateRunStepSeq(-1); @@ -184,7 +195,7 @@ namespace Project } PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] MarkStop 신구 확인 완료"); } - else PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}]마크스탑이 미리 들어와있어. 이동및 스탑을 하지 않습니다"); + //else PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}]마크스탑이 미리 들어와있어. 이동및 스탑을 하지 않습니다"); PUB.sm.UpdateRunStepSeq(); return false; @@ -215,69 +226,45 @@ namespace Project } else { - //하드웨어 상태 확인 - //var turnState = PUB.AGV.TurnInformation?.StateOld ?? arDev.eNarumiTurn.None; - //if (turnState == arDev.eNarumiTurn.Right) - //{ - // SetRunStepError(ENIGProtocol.AGVErrorCode.TURN_FAIL, $"[{funcname}-{PUB.sm.RunStepSeq}] 턴 방향 불일치(Current:{turnState}). 버퍼진출시에는 LEFT-TURN 상태여야 합니다"); - // return false; - //} - //else - //{ - //정상 (None) -> 턴 명령 실행 - PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] AGV Right Turn 명령 전송"); PUB.AGV.AGVMoveRight180Turn(); - //} + PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] AGV Right Turn"); + VAR.TIME.Update(eVarTime.LastTurnCommandTime); + PUB._mapCanvas.SetAlertMessage($"턴 실행"); } PUB.sm.UpdateRunStepSeq(); return false; } else if (PUB.sm.RunStepSeq == idx++) { - //이동확인 - if (PUB.AGV.system1.agv_run == false) + //이미 완료된 상태라면 대기 과정을 건너뛴다. + if (PUB._virtualAGV.Turn == AGVNavigationCore.Models.AGVTurn.R90) { - //최소3초기다려준다. - if (seqtime.TotalSeconds > 3) + PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] 이미 턴이완료된 상태입니다"); + } + else + { + //왼쪽턴이 완료되지 않은경우 + if (PUB.AGV.TurnInformation.State != arDev.eNarumiTurn.Right) { - if (PUB._virtualAGV.Turn == AGVNavigationCore.Models.AGVTurn.R90) + //움직임 확인을 위해 3초간은 검증을 유예한다 + if (PUB.AGV.TurnInformation.Runtime.TotalSeconds < 3) return false; + + //턴 이동 상태가 확인되어야 한다. + var overtime = 30; + if (PUB.AGV.TurnInformation.Runtime.TotalSeconds > overtime) { - //이미 완료된 상태이므로 이동 확인 패스 - PUB.sm.UpdateRunStepSeq(); + //30초동안 AGV까 움직이지 않았다면 오류 처리한다. + SetRunStepError(ENIGProtocol.AGVErrorCode.TURN_FAIL, $"[{funcname}] {overtime}초이내 턴 감지 안됨"); return false; } - - SetRunStepError(ENIGProtocol.AGVErrorCode.TURN_FAIL); + else PUB._mapCanvas.SetAlertMessage($"턴 진행 중({PUB.AGV.TurnInformation.Runtime.TotalSeconds:N0}/{overtime})"); + return false; } - return false; - } - PUB.sm.UpdateRunStepSeq(); - return false; - } - else if (PUB.sm.RunStepSeq == idx++) - { - //멈춤확인 - if (PUB.AGV.system1.agv_run == true) - { - if (seqtime.TotalSeconds > 25) - { - SetRunStepError(ENIGProtocol.AGVErrorCode.TURN_FAIL); - } - return false; + PUB._virtualAGV.Turn = AGVNavigationCore.Models.AGVTurn.None; //턴완료 + PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] Turn(right) 완료 - 위치복귀됨"); } - //턴 완료 상태 업데이트 - if (PUB._virtualAGV.Turn != AGVNavigationCore.Models.AGVTurn.R90) - { - if (PUB._virtualAGV.Turn == AGVNavigationCore.Models.AGVTurn.None) - PUB._virtualAGV.Turn = AGVNavigationCore.Models.AGVTurn.R90; //left에서 right 턴을 했으니 none 이다 - else - PUB._virtualAGV.Turn = AGVNavigationCore.Models.AGVTurn.None; - - PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] Turn State Updated to {PUB._virtualAGV.Turn}"); - } - - PUB.sm.UpdateRunStepSeq(); + PUB.sm.UpdateRunStepSeq(); //이미완료된상태이므로 다음으로 진행한다. return false; } else if (PUB.sm.RunStepSeq == idx++) diff --git a/HMI/Project/StateMachine/Step/_SM_RUN_EXIT.cs b/HMI/Project/StateMachine/Step/_SM_RUN_EXIT.cs index 53f048b..c5ca003 100644 --- a/HMI/Project/StateMachine/Step/_SM_RUN_EXIT.cs +++ b/HMI/Project/StateMachine/Step/_SM_RUN_EXIT.cs @@ -14,22 +14,23 @@ namespace Project /// /// 장비엣 빠젼나온다. /// - public Boolean _SM_RUN_EXIT(bool isFirst, TimeSpan seqTime) + public Boolean _SM_RUN_EXIT(bool isFirst, TimeSpan seqtime) { var idx = 1; - var funcname = PUB.sm.RunStep.ToString(); + var funcname = $"[EXIT-{PUB.sm.RunStep}]"; //충전 상태가 OFF되어야 동작하게한다 - if (_SM_RUN_CHARGE_GOFF(isFirst, seqTime) == false) return false; + if (_SM_RUN_CHARGE_GOFF(isFirst, seqtime) == false) return false; //라이더멈춤이 설정되어있다면 음성으로 알려준다 if (CheckLiderStop() == false) return false; if (PUB.sm.RunStepSeq == idx++) { - PUB.log.Add("OUT작업-시작"); - PUB.Speak("작업을 시작합니다"); + PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] OUT작업-시작"); + PUB.Speak("작업을 시작합니다(안전을위해 AGVSTOP신호를 전송합니다)"); PUB.AGV.AGVMoveStop(funcname); + VAR.I32[eVarInt32.RetryLift] = 0; PUB.sm.UpdateRunStepSeq(); return false; } @@ -38,7 +39,7 @@ namespace Project //작업형태에 따라서. 리프트를 제어한다. var liftCmd = arDev.Narumi.LiftCommand.DN; if (PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOnExit) liftCmd = arDev.Narumi.LiftCommand.UP; - + VAR.I32[eVarInt32.RetryLift] += 1; PUB.AGV.LiftControl(liftCmd); PUB.sm.UpdateRunStepSeq(); return false; @@ -62,21 +63,32 @@ namespace Project } else { - var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime); - if (ts.TotalSeconds > 10) + if (seqtime.TotalSeconds > 20) { - SetRunStepError(ENIGProtocol.AGVErrorCode.LIFT_ERROR, $"[{funcname}] 리프트({liftCmd})이 확인되지 않습니다"); + if (VAR.I32[eVarInt32.RetryLift] < 3) + { + PUB.log.AddAT($"[{funcname}-{PUB.sm.RunStepSeq}] 리프트가 동작({liftCmd})하지 않아 재시도 합니다"); + PUB.sm.UpdateRunStepSeq(-1); + } + else + { + SetRunStepError(ENIGProtocol.AGVErrorCode.LIFT_ERROR, + $"[{funcname}-{PUB.sm.RunStepSeq}] 리프트가 동작({liftCmd})하지 않습니다"); + VAR.I32[eVarInt32.RetryLift] = 0; + } } + else PUB._mapCanvas.SetAlertMessage($"리프트 하강 확인 중({seqtime.TotalSeconds:N0}/20)"); return false; } - - PUB.log.Add("리프트 동작 확인 완료"); + VAR.I32[eVarInt32.RetryMoveset] = 0; + PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] 리프트 동작 확인 완료"); PUB.sm.UpdateRunStepSeq(); return false; } else if (PUB.sm.RunStepSeq == idx++) { - //빈 상태로 아웃해야한다. + //라이더 끈상태로 빠져나와야 한다 + VAR.I32[eVarInt32.RetryMoveset] += 1; var ret = PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData { Bunki = arDev.Narumi.eBunki.Strate, @@ -84,22 +96,45 @@ namespace Project PBSSensor = 0, Speed = arDev.Narumi.eMoveSpd.Low, }); - //명령이 실패되었다면 재시도를 한다 if (ret != arDev.eNarumiCommandResult.Success) - { - if (ret >= arDev.eNarumiCommandResult.Error) - { - SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_SPEED_SET_FAIL); - } - return false; - } + PUB.log.AddAT($"[{funcname}-{PUB.sm.RunStepSeq}] moveset return fail:{ret}"); PUB.sm.UpdateRunStepSeq(); return false; } else if (PUB.sm.RunStepSeq == idx++) + { + //moveset 결과확인 + if (PUB.AGV.data.Speed != 'L' || + PUB.AGV.data.Sts != 'S' || + PUB.AGV.data.Direction != 'F') + { + if (seqtime.TotalSeconds > 5) + { + if (VAR.I32[eVarInt32.RetryMoveset] < 3) + { + PUB.log.AddAT($"[{funcname}-{PUB.sm.RunStepSeq}] MoveSet이 확인되지 않아 재시도 합니다"); + PUB.sm.UpdateRunStepSeq(-1); + } + else + { + SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_SPEED_SET_FAIL, + $"[{funcname}-{PUB.sm.RunStepSeq}] MoveSet 실패"); + VAR.I32[eVarInt32.RetryMoveset] = 0; + } + } + else PUB._mapCanvas.SetAlertMessage($"이동설정 확인 중({seqtime.TotalSeconds:N0}/20)"); + return false; + } + VAR.I32[eVarInt32.RetryMove] = 0; + PUB.sm.UpdateRunStepSeq(); + return false; + } + else if (PUB.sm.RunStepSeq == idx++) { //전진이동 + PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] 전진이동"); + VAR.I32[eVarInt32.RetryMove] += 1; PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward); PUB.sm.UpdateRunStepSeq(); return false; @@ -109,14 +144,33 @@ namespace Project //AGV구동을 확인하고 마크스탑을 설정한다. if (PUB.AGV.system1.agv_run == false) { - if (seqTime.TotalMilliseconds > 1000) + if (seqtime.TotalSeconds > 3) { - //구동이확인되지 않으면 오류처리를 한다. - SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_RUN_FAIL); + if (VAR.I32[eVarInt32.RetryMove] < 3) + { + PUB.log.AddAT($"[{funcname}-{PUB.sm.RunStepSeq}] AGV전진이 확인되지 않아 재시도 합니다"); + PUB.sm.UpdateRunStepSeq(-1); + } + else + { + SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_RUN_FAIL, + $"[{funcname}-{PUB.sm.RunStepSeq}] agv 구동확인 안됨"); + VAR.I32[eVarInt32.RetryMove] = 0; + } } + else PUB._mapCanvas.SetAlertMessage($"AGV RUN 확인 중({seqtime.TotalSeconds:N0}/20)"); return false; } + //마크스탑설정 + VAR.I32[eVarInt32.RetryMarkStop] = 0; + PUB.sm.UpdateRunStepSeq(); + return false; + } + else if (PUB.sm.RunStepSeq == idx++) + { + PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] 마크스탑신호를 전달합니다"); + VAR.I32[eVarInt32.RetryMarkStop] += 1; PUB.AGV.AGVMoveStop(funcname, arDev.Narumi.eStopOpt.MarkStop); PUB.sm.UpdateRunStepSeq(); return false; @@ -126,10 +180,21 @@ namespace Project //마크스탑신호가 3초이내로 들어와야 한다 if (PUB.AGV.data.Speed != 'S') { - if (seqTime.TotalMilliseconds > 3000) + if (seqtime.TotalSeconds > 20) { - SetRunStepError(ENIGProtocol.AGVErrorCode.MARK_TIMEOUT); + if (VAR.I32[eVarInt32.RetryMarkStop] < 3) + { + PUB.log.AddAT($"[{funcname}-{PUB.sm.RunStepSeq}] 마크스탑이 확인되지 않아 재시도 합니다"); + PUB.sm.UpdateRunStepSeq(-1); + } + else + { + SetRunStepError(ENIGProtocol.AGVErrorCode.MARK_STOP_FAIL, + $"[{funcname}-{PUB.sm.RunStepSeq}] 마크스탑이 확인되지 않습니다"); + VAR.I32[eVarInt32.RetryMarkStop] = 0; + } } + else PUB._mapCanvas.SetAlertMessage($"리프트 하강 확인 중({seqtime.TotalSeconds:N0}/20)"); return false; } PUB.sm.UpdateRunStepSeq(); @@ -140,7 +205,7 @@ namespace Project //AGV가 멈출때까지 기다린다. if (PUB.AGV.system1.agv_run == true) { - if (seqTime.TotalSeconds > 10) + if (seqtime.TotalSeconds > 10) { SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_STOP_FAIL); } @@ -154,7 +219,7 @@ namespace Project //마크센서입력을 확인한다. if (PUB.AGV.signal1.mark_sensor == false) { - if (seqTime.TotalSeconds > 5) + if (seqtime.TotalSeconds > 5) { SetRunStepError(ENIGProtocol.AGVErrorCode.MARK_SENSOR_FAIL); } diff --git a/HMI/Project/StateMachine/Step/_Util.cs b/HMI/Project/StateMachine/Step/_Util.cs index 79add7d..18a4533 100644 --- a/HMI/Project/StateMachine/Step/_Util.cs +++ b/HMI/Project/StateMachine/Step/_Util.cs @@ -297,10 +297,17 @@ namespace Project // 목적지 도착 여부 확인 if (PUB.AGV.signal1.mark_sensor == false) { - - PUB.log.AddI($"목표도착되었으나 마크센서가 감지되지 않아 완료처리 하지않습니다"); - return false; - + if(PUB._virtualAGV.TargetNode.StationType != StationType.Normal) + { + PUB.log.AddAT($"목표도착되었으나 마크센서가 감지되지 않아 완료처리 하지않습니다"); + return false; + } + else + { + //일반노드가목표인경우에는 완료처리한다. + PUB.log.AddI($"일반노드는 마크센서가 감지되지 않아도 완료처리 합니다"); + return true; + } } // 경로가 존재한다면... diff --git a/HMI/Project/StateMachine/_AGV.cs b/HMI/Project/StateMachine/_AGV.cs index acde730..dda272d 100644 --- a/HMI/Project/StateMachine/_AGV.cs +++ b/HMI/Project/StateMachine/_AGV.cs @@ -185,6 +185,14 @@ namespace Project PUB._mapCanvas.SetAGVPosition(PUB.setting.MCID, CurrentNode, MotDireciton); PUB._virtualAGV.SetPosition(CurrentNode, MotDireciton); PUB.SaveLastPosition(); + + //노드가 들어왔는데. 일반 노드라면.. 턴 정보를 제거한다. + if (CurrentNode.StationType != StationType.Buffer && PUB._virtualAGV.Turn != AGVTurn.None) + { + PUB.log.AddAT($"현재노드위치가 버퍼가 아니라서 턴정보를 초기화합니다{PUB._virtualAGV.Turn}"); + PUB._virtualAGV.Turn = AGVTurn.None; + } + } //태그를 읽었다면 상태를 바로 전송한다 diff --git a/HMI/Project/StateMachine/_Loop.cs b/HMI/Project/StateMachine/_Loop.cs index 86304d6..33443b3 100644 --- a/HMI/Project/StateMachine/_Loop.cs +++ b/HMI/Project/StateMachine/_Loop.cs @@ -172,8 +172,15 @@ namespace Project if (PUB._mapCanvas != null) { this.Invoke(new Action(() => { + + + AutoLoadLastPosition(); + PUB._mapCanvas.ExitSyncMode( AGVNavigationCore.Controls.UnifiedAGVCanvas.CanvasMode.Run); })); + + + } } diff --git a/HMI/Project/StateMachine/_SPS.cs b/HMI/Project/StateMachine/_SPS.cs index 892b0f4..e040391 100644 --- a/HMI/Project/StateMachine/_SPS.cs +++ b/HMI/Project/StateMachine/_SPS.cs @@ -49,8 +49,17 @@ namespace Project { if (VAR.BOOL[eVarBool.DISABLE_AUTOCONN_XBEE] == false) { - ConnectSerialPort(PUB.XBE, PUB.setting.Port_XBE, PUB.setting.Baud_XBE, - eVarTime.LastConn_XBE, eVarTime.LastConnTry_XBE, null); + if(PUB.XBE.senderrcnt>5) + { + ConnectSerialPort(PUB.XBE, PUB.setting.Port_XBE, PUB.setting.Baud_XBE, + eVarTime.LastConn_XBE, eVarTime.LastConnTry_XBE, eVarTime.LastRecv_XBE); + } + else + { + ConnectSerialPort(PUB.XBE, PUB.setting.Port_XBE, PUB.setting.Baud_XBE, + eVarTime.LastConn_XBE, eVarTime.LastConnTry_XBE, null); + } + } } diff --git a/HMI/Project/StateMachine/_Xbee.cs b/HMI/Project/StateMachine/_Xbee.cs index 35f9ebe..0a1d6c0 100644 --- a/HMI/Project/StateMachine/_Xbee.cs +++ b/HMI/Project/StateMachine/_Xbee.cs @@ -210,8 +210,20 @@ namespace Project return; } + + + //노드가 들어왔는데. 일반 노드라면.. 턴 정보를 제거한다. + if (PUB._virtualAGV.CurrentNode != null && + PUB._virtualAGV.CurrentNode.StationType != StationType.Buffer && + PUB._virtualAGV.Turn != AGVTurn.None) + { + PUB.log.AddAT($"[{logPrefix}-Goto] 현재노드위치가 버퍼가 아니라서 턴정보를 초기화합니다{PUB._virtualAGV.Turn}"); + PUB._virtualAGV.Turn = AGVTurn.None; + } + + //s/w턴이 걸려있다면 이동 불가로한다.(버퍼 작업중이다) - if(PUB._virtualAGV.Turn != AGVTurn.None) + if (PUB._virtualAGV.Turn != AGVTurn.None) { SetRunStepError(ENIGProtocol.AGVErrorCode.BUFFER_NOT_COMPLETE, $"[{logPrefix}-Goto] 버퍼작업이 완료되지 않았습니다"); return; diff --git a/HMI/Project/ViewForm/fAuto.Designer.cs b/HMI/Project/ViewForm/fAuto.Designer.cs index 4935a95..a654b74 100644 --- a/HMI/Project/ViewForm/fAuto.Designer.cs +++ b/HMI/Project/ViewForm/fAuto.Designer.cs @@ -32,63 +32,65 @@ namespace Project.ViewForm /// private void InitializeComponent() { - components = new System.ComponentModel.Container(); - timer1 = new System.Windows.Forms.Timer(components); - ctlAuto1 = new CtlAuto(); - panel1 = new Panel(); - SuspendLayout(); + this.components = new System.ComponentModel.Container(); + this.timer1 = new System.Windows.Forms.Timer(this.components); + this.ctlAuto1 = new Project.CtlAuto(); + this.panel1 = new System.Windows.Forms.Panel(); + this.SuspendLayout(); // // timer1 // - timer1.Interval = 200; + this.timer1.Interval = 200; + this.timer1.Tick += new System.EventHandler(this.timer1_Tick); // // ctlAuto1 // - ctlAuto1.BackColor = Color.FromArgb(32, 32, 32); - ctlAuto1.BorderColor = Color.Transparent; - ctlAuto1.Font = new Font("맑은 고딕", 20F, FontStyle.Regular, GraphicsUnit.Point, 129); - ctlAuto1.Font_BMS_Level = new Font("Bahnschrift Condensed", 250F, FontStyle.Bold, GraphicsUnit.Point, 0); - ctlAuto1.Font_BMS_Volt = new Font("Bahnschrift Condensed", 50.25F, FontStyle.Bold); - ctlAuto1.Font_MAIN_BMSLevel = new Font("Arial Narrow", 150F, FontStyle.Bold); - ctlAuto1.ForeColor = Color.White; - ctlAuto1.ItemGap = 0; - ctlAuto1.Items = null; - ctlAuto1.Location = new Point(835, 338); - ctlAuto1.MinimumSize = new Size(100, 30); - ctlAuto1.Name = "ctlAuto1"; - ctlAuto1.ProgressMax = 100F; - ctlAuto1.ProgressVal = 50F; - ctlAuto1.Scean = CtlAuto.eScean.Normal; - ctlAuto1.Size = new Size(179, 241); - ctlAuto1.StatusMessage = "상태메세지 입니다"; - ctlAuto1.StopMessage = ""; - ctlAuto1.StopTime = new DateTime(0L); - ctlAuto1.TabIndex = 20; - ctlAuto1.Text = "ctlAuto1"; + this.ctlAuto1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32))))); + this.ctlAuto1.BorderColor = System.Drawing.Color.Transparent; + this.ctlAuto1.Font = new System.Drawing.Font("맑은 고딕", 20F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129))); + this.ctlAuto1.Font_BMS_Level = new System.Drawing.Font("Bahnschrift Condensed", 250F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ctlAuto1.Font_BMS_Volt = new System.Drawing.Font("Bahnschrift Condensed", 50.25F, System.Drawing.FontStyle.Bold); + this.ctlAuto1.Font_MAIN_BMSLevel = new System.Drawing.Font("Microsoft Sans Serif", 150F, System.Drawing.FontStyle.Bold); + this.ctlAuto1.ForeColor = System.Drawing.Color.White; + this.ctlAuto1.ItemGap = 0; + this.ctlAuto1.Items = null; + this.ctlAuto1.Location = new System.Drawing.Point(835, 338); + this.ctlAuto1.MinimumSize = new System.Drawing.Size(100, 30); + this.ctlAuto1.Name = "ctlAuto1"; + this.ctlAuto1.ProgressMax = 100F; + this.ctlAuto1.ProgressVal = 50F; + this.ctlAuto1.Scean = Project.CtlAuto.eScean.Normal; + this.ctlAuto1.Size = new System.Drawing.Size(179, 241); + this.ctlAuto1.StatusMessage = "상태메세지 입니다"; + this.ctlAuto1.StopMessage = ""; + this.ctlAuto1.StopTime = new System.DateTime(((long)(0))); + this.ctlAuto1.TabIndex = 20; + this.ctlAuto1.Text = "ctlAuto1"; // // panel1 // - panel1.Dock = DockStyle.Fill; - panel1.Font = new Font("Tahoma", 8F, FontStyle.Bold); - panel1.Location = new Point(0, 0); - panel1.Name = "panel1"; - panel1.Size = new Size(1014, 579); - panel1.TabIndex = 21; + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Font = new System.Drawing.Font("Tahoma", 8F, System.Drawing.FontStyle.Bold); + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(1014, 579); + this.panel1.TabIndex = 21; // // fAuto // - AutoScaleMode = AutoScaleMode.None; - BackColor = Color.FromArgb(15, 15, 15); - ClientSize = new Size(1014, 579); - Controls.Add(panel1); - Controls.Add(ctlAuto1); - DoubleBuffered = true; - FormBorderStyle = FormBorderStyle.None; - Name = "fAuto"; - Text = "fAuto"; - Load += fAuto_Load; - VisibleChanged += fAuto_VisibleChanged; - ResumeLayout(false); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(15)))), ((int)(((byte)(15)))), ((int)(((byte)(15))))); + this.ClientSize = new System.Drawing.Size(1014, 579); + this.Controls.Add(this.panel1); + this.Controls.Add(this.ctlAuto1); + this.DoubleBuffered = true; + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.Name = "fAuto"; + this.Text = "fAuto"; + this.Load += new System.EventHandler(this.fAuto_Load_1); + this.VisibleChanged += new System.EventHandler(this.fAuto_VisibleChanged); + this.ResumeLayout(false); + } #endregion diff --git a/HMI/Project/ViewForm/fAuto.cs b/HMI/Project/ViewForm/fAuto.cs index 6e4fb68..a4e6090 100644 --- a/HMI/Project/ViewForm/fAuto.cs +++ b/HMI/Project/ViewForm/fAuto.cs @@ -141,7 +141,7 @@ namespace Project.ViewForm PUB.AGV.DataReceive += AGV_DataReceive; - this.timer1.Start(); + } private void AGV_DataReceive(object sender, arDev.Narumi.DataEventArgs e) { @@ -194,34 +194,7 @@ namespace Project.ViewForm private void timer1_Tick_1(object sender, EventArgs e) { - //if (this.Visible == false) return; - //if (tmrun == true) return; - //tmrun = true; - - //this.ctlAuto1.OnUpdateMode = true; - - //if (this.ctlAuto1.Scean == CtlAuto.eScean.Progress) - //{ - // ctlAuto1.ProgressVal = PUB.Result.SMSG_ProgressValue; - // ctlAuto1.ProgressMax = PUB.Result.SMSG_ProgressMax; - // ctlAuto1.StatusMessage = VAR.STR?.Get(eVarString.StatusMessage) ?? string.Empty; - //} - //this.ctlAuto1.StopMessage = string.Empty; - - //if (PUB.sm.Step == StateMachine.eSMStep.RUN) - //{ - // this.ctlAuto1.runStep = PUB.sm.RunStep; - //} - //else - //{ - // this.ctlAuto1.runStep = ERunStep.READY; - //} - //this.ctlAuto1.OnUpdateMode = false; - //this.ctlAuto1.Invalidate(); - - //PUB.mapctl.PredictNextAction(); - - //tmrun = false; + } private void HandleRunModeClick(MapNode targetNode) @@ -267,5 +240,56 @@ namespace Project.ViewForm return; } } + + private void timer1_Tick(object sender, EventArgs e) + { + + if (this.Visible == false) return; + if (tmrun == true) return; + if (PUB.sm.Step < eSMStep.IDLE) return; + if (PUB._mapCanvas == null) return; + tmrun = true; + + + var errmsg = string.Empty; + if(PUB.AGV.IsOpen==false) + { + errmsg = "AGV컨트롤러 연결실패"; + } + else if(PUB.XBE.IsOpen==false ) + { + errmsg = "XBEE 연결실패"; + } + else if (PUB.XBE.senderrcnt > 5) + { + errmsg = "XBEE 통신불가"; + } + else if(PUB.AGV.error.Value > 0) + { + errmsg = PUB.AGV.error.ToString(); + } + else if(PUB.AGV.system1.stop_by_front_detect) + { + errmsg = "전방 물체감지로 인해 정지"; + } + else if (PUB.BMS.IsOpen == false) + { + errmsg = "BMS 연결실패"; + } + else if(VAR.BOOL[eVarBool.FLAG_AUTORUN]==false) + { + errmsg = "자동모드가 아닙니다"; + } + + PUB._mapCanvas.SetAlertMessage(errmsg); + + + tmrun = false; + } + + private void fAuto_Load_1(object sender, EventArgs e) + { + this.timer1.Start(); + } } } diff --git a/HMI/Project/fMain.cs b/HMI/Project/fMain.cs index 790bcea..de8eb48 100644 --- a/HMI/Project/fMain.cs +++ b/HMI/Project/fMain.cs @@ -261,6 +261,57 @@ namespace Project PUB.AddEEDB("프로그램 시작"); } + void AutoLoadLastPosition() + { + PUB.log.Add("autoload last position"); + //마지막위치복원 + // 마지막 위치 로드 + var lastPos = PUB.LoadLastPosition(); + if (lastPos != null) + { + var sb = new System.Text.StringBuilder(); + var curNode = PUB.FindByNodeID(lastPos.NodeId); + var prevNode = PUB.FindByNodeID(lastPos.PrevNode); + var targNode = PUB.FindByNodeID(lastPos.TargetNode); + var staNode = PUB.FindByNodeID(lastPos.StartNode); + if (prevNode != null) + { + PUB._virtualAGV.SetPosition(prevNode, lastPos.PrevDirection); + PUB._mapCanvas.SetAGVPosition(PUB.setting.MCID, prevNode, lastPos.PrevDirection); + sb.AppendLine($"이전: {prevNode.ID2}, {lastPos.PrevDirection}"); + } + if (curNode != null) + { + PUB._virtualAGV.SetPosition(curNode, lastPos.Direction); + PUB._mapCanvas.SetAGVPosition(PUB.setting.MCID, curNode, lastPos.Direction); + sb.AppendLine($"현재: {curNode.ID2}, {lastPos.Direction}"); + } + if (staNode != null) + { + PUB._virtualAGV.StartNode = staNode; + sb.AppendLine($"시직:{staNode.ID2}"); + } + if (targNode != null) + { + PUB._virtualAGV.TargetNode = targNode; + sb.AppendLine($"대상:{targNode.ID2}"); + } + + PUB._virtualAGV.Turn = lastPos.Turn; + sb.AppendLine($"S/W회전:{lastPos.Turn}"); + + if (lastPos.AGV_Turn != null) + { + PUB.AGV.TurnInformation = lastPos.AGV_Turn; + sb.AppendLine($"H/W회전:{lastPos.AGV_Turn}"); + } + + PUB.log.Add($"위치복원\n{sb}"); + } + else PUB.log.AddE($"마지막위치가 없습니다"); + + + } void AutoLoadMapData() { //auto load @@ -279,11 +330,16 @@ namespace Project if (files.Any()) filePath = files[0]; } + if(PUB._mapCanvas == null) + { + UTIL.MsgE("Canvas null"); + } + if (filePath.Exists) { var result = MapLoader.LoadMapFromFile(filePath.FullName); - if (result.Success) + if (result != null && result.Success) { PUB._mapCanvas.SetMapLoadResult(result); PUB._mapCanvas.MapFileName = filePath.FullName; @@ -301,7 +357,7 @@ namespace Project PUB.log.Add($"가상 AGV 생성: PointZero 위치"); } - else if (PUB._virtualAGV != null) + else { PUB._virtualAGV.LowBatteryThreshold = PUB.setting.BatteryLimit_Low; // 기존 AGV가 있으면 캔버스에 다시 연결 @@ -310,50 +366,6 @@ namespace Project } PUB.log.Add($"맵 파일 로드 완료: {filePath.Name}, 노드 수: {result.Nodes.Count}"); - //마지막위치복원 - // 마지막 위치 로드 - var lastPos = PUB.LoadLastPosition(); - if (lastPos != null) - { - var sb = new System.Text.StringBuilder(); - var curNode = PUB.FindByNodeID(lastPos.NodeId); - var prevNode = PUB.FindByNodeID(lastPos.PrevNode); - var targNode = PUB.FindByNodeID(lastPos.TargetNode); - var staNode = PUB.FindByNodeID(lastPos.StartNode); - if(prevNode != null) - { - PUB._virtualAGV.SetPosition(prevNode, lastPos.PrevDirection); - PUB._mapCanvas.SetAGVPosition(PUB.setting.MCID, prevNode, lastPos.PrevDirection); - sb.AppendLine($"이전: {prevNode.ID2}, {lastPos.PrevDirection}"); - } - if (curNode != null) - { - PUB._virtualAGV.SetPosition(curNode, lastPos.Direction); - PUB._mapCanvas.SetAGVPosition(PUB.setting.MCID, curNode, lastPos.Direction); - sb.AppendLine($"현재: {curNode.ID2}, {lastPos.Direction}"); - } - if (staNode != null) - { - PUB._virtualAGV.StartNode = staNode; - sb.AppendLine($"시직:{staNode.ID2}"); - } - if (targNode != null) - { - PUB._virtualAGV.TargetNode = targNode; - sb.AppendLine($"대상:{targNode.ID2}"); - } - - PUB._virtualAGV.Turn = lastPos.Turn; - sb.AppendLine($"S/W회전:{lastPos.Turn}"); - - if(lastPos.AGV_Turn != null) - { - PUB.AGV.TurnInformation = lastPos.AGV_Turn; - sb.AppendLine($"H/W회전:{lastPos.AGV_Turn}"); - } - - PUB.log.Add($"위치복원\n{sb}"); - } //// 🔥 초기 위치 설정 및 확인 화면 표시 @@ -374,6 +386,8 @@ namespace Project // } // } //})); + + PUB._mapCanvas.SetView(287.6f, -147.6f, 1.13f); } else { diff --git a/HMI/SubProject/CommData/Enum.cs b/HMI/SubProject/CommData/Enum.cs index 5ca8a3b..b2030cc 100644 --- a/HMI/SubProject/CommData/Enum.cs +++ b/HMI/SubProject/CommData/Enum.cs @@ -17,6 +17,7 @@ namespace COMM RetryManget, RetryLift, RetryMove, + RetryMoveset, RetryMarkStop, } public enum eVarUInt32