From 07ddc0425fe50bda89a0dd1f3a1d0dbeb23ea2f4 Mon Sep 17 00:00:00 2001 From: backuppc Date: Fri, 12 Dec 2025 14:29:06 +0900 Subject: [PATCH] =?UTF-8?q?=EC=97=90=EB=AE=AC=EB=A0=88=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=20=EA=B0=9C=EB=B0=9C=20=EC=A0=84.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AGVNavigationCore.csproj | 3 +- .../Controls/UnifiedAGVCanvas.cs | 1 + .../AGVNavigationCore/Models/AGVCommand.cs | 54 ++ .../AGVNavigationCore/Models/Enums.cs | 70 ++- .../AGVNavigationCore/Models/IMovableAGV.cs | 2 +- .../AGVNavigationCore/Models/VirtualAGV.cs | 188 +++---- .../AGVSimulator/Forms/SimulatorForm.cs | 4 +- Cs_HMI/Project/AGV4.csproj | 15 +- Cs_HMI/Project/CSetting.cs | 26 +- Cs_HMI/Project/Class/CResult.cs | 5 +- Cs_HMI/Project/PUB.cs | 48 +- Cs_HMI/Project/StateMachine/Step/_SM_RUN.cs | 394 +------------- .../StateMachine/Step/_SM_RUN_BUFFER_IN.cs | 4 +- .../StateMachine/Step/_SM_RUN_BUFFER_OUT.cs | 2 +- .../StateMachine/Step/_SM_RUN_CHGOFF.cs | 15 +- .../StateMachine/Step/_SM_RUN_GOCHARGE.cs | 19 +- .../StateMachine/Step/_SM_RUN_GOHOME.cs | 35 +- .../StateMachine/Step/_SM_RUN_POSCHK.cs | 55 +- .../StateMachine/Step/_SM_RUN_RESET.cs | 5 - .../Project/StateMachine/Step/_SM_RUN_SYNC.cs | 6 +- Cs_HMI/Project/StateMachine/Step/_Util.cs | 228 ++++++++ Cs_HMI/Project/StateMachine/_AGV.cs | 151 +++--- Cs_HMI/Project/StateMachine/_Loop.cs | 13 +- Cs_HMI/Project/StateMachine/_TMDisplay.cs | 3 +- Cs_HMI/Project/StateMachine/_Xbee.cs | 2 +- Cs_HMI/Project/ViewForm/fManual.cs | 4 +- Cs_HMI/Project/fMain.Designer.cs | 486 +++++------------- Cs_HMI/Project/fMain.cs | 122 +---- Cs_HMI/Project/fSetup.Designer.cs | 59 +-- Cs_HMI/Project/fSetup.cs | 10 +- Cs_HMI/{CLAUDE.md => README.md} | 74 ++- Cs_HMI/StateMachine/EnumStruct.cs | 7 +- Cs_HMI/SubProject/AGV/EnumData.cs | 6 +- Cs_HMI/SubProject/CommData/Enum.cs | 15 +- Cs_HMI/docs/GOHOME_Analysis.md | 63 +++ 35 files changed, 952 insertions(+), 1242 deletions(-) create mode 100644 Cs_HMI/AGVLogic/AGVNavigationCore/Models/AGVCommand.cs create mode 100644 Cs_HMI/Project/StateMachine/Step/_Util.cs rename Cs_HMI/{CLAUDE.md => README.md} (78%) create mode 100644 Cs_HMI/docs/GOHOME_Analysis.md diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/AGVNavigationCore.csproj b/Cs_HMI/AGVLogic/AGVNavigationCore/AGVNavigationCore.csproj index 38dd5f6..5b614e9 100644 --- a/Cs_HMI/AGVLogic/AGVNavigationCore/AGVNavigationCore.csproj +++ b/Cs_HMI/AGVLogic/AGVNavigationCore/AGVNavigationCore.csproj @@ -1,4 +1,4 @@ - + @@ -73,6 +73,7 @@ UnifiedAGVCanvas.cs UserControl + diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.cs index adf7d1e..ffcd7d4 100644 --- a/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.cs +++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.cs @@ -163,6 +163,7 @@ namespace AGVNavigationCore.Controls #region Properties + public string PredictMessage { get; set; } = ""; public string MapFileName { get; set; } = ""; /// diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Models/AGVCommand.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Models/AGVCommand.cs new file mode 100644 index 0000000..169a76c --- /dev/null +++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Models/AGVCommand.cs @@ -0,0 +1,54 @@ +namespace AGVNavigationCore.Models +{ + /// + /// AGV 제어 명령 클래스 (실제 AGV 제어용) + /// Predict() 메서드가 반환하는 다음 동작 명령 + /// + public class AGVCommand + { + /// 모터 명령 (정지/전진/후진) + public MotorCommand Motor { get; set; } + + /// 마그넷 위치 (직진/왼쪽/오른쪽) + public MagnetPosition Magnet { get; set; } + + /// 속도 레벨 (저속/중속/고속) + public SpeedLevel Speed { get; set; } + + /// 명령 이유 메세지- (디버깅/로깅용) + public string Message { get; set; } + + /// 명령 이유- (디버깅/로깅용) + public eAGVCommandReason Reason { get; set; } + + /// + /// 생성자 + /// + public AGVCommand(MotorCommand motor, MagnetPosition magnet, SpeedLevel speed, eAGVCommandReason reason, string reasonmessage = "") + { + Motor = motor; + Magnet = magnet; + Speed = speed; + Reason = reason; + Message = reasonmessage; + } + + /// + /// 기본 생성자 + /// + public AGVCommand() + { + Motor = MotorCommand.Stop; + Magnet = MagnetPosition.S; + Speed = SpeedLevel.L; + Message = ""; + Reason = eAGVCommandReason.Normal; + } + + public override string ToString() + { + return $"Motor:{Motor}, Magnet:{Magnet}, Speed:{Speed},Reason:{Reason}" + + (string.IsNullOrEmpty(Message) ? "" : $" ({Message})"); + } + } +} \ No newline at end of file diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Models/Enums.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Models/Enums.cs index 457de0c..e2bf108 100644 --- a/Cs_HMI/AGVLogic/AGVNavigationCore/Models/Enums.cs +++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Models/Enums.cs @@ -2,7 +2,7 @@ using System; namespace AGVNavigationCore.Models { - + /// /// 노드 타입 열거형 @@ -141,50 +141,42 @@ namespace AGVNavigationCore.Models H } - /// - /// AGV 제어 명령 클래스 (실제 AGV 제어용) - /// Predict() 메서드가 반환하는 다음 동작 명령 - /// - public class AGVCommand - { - /// 모터 명령 (정지/전진/후진) - public MotorCommand Motor { get; set; } - - /// 마그넷 위치 (직진/왼쪽/오른쪽) - public MagnetPosition Magnet { get; set; } - - /// 속도 레벨 (저속/중속/고속) - public SpeedLevel Speed { get; set; } - - /// 명령 이유 (디버깅/로깅용) - public string Reason { get; set; } + public enum eAGVCommandReason + { + /// + /// 초기 미지정 + /// + Normal, /// - /// 생성자 + /// 위치 미확정 /// - public AGVCommand(MotorCommand motor, MagnetPosition magnet, SpeedLevel speed, string reason = "") - { - Motor = motor; - Magnet = magnet; - Speed = speed; - Reason = reason; - } + UnknownPosition, /// - /// 기본 생성자 + /// 대상경로없음 /// - public AGVCommand() - { - Motor = MotorCommand.Stop; - Magnet = MagnetPosition.S; - Speed = SpeedLevel.L; - Reason = ""; - } + NoTarget, + + /// + /// 경로없음 + /// + NoPath, + + /// + /// 경로이탈 + /// + PathOut, + + /// + /// 마크스탑을 해야한다 + /// + MarkStop, + + /// + /// 완료 + /// + Complete, - public override string ToString() - { - return $"Motor:{Motor}, Magnet:{Magnet}, Speed:{Speed}" + - (string.IsNullOrEmpty(Reason) ? "" : $" ({Reason})"); - } } } \ No newline at end of file diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Models/IMovableAGV.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Models/IMovableAGV.cs index 32360bf..98b4a14 100644 --- a/Cs_HMI/AGVLogic/AGVNavigationCore/Models/IMovableAGV.cs +++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Models/IMovableAGV.cs @@ -140,7 +140,7 @@ namespace AGVNavigationCore.Models /// /// 현재 노드 ID 조회 /// - string GetCurrentNodeId(); + MapNode GetCurrentNode(); /// /// AGV 상태 정보 문자열 조회 diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Models/VirtualAGV.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Models/VirtualAGV.cs index 998fd64..5ae5442 100644 --- a/Cs_HMI/AGVLogic/AGVNavigationCore/Models/VirtualAGV.cs +++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Models/VirtualAGV.cs @@ -43,7 +43,7 @@ namespace AGVNavigationCore.Models /// public event EventHandler ErrorOccurred; - + #endregion @@ -217,6 +217,8 @@ namespace AGVNavigationCore.Models _currentPosition = position; } + + /// /// 감지된 RFID 설정 (실제 RFID 센서에서) /// @@ -259,6 +261,19 @@ namespace AGVNavigationCore.Models } } + /// + /// 현재 노드id의 개체를 IsPass 로 설정합니다 + /// + public bool SetCurrentNodeMarkStop() + { + if (_currentNode == null) return false; + var 미완료된처음노드 = _currentPath.DetailedPath.Where(t => t.IsPass == false).OrderBy(t => t.seq).FirstOrDefault(); + if (미완료된처음노드 == null) return false; + 미완료된처음노드.IsPass = true; + Console.WriteLine($"미완료된처음노드를 true러치합니다"); + return true; + } + /// /// 다음 동작 예측 (실제 AGV 제어용) /// AGV가 지속적으로 호출하여 현재 상태와 예측 상태를 일치시킴 @@ -273,7 +288,8 @@ namespace AGVNavigationCore.Models return new AGVCommand( MotorCommand.Forward, MagnetPosition.S, // 직진 - SpeedLevel.L, // 저속 + SpeedLevel.L, // 저속 + eAGVCommandReason.UnknownPosition, $"위치 미확정 (RFID {_detectedRfids.Count}/2) - 전진하여 RFID 탐색" ); } @@ -285,6 +301,7 @@ namespace AGVNavigationCore.Models MotorCommand.Stop, MagnetPosition.S, SpeedLevel.L, + eAGVCommandReason.NoPath, $"위치 확정 완료 (목적지 미설정) - 현재:{_currentNode?.NodeId ?? "알수없음"}" ); } @@ -293,12 +310,32 @@ namespace AGVNavigationCore.Models var lastNode = _currentPath.DetailedPath.Last(); if (_currentPath.DetailedPath.Where(t => t.seq < lastNode.seq && t.IsPass == false).Any() == false) { - return new AGVCommand( - MotorCommand.Stop, - MagnetPosition.S, - SpeedLevel.L, - $"목적지 도착 - 최종:{_currentNode?.NodeId ?? "알수없음"}" - ); + // 마지막 노드에 도착했는지 확인 (현재 노드가 마지막 노드와 같은지) + if (_currentNode != null && _currentNode.NodeId == lastNode.NodeId) + { + if (lastNode.IsPass) //이미완료되었다. + { + return new AGVCommand( + MotorCommand.Stop, + MagnetPosition.S, + SpeedLevel.L, + eAGVCommandReason.Complete, + $"목적지 도착 - 최종:{_currentNode?.NodeId ?? "알수없음"}" + ); + } + else + { + //마지막노드는 일혔지만 완료되지 않았다. 마크스탑필요 + return new AGVCommand( + MotorCommand.Stop, + MagnetPosition.S, + SpeedLevel.L, + eAGVCommandReason.MarkStop, + $"목적지 도착 전(MarkStop) - 최종:{_currentNode?.NodeId ?? "알수없음"}" + ); + } + + } } // 4. 경로이탈 @@ -309,120 +346,14 @@ namespace AGVNavigationCore.Models MotorCommand.Stop, MagnetPosition.S, SpeedLevel.L, + eAGVCommandReason.PathOut, $"(재탐색요청)경로이탈 현재위치:{_currentNode.NodeId}" ); } - // 5. 방향체크 - //if(CurrentDirection != TargetNode.MotorDirection) - //{ - // return new AGVCommand( - // MotorCommand.Stop, - // MagnetPosition.S, - // SpeedLevel.L, - // $"(재탐색요청)모터방향 불일치 현재위치:{_currentNode.NodeId}" - // ); - //} - - - //this.CurrentNodeId - return GetCommandFromPath(CurrentNodeId, "경로 실행 시작"); - // 4. 위치 확정 + 경로 실행 중 → 현재 상태에 따른 명령 예측 - switch (_currentState) - { - case AGVState.Idle: - // 🔥 경로가 있다면 이동 시작 (경로 실행 대기 중) - if (_currentPath != null && _remainingNodes != null && _remainingNodes.Count > 0) - { - // DetailedPath에서 다음 노드 정보 가져오기 - return GetCommandFromPath(_remainingNodes[0], "경로 실행 시작"); - } - // 경로가 없으면 대기 - return new AGVCommand( - MotorCommand.Stop, - MagnetPosition.S, - SpeedLevel.L, - "대기 중 (경로 없음)" - ); - - case AGVState.Moving: - { - // 이동 중 - DetailedPath에서 현재/다음 노드 정보 가져오기 - if (_currentPath != null && _remainingNodes != null && _remainingNodes.Count > 0) - { - return GetCommandFromPath(_remainingNodes[0], "이동 중"); - } - - // 경로 정보가 없으면 기본 명령 (fallback) - var motorCmd = _currentDirection == AgvDirection.Forward - ? MotorCommand.Forward - : MotorCommand.Backward; - - return new AGVCommand( - motorCmd, - MagnetPosition.S, - SpeedLevel.M, - $"이동 중 (DetailedPath 없음)" - ); - } - - case AGVState.Rotating: - // 회전 중 - 정지 상태에서 마그넷만 조정 - MagnetPosition magnetPos = MagnetPosition.S; - if (_currentDirection == AgvDirection.Left) - magnetPos = MagnetPosition.L; - else if (_currentDirection == AgvDirection.Right) - magnetPos = MagnetPosition.R; - - return new AGVCommand( - MotorCommand.Stop, // 회전은 정지 상태에서 - magnetPos, - SpeedLevel.L, - $"회전 중 ({_currentDirection})" - ); - - case AGVState.Docking: - { - // 도킹 중 - 저속으로 전진 또는 후진 - var dockingMotor = _dockingDirection == DockingDirection.Forward - ? MotorCommand.Forward - : MotorCommand.Backward; - - return new AGVCommand( - dockingMotor, - MagnetPosition.S, - SpeedLevel.L, // 도킹은 항상 저속 - $"도킹 중 ({_dockingDirection})" - ); - } - - case AGVState.Charging: - return new AGVCommand( - MotorCommand.Stop, - MagnetPosition.S, - SpeedLevel.L, - "충전 중" - ); - - case AGVState.Error: - return new AGVCommand( - MotorCommand.Stop, - MagnetPosition.S, - SpeedLevel.L, - "오류 발생" - ); - - default: - return new AGVCommand( - MotorCommand.Stop, - MagnetPosition.S, - SpeedLevel.L, - "알 수 없는 상태" - ); - } } #endregion @@ -442,7 +373,7 @@ namespace AGVNavigationCore.Models /// /// 현재 노드 ID 조회 /// - public string GetCurrentNodeId() => _currentNode?.NodeId; + public MapNode GetCurrentNode() => _currentNode; /// /// AGV 정보 조회 @@ -682,6 +613,7 @@ namespace AGVNavigationCore.Models defaultMotor, MagnetPosition.S, SpeedLevel.M, + eAGVCommandReason.NoPath, $"{actionDescription} (DetailedPath 없음)" ); } @@ -701,6 +633,7 @@ namespace AGVNavigationCore.Models defaultMotor, MagnetPosition.S, SpeedLevel.M, + eAGVCommandReason.NoTarget, $"{actionDescription} (노드 {targetNodeId} 정보 없음)" ); } @@ -745,6 +678,7 @@ namespace AGVNavigationCore.Models motorCmd, magnetPos, speed, + eAGVCommandReason.Normal, $"{actionDescription} → {targetNodeId} (Motor:{motorCmd}, Magnet:{magnetPos})" ); } @@ -817,7 +751,27 @@ namespace AGVNavigationCore.Models } public MapNode StartNode { get; set; } = null; - public MapNode TargetNode { get; set; } = null; + + private MapNode _targetnode = null; + + /// + /// 목적지를 설정합니다. 목적지가 변경되면 경로계산정보가 삭제 됩니다. + /// + public MapNode TargetNode + { + get + { + return _targetnode; + } + set + { + if (_targetnode != value) + { + _currentPath = null; + _targetnode = value; + } + } + } private void ProcessNextNode() { diff --git a/Cs_HMI/AGVLogic/AGVSimulator/Forms/SimulatorForm.cs b/Cs_HMI/AGVLogic/AGVSimulator/Forms/SimulatorForm.cs index 05ea7f1..a318792 100644 --- a/Cs_HMI/AGVLogic/AGVSimulator/Forms/SimulatorForm.cs +++ b/Cs_HMI/AGVLogic/AGVSimulator/Forms/SimulatorForm.cs @@ -1803,7 +1803,7 @@ namespace AGVSimulator.Forms $"모터: {command.Motor}\n" + $"마그넷: {command.Magnet}\n" + $"속도: {command.Speed}\n" + - $"이유: {command.Reason}\n\n" + + $"이유: {command.Message}\n\n" + $"---\n" + $"현재 상태: {agv.CurrentState}\n" + $"현재 방향: {agv.CurrentDirection}\n" + @@ -1824,7 +1824,7 @@ namespace AGVSimulator.Forms // 첫 번째 AGV의 다음 행동 예측 var agv = _agvList[0]; var command = agv.Predict(); - this.lbPredict.Text = $"Motor:{command.Motor},Magnet:{command.Magnet},Speed:{command.Speed} : {command.Reason}"; + this.lbPredict.Text = $"Motor:{command.Motor},Magnet:{command.Magnet},Speed:{command.Speed} : {command.Message}"; } diff --git a/Cs_HMI/Project/AGV4.csproj b/Cs_HMI/Project/AGV4.csproj index a8464ec..8673859 100644 --- a/Cs_HMI/Project/AGV4.csproj +++ b/Cs_HMI/Project/AGV4.csproj @@ -284,6 +284,15 @@ + + Form + + + Form + + + Form + Form @@ -305,12 +314,6 @@ Form - - Form - - - Form - Form diff --git a/Cs_HMI/Project/CSetting.cs b/Cs_HMI/Project/CSetting.cs index 9b103c9..9bd47c3 100644 --- a/Cs_HMI/Project/CSetting.cs +++ b/Cs_HMI/Project/CSetting.cs @@ -254,20 +254,10 @@ namespace Project [Browsable(false)] public string musicfile { get; set; } - /// - /// FVI로 가능 방향이 Backward 인가? - /// Forward 방향이라면 false 를 한다 - /// - [Browsable(false)] - public Boolean AGV_Direction_FVI_Backward { get; set; } + [Browsable(false)] public Boolean Enable_Speak { get; set; } - //public Boolean Disable_BMS { get; set; } - //public Boolean Log_BMS_Tx { get; set; } - //public Boolean Log_BMS_Rx { get; set; } - //public double ChargeLimitLow { get; set; } - //public double ChargeLimitHigh { get; set; } [Browsable(false)] public string AGV_PANID { get; set; } @@ -338,7 +328,7 @@ namespace Project /// 스피커출력 간격 /// [DisplayName("Speak Term")] - public int doorSoundTerm { get; set; } + public int alarmSoundTerm { get; set; } [Browsable(false)] public int musicvol { get; set; } @@ -346,6 +336,16 @@ namespace Project public bool Enable_Music { get; set; } #endregion + #region "Node Mapping" + + [Category("Node Mapping"),DisplayName("Charger")] + public string NodeMAP_RFID_Charger { get; set; } + + [Category("Node Mapping"), DisplayName("Home")] + public string NodeMAP_RFID_Home { get; set; } + + #endregion + [Browsable(false)] public string LastMapFile { get; set; } @@ -429,7 +429,7 @@ namespace Project //충전은 10분간격으로 재시도 한다 if (ChargeRetryTerm == 0) ChargeRetryTerm = 600; - if (doorSoundTerm == 0) doorSoundTerm = 15; //기본 15초 + if (alarmSoundTerm == 0) alarmSoundTerm = 15; //기본 15초 if (ChargeSearchTime == 0) ChargeSearchTime = 25; //최대 충전진행 시간(기본 1시간) if (ChargeMaxTime == 0) ChargeMaxTime = 3600; diff --git a/Cs_HMI/Project/Class/CResult.cs b/Cs_HMI/Project/Class/CResult.cs index f26b037..0eb814d 100644 --- a/Cs_HMI/Project/Class/CResult.cs +++ b/Cs_HMI/Project/Class/CResult.cs @@ -67,8 +67,7 @@ namespace Project /// private ePosition _targetPos = ePosition.NONE; - public event EventHandler TargetPosSet; - + public string result_message = ""; public double result_progressmax = 0; public double result_progressvalue = 0; @@ -91,8 +90,6 @@ namespace Project set { _targetPos = value; - TargetPosSet?.Invoke(this, null); - PUB.log.Add(string.Format("대상위치설정:{0}", value)); } } diff --git a/Cs_HMI/Project/PUB.cs b/Cs_HMI/Project/PUB.cs index 7853486..48f61b6 100644 --- a/Cs_HMI/Project/PUB.cs +++ b/Cs_HMI/Project/PUB.cs @@ -94,7 +94,14 @@ namespace Project else return false; } - public static void Speak(string m, Boolean force = false, bool addlog = true) + /// + /// 스피커를 통한 음성을 출력합니다 + /// 출력되는 음성은 기본로그에도 자동 포함됩니다 + /// + /// + /// + /// 로그에도 출력 합니다 + public static void Speak(string m, Boolean force = false, bool addlog = true,string logcate="") { if (force == false && PUB.setting.Enable_Speak == false) { @@ -105,7 +112,11 @@ namespace Project voice.SpeakAsyncCancelAll(); if (voice.State == SynthesizerState.Ready) voice.SpeakAsync(m); - if (addlog) PUB.log.Add("SPEAK", m); + if (addlog) + { + if (logcate.isEmpty()) logcate = "SPEAK"; + PUB.log.Add(logcate, m); + } } /// @@ -150,7 +161,7 @@ namespace Project public static AR.Log log, logagv, logplc, logbms, logxbee; public static Boolean bPlayMusic = false; - + /// /// 사용자 인풋 감지 시간 @@ -382,6 +393,9 @@ namespace Project return Lang.AGV연결실패; case eECode.PLCCONN: return Lang.PLC통신실패; + case eECode.MESSAGE_ERROR: + if (values.Length > 0) return values[0].ToString(); + return "Message Error"; default: return err.ToString(); @@ -582,7 +596,33 @@ namespace Project } #region VirtualAGV 실제 데이터 동기화 - + public static MapNode FindByNodeID(string nodeidx) + { + if (_mapNodes == null || _mapNodes.Any() == false) return null; + if (nodeidx.isEmpty()) return null; + return _mapNodes.Where(t => t.NodeId.Equals(nodeidx)).FirstOrDefault(); + } + public static MapNode FindByRFID(string rfidValue) + { + if (_mapNodes == null || _mapNodes.Any() == false) return null; + if (rfidValue.isEmpty()) return null; + return _mapNodes.Where(t => t.RfidId.Equals(rfidValue)).FirstOrDefault(); + } + public static List FindByNodeAlias(string alias) + { + if (_mapNodes == null || _mapNodes.Any() == false) return null; + if (alias.isEmpty()) return null; + var lst = _mapNodes.Where(t => t.NodeAlias.Equals(alias)); + if (lst.Any() == false) return null; + return lst.ToList(); + } + public static List FindByNodeType(AGVNavigationCore.Models.MapNode type) + { + if (_mapNodes == null || _mapNodes.Any() == false) return null; + var lst = _mapNodes.Where(t => t.Type.Equals(type)); + if (lst.Any() == false) return null; + return lst.ToList(); + } /// /// RFID 읽기 시 해당 노드 위치로 AGV 업데이트 /// diff --git a/Cs_HMI/Project/StateMachine/Step/_SM_RUN.cs b/Cs_HMI/Project/StateMachine/Step/_SM_RUN.cs index f87616d..117a41f 100644 --- a/Cs_HMI/Project/StateMachine/Step/_SM_RUN.cs +++ b/Cs_HMI/Project/StateMachine/Step/_SM_RUN.cs @@ -84,7 +84,7 @@ namespace Project if (PUB.AGV.system1.stop_by_front_detect == true) { var tsSpeak = DateTime.Now - LastSpeakTime; - if (tsSpeak.TotalSeconds >= PUB.setting.doorSoundTerm) + if (tsSpeak.TotalSeconds >= PUB.setting.alarmSoundTerm) { PUB.Speak(Lang.전방에물체가감지되었습니다); LastSpeakTime = DateTime.Now; @@ -96,7 +96,7 @@ namespace Project if (PUB.AGV.error.runerror_by_no_magent_line == true) { var tsSpeak = DateTime.Now - LastSpeakTime; - if (tsSpeak.TotalSeconds >= PUB.setting.doorSoundTerm) + if (tsSpeak.TotalSeconds >= PUB.setting.alarmSoundTerm) { PUB.Speak(Lang.선로를이탈했습니다); LastSpeakTime = DateTime.Now; @@ -105,45 +105,18 @@ namespace Project } //현재위치를 모르는 상태라면 이동하여 현재 위치를 찾는다 - if (PUB._virtualAGV.CurrentNodeId.isEmpty())// .cur. . CurrentPos == ePosition.NONE) - { - //이동중이지 않거나 홈이동상태가 아니라면? - if (PUB.AGV.system1.agv_run == false || PUB.sm.RunStep != ERunStep.GOHOME) - { - //현재위치를 검색해야함 - PUB.sm.ClearRunStep(); - PUB.sm.SetNewRunStep(ERunStep.GOHOME); - PUB.AddEEDB($"READY상태에서 현재위치를 몰라 홈으로 이동 백업스텝:{PUB.sm.RunStep}"); - PUB.sm.BackupRunStep.Push(PUB.sm.RunStep); //현재 상태를 백업 - return; - } - VAR.STR[eVarString.ChargeCheckMsg] = "현재 위치 모름"; - } + if (_SM_RUN_POSCHK(isFirst, stepTime) == false) return; //나머지 상황체크 switch (PUB.sm.RunStep) { case ERunStep.GOHOME: - if (runStepisFirst) + if (_SM_RUN_GOHOME(runStepisFirst, PUB.sm.GetRunSteptime) == true) { - PUB.Speak(Lang.FindCurrentPisition); - } - else if (_SM_RUN_GOHOME(runStepisFirst, PUB.sm.GetRunSteptime)) - { - //230601 - PUB.Speak(Lang.홈이동완료대기상태로전환합니다); - VAR.TIME.Update(eVarTime.ChargeTry); - - ERunStep NextStep = ERunStep.READY; - if (PUB.sm.BackupRunStep.Count > 0) - NextStep = PUB.sm.BackupRunStep.Pop(); - - PUB.log.Add($"현재위치 검색완료로 {NextStep} 으로 RUNSTEP값을 변경 합니다"); - PUB.sm.SetNewRunStep(NextStep); //대기상태로 전환한다 - return; + PUB.log.Add($"홈 이동이 완료되어 준비상태로 전환합니다"); + PUB.sm.SetNewRunStep(ERunStep.READY); } break; - case ERunStep.GOTO: //목적지까지 이동하는 경우 if (_SM_RUN_GOTO(runStepisFirst, PUB.sm.GetRunSteptime) == true) { @@ -152,27 +125,27 @@ namespace Project PUB.log.Add($"목적지({target.RfidId}) 도착완료 타입:{target.Type}, 출발지:{PUB._virtualAGV.StartNode.RfidId}"); if (target.Type == AGVNavigationCore.Models.NodeType.Buffer) { - + //현재위치가 마지막경로의 NODEID와 일치해야한다 var lastPath = PUB._virtualAGV.CurrentPath.DetailedPath.LastOrDefault(); - if(lastPath.NodeId.Equals(PUB._virtualAGV.CurrentNodeId)) + if (lastPath.NodeId.Equals(PUB._virtualAGV.CurrentNodeId)) { //버퍼진입전 노드에 도착완료했따 PUB.XBE.BufferInReady = true; - PUB.XBE.BufferReadyError = false; + PUB.XBE.BufferReadyError = false; } else { //마지막위치가 아닌 다른 위치에 있으니 버퍼 작업을 할 수없다 PUB.log.AddAT("목적지 버퍼이동완료 했지만 마지막 노드가 아닙니다"); PUB.XBE.BufferInReady = false; - PUB.XBE.BufferReadyError = true; + PUB.XBE.BufferReadyError = true; } PUB.XBE.BufferInComplete = false; PUB.XBE.BufferOutComplete = false; } - - else if(target.Type == AGVNavigationCore.Models.NodeType.Charging) + + else if (target.Type == AGVNavigationCore.Models.NodeType.Charging) { } @@ -191,7 +164,7 @@ namespace Project else { //목적지다 다른 형태이다 - + } PUB._virtualAGV.Turn = AGVNavigationCore.Models.AGVTurn.None; PUB.sm.SetNewRunStep(ERunStep.READY); @@ -271,8 +244,8 @@ namespace Project PUB.Result.TargetPos = ePosition.QC; } PUB.Result.CurrentPosCW = "1"; - PUB.sm.SetNewRunStep(ERunStep.GOHOME); - PUB.log.AddAT("충전 해제로 홈으로 이동"); + PUB.sm.SetNewRunStep(ERunStep.READY); + PUB.log.AddAT("충전 해제로 대기상태로 전환 합니다"); } } break; @@ -313,342 +286,5 @@ namespace Project } - bool CheckStopCondition() - { - return true; - } - - - void CheckAGVMoveTo(eGoDir dir) - { - //계속내려간다 - if (dir == eGoDir.Down) - { - var tsCmd = DateTime.Now - LastCommandTime; - if (tsCmd.TotalMilliseconds >= 1999) - { - //현재 동작중인상태에서 방향이 맞지 않다면 일단 움직임을 멈춘다 - if (PUB.AGV.system1.agv_run) - { - if (PUB.AGV.data.Direction == 'B') - { - PUB.log.Add($"방향이 맞지 않아 정지 합니다({dir})"); - PUB.AGV.AGVMoveStop("CheckAGVMoveTo"); - } - else if (PUB.AGV.data.Speed == 'S') - { - PUB.log.Add($"마크정지를 해제하기 위해 장비를 멈춥니다"); - } - } - else - { - //움직이지 않으므로 전진하도록 한다 - PUB.log.Add($"AGV 기동 방향(DOWN):{dir}"); - PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward); - } - LastCommandTime = DateTime.Now; - } - } - else - { - var tsCmd = DateTime.Now - LastCommandTime; - if (tsCmd.TotalMilliseconds >= 1999) - { - if (PUB.AGV.system1.agv_run) - { - if (PUB.AGV.data.Direction == 'F') - { - PUB.log.Add($"방향이 맞지 않아 정지 합니다({dir})"); - PUB.AGV.AGVMoveStop("CheckAGVMoveTo"); - } - else if (PUB.AGV.data.Speed == 'S') - { - PUB.log.Add($"마크정지를 해제하기 위해 장비를 멈춥니다"); - } - } - else - { - PUB.log.Add($"AGV 기동 방향(UP):{dir}"); - PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward); - } - LastCommandTime = DateTime.Now; - } - } - } - - void CheckAGVStopbyMARK(string sender) - { - //계속내려간다 - var tsCmd = DateTime.Now - LastCommandTime; - if (VAR.BOOL[eVarBool.NEXTSTOP_MARK] == false || tsCmd.TotalMilliseconds >= 1500) - { - PUB.AGV.AGVMoveStop("CheckAGVStopbyMARK", arDev.Narumi.eStopOpt.MarkStop); - LastCommandTime = DateTime.Now; - PUB.log.Add($"[{sender}] MARK신호에 멈춤 설정"); - } - } - - Boolean UpdateMotionPositionForMark(string sender) - { - //이머전시상태에서는 처리하지 않는다. - if (VAR.BOOL[eVarBool.EMERGENCY]) return false; - - //DOWN 작업 - // if (goDIR == eGoDir.Down) - { - //1. 현재위치 > 대상위치 - if (PUB.Result.CurrentPos > PUB.Result.TargetPos) - { - //계속내려간다 - if (PUB.setting.AGV_Direction_FVI_Backward) - CheckAGVMoveTo(eGoDir.Down); - else - CheckAGVMoveTo(eGoDir.Up); - } - //2. 현재위치 < 대상위치 - else if (PUB.Result.CurrentPos < PUB.Result.TargetPos) - { - //올라가야한다 - if (PUB.setting.AGV_Direction_FVI_Backward) - CheckAGVMoveTo(eGoDir.Up); - else - CheckAGVMoveTo(eGoDir.Down); - } - //3. 현재위치 = 대상위치 - else - { - //현재위치가 확정되었는가? - var actpos = ctlPos1.GetPositionActive(PUB.Result.CurrentPos); - if (actpos == false && PUB.AGV.system1.agv_stop == true) - { - //위치확정이되지 않았다면 AGV멈춤시에 기동하게 한다. - var lastcom = DateTime.Now - LastCommandTime; - if (lastcom.TotalSeconds > 3) - { - if (PUB.Result.CurrentPosCW == "1") - { - if (PUB.setting.AGV_Direction_FVI_Backward) - PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward); - else - PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward); - } - - else - { - if (PUB.setting.AGV_Direction_FVI_Backward) - PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward); - else - PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward); - } - - - LastCommandTime = DateTime.Now; - PUB.logagv.Add($"AGV가 멈춰있다 동작을 재개 합니다"); - } - } - else - { - //마크센서가 들어와잇고, 위치가 act 되어있다면 해당 위치에 있는 것이다 - if (PUB.AGV.error.Emergency == false && - PUB.AGV.system1.agv_stop && - PUB.AGV.signal.mark_sensor && actpos && - PUB.Result.CurrentPos == PUB.Result.TargetPos) - { - //PUB.AGV.AGVMoveStop(); - return true; - } - - if (PUB.AGV.system1.agv_stop == true && PUB.AGV.system1.agv_run == false) - { - PUB.log.Add($"멈춰있으므로 이동을 시작 합니다"); - if (PUB.Result.CurrentPosCW == "1") - { - if (PUB.setting.AGV_Direction_FVI_Backward) - PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward); - else - PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward); - } - else - { - if (PUB.setting.AGV_Direction_FVI_Backward) - PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward); - else - PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward); - } - - } - - //AGV는 아래로 FVI방향으로 내려가고 있다 - if (VAR.BOOL[eVarBool.AGVDIR_UP] == false) - { - if (PUB.Result.CurrentPosCW == "0") - { - //장비가 마크센서에의해 멈췃다면 완료이다 - if (PUB.AGV.error.Emergency == false && PUB.AGV.signal.mark_sensor) - { - PUB.AGV.AGVMoveStop("UPdateMotionPositionForMark"); - return true; - } - else CheckAGVStopbyMARK(sender); - } - else if (PUB.Result.CurrentPosCW == "1") - { - //내려가는 작업이고 AGV는 올라가고 있는데 RFID는 위졲이 감지되었다면 아래로 내려가야한다 - CheckAGVMoveTo(eGoDir.Up); - } - else - { - PUB.Result.CurrentPosCW = "1"; - CheckAGVMoveTo(eGoDir.Up); - } - } - //AGV는 Qc방향으로 올라가고 있다 - else - { - if (PUB.Result.CurrentPosCW == "1") - { - //네려가는 방향에서 내려가는 위치가 인식되었다면 마크에서 멈춰야 한다 - if (PUB.AGV.error.Emergency == false && PUB.AGV.signal.mark_sensor) - { - PUB.AGV.AGVMoveStop("UPdateMotionPositionForMark"); - return true; - } - else CheckAGVStopbyMARK(sender); - } - else if (PUB.Result.CurrentPosCW == "0") - { - //내려가는 작업이고 AGV는 올라가고 있는데 RFID는 위졲이 감지되었다면 아래로 내려가야한다 - CheckAGVMoveTo(eGoDir.Down); - } - else - { - PUB.Result.CurrentPosCW = "0"; - CheckAGVMoveTo(eGoDir.Down); - } - } - } - - - } - } - //UP 작업 - //else - //{ - // //1. 현재위치 > 대상위치 - // if (PUB.Result.CurrentPos > PUB.Result.TargetPos) - // { - // //계속내려간다 - // CheckAGVMoveTo(eGoDir.Down); - // } - // //2. 현재위치 < 대상위치 - // else if (PUB.Result.CurrentPos < PUB.Result.TargetPos) - // { - // //올라가야한다 - // CheckAGVMoveTo(eGoDir.Up); - // } - // //3. 현재위치 = 대상위치 - // else - // { - // //AGV는 위로가고 있다 - // if (VAR.BOOL[eVarBool.AGVDIR_UP] == true) - // { - // if (PUB.Result.CurrentPosCW == "0") - // { - // //장비가 마크센서에의해 멈췃다면 완료이다 - // if (PUB.AGV.system1.agv_stop && PUB.AGV.system1.stop_by_front_detect == false && PUB.AGV.error.Emergency == false && PUB.AGV.signal.mark_sensor) - // { - // return true; - // } - // else CheckAGVStopbyMARK(); - // } - // else if (PUB.Result.CurrentPosCW == "1") - // { - // //내려가는 작업이고 AGV는 올라가고 있는데 RFID는 위졲이 감지되었다면 아래로 내려가야한다 - // CheckAGVMoveTo(eGoDir.Down); - // } - // } - // //AGV는 내려가고 있다 - // else if (VAR.BOOL[eVarBool.AGVDIR_UP] == false) - // { - // if (PUB.Result.CurrentPosCW == "1") - // { - // //네려가는 방향에서 내려가는 위치가 인식되었다면 마크에서 멈춰야 한다 - // if (PUB.AGV.system1.agv_stop && PUB.AGV.system1.stop_by_front_detect == false && PUB.AGV.error.Emergency == false && PUB.AGV.signal.mark_sensor) - // { - // return true; - // } - // else CheckAGVStopbyMARK(); - // } - // else if (PUB.Result.CurrentPosCW == "0") - // { - // //내려가는 작업이고 AGV는 올라가고 있는데 RFID는 위졲이 감지되었다면 아래로 내려가야한다 - // CheckAGVMoveTo(eGoDir.Up); - // } - // } - // } - //} - - - - - - - return false; - } - Boolean UpdateMotionPositionForCharger(string sender) - { - if (VAR.BOOL[eVarBool.AGVDIR_UP] == false)// PUB.flag.get(EFlag.FLAG_DIR_BW) == true) - { - //충전기 검색은 항상 뒤로 검색한다 - var tsCmd = DateTime.Now - tm_gocharge_command; - if (tsCmd.TotalMilliseconds >= 1999 && - PUB.AGV.error.Emergency == false && - PUB.AGV.system1.agv_run == false) - { - //PUB.PLC.Move(Device.PLC.Rundirection.Backward, "UpdateMotionPosition(" + sender + ")"); - PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward);// - tm_gocharge_command = DateTime.Now; - } - } - else - { - //CCW (역방향 ) - //if (Pub.Result.RFIDPos < ePosition.CHARGE || Pub.Result.RFIDPos > ePosition.QC) - //{ - // //정상적이라면 RFID값은 QC + 혹은 QC - 에 있어야 하므로 항상 차저보다 높이 있다 - // //그렇지 않다면 초기화해서 QC검색부터 다시 실행하게 한다 - // //여기는 비정상 위치 값이다. - // Pub.sm.SetStepSeq(1); - //} - //else - //{ - //현재위치가 충전위치이고, 움직이지 않았다면 완료된 경우라 할수 있따 - if (PUB.Result.CurrentPos == ePosition.CHARGE && - PUB.AGV.signal.mark_sensor == true) - { - PUB.log.AddI("충전위치 검색 완료"); - return true; - } - else - { - //이동중이지 않다면 항상 이동을 해줘야한다 - var tsCmd = DateTime.Now - LastCommandTime; - if (tsCmd.TotalMilliseconds >= 1999 && - PUB.AGV.error.Emergency == false && - PUB.AGV.system1.agv_run == false) - { - //PUB.PLC.Move(Device.PLC.Rundirection.Backward, "UpdateMotionPosition #1(" + sender + ")"); - PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward);// - LastCommandTime = DateTime.Now; - } - } - //} - } - - return false; - } - - - }//cvass } diff --git a/Cs_HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_IN.cs b/Cs_HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_IN.cs index 5d3f44b..1628658 100644 --- a/Cs_HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_IN.cs +++ b/Cs_HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_IN.cs @@ -45,7 +45,7 @@ namespace Project if (PUB.AGV.system1.stop_by_front_detect == true) { var tsSpeak = DateTime.Now - LastSpeakTime; - if (tsSpeak.TotalSeconds >= PUB.setting.doorSoundTerm) + if (tsSpeak.TotalSeconds >= PUB.setting.alarmSoundTerm) { PUB.Speak(Lang.전방에물체가감지되었습니다); LastSpeakTime = DateTime.Now; @@ -214,7 +214,7 @@ namespace Project else if (PUB.sm.RunStepSeq == idx++) { //마크스탑신호가 3초이내로 들어와야 한다 - if (PUB.AGV.signal.mark_sensor == false) + if (VAR.BOOL[eVarBool.NEXTSTOP_MARK] == false) { var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime); if (ts.TotalSeconds > 3) diff --git a/Cs_HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_OUT.cs b/Cs_HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_OUT.cs index 3ff6561..3c5991d 100644 --- a/Cs_HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_OUT.cs +++ b/Cs_HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_OUT.cs @@ -34,7 +34,7 @@ namespace Project if (PUB.AGV.system1.stop_by_front_detect == true) { var tsSpeak = DateTime.Now - LastSpeakTime; - if (tsSpeak.TotalSeconds >= PUB.setting.doorSoundTerm) + if (tsSpeak.TotalSeconds >= PUB.setting.alarmSoundTerm) { PUB.Speak(Lang.전방에물체가감지되었습니다); LastSpeakTime = DateTime.Now; diff --git a/Cs_HMI/Project/StateMachine/Step/_SM_RUN_CHGOFF.cs b/Cs_HMI/Project/StateMachine/Step/_SM_RUN_CHGOFF.cs index 22030eb..575d16f 100644 --- a/Cs_HMI/Project/StateMachine/Step/_SM_RUN_CHGOFF.cs +++ b/Cs_HMI/Project/StateMachine/Step/_SM_RUN_CHGOFF.cs @@ -14,6 +14,8 @@ namespace Project public Boolean _SM_RUN_CHGOFF(bool isFirst, TimeSpan stepTime) { + + //충전중인지 확인한다. if (VAR.BOOL[eVarBool.FLAG_CHARGEONA] == true || PUB.AGV.system1.Battery_charging == true) { @@ -25,7 +27,7 @@ namespace Project PUB.Speak(Lang.충전을해제합니다); } } - + //AGV는 충전을 해제한 상태이다 if (PUB.AGV.system1.Battery_charging == false) { @@ -47,6 +49,17 @@ namespace Project PUB.AGV.AGVCharge(PUB.setting.ChargerID, false); VAR.TIME.Update(eVarTime.SendChargeOff); } + + + // 1분 타임아웃 체크 + if (stepTime.TotalMinutes >= 1) + { + PUB.XBE.errorMessage = $"충전해제가 실패되었습니다(1분)"; + PUB.log.AddE(PUB.XBE.errorMessage); + PUB.sm.SetNewStep(eSMStep.IDLE); + return false; + } + } return false; } diff --git a/Cs_HMI/Project/StateMachine/Step/_SM_RUN_GOCHARGE.cs b/Cs_HMI/Project/StateMachine/Step/_SM_RUN_GOCHARGE.cs index 0d21c1a..7d05d8f 100644 --- a/Cs_HMI/Project/StateMachine/Step/_SM_RUN_GOCHARGE.cs +++ b/Cs_HMI/Project/StateMachine/Step/_SM_RUN_GOCHARGE.cs @@ -38,7 +38,7 @@ namespace Project if (PUB.AGV.system1.stop_by_front_detect == true) { var tsSpeak = DateTime.Now - LastSpeakTime; - if (tsSpeak.TotalSeconds >= PUB.setting.doorSoundTerm) + if (tsSpeak.TotalSeconds >= PUB.setting.alarmSoundTerm) { PUB.Speak(Lang.전방에물체가감지되었습니다); LastSpeakTime = DateTime.Now; @@ -63,8 +63,16 @@ namespace Project var idx = 1; if (PUB.sm.RunStepSeq == idx++) { - PUB.Speak(Lang.충전을위해홈위치로이동합니다); - PUB.Result.TargetPos = ePosition.QC; + var targetnode = PUB.FindByRFID(PUB.setting.NodeMAP_RFID_Charger); + if(targetnode == null) + { + PUB.log.AddE($"충전기 노드가 설정되지 않았습니다"); + PUB.sm.SetNewRunStep(ERunStep.READY); + return false; + } + + //충전기로 대상을 설정한다 + PUB._virtualAGV.TargetNode = targetnode; VAR.TIME.Update(eVarTime.ChargeSearch); PUB.sm.UpdateRunStepSeq(); PUB.log.Add($"충전:대상위치 QC 시작"); @@ -73,7 +81,7 @@ namespace Project else if (PUB.sm.RunStepSeq == idx++) { //모션 전후진 제어 - if (UpdateMotionPositionForMark("GOCHARGE #1") == true) + if ( UpdateMotionPositionForCharger("GOCHARGE #1") == true) { PUB.log.Add($"충전:충전기 검색 전 QC위치 확인 완료"); PUB.sm.UpdateRunStepSeq(); @@ -200,9 +208,6 @@ namespace Project PUB.Result.CurrentPos = ePosition.CHARGE; //현재위치를 충전기로 한다 PUB.Result.TargetPos = ePosition.CHARGE; PUB.Result.CurrentPosCW = "1"; - ctlPos1.SetPosition(ePosition.CHARGE); - ctlPos1.SetPositionActive(ePosition.CHARGE); - ctlPos1.Invalidate(); PUB.sm.UpdateRunStepSeq(); return false; } diff --git a/Cs_HMI/Project/StateMachine/Step/_SM_RUN_GOHOME.cs b/Cs_HMI/Project/StateMachine/Step/_SM_RUN_GOHOME.cs index 56506b5..5a86d6c 100644 --- a/Cs_HMI/Project/StateMachine/Step/_SM_RUN_GOHOME.cs +++ b/Cs_HMI/Project/StateMachine/Step/_SM_RUN_GOHOME.cs @@ -13,27 +13,18 @@ namespace Project { public Boolean _SM_RUN_GOHOME(bool isFirst, TimeSpan stepTime) { + var funcName = "_SM_RUN_GOHOME"; if (runStepisFirst) { - // PUB.flag.set(EFlag.FLAG_NEXTSTOP_ALIGN, false); - - //VAR.BOOL[eVarBool.FLAG_NEXTSTOP_MARK] = false;//); VAR.BOOL[eVarBool.FLAG_NEXTSTOP_ALIGN] = false;//); } - //220629 - // if(PUB.flag.get(EFlag.FLAG_GO_CHAGER_TEMP)) - //{ - // PUB.flag.set(EFlag.FLAG_GO_CHAGER_TEMP, false); - //} - //HW 연결오류 if (PUB.AGV.IsOpen == false) { PUB.Result.SetResultMessage(eResult.Hardware, eECode.AGVCONN, eNextStep.ERROR); return false; } - //충전 상태가 OFF되어야 동작하게한다 if (_SM_RUN_CHGOFF(isFirst, stepTime) == false) @@ -43,7 +34,7 @@ namespace Project if (PUB.AGV.system1.stop_by_front_detect == true) { var tsSpeak = DateTime.Now - LastSpeakTime; - if (tsSpeak.TotalSeconds >= PUB.setting.doorSoundTerm) + if (tsSpeak.TotalSeconds >= PUB.setting.alarmSoundTerm) { PUB.Speak(Lang.전방에물체가감지되었습니다); LastSpeakTime = DateTime.Now; @@ -51,27 +42,29 @@ namespace Project return false; } - //현재 위치가 결정되어있는지 체크한다 - if (_SM_RUN_POSCHK(isFirst, stepTime) == false) - return false; - var idx = 1; if (PUB.sm.RunStepSeq == idx++) { PUB.Speak(Lang.홈으로이동합니다); - //홈은 무조건 QC위치로 간다 - PUB.AddEEDB($"홈검색시작({PUB.Result.TargetPos})"); - PUB.Result.TargetPos = ePosition.QC; + var homenode = PUB.FindByRFID(PUB.setting.NodeMAP_RFID_Home); + if (homenode == null) + { + PUB.log.Add($"홈위치의 노드맵핑(환경설정)이 없습니다"); + PUB.sm.SetNewRunStep(ERunStep.READY); + return false; + } + PUB._virtualAGV.TargetNode = homenode; + PUB.AddEEDB($"홈검색시작({homenode.RfidId})"); PUB.sm.UpdateRunStepSeq(); return false; } else if (PUB.sm.RunStepSeq == idx++) { //모션 전후진 제어 - if (UpdateMotionPositionForMark("GOHOME")) + if (UpdateMotionPositionForMark(funcName)) { - PUB.AGV.AGVMoveStop("SM_RUN_GOHOME"); + PUB.AGV.AGVMoveStop(funcName); PUB.sm.UpdateRunStepSeq(); } return false; @@ -79,7 +72,7 @@ namespace Project else if (PUB.sm.RunStepSeq == idx++) { //QC까지 모두 완료되었다.(완전히 정차할때까지 기다린다) - PUB.Speak(Lang.홈검색완료, true); + PUB.Speak(Lang.홈검색완료, true); PUB.AddEEDB($"홈검색완료({PUB.Result.TargetPos})"); PUB.sm.UpdateRunStepSeq(); return false; diff --git a/Cs_HMI/Project/StateMachine/Step/_SM_RUN_POSCHK.cs b/Cs_HMI/Project/StateMachine/Step/_SM_RUN_POSCHK.cs index f1b66e8..3fb4cd6 100644 --- a/Cs_HMI/Project/StateMachine/Step/_SM_RUN_POSCHK.cs +++ b/Cs_HMI/Project/StateMachine/Step/_SM_RUN_POSCHK.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; +using AR; +using COMM; namespace Project { @@ -10,45 +12,30 @@ namespace Project { public Boolean _SM_RUN_POSCHK(bool isFirst, TimeSpan stepTime) { - //현재 위치가 찾아지지 않았다면. 먼저 위치를 찾는다. 위로 이동시켜서 찾는다. - if (PUB.Result.CurrentPos == ePosition.NONE) + //현재위치가 설정되어있는지 확인한다, 현재위치값이 있는 경우 True 를 반환 + var currentnode = PUB.FindByNodeID(PUB._virtualAGV.CurrentNodeId); + if (currentnode != null) return true; + + //이동을 하지 않고있다면 전진을 진행한다 + if (PUB.AGV.system1.agv_run == false) { - if (isFirst) + var ts = VAR.TIME.RUN(eVarTime.LastRunCommandTime); + if (ts.TotalSeconds > 5) { - PUB.Speak( Lang.현재위치를검색합니다); - } - - if (PUB.AGV.system1.agv_run) - { - //방향을 체크한다 - var basedir = PUB.setting.AGV_Direction_FVI_Backward ? 'F' : 'B'; - if (PUB.AGV.data.Direction == basedir) + PUB.log.Add($"현재위치를 몰라 전진 이동 합니다"); + PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData { - var ts = DateTime.Now - LastCommandTime; - if (ts.TotalMilliseconds >= 1999) - { - PUB.AGV.AGVMoveStop("SM_RUN_POSCHK",arDev.Narumi.eStopOpt.Stop); - LastCommandTime = DateTime.Now; - } - } + Bunki = arDev.Narumi.eBunki.Strate, + Direction = arDev.Narumi.eMoveDir.Forward, + PBSSensor = 1, + Speed = arDev.Narumi.eMoveSpd.Low, + }); + PUB.AGV.AGVMoveRun(); + VAR.TIME.Update(eVarTime.LastRunCommandTime); } - else if (PUB.AGV.system1.agv_run == false) - { - //전진이동한다 - var ts = DateTime.Now - LastCommandTime; - if (ts.TotalMilliseconds >= 1999) - { - if (PUB.setting.AGV_Direction_FVI_Backward) - PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward);// - else - PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward);// - LastCommandTime = DateTime.Now; - } - } - - return false; } - else return true; + VAR.STR[eVarString.StatusMessage] = "현재 위치를 알 수 없습니다"; + return false; } } } diff --git a/Cs_HMI/Project/StateMachine/Step/_SM_RUN_RESET.cs b/Cs_HMI/Project/StateMachine/Step/_SM_RUN_RESET.cs index 3250203..d37d923 100644 --- a/Cs_HMI/Project/StateMachine/Step/_SM_RUN_RESET.cs +++ b/Cs_HMI/Project/StateMachine/Step/_SM_RUN_RESET.cs @@ -83,11 +83,6 @@ namespace Project PUB.Result.TargetPos = ePosition.NONE; PUB.Result.CurrentPos = ePosition.NONE; PUB.Result.CurrentPosCW = "0"; - ctlPos1.SetPositionDeActive(); - ctlPos1.SetPosition(ePosition.NONE); - ctlPos1.SetDirection("0"); - ctlPos1.Invalidate(); - PUB.sm.UpdateRunStepSeq(); return false; } diff --git a/Cs_HMI/Project/StateMachine/Step/_SM_RUN_SYNC.cs b/Cs_HMI/Project/StateMachine/Step/_SM_RUN_SYNC.cs index 9aca868..c42d5d3 100644 --- a/Cs_HMI/Project/StateMachine/Step/_SM_RUN_SYNC.cs +++ b/Cs_HMI/Project/StateMachine/Step/_SM_RUN_SYNC.cs @@ -80,7 +80,7 @@ namespace Project //synlist.Add("SBN", PUB.setting.ChargerID.ToString("0000")); synlist.Add("SGS", PUB.setting.GDSValue.ToString("0000")); - + VAR.I32[eVarInt32.SyncItemCount] = synlist.Count; PUB.AddEEDB($"SYNC시작({PUB.Result.TargetPos})"); @@ -101,7 +101,7 @@ namespace Project } else if (PUB.sm.RunStepSeq == idx++) { - //통신 확인되었으므로 스피드를 전송한다. + //통신 확인되었으므로 설정값들을 if (synidx < synlist.Count) { var item = synlist.ElementAt(synidx); @@ -111,7 +111,7 @@ namespace Project // 캔버스에 동기화 상태 표시 if (PUB._mapCanvas != null) { - float progress = (float)synidx / synlist.Count; + float progress = (float)synidx / VAR.I32[eVarInt32.SyncItemCount]; PUB._mapCanvas.SetSyncStatus("장비 설정 동기화 중...", progress, $"항목: {item.Key} ({synidx + 1}/{synlist.Count})"); } } diff --git a/Cs_HMI/Project/StateMachine/Step/_Util.cs b/Cs_HMI/Project/StateMachine/Step/_Util.cs new file mode 100644 index 0000000..8cf66d4 --- /dev/null +++ b/Cs_HMI/Project/StateMachine/Step/_Util.cs @@ -0,0 +1,228 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using Project.StateMachine; +using COMM; +using AR; + +namespace Project +{ + public partial class fMain + { + + bool CheckStopCondition() + { + return true; + } + + /// + /// 설정된 목적지까지 이동을 완료 한 후 True를 반환합니다. + /// 목적지 : PUB._virtualAGV.TargetNode + /// + /// + /// + /// + Boolean UpdateMotionPositionForMark(string sender) + { + //현재위치를 모르는 상태라면 이동하여 현재 위치를 찾는다 + if (_SM_RUN_POSCHK(false, new TimeSpan()) == false) return false; + + //현재위치노드 오류 + var currentNode = PUB.FindByNodeID(PUB._virtualAGV.CurrentNodeId); + if (currentNode == null) + { + PUB.log.AddE($"현재위치노드가 없습니다"); + PUB.sm.SetNewRunStep(ERunStep.READY); + return false; + } + + //시작노드값이 없다면 현재위치를 노드로 결정한다 + if (PUB._virtualAGV.StartNode == null) + PUB._virtualAGV.StartNode = PUB.FindByNodeID(PUB._virtualAGV.CurrentNodeId); + + //시작노드가없다면 오류 + if (PUB._virtualAGV.StartNode == null) + { + PUB.log.AddE($"경로시작노드가 없습니다"); + PUB.sm.SetNewRunStep(ERunStep.READY); + return false; + } + + //대상노드가 없다면 오류 + if (PUB._virtualAGV.TargetNode == null) + { + PUB.log.AddE($"경로종료노드가 없습니다"); + PUB.sm.SetNewRunStep(ERunStep.READY); + return false; + } + + //경로 생성(경로정보가 없거나 현재노드가 경로에 없는경우) + if (PUB._virtualAGV.CurrentPath == null || + PUB._virtualAGV.CurrentPath.DetailedPath.Any() == false || + PUB._virtualAGV.CurrentPath.DetailedPath.Where(t => t.NodeId.Equals(currentNode.NodeId)).Any() == false) + { + if (PUB.AGV.system1.agv_run) + { + PUB.log.Add($"경로 재생성으로 인해 구동을 멈춥니다"); + PUB.AGV.AGVMoveStop("경로재생성"); + } + + var PathResult = CalcPath(PUB._virtualAGV.StartNode, PUB._virtualAGV.TargetNode); + if (PathResult.result == null) + { + PUB.log.AddE($"경로가 계산되지 않았습니다"); + PUB.sm.SetNewRunStep(ERunStep.READY); + return false; + } + + PUB.log.AddI($"경로생성 {PUB._virtualAGV.StartNode.RfidId} -> {PUB._virtualAGV.TargetNode.RfidId}"); + } + + //predict 를 이용하여 다음 이동을 모두 확인한다. + var nextAction = PUB._virtualAGV.Predict(); + + var message = $"[다음 행동 예측]\n\n" + + $"모터: {nextAction.Motor}\n" + + $"마그넷: {nextAction.Magnet}\n" + + $"속도: {nextAction.Speed}\n" + + $"이유: {nextAction.Message}\n\n" + + $"---\n" + + $"현재 상태: {PUB._virtualAGV.CurrentState}\n" + + $"현재 방향: {PUB._virtualAGV.CurrentDirection}\n" + + $"위치 확정: {PUB._virtualAGV.IsPositionConfirmed} (RFID {PUB._virtualAGV.DetectedRfidCount}개)\n" + + $"현재 노드: {PUB._virtualAGV.CurrentNodeId ?? "없음"}"; + + //모터에서 정지를 요청했다 + if (nextAction.Motor == AGVNavigationCore.Models.MotorCommand.Stop) + { + if (PUB.AGV.system1.agv_run) + { + // 완료(Complete) 상태라면 MarkStop 전송 + if (nextAction.Reason == AGVNavigationCore.Models.eAGVCommandReason.MarkStop) + { + PUB.log.Add("다음행동예측에서 MARK STOP이 확인되었습니다"); + PUB.AGV.AGVMoveStop(nextAction.Message, arDev.Narumi.eStopOpt.MarkStop); + } + else + { + PUB.log.Add("다음행동예측에서 장비 멈춤이 확인되었습니다"); + PUB.AGV.AGVMoveStop(nextAction.Message); + } + } + + // 목적지 도착 여부 확인 + // 현재 노드가 타겟 노드와 같고, 위치가 확정된 상태라면 도착으로 간주 + // 단, AGV가 실제로 멈췄는지 확인 (agv_run == false) + if (PUB._virtualAGV.IsPositionConfirmed && + PUB._virtualAGV.CurrentNodeId == PUB._virtualAGV.TargetNode.NodeId) + { + if (PUB.AGV.system1.agv_run == false) + { + return true; + } + } + + return false; + } + else + { + // 이동 명령 변환 (AGVNavigationCore -> arDev.Narumi) + var bunki = arDev.Narumi.eBunki.Strate; + if (nextAction.Magnet == AGVNavigationCore.Models.MagnetPosition.L) bunki = arDev.Narumi.eBunki.Left; + else if (nextAction.Magnet == AGVNavigationCore.Models.MagnetPosition.R) bunki = arDev.Narumi.eBunki.Right; + + var dir = arDev.Narumi.eMoveDir.Forward; + if (nextAction.Motor == AGVNavigationCore.Models.MotorCommand.Backward) dir = arDev.Narumi.eMoveDir.Backward; + + var spd = arDev.Narumi.eMoveSpd.Low; + if (nextAction.Speed == AGVNavigationCore.Models.SpeedLevel.M) spd = arDev.Narumi.eMoveSpd.Mid; + else if (nextAction.Speed == AGVNavigationCore.Models.SpeedLevel.H) spd = arDev.Narumi.eMoveSpd.High; + + // 명령 설정 + // 현재 상태와 다를 때만 전송 (불필요한 통신 부하 방지) + if (PUB.AGV.data.Sts != bunki.ToString()[0] || + PUB.AGV.data.Direction != dir.ToString()[0] || + PUB.AGV.data.Speed != spd.ToString()[0]) + { + PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData + { + Bunki = bunki, + Direction = dir, + PBSSensor = 1, + Speed = spd, + }); + PUB.log.Add($"Predict Run Setting = bunki:{bunki},dir:{dir},pbs:1,spd:{spd}"); + } + + // AGV가 정지 상태라면 구동 시작 + if (PUB.AGV.system1.agv_run == false) + { + var runOpt = (dir == arDev.Narumi.eMoveDir.Forward) ? arDev.Narumi.eRunOpt.Forward : arDev.Narumi.eRunOpt.Backward; + PUB.AGV.AGVMoveRun(runOpt); + } + + return false; + } + + } + + /// + /// 충전기검색시퀀스 + /// + /// + /// + Boolean UpdateMotionPositionForCharger(string sender) + { + if (VAR.BOOL[eVarBool.AGVDIR_BACK] == false)// PUB.flag.get(EFlag.FLAG_DIR_BW) == true) + { + //충전기 검색은 항상 앞으로 검색한다 + var tsCmd = DateTime.Now - tm_gocharge_command; + if (tsCmd.TotalMilliseconds >= 1999 && + PUB.AGV.error.Emergency == false && + PUB.AGV.system1.agv_run == false) + { + PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData + { + Bunki = arDev.Narumi.eBunki.Strate, + Direction = arDev.Narumi.eMoveDir.Forward, + PBSSensor = 1, + Speed = arDev.Narumi.eMoveSpd.Low, + }); + PUB.AGV.AGVMoveRun();// + tm_gocharge_command = DateTime.Now; + } + } + else + { + //현재위치가 충전위치이고, 움직이지 않았다면 완료된 경우라 할수 있따 + if (PUB._virtualAGV.CurrentNodeId.Equals(PUB.setting.NodeMAP_RFID_Charger) && + VAR.BOOL[eVarBool.MARK_SENSOR] == true) + { + PUB.log.AddI("충전위치 검색 완료"); + return true; + } + else + { + //이동중이지 않다면 항상 이동을 해줘야한다 + var tsCmd = DateTime.Now - LastCommandTime; + if (tsCmd.TotalMilliseconds >= 1999 && + PUB.AGV.error.Emergency == false && + PUB.AGV.system1.agv_run == false) + { + //PUB.PLC.Move(Device.PLC.Rundirection.Backward, "UpdateMotionPosition #1(" + sender + ")"); + PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward);// + LastCommandTime = DateTime.Now; + } + } + //} + } + + return false; + } + + + + }//cvass +} diff --git a/Cs_HMI/Project/StateMachine/_AGV.cs b/Cs_HMI/Project/StateMachine/_AGV.cs index 526b332..df5491f 100644 --- a/Cs_HMI/Project/StateMachine/_AGV.cs +++ b/Cs_HMI/Project/StateMachine/_AGV.cs @@ -49,82 +49,48 @@ namespace Project case arDev.Narumi.DataType.STS: { //마크센서 확인 - var chg_mark1 = PUB.AGV.signal.GetChanged(arDev.Narumi.Signal.eflag.mark_sensor_1); - var chg_mark2 = PUB.AGV.signal.GetChanged(arDev.Narumi.Signal.eflag.mark_sensor_1); - var chg_run = PUB.AGV.system1.GetChanged(arDev.Narumi.SystemFlag1.eflag.agv_run); - var chg_stop = PUB.AGV.system1.GetChanged(arDev.Narumi.SystemFlag1.eflag.agv_stop); + var agv_err = PUB.AGV.error.Value; + var agv_emg = PUB.AGV.error.Emergency; + var agv_chg = PUB.AGV.system1.Battery_charging; + var agv_stp = PUB.AGV.system1.agv_stop; + var agv_run = PUB.AGV.system1.agv_run; + var agv_mrk = PUB.AGV.signal.mark_sensor; + + //if (chg_run && PUB.AGV.system1.agv_run) PUB.Speak("이동을 시작 합니다"); - VAR.BOOL[eVarBool.AGVDIR_UP] = PUB.AGV.data.Direction == 'B'; - VAR.BOOL[eVarBool.AGV_ERROR] = PUB.AGV.error.Value > 0; - VAR.BOOL[eVarBool.EMERGENCY] = PUB.AGV.error.Emergency; + VAR.BOOL[eVarBool.AGVDIR_BACK] = PUB.AGV.data.Direction == 'B'; - ////모터방향 입력 - //if (PUB.AGV.data.Direction == 'B') - // PUB.mapctl.Manager.agv.Current_Motor_Direction = AGVControl.AgvDir.Backward; - //else - // PUB.mapctl.Manager.agv.Current_Motor_Direction = AGVControl.AgvDir.Forward; - - ////현재 속도 - //if (PUB.AGV.data.Speed == 'H') - // PUB.mapctl.Manager.agv.CurrentSpeed = AGVControl.AgvSpeed.High; - //else if (PUB.AGV.data.Speed == 'M') - // PUB.mapctl.Manager.agv.CurrentSpeed = AGVControl.AgvSpeed.Middle; - //else if (PUB.AGV.data.Speed == 'L') - // PUB.mapctl.Manager.agv.CurrentSpeed = AGVControl.AgvSpeed.Low; - //else if (PUB.AGV.data.Speed == 'S') - // PUB.mapctl.Manager.agv.CurrentSpeed = AGVControl.AgvSpeed.MarkStop; - - ////이동방향 - //if (PUB.AGV.data.Sts == 'S') - // PUB.mapctl.Manager.agv.CurrentSTS = AGVControl.AgvSts.Straight; - //else if (PUB.AGV.data.Sts == 'L') - // PUB.mapctl.Manager.agv.CurrentSTS = AGVControl.AgvSts.Left; - //else if (PUB.AGV.data.Sts == 'R') - // PUB.mapctl.Manager.agv.CurrentSTS = AGVControl.AgvSts.Right; - - - //PUB.mapctl.Manager.agv.IsMoving = PUB.AGV.system1.agv_run; - //PUB.mapctl.Manager.agv.IsMarkCheck = PUB.AGV.system1.Mark1_check || PUB.AGV.system1.Mark2_check; - - if (PUB.AGV.signal.mark_sensor == false) + if (VAR.BOOL[eVarBool.AGV_ERROR] != (agv_err > 0)) { - if (VAR.BOOL[eVarBool.MARK_SENSOROFF] == false) - { - VAR.BOOL[eVarBool.MARK_SENSOROFF] = true; - VAR.TIME[eVarTime.MarkSensorOff] = DateTime.Now; - PUB.log.Add($"마크센서off를 설정"); - } + VAR.BOOL[eVarBool.AGV_ERROR] = (agv_err > 0); + PUB.logagv.Add($"new AGV_ERROR ({PUB.AGV.error.Value})"); } - else + if (VAR.BOOL[eVarBool.EMERGENCY] != agv_emg) { - if (VAR.BOOL[eVarBool.MARK_SENSOROFF] == true) - { - VAR.BOOL[eVarBool.MARK_SENSOROFF] = false; - VAR.TIME[eVarTime.MarkSensorOff] = DateTime.Now; - PUB.log.Add($"마크센서off를 해제"); - } + VAR.BOOL[eVarBool.EMERGENCY] = agv_emg; + PUB.logagv.Add($"new EMERGENCY ({VAR.BOOL[eVarBool.EMERGENCY]})"); } //차징상태변경 - if (_charging != PUB.AGV.system1.Battery_charging) + if (_charging != agv_chg) { - if (PUB.AGV.system1.Battery_charging) + if (agv_chg) { VAR.TIME[eVarTime.ChargeStart] = DateTime.Now; PUB.logagv.Add($"충전시작:{VAR.TIME[eVarTime.ChargeStart]}"); } - _charging = PUB.AGV.system1.Battery_charging; + _charging = agv_chg; } //배터리충전상태 - if (VAR.BOOL[eVarBool.FLAG_CHARGEONA] != PUB.AGV.system1.Battery_charging) + if (VAR.BOOL[eVarBool.FLAG_CHARGEONA] != agv_chg) { - PUB.log.Add($"충전상태전환 {PUB.AGV.system1.Battery_charging}"); - VAR.BOOL[eVarBool.FLAG_CHARGEONA] = PUB.AGV.system1.Battery_charging; + PUB.log.Add($"충전상태전환 {agv_chg}"); + VAR.BOOL[eVarBool.FLAG_CHARGEONA] = agv_chg; } //자동충전해제시 곧바로 수동 충전되는 경우가 있어 자동 상태를 BMS에 넣는다 230118 - PUB.BMS.AutoCharge = PUB.AGV.system1.Battery_charging; + PUB.BMS.AutoCharge = agv_chg; if (PUB.AGV.error.Charger_pos_error != VAR.BOOL[eVarBool.CHG_POSERR]) { @@ -135,41 +101,41 @@ namespace Project VAR.BOOL[eVarBool.CHG_POSERR] = PUB.AGV.error.Charger_pos_error; } - if (VAR.BOOL[eVarBool.MARK_SENSOROFF] == true && PUB.AGV.signal.mark_sensor == false) + //나르미가 멈췄다면 다음 마크 이동 기능이 OFF 된다 + if (agv_stp) { - //현재 활성화된 위치를 꺼준다 - if (this.ctlPos1.GetPositionActive(PUB.Result.CurrentPos)) + if (VAR.BOOL[eVarBool.NEXTSTOP_MARK]) { - var ts = VAR.TIME.RUN(eVarTime.MarkSensorOff); - if (ts.TotalSeconds >= 2) - { - ctlPos1.SetPositionDeActive(); - PUB.log.Add($"현재 활성위치를 해제 함"); - } + VAR.BOOL[eVarBool.NEXTSTOP_MARK] = false; + PUB.logagv.Add($"NEXTSTOP_MARK 변경({VAR.BOOL[eVarBool.NEXTSTOP_MARK]})"); } - } - //나르미가 멈췄다면 다음 마크 이동 기능이 OFF 된다 - if (PUB.AGV.system1.agv_stop) - VAR.BOOL[eVarBool.NEXTSTOP_MARK] = false; - + //마크센서 상태가 변경이 되었다면 if (VAR.BOOL[eVarBool.MARK_SENSOR] != PUB.AGV.signal.mark_sensor) { - if (PUB.AGV.signal.mark_sensor) - { - //현재위치를 확정한다 - var curact = ctlPos1.GetPositionActive(PUB.Result.CurrentPos); - if (curact == false) - { - PUB.log.Add($"마크센서로인해 현재위치 설정완료:{PUB.Result.CurrentPos}"); - ctlPos1.SetPositionActive(PUB.Result.CurrentPos); - ctlPos1.SetDirection(""); - ctlPos1.Invalidate(); - } - } + PUB.logagv.Add($"MARK_SENSOR 변경({PUB.AGV.signal.mark_sensor})"); VAR.BOOL[eVarBool.MARK_SENSOR] = PUB.AGV.signal.mark_sensor; + + //AGV가 멈췄고 마크센서가 ON되었다면 마지막 RFID 위치가 확정된경우이다 + if (agv_stp && VAR.BOOL[eVarBool.MARK_SENSOR]) + { + PUB.log.Add("마크스탑이 확인되어 최종위치를 PASS 처리 합니다"); + var curnode = PUB._virtualAGV.SetCurrentNodeMarkStop(); + if (curnode == true) + { + PUB.log.Add($"마크스탑으로 해당노드의 이동을 확정합니다"); + } + else PUB.log.AddAT($"마크스탑이 확인되었으나 현재 노드가없어 PASS를 설정하지 못함"); + } } + if (VAR.BOOL[eVarBool.MARK_SENSOROFF] != VAR.BOOL[eVarBool.MARK_SENSOR]) + { + VAR.BOOL[eVarBool.MARK_SENSOROFF] = !VAR.BOOL[eVarBool.MARK_SENSOR]; + VAR.TIME[eVarTime.MarkSensorOff] = DateTime.Now; + PUB.log.Add($"MARK_SENSOROFF 변경({VAR.BOOL[eVarBool.MARK_SENSOROFF]})"); + } + } break; case arDev.Narumi.DataType.TAG: @@ -197,7 +163,7 @@ namespace Project NodeId = newNodeId, RfidId = PUB.Result.LastTAG, Name = $"자동추가_{PUB.Result.LastTAG}", - Type = NodeType.Normal, + Type = NodeType.Normal, Position = new Point(100, 100), // 기본 위치 IsActive = true, DisplayColor = Color.Orange, // 자동 추가된 노드는 오렌지색으로 표시 @@ -239,8 +205,23 @@ namespace Project } //이 후 상황을 예측한다 - var command = PUB._virtualAGV.Predict(); - var preditMSG = $"Motor:{command.Motor},Magnet:{command.Magnet},Speed:{command.Speed} : {command.Reason}"; + if (PUB._mapCanvas != null) + { + var nextAction = PUB._virtualAGV.Predict(); + var message = $"[다음 행동 예측]\n\n" + + $"모터: {nextAction.Motor}\n" + + $"마그넷: {nextAction.Magnet}\n" + + $"속도: {nextAction.Speed}\n" + + $"이유: {nextAction.Message}\n\n" + + $"---\n" + + $"현재 상태: {PUB._virtualAGV.CurrentState}\n" + + $"현재 방향: {PUB._virtualAGV.CurrentDirection}\n" + + $"위치 확정: {PUB._virtualAGV.IsPositionConfirmed} (RFID {PUB._virtualAGV.DetectedRfidCount}개)\n" + + $"현재 노드: {PUB._virtualAGV.CurrentNodeId ?? "없음"}"; + + PUB._mapCanvas.PredictMessage = message; + } + } catch (Exception ex) { diff --git a/Cs_HMI/Project/StateMachine/_Loop.cs b/Cs_HMI/Project/StateMachine/_Loop.cs index 6a8c45c..f97eb72 100644 --- a/Cs_HMI/Project/StateMachine/_Loop.cs +++ b/Cs_HMI/Project/StateMachine/_Loop.cs @@ -159,7 +159,12 @@ namespace Project // 동기화 모드 종료 (혹시 남아있을 경우) if (PUB._mapCanvas != null) - PUB._mapCanvas.ExitSyncMode(); + { + this.Invoke(new Action(() => { + PUB._mapCanvas.ExitSyncMode(); + })); + } + } //자동소거기능 @@ -183,6 +188,12 @@ namespace Project break; case eSMStep.SYNC: + if(e.isFirst) + { + // 동기화 완료 시 캔버스 모드 복귀 + if (PUB._mapCanvas != null) + PUB._mapCanvas.SetSyncStatus("설정 동기화", 0f, "환경설정 값으로 AGV컨트롤러를 설정 합니다"); + } if (_SM_RUN_SYNC(runStepisFirst, PUB.sm.GetRunSteptime)) { var b1 = PUB.XBE.IsOpen; diff --git a/Cs_HMI/Project/StateMachine/_TMDisplay.cs b/Cs_HMI/Project/StateMachine/_TMDisplay.cs index 390e52b..17bcd9d 100644 --- a/Cs_HMI/Project/StateMachine/_TMDisplay.cs +++ b/Cs_HMI/Project/StateMachine/_TMDisplay.cs @@ -241,6 +241,7 @@ namespace Project var bCharge = (PUB.sm.RunStep == ERunStep.GOCHARGE || PUB.sm.RunStep == ERunStep.CHARGECHECK || VAR.BOOL[eVarBool.FLAG_CHARGEONA] == true); + //가동, 목적지가 충전기라면 홈 이동이다 var bHome = PUB.sm.Step == eSMStep.RUN && (PUB.sm.RunStep == ERunStep.GOHOME); //var bChargeM = PUB.flag.get(EFlag.FLAG_CHARGEONM); var bAuto = VAR.BOOL[eVarBool.FLAG_AUTORUN]; @@ -368,7 +369,7 @@ namespace Project } IOState.setTitle(inputrow, inputcol, "RUN"); IOState.setValue(inputrow, inputcol++, (PUB.AGV.system1.agv_run ? 1 : 0)); - IOState.setTitle(inputrow, inputcol, "MARK"); IOState.setValue(inputrow, inputcol++, (PUB.AGV.signal.mark_sensor ? 1 : (VAR.BOOL[eVarBool.NEXTSTOP_MARK] ? 2 : 0))); + IOState.setTitle(inputrow, inputcol, "MARK"); IOState.setValue(inputrow, inputcol++, (VAR.BOOL[eVarBool.MARK_SENSOR] ? 1 : (VAR.BOOL[eVarBool.NEXTSTOP_MARK] ? 2 : 0))); IOState.setTitle(inputrow, inputcol, "CHG"); IOState.setValue(inputrow, inputcol++, (PUB.AGV.system1.Battery_charging ? 1 : 0)); IOState.setTitle(inputrow, inputcol, "ITM"); IOState.setValue(inputrow, inputcol++, (VAR.BOOL[eVarBool.ITEMON] ? 1 : 0)); IOState.Invalidate(); diff --git a/Cs_HMI/Project/StateMachine/_Xbee.cs b/Cs_HMI/Project/StateMachine/_Xbee.cs index c4d75bc..aa80271 100644 --- a/Cs_HMI/Project/StateMachine/_Xbee.cs +++ b/Cs_HMI/Project/StateMachine/_Xbee.cs @@ -160,7 +160,7 @@ namespace Project var bunkidata = new arDev.Narumi.BunkiData(); //speed; - if (AutSpeed == 1) bunkidata.Speed = arDev.Narumi.eMoveSpd.Middle; + if (AutSpeed == 1) bunkidata.Speed = arDev.Narumi.eMoveSpd.Mid; else if (AutSpeed == 2) bunkidata.Speed = arDev.Narumi.eMoveSpd.High; else bunkidata.Speed = arDev.Narumi.eMoveSpd.Low; diff --git a/Cs_HMI/Project/ViewForm/fManual.cs b/Cs_HMI/Project/ViewForm/fManual.cs index f1b55d0..2e2c388 100644 --- a/Cs_HMI/Project/ViewForm/fManual.cs +++ b/Cs_HMI/Project/ViewForm/fManual.cs @@ -291,7 +291,7 @@ namespace Project.ViewForm if (radspdh.Checked) p.Speed = arDev.Narumi.eMoveSpd.High; else if (radspdl.Checked) p.Speed = arDev.Narumi.eMoveSpd.Low; - else p.Speed = arDev.Narumi.eMoveSpd.Middle; + else p.Speed = arDev.Narumi.eMoveSpd.Mid; if (radpbs1.Checked) p.PBSSensor = 2; else if (radpbs2.Checked) p.PBSSensor = 2; @@ -307,7 +307,7 @@ namespace Project.ViewForm private void btChargeOn_Click(object sender, EventArgs e) { - if (PUB.AGV.signal.mark_sensor == false) + if (VAR.BOOL[eVarBool.MARK_SENSOR] == false) { UTIL.MsgE("마크센서가 확인되지 않아 충전을 시작할 수 없습니다"); return; diff --git a/Cs_HMI/Project/fMain.Designer.cs b/Cs_HMI/Project/fMain.Designer.cs index d14d87c..bf1e9b1 100644 --- a/Cs_HMI/Project/fMain.Designer.cs +++ b/Cs_HMI/Project/fMain.Designer.cs @@ -44,22 +44,6 @@ namespace Project arFrame.Control.ColorListItem colorListItem9 = new arFrame.Control.ColorListItem(); arFrame.Control.ColorListItem colorListItem10 = new arFrame.Control.ColorListItem(); arFrame.Control.ColorListItem colorListItem11 = new arFrame.Control.ColorListItem(); - Project.CtlPos.item item1 = new Project.CtlPos.item(); - Project.CtlPos.item item2 = new Project.CtlPos.item(); - Project.CtlPos.item item3 = new Project.CtlPos.item(); - Project.CtlPos.item item4 = new Project.CtlPos.item(); - Project.CtlPos.item item5 = new Project.CtlPos.item(); - Project.CtlPos.item item6 = new Project.CtlPos.item(); - Project.CtlPos.item item7 = new Project.CtlPos.item(); - Project.CtlPos.item item8 = new Project.CtlPos.item(); - Project.CtlPos.item item9 = new Project.CtlPos.item(); - Project.CtlPos.item item10 = new Project.CtlPos.item(); - Project.CtlPos.item item11 = new Project.CtlPos.item(); - Project.CtlPos.item item12 = new Project.CtlPos.item(); - Project.CtlPos.item item13 = new Project.CtlPos.item(); - Project.CtlPos.item item14 = new Project.CtlPos.item(); - Project.CtlPos.item item15 = new Project.CtlPos.item(); - Project.CtlPos.item item16 = new Project.CtlPos.item(); this.tmDisplay = new System.Windows.Forms.Timer(this.components); this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); this.MenuLift = new System.Windows.Forms.Button(); @@ -125,7 +109,6 @@ namespace Project this.lbIDLE = new arCtl.arLabel(); this.lbStStep = new arCtl.arLabel(); this.panTopMenu = new System.Windows.Forms.Panel(); - this.lbBat = new AGVControl.BatteryLevelGauge(); this.pictureBox1 = new System.Windows.Forms.PictureBox(); this.cmDebug = new System.Windows.Forms.ContextMenuStrip(this.components); this.mapFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -138,12 +121,12 @@ namespace Project this.debugtestToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.pandBottomDIO = new System.Windows.Forms.Panel(); this.panel9 = new System.Windows.Forms.Panel(); - this.IOState = new arFrame.Control.GridView(); - this.SSInfo = new arFrame.Control.GridView(); this.panDlg = new System.Windows.Forms.Panel(); this.arPanel2 = new arCtl.arPanel(); this.arPanel1 = new arCtl.arPanel(); - this.ctlPos1 = new Project.CtlPos(); + this.IOState = new arFrame.Control.GridView(); + this.SSInfo = new arFrame.Control.GridView(); + this.lbBat = new AGVControl.BatteryLevelGauge(); this.panRight.SuspendLayout(); this.tableLayoutPanel1.SuspendLayout(); this.panel4.SuspendLayout(); @@ -299,7 +282,7 @@ namespace Project this.btAutoRun.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.ForwardDiagonal; this.btAutoRun.GradientRepeatBG = false; this.btAutoRun.isButton = true; - this.btAutoRun.Location = new System.Drawing.Point(0, 300); + this.btAutoRun.Location = new System.Drawing.Point(0, 360); this.btAutoRun.Margin = new System.Windows.Forms.Padding(0); this.btAutoRun.MouseDownColor = System.Drawing.Color.Empty; this.btAutoRun.MouseOverColor = System.Drawing.Color.Empty; @@ -320,7 +303,7 @@ namespace Project this.btAutoRun.SignAlign = System.Drawing.ContentAlignment.BottomRight; this.btAutoRun.SignColor = System.Drawing.Color.Yellow; this.btAutoRun.SignFont = new System.Drawing.Font("Consolas", 7F, System.Drawing.FontStyle.Italic); - this.btAutoRun.Size = new System.Drawing.Size(259, 152); + this.btAutoRun.Size = new System.Drawing.Size(259, 180); this.btAutoRun.TabIndex = 22; this.btAutoRun.Text = "수동"; this.btAutoRun.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; @@ -367,7 +350,7 @@ namespace Project this.btChargeA.SignAlign = System.Drawing.ContentAlignment.BottomRight; this.btChargeA.SignColor = System.Drawing.Color.Yellow; this.btChargeA.SignFont = new System.Drawing.Font("Consolas", 7F, System.Drawing.FontStyle.Italic); - this.btChargeA.Size = new System.Drawing.Size(143, 150); + this.btChargeA.Size = new System.Drawing.Size(143, 180); this.btChargeA.TabIndex = 141; this.btChargeA.Text = "자동충전"; this.btChargeA.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; @@ -393,7 +376,7 @@ namespace Project this.lbTime.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical; this.lbTime.GradientRepeatBG = false; this.lbTime.isButton = false; - this.lbTime.Location = new System.Drawing.Point(5, 593); + this.lbTime.Location = new System.Drawing.Point(5, 681); this.lbTime.Margin = new System.Windows.Forms.Padding(0); this.lbTime.MouseDownColor = System.Drawing.Color.Yellow; this.lbTime.MouseOverColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); @@ -979,10 +962,10 @@ namespace Project this.panRight.Controls.Add(this.panel3); this.panRight.Controls.Add(this.panel1); this.panRight.Dock = System.Windows.Forms.DockStyle.Right; - this.panRight.Location = new System.Drawing.Point(1015, 146); + this.panRight.Location = new System.Drawing.Point(1015, 58); this.panRight.Name = "panRight"; this.panRight.Padding = new System.Windows.Forms.Padding(5, 0, 0, 0); - this.panRight.Size = new System.Drawing.Size(264, 618); + this.panRight.Size = new System.Drawing.Size(264, 706); this.panRight.TabIndex = 131; // // tableLayoutPanel1 @@ -1001,7 +984,7 @@ namespace Project this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); - this.tableLayoutPanel1.Size = new System.Drawing.Size(259, 452); + this.tableLayoutPanel1.Size = new System.Drawing.Size(259, 540); this.tableLayoutPanel1.TabIndex = 0; // // btHome @@ -1043,7 +1026,7 @@ namespace Project this.btHome.SignAlign = System.Drawing.ContentAlignment.BottomRight; this.btHome.SignColor = System.Drawing.Color.Yellow; this.btHome.SignFont = new System.Drawing.Font("Consolas", 7F, System.Drawing.FontStyle.Italic); - this.btHome.Size = new System.Drawing.Size(116, 300); + this.btHome.Size = new System.Drawing.Size(116, 360); this.btHome.TabIndex = 141; this.btHome.Text = "홈"; this.btHome.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; @@ -1068,7 +1051,7 @@ namespace Project this.btChargeM.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.ForwardDiagonal; this.btChargeM.GradientRepeatBG = false; this.btChargeM.isButton = true; - this.btChargeM.Location = new System.Drawing.Point(116, 150); + this.btChargeM.Location = new System.Drawing.Point(116, 180); this.btChargeM.Margin = new System.Windows.Forms.Padding(0); this.btChargeM.MouseDownColor = System.Drawing.Color.Yellow; this.btChargeM.MouseOverColor = System.Drawing.Color.Lime; @@ -1089,7 +1072,7 @@ namespace Project this.btChargeM.SignAlign = System.Drawing.ContentAlignment.BottomRight; this.btChargeM.SignColor = System.Drawing.Color.Yellow; this.btChargeM.SignFont = new System.Drawing.Font("Consolas", 7F, System.Drawing.FontStyle.Italic); - this.btChargeM.Size = new System.Drawing.Size(143, 150); + this.btChargeM.Size = new System.Drawing.Size(143, 180); this.btChargeM.TabIndex = 141; this.btChargeM.Text = "수동충전"; this.btChargeM.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; @@ -1130,13 +1113,13 @@ namespace Project this.lbCntQA.ColorTheme = arCtl.arLabel.eColorTheme.Custom; this.lbCntQA.Cursor = System.Windows.Forms.Cursors.Arrow; this.lbCntQA.Dock = System.Windows.Forms.DockStyle.Left; - this.lbCntQA.Font = new System.Drawing.Font("Consolas", 25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lbCntQA.Font = new System.Drawing.Font("Consolas", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lbCntQA.ForeColor = System.Drawing.Color.Gray; this.lbCntQA.GradientEnable = true; this.lbCntQA.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.ForwardDiagonal; this.lbCntQA.GradientRepeatBG = false; this.lbCntQA.isButton = false; - this.lbCntQA.Location = new System.Drawing.Point(161, 0); + this.lbCntQA.Location = new System.Drawing.Point(180, 0); this.lbCntQA.Margin = new System.Windows.Forms.Padding(0); this.lbCntQA.MouseDownColor = System.Drawing.Color.Yellow; this.lbCntQA.MouseOverColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); @@ -1157,7 +1140,7 @@ namespace Project this.lbCntQA.SignAlign = System.Drawing.ContentAlignment.BottomRight; this.lbCntQA.SignColor = System.Drawing.Color.Yellow; this.lbCntQA.SignFont = new System.Drawing.Font("Consolas", 7F, System.Drawing.FontStyle.Italic); - this.lbCntQA.Size = new System.Drawing.Size(93, 49); + this.lbCntQA.Size = new System.Drawing.Size(78, 49); this.lbCntQA.TabIndex = 6; this.lbCntQA.Text = "0000"; this.lbCntQA.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; @@ -1175,13 +1158,13 @@ namespace Project this.arLabel4.ColorTheme = arCtl.arLabel.eColorTheme.Custom; this.arLabel4.Cursor = System.Windows.Forms.Cursors.Arrow; this.arLabel4.Dock = System.Windows.Forms.DockStyle.Left; - this.arLabel4.Font = new System.Drawing.Font("Consolas", 15F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.arLabel4.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.arLabel4.Font = new System.Drawing.Font("Bahnschrift Condensed", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.arLabel4.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(255)))), ((int)(((byte)(192))))); this.arLabel4.GradientEnable = true; this.arLabel4.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.ForwardDiagonal; this.arLabel4.GradientRepeatBG = false; this.arLabel4.isButton = false; - this.arLabel4.Location = new System.Drawing.Point(127, 0); + this.arLabel4.Location = new System.Drawing.Point(129, 0); this.arLabel4.Margin = new System.Windows.Forms.Padding(0); this.arLabel4.MouseDownColor = System.Drawing.Color.Yellow; this.arLabel4.MouseOverColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); @@ -1201,10 +1184,10 @@ namespace Project this.arLabel4.Sign = ""; this.arLabel4.SignAlign = System.Drawing.ContentAlignment.BottomRight; this.arLabel4.SignColor = System.Drawing.Color.Yellow; - this.arLabel4.SignFont = new System.Drawing.Font("Consolas", 15F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic)))); - this.arLabel4.Size = new System.Drawing.Size(34, 49); + this.arLabel4.SignFont = new System.Drawing.Font("Consolas", 12F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic)))); + this.arLabel4.Size = new System.Drawing.Size(51, 49); this.arLabel4.TabIndex = 5; - this.arLabel4.Text = "QA"; + this.arLabel4.Text = "CHARGER"; this.arLabel4.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; this.arLabel4.TextShadow = true; this.arLabel4.TextVisible = true; @@ -1220,13 +1203,13 @@ namespace Project this.lbCntQC.ColorTheme = arCtl.arLabel.eColorTheme.Custom; this.lbCntQC.Cursor = System.Windows.Forms.Cursors.Arrow; this.lbCntQC.Dock = System.Windows.Forms.DockStyle.Left; - this.lbCntQC.Font = new System.Drawing.Font("Consolas", 25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lbCntQC.Font = new System.Drawing.Font("Consolas", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lbCntQC.ForeColor = System.Drawing.Color.Gray; this.lbCntQC.GradientEnable = true; this.lbCntQC.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.ForwardDiagonal; this.lbCntQC.GradientRepeatBG = false; this.lbCntQC.isButton = false; - this.lbCntQC.Location = new System.Drawing.Point(34, 0); + this.lbCntQC.Location = new System.Drawing.Point(51, 0); this.lbCntQC.Margin = new System.Windows.Forms.Padding(0); this.lbCntQC.MouseDownColor = System.Drawing.Color.Yellow; this.lbCntQC.MouseOverColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); @@ -1247,7 +1230,7 @@ namespace Project this.lbCntQC.SignAlign = System.Drawing.ContentAlignment.BottomRight; this.lbCntQC.SignColor = System.Drawing.Color.Yellow; this.lbCntQC.SignFont = new System.Drawing.Font("Consolas", 7F, System.Drawing.FontStyle.Italic); - this.lbCntQC.Size = new System.Drawing.Size(93, 49); + this.lbCntQC.Size = new System.Drawing.Size(78, 49); this.lbCntQC.TabIndex = 4; this.lbCntQC.Text = "0000"; this.lbCntQC.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; @@ -1265,7 +1248,7 @@ namespace Project this.arLabel9.ColorTheme = arCtl.arLabel.eColorTheme.Custom; this.arLabel9.Cursor = System.Windows.Forms.Cursors.Arrow; this.arLabel9.Dock = System.Windows.Forms.DockStyle.Left; - this.arLabel9.Font = new System.Drawing.Font("Consolas", 15F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.arLabel9.Font = new System.Drawing.Font("Bahnschrift Condensed", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.arLabel9.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); this.arLabel9.GradientEnable = true; this.arLabel9.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.ForwardDiagonal; @@ -1291,10 +1274,10 @@ namespace Project this.arLabel9.Sign = ""; this.arLabel9.SignAlign = System.Drawing.ContentAlignment.BottomRight; this.arLabel9.SignColor = System.Drawing.Color.Yellow; - this.arLabel9.SignFont = new System.Drawing.Font("Consolas", 15F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic)))); - this.arLabel9.Size = new System.Drawing.Size(34, 49); + this.arLabel9.SignFont = new System.Drawing.Font("Consolas", 12F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic)))); + this.arLabel9.Size = new System.Drawing.Size(51, 49); this.arLabel9.TabIndex = 4; - this.arLabel9.Text = "QC"; + this.arLabel9.Text = "UNLOADER"; this.arLabel9.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; this.arLabel9.TextShadow = true; this.arLabel9.TextVisible = true; @@ -1323,13 +1306,13 @@ namespace Project this.lbCntDN.ColorTheme = arCtl.arLabel.eColorTheme.Custom; this.lbCntDN.Cursor = System.Windows.Forms.Cursors.Arrow; this.lbCntDN.Dock = System.Windows.Forms.DockStyle.Left; - this.lbCntDN.Font = new System.Drawing.Font("Consolas", 25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lbCntDN.Font = new System.Drawing.Font("Consolas", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lbCntDN.ForeColor = System.Drawing.Color.Gray; this.lbCntDN.GradientEnable = true; this.lbCntDN.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.ForwardDiagonal; this.lbCntDN.GradientRepeatBG = false; this.lbCntDN.isButton = false; - this.lbCntDN.Location = new System.Drawing.Point(161, 0); + this.lbCntDN.Location = new System.Drawing.Point(180, 0); this.lbCntDN.Margin = new System.Windows.Forms.Padding(0); this.lbCntDN.MouseDownColor = System.Drawing.Color.Yellow; this.lbCntDN.MouseOverColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); @@ -1350,7 +1333,7 @@ namespace Project this.lbCntDN.SignAlign = System.Drawing.ContentAlignment.BottomRight; this.lbCntDN.SignColor = System.Drawing.Color.Yellow; this.lbCntDN.SignFont = new System.Drawing.Font("Consolas", 7F, System.Drawing.FontStyle.Italic); - this.lbCntDN.Size = new System.Drawing.Size(93, 49); + this.lbCntDN.Size = new System.Drawing.Size(78, 49); this.lbCntDN.TabIndex = 4; this.lbCntDN.Text = "0000"; this.lbCntDN.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; @@ -1369,13 +1352,13 @@ namespace Project this.arLabel7.ColorTheme = arCtl.arLabel.eColorTheme.Custom; this.arLabel7.Cursor = System.Windows.Forms.Cursors.Arrow; this.arLabel7.Dock = System.Windows.Forms.DockStyle.Left; - this.arLabel7.Font = new System.Drawing.Font("Consolas", 15F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.arLabel7.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.arLabel7.Font = new System.Drawing.Font("Bahnschrift Condensed", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.arLabel7.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(192)))), ((int)(((byte)(255))))); this.arLabel7.GradientEnable = true; this.arLabel7.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.ForwardDiagonal; this.arLabel7.GradientRepeatBG = false; this.arLabel7.isButton = false; - this.arLabel7.Location = new System.Drawing.Point(127, 0); + this.arLabel7.Location = new System.Drawing.Point(129, 0); this.arLabel7.Margin = new System.Windows.Forms.Padding(0); this.arLabel7.MouseDownColor = System.Drawing.Color.Yellow; this.arLabel7.MouseOverColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); @@ -1395,10 +1378,10 @@ namespace Project this.arLabel7.Sign = ""; this.arLabel7.SignAlign = System.Drawing.ContentAlignment.BottomRight; this.arLabel7.SignColor = System.Drawing.Color.Yellow; - this.arLabel7.SignFont = new System.Drawing.Font("Consolas", 15F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic)))); - this.arLabel7.Size = new System.Drawing.Size(34, 49); + this.arLabel7.SignFont = new System.Drawing.Font("Consolas", 12F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic)))); + this.arLabel7.Size = new System.Drawing.Size(51, 49); this.arLabel7.TabIndex = 4; - this.arLabel7.Text = "DN"; + this.arLabel7.Text = "CLEANNER"; this.arLabel7.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; this.arLabel7.TextShadow = true; this.arLabel7.TextVisible = true; @@ -1414,13 +1397,13 @@ namespace Project this.lbCNtUP.ColorTheme = arCtl.arLabel.eColorTheme.Custom; this.lbCNtUP.Cursor = System.Windows.Forms.Cursors.Arrow; this.lbCNtUP.Dock = System.Windows.Forms.DockStyle.Left; - this.lbCNtUP.Font = new System.Drawing.Font("Consolas", 25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lbCNtUP.Font = new System.Drawing.Font("Consolas", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lbCNtUP.ForeColor = System.Drawing.Color.Gray; this.lbCNtUP.GradientEnable = true; this.lbCNtUP.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.ForwardDiagonal; this.lbCNtUP.GradientRepeatBG = false; this.lbCNtUP.isButton = false; - this.lbCNtUP.Location = new System.Drawing.Point(34, 0); + this.lbCNtUP.Location = new System.Drawing.Point(51, 0); this.lbCNtUP.Margin = new System.Windows.Forms.Padding(0); this.lbCNtUP.MouseDownColor = System.Drawing.Color.Yellow; this.lbCNtUP.MouseOverColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); @@ -1441,7 +1424,7 @@ namespace Project this.lbCNtUP.SignAlign = System.Drawing.ContentAlignment.BottomRight; this.lbCNtUP.SignColor = System.Drawing.Color.Yellow; this.lbCNtUP.SignFont = new System.Drawing.Font("Consolas", 7F, System.Drawing.FontStyle.Italic); - this.lbCNtUP.Size = new System.Drawing.Size(93, 49); + this.lbCNtUP.Size = new System.Drawing.Size(78, 49); this.lbCNtUP.TabIndex = 4; this.lbCNtUP.Text = "0000"; this.lbCNtUP.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; @@ -1460,7 +1443,7 @@ namespace Project this.arLabel8.ColorTheme = arCtl.arLabel.eColorTheme.Custom; this.arLabel8.Cursor = System.Windows.Forms.Cursors.Arrow; this.arLabel8.Dock = System.Windows.Forms.DockStyle.Left; - this.arLabel8.Font = new System.Drawing.Font("Consolas", 15F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.arLabel8.Font = new System.Drawing.Font("Bahnschrift Condensed", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.arLabel8.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(255))))); this.arLabel8.GradientEnable = true; this.arLabel8.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.ForwardDiagonal; @@ -1486,10 +1469,10 @@ namespace Project this.arLabel8.Sign = ""; this.arLabel8.SignAlign = System.Drawing.ContentAlignment.BottomRight; this.arLabel8.SignColor = System.Drawing.Color.Yellow; - this.arLabel8.SignFont = new System.Drawing.Font("Consolas", 15F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic)))); - this.arLabel8.Size = new System.Drawing.Size(34, 49); + this.arLabel8.SignFont = new System.Drawing.Font("Consolas", 12F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic)))); + this.arLabel8.Size = new System.Drawing.Size(51, 49); this.arLabel8.TabIndex = 4; - this.arLabel8.Text = "UP"; + this.arLabel8.Text = "LOADER"; this.arLabel8.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; this.arLabel8.TextShadow = true; this.arLabel8.TextVisible = true; @@ -1498,7 +1481,7 @@ namespace Project // this.panel5.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(18)))), ((int)(((byte)(18)))), ((int)(((byte)(18))))); this.panel5.Dock = System.Windows.Forms.DockStyle.Bottom; - this.panel5.Location = new System.Drawing.Point(5, 588); + this.panel5.Location = new System.Drawing.Point(5, 676); this.panel5.Name = "panel5"; this.panel5.Size = new System.Drawing.Size(259, 5); this.panel5.TabIndex = 142; @@ -1639,26 +1622,6 @@ namespace Project this.panTopMenu.Size = new System.Drawing.Size(1278, 50); this.panTopMenu.TabIndex = 134; // - // lbBat - // - this.lbBat.BorderColor = System.Drawing.Color.DimGray; - this.lbBat.CurA = 0F; - this.lbBat.Dock = System.Windows.Forms.DockStyle.Right; - this.lbBat.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.lbBat.ForeColor = System.Drawing.Color.Gray; - this.lbBat.IsOpen = true; - this.lbBat.Location = new System.Drawing.Point(830, 0); - this.lbBat.MaxA = 0F; - this.lbBat.Name = "lbBat"; - this.lbBat.Padding = new System.Windows.Forms.Padding(0, 12, 0, 12); - this.lbBat.sign = "%"; - this.lbBat.Size = new System.Drawing.Size(48, 50); - this.lbBat.TabIndex = 23; - this.lbBat.Text = "12"; - this.lbBat.VLevel = 50F; - this.lbBat.Volt = 0F; - this.lbBat.Click += new System.EventHandler(this.lbBat_Click); - // // pictureBox1 // this.pictureBox1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40))))); @@ -1769,6 +1732,70 @@ namespace Project this.panel9.Size = new System.Drawing.Size(1278, 35); this.panel9.TabIndex = 0; // + // panDlg + // + this.panDlg.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(64))))); + this.panDlg.Dock = System.Windows.Forms.DockStyle.Fill; + this.panDlg.Location = new System.Drawing.Point(1, 58); + this.panDlg.Margin = new System.Windows.Forms.Padding(0); + this.panDlg.Name = "panDlg"; + this.panDlg.Size = new System.Drawing.Size(1014, 706); + this.panDlg.TabIndex = 146; + // + // arPanel2 + // + this.arPanel2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(5)))), ((int)(((byte)(5)))), ((int)(((byte)(5))))); + this.arPanel2.BackColor2 = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20))))); + this.arPanel2.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25))))); + this.arPanel2.BorderSize = new System.Windows.Forms.Padding(0, 0, 0, 5); + this.arPanel2.Dock = System.Windows.Forms.DockStyle.Top; + this.arPanel2.Font = new System.Drawing.Font("Consolas", 10F, System.Drawing.FontStyle.Italic); + this.arPanel2.ForeColor = System.Drawing.Color.Khaki; + this.arPanel2.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical; + this.arPanel2.GradientRepeatBG = false; + this.arPanel2.Location = new System.Drawing.Point(1, 55); + this.arPanel2.Name = "arPanel2"; + this.arPanel2.ProgressColor1 = System.Drawing.Color.LightSkyBlue; + this.arPanel2.ProgressColor2 = System.Drawing.Color.DeepSkyBlue; + this.arPanel2.ProgressMax = 100F; + this.arPanel2.ProgressMin = 0F; + this.arPanel2.ProgressPadding = new System.Windows.Forms.Padding(0); + this.arPanel2.ProgressValue = 0F; + this.arPanel2.ShadowColor = System.Drawing.Color.Black; + this.arPanel2.ShowBorder = true; + this.arPanel2.Size = new System.Drawing.Size(1278, 3); + this.arPanel2.TabIndex = 145; + this.arPanel2.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + this.arPanel2.TextShadow = false; + this.arPanel2.UseProgressBar = false; + // + // arPanel1 + // + this.arPanel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(5)))), ((int)(((byte)(5)))), ((int)(((byte)(5))))); + this.arPanel1.BackColor2 = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20))))); + this.arPanel1.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25))))); + this.arPanel1.BorderSize = new System.Windows.Forms.Padding(0, 0, 0, 5); + this.arPanel1.Dock = System.Windows.Forms.DockStyle.Top; + this.arPanel1.Font = new System.Drawing.Font("Consolas", 10F, System.Drawing.FontStyle.Italic); + this.arPanel1.ForeColor = System.Drawing.Color.Khaki; + this.arPanel1.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical; + this.arPanel1.GradientRepeatBG = false; + this.arPanel1.Location = new System.Drawing.Point(1, 51); + this.arPanel1.Name = "arPanel1"; + this.arPanel1.ProgressColor1 = System.Drawing.Color.LightSkyBlue; + this.arPanel1.ProgressColor2 = System.Drawing.Color.DeepSkyBlue; + this.arPanel1.ProgressMax = 100F; + this.arPanel1.ProgressMin = 0F; + this.arPanel1.ProgressPadding = new System.Windows.Forms.Padding(0); + this.arPanel1.ProgressValue = 0F; + this.arPanel1.ShadowColor = System.Drawing.Color.Black; + this.arPanel1.ShowBorder = true; + this.arPanel1.Size = new System.Drawing.Size(1278, 4); + this.arPanel1.TabIndex = 135; + this.arPanel1.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + this.arPanel1.TextShadow = false; + this.arPanel1.UseProgressBar = false; + // // IOState // this.IOState.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(50)))), ((int)(((byte)(50))))); @@ -1921,280 +1948,25 @@ namespace Project ((ushort)(0))}; this.SSInfo.Click += new System.EventHandler(this.SSInfo_Click); // - // panDlg + // lbBat // - this.panDlg.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(64))))); - this.panDlg.Dock = System.Windows.Forms.DockStyle.Fill; - this.panDlg.Location = new System.Drawing.Point(1, 146); - this.panDlg.Margin = new System.Windows.Forms.Padding(0); - this.panDlg.Name = "panDlg"; - this.panDlg.Size = new System.Drawing.Size(1014, 618); - this.panDlg.TabIndex = 146; - // - // arPanel2 - // - this.arPanel2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(5)))), ((int)(((byte)(5)))), ((int)(((byte)(5))))); - this.arPanel2.BackColor2 = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20))))); - this.arPanel2.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25))))); - this.arPanel2.BorderSize = new System.Windows.Forms.Padding(0, 0, 0, 5); - this.arPanel2.Dock = System.Windows.Forms.DockStyle.Top; - this.arPanel2.Font = new System.Drawing.Font("Consolas", 10F, System.Drawing.FontStyle.Italic); - this.arPanel2.ForeColor = System.Drawing.Color.Khaki; - this.arPanel2.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical; - this.arPanel2.GradientRepeatBG = false; - this.arPanel2.Location = new System.Drawing.Point(1, 143); - this.arPanel2.Name = "arPanel2"; - this.arPanel2.ProgressColor1 = System.Drawing.Color.LightSkyBlue; - this.arPanel2.ProgressColor2 = System.Drawing.Color.DeepSkyBlue; - this.arPanel2.ProgressMax = 100F; - this.arPanel2.ProgressMin = 0F; - this.arPanel2.ProgressPadding = new System.Windows.Forms.Padding(0); - this.arPanel2.ProgressValue = 0F; - this.arPanel2.ShadowColor = System.Drawing.Color.Black; - this.arPanel2.ShowBorder = true; - this.arPanel2.Size = new System.Drawing.Size(1278, 3); - this.arPanel2.TabIndex = 145; - this.arPanel2.TextAlign = System.Drawing.ContentAlignment.MiddleRight; - this.arPanel2.TextShadow = false; - this.arPanel2.UseProgressBar = false; - // - // arPanel1 - // - this.arPanel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(5)))), ((int)(((byte)(5)))), ((int)(((byte)(5))))); - this.arPanel1.BackColor2 = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20))))); - this.arPanel1.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25))))); - this.arPanel1.BorderSize = new System.Windows.Forms.Padding(0, 0, 0, 5); - this.arPanel1.Dock = System.Windows.Forms.DockStyle.Top; - this.arPanel1.Font = new System.Drawing.Font("Consolas", 10F, System.Drawing.FontStyle.Italic); - this.arPanel1.ForeColor = System.Drawing.Color.Khaki; - this.arPanel1.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical; - this.arPanel1.GradientRepeatBG = false; - this.arPanel1.Location = new System.Drawing.Point(1, 51); - this.arPanel1.Name = "arPanel1"; - this.arPanel1.ProgressColor1 = System.Drawing.Color.LightSkyBlue; - this.arPanel1.ProgressColor2 = System.Drawing.Color.DeepSkyBlue; - this.arPanel1.ProgressMax = 100F; - this.arPanel1.ProgressMin = 0F; - this.arPanel1.ProgressPadding = new System.Windows.Forms.Padding(0); - this.arPanel1.ProgressValue = 0F; - this.arPanel1.ShadowColor = System.Drawing.Color.Black; - this.arPanel1.ShowBorder = true; - this.arPanel1.Size = new System.Drawing.Size(1278, 4); - this.arPanel1.TabIndex = 135; - this.arPanel1.TextAlign = System.Drawing.ContentAlignment.MiddleRight; - this.arPanel1.TextShadow = false; - this.arPanel1.UseProgressBar = false; - // - // ctlPos1 - // - this.ctlPos1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32))))); - this.ctlPos1.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40))))); - this.ctlPos1.Dock = System.Windows.Forms.DockStyle.Top; - this.ctlPos1.Font = new System.Drawing.Font("맑은 고딕", 30F, System.Drawing.FontStyle.Bold); - this.ctlPos1.ForeColor = System.Drawing.Color.White; - this.ctlPos1.ItemGap = 5; - item1.Active = true; - item1.Direction = '1'; - item1.Enable_Direction = true; - item1.Focus = false; - item1.fullrect = new System.Drawing.Rectangle(8, 8, 10, 75); - item1.ItemType = Project.CtlPos.itemtype.NLimit; - item1.leftrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item1.Position = Project.ePosition.NOT; - item1.rightrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item1.Target = false; - item1.Title = "N"; - item2.Active = false; - item2.Direction = '1'; - item2.Enable_Direction = true; - item2.Focus = false; - item2.fullrect = new System.Drawing.Rectangle(23, 8, 138, 58); - item2.ItemType = Project.CtlPos.itemtype.Item; - item2.leftrect = new System.Drawing.Rectangle(23, 70, 67, 13); - item2.Position = Project.ePosition.QA; - item2.rightrect = new System.Drawing.Rectangle(94, 70, 67, 13); - item2.Target = false; - item2.Title = "QC"; - item3.Active = false; - item3.Direction = '0'; - item3.Enable_Direction = true; - item3.Focus = false; - item3.fullrect = new System.Drawing.Rectangle(166, 8, 10, 75); - item3.ItemType = Project.CtlPos.itemtype.Spacer; - item3.leftrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item3.Position = Project.ePosition.QA_QC; - item3.rightrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item3.Target = false; - item3.Title = null; - item4.Active = false; - item4.Direction = '1'; - item4.Enable_Direction = true; - item4.Focus = false; - item4.fullrect = new System.Drawing.Rectangle(181, 8, 138, 58); - item4.ItemType = Project.CtlPos.itemtype.Item; - item4.leftrect = new System.Drawing.Rectangle(181, 70, 67, 13); - item4.Position = Project.ePosition.QC; - item4.rightrect = new System.Drawing.Rectangle(252, 70, 67, 13); - item4.Target = true; - item4.Title = "QA"; - item5.Active = true; - item5.Direction = '0'; - item5.Enable_Direction = false; - item5.Focus = true; - item5.fullrect = new System.Drawing.Rectangle(324, 8, 138, 75); - item5.ItemType = Project.CtlPos.itemtype.Item; - item5.leftrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item5.Position = Project.ePosition.CHARGE; - item5.rightrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item5.Target = false; - item5.Title = "BAT"; - item6.Active = false; - item6.Direction = '0'; - item6.Enable_Direction = true; - item6.Focus = false; - item6.fullrect = new System.Drawing.Rectangle(467, 8, 10, 75); - item6.ItemType = Project.CtlPos.itemtype.Spacer; - item6.leftrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item6.Position = Project.ePosition.QC_F1; - item6.rightrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item6.Target = false; - item6.Title = null; - item7.Active = false; - item7.Direction = '2'; - item7.Enable_Direction = true; - item7.Focus = false; - item7.fullrect = new System.Drawing.Rectangle(482, 8, 138, 58); - item7.ItemType = Project.CtlPos.itemtype.Item; - item7.leftrect = new System.Drawing.Rectangle(482, 70, 67, 13); - item7.Position = Project.ePosition.F1; - item7.rightrect = new System.Drawing.Rectangle(553, 70, 67, 13); - item7.Target = false; - item7.Title = "#1"; - item8.Active = false; - item8.Direction = '0'; - item8.Enable_Direction = true; - item8.Focus = false; - item8.fullrect = new System.Drawing.Rectangle(625, 8, 10, 75); - item8.ItemType = Project.CtlPos.itemtype.Spacer; - item8.leftrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item8.Position = Project.ePosition.F1_F2; - item8.rightrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item8.Target = false; - item8.Title = null; - item9.Active = false; - item9.Direction = '0'; - item9.Enable_Direction = true; - item9.Focus = false; - item9.fullrect = new System.Drawing.Rectangle(640, 8, 138, 58); - item9.ItemType = Project.CtlPos.itemtype.Item; - item9.leftrect = new System.Drawing.Rectangle(640, 70, 67, 13); - item9.Position = Project.ePosition.F2; - item9.rightrect = new System.Drawing.Rectangle(711, 70, 67, 13); - item9.Target = false; - item9.Title = "#2"; - item10.Active = false; - item10.Direction = '0'; - item10.Enable_Direction = true; - item10.Focus = false; - item10.fullrect = new System.Drawing.Rectangle(783, 8, 10, 75); - item10.ItemType = Project.CtlPos.itemtype.Spacer; - item10.leftrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item10.Position = Project.ePosition.F2_F3; - item10.rightrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item10.Target = false; - item10.Title = null; - item11.Active = false; - item11.Direction = '1'; - item11.Enable_Direction = true; - item11.Focus = false; - item11.fullrect = new System.Drawing.Rectangle(798, 8, 138, 58); - item11.ItemType = Project.CtlPos.itemtype.Item; - item11.leftrect = new System.Drawing.Rectangle(798, 70, 67, 13); - item11.Position = Project.ePosition.F3; - item11.rightrect = new System.Drawing.Rectangle(869, 70, 67, 13); - item11.Target = false; - item11.Title = "#3"; - item12.Active = false; - item12.Direction = '0'; - item12.Enable_Direction = true; - item12.Focus = false; - item12.fullrect = new System.Drawing.Rectangle(941, 8, 10, 75); - item12.ItemType = Project.CtlPos.itemtype.Spacer; - item12.leftrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item12.Position = Project.ePosition.F3_F4; - item12.rightrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item12.Target = false; - item12.Title = null; - item13.Active = false; - item13.Direction = '2'; - item13.Enable_Direction = true; - item13.Focus = false; - item13.fullrect = new System.Drawing.Rectangle(956, 8, 138, 58); - item13.ItemType = Project.CtlPos.itemtype.Item; - item13.leftrect = new System.Drawing.Rectangle(956, 70, 67, 13); - item13.Position = Project.ePosition.F4; - item13.rightrect = new System.Drawing.Rectangle(1027, 70, 67, 13); - item13.Target = false; - item13.Title = "#4"; - item14.Active = false; - item14.Direction = '0'; - item14.Enable_Direction = true; - item14.Focus = false; - item14.fullrect = new System.Drawing.Rectangle(1099, 8, 10, 75); - item14.ItemType = Project.CtlPos.itemtype.Spacer; - item14.leftrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item14.Position = Project.ePosition.F4_F5; - item14.rightrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item14.Target = false; - item14.Title = null; - item15.Active = false; - item15.Direction = '2'; - item15.Enable_Direction = true; - item15.Focus = false; - item15.fullrect = new System.Drawing.Rectangle(1114, 8, 138, 58); - item15.ItemType = Project.CtlPos.itemtype.Item; - item15.leftrect = new System.Drawing.Rectangle(1114, 70, 67, 13); - item15.Position = Project.ePosition.F5; - item15.rightrect = new System.Drawing.Rectangle(1185, 70, 67, 13); - item15.Target = false; - item15.Title = "#5"; - item16.Active = true; - item16.Direction = '1'; - item16.Enable_Direction = true; - item16.Focus = false; - item16.fullrect = new System.Drawing.Rectangle(1257, 8, 10, 75); - item16.ItemType = Project.CtlPos.itemtype.PLimit; - item16.leftrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item16.Position = Project.ePosition.POT; - item16.rightrect = new System.Drawing.Rectangle(0, 0, 0, 0); - item16.Target = false; - item16.Title = "P"; - this.ctlPos1.Items = new Project.CtlPos.item[] { - item1, - item2, - item3, - item4, - item5, - item6, - item7, - item8, - item9, - item10, - item11, - item12, - item13, - item14, - item15, - item16}; - this.ctlPos1.Location = new System.Drawing.Point(1, 55); - this.ctlPos1.MinimumSize = new System.Drawing.Size(100, 30); - this.ctlPos1.msg = null; - this.ctlPos1.Name = "ctlPos1"; - this.ctlPos1.Padding = new System.Windows.Forms.Padding(8); - this.ctlPos1.Size = new System.Drawing.Size(1278, 88); - this.ctlPos1.TabIndex = 0; - this.ctlPos1.Text = "ctlPos1"; - this.ctlPos1.Visible = false; + this.lbBat.BorderColor = System.Drawing.Color.DimGray; + this.lbBat.CurA = 0F; + this.lbBat.Dock = System.Windows.Forms.DockStyle.Right; + this.lbBat.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lbBat.ForeColor = System.Drawing.Color.Gray; + this.lbBat.IsOpen = true; + this.lbBat.Location = new System.Drawing.Point(830, 0); + this.lbBat.MaxA = 0F; + this.lbBat.Name = "lbBat"; + this.lbBat.Padding = new System.Windows.Forms.Padding(0, 12, 0, 12); + this.lbBat.sign = "%"; + this.lbBat.Size = new System.Drawing.Size(48, 50); + this.lbBat.TabIndex = 23; + this.lbBat.Text = "12"; + this.lbBat.VLevel = 50F; + this.lbBat.Volt = 0F; + this.lbBat.Click += new System.EventHandler(this.lbBat_Click); // // fMain // @@ -2205,7 +1977,6 @@ namespace Project this.Controls.Add(this.panRight); this.Controls.Add(this.arPanel2); this.Controls.Add(this.pandBottomDIO); - this.Controls.Add(this.ctlPos1); this.Controls.Add(this.arPanel1); this.Controls.Add(this.panTopMenu); this.DoubleBuffered = true; @@ -2297,7 +2068,6 @@ namespace Project private System.Windows.Forms.Button MenuAuto; private System.Windows.Forms.Panel panDlg; private System.Windows.Forms.Button MenuLog; - private CtlPos ctlPos1; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; private arCtl.arLabel btHome; private arCtl.arLabel btTopMenu_Volume; diff --git a/Cs_HMI/Project/fMain.cs b/Cs_HMI/Project/fMain.cs index c407029..21767e3 100644 --- a/Cs_HMI/Project/fMain.cs +++ b/Cs_HMI/Project/fMain.cs @@ -66,7 +66,6 @@ namespace Project this.panTopMenu.MouseDown += LbTitle_MouseDown; this.panTopMenu.DoubleClick += LbTitle_DoubleClick; - this.ctlPos1.ItemClick += CtlPos1_ItemClick; this.MouseMove += (s1, e1) => { if (DateTime.Now > PUB.LastInputTime) PUB.LastInputTime = DateTime.Now; }; this.FormClosing += __Closing; @@ -101,19 +100,6 @@ namespace Project } } - /// - /// 상단 위치 표시기의 대상 위치값을 표시 합니다 - /// - /// - /// - private void Display_Position_TargetPosSet(object sender, EventArgs e) - { - //대상위치가 설정되었다x - this.ctlPos1.SetTargetPosition(PUB.Result.TargetPos); - this.ctlPos1.Invalidate(); - } - - private void __Closing(object sender, FormClosingEventArgs e) { // 장치 관리 태스크는 _STEP_CLOSING_START에서 종료됨 @@ -176,50 +162,31 @@ namespace Project private void __Load(object sender, EventArgs e) { this.Text = Application.ProductName + " ver " + Application.ProductVersion; - //this.lbTitle.Text = this.Text; - PUB.init(); //public initialize - if (PUB.setting.FullScreen) this.WindowState = FormWindowState.Maximized; - // PUB.log.RaiseMsg += log_RaiseMsg; + PUB.init(); + if (PUB.setting.FullScreen) + { + this.FormBorderStyle = FormBorderStyle.None; + this.WindowState = FormWindowState.Maximized; + } this.Show(); - - PUB.Result.TargetPosSet += Display_Position_TargetPosSet; - - this.ctlPos1.ClearData(); - this.ctlPos1.Invalidate(); - - //lbDM1.Text = ""; - //sbBatteryLv.Text = ""; - btHome.Text = "홈"; - btChargeA.Text = "자동충전"; - VAR.STR[eVarString.SWVersion] = Application.ProductVersion; Application.DoEvents(); - //setting dio events + VAR.STR[eVarString.SWVersion] = Application.ProductVersion; + + //SETTING H/W this.IOState.ItemClick += gridView2_ItemClick; - //PUB.flag.ValueChanged += Flag_ValueChagned; VAR.BOOL.PropertyChanged += BOOL_PropertyChanged; - - /////모터용 pLC - //PUB.PLC = new arDev.FakePLC(); - //PUB.PLC.ValueChanged += PLC_DioChanged; - //PUB.PLC.FlagChanged += PLC_FlagChanged; - //PUB.PLC.Message += PLC_Message; - //지그비통신 PUB.XBE = new Device.Xbee(); PUB.XBE.MessageReceived += XBE_MessageReceived; PUB.XBE.ProtocReceived += XBE_ProtocReceived; - //HWState.setTitle(1, 3, Pub.setting.Port_Xbee); - //HWState.setTitle(1, 0, Pub.setting.Address_RFID); - //AGV PUB.AGV = new arDev.Narumi(); PUB.AGV.Message += AGV_Message; PUB.AGV.DataReceive += AGV_DataReceive; - //배터리관리시스템 PUB.BMS = new arDev.BMS(); PUB.BMS.BMSDataReceive += Bms_BMSDataReceive; @@ -266,19 +233,11 @@ namespace Project } PUB.sm.StepChanged += sm_StepChanged; - PUB.log.Add("StateMachine", "StepChanged 이벤트 등록 완료"); - PUB.sm.Message += sm_Message; - PUB.log.Add("StateMachine", "Message 이벤트 등록 완료"); - PUB.sm.Running += sm_Running; - PUB.log.Add("StateMachine", "Running 이벤트 등록 완료"); - PUB.sm.SPS += sm_SPS; - PUB.log.Add("StateMachine", "SPS 이벤트 등록 완료"); - PUB.sm.Start(); - PUB.log.Add("StateMachine", $"Start() 호출 완료 - IsThreadRun:{PUB.sm.IsThreadRun}"); + PUB.log.Add("StateMachine", "SM 이벤트 등록 완료"); // 스레드 시작 대기 (최대 3초) for (int i = 0; i < 30; i++) @@ -307,10 +266,8 @@ namespace Project PUB.log.Add("Display", "Display Timer 시작 완료"); this.btDebug.Visible = System.Diagnostics.Debugger.IsAttached || PUB.setting.UseDebugMode; - PUB.log.Add("Program Start"); - //수량표시 PUB.counter.PropertyChanged += (s1, e1) => Update_Count(); Update_Count(); @@ -322,11 +279,8 @@ namespace Project MenuLog.PerformClick(); PUB.AddEEDB("프로그램 시작"); - } - - #region "Mouse Form Move" private Boolean fMove = false; @@ -417,12 +371,12 @@ namespace Project void func_sw_start(bool Prompt = false) { - if (PUB.sm.Step < eSMStep.IDLE) + if (PUB.sm.Step == eSMStep.SYNC) { UTIL.MsgE("초기화 중에는 사용할 수 없습니다\n초기화가 완료 된 후 시도하세요"); return; } - if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == false || PUB.sm.Step != eSMStep.RUN) //자동상태가 아니라면 + if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == false) //자동상태가 아니라면 { PUB.AGV.AGVErrorReset(); if (Prompt) @@ -433,9 +387,13 @@ namespace Project //충전상태확인 if (PUB.CheckManualChargeMode() == false) return; PUB.popup.needClose = true; - PUB.sm.bPause = false; + //PUB.sm.bPause = false; + //PUB.sm.ClearRunStep(); + //PUB.sm.SetNewRunStep(ERunStep.READY); PUB.sm.SetNewStep(eSMStep.RUN); - PUB.Speak(Lang.자동전환); + PUB.Speak(Lang.자동전환, addlog: false); + + PUB.log.Add($"자동전환 이전스텝:{PUB.sm.RunStep},IDX:{PUB.sm.RunStepSeq}]"); } else { @@ -489,31 +447,6 @@ namespace Project } - private void CtlPos1_ItemClick(object sender, CtlPos.ItemClickEventArgs e) - { - if (VAR.BOOL[eVarBool.FLAG_CHARGEONM] == true) - { - UTIL.MsgE("수동 충전 상태이므로 진행 할 수 없습니다"); - return; - } - if (VAR.BOOL[eVarBool.EMERGENCY] == true) - { - var dlgE = UTIL.MsgQ("비상정지 상태입니다.\n오류를 먼저 소거하고 실행 할까요?"); - if (dlgE == DialogResult.Yes) PUB.AGV.AGVErrorReset(); - else return; - } - //위치표시 컨트롤에서 아이템을 클릭했다 - var dlg = new Dialog.fJobSelect(); - PUB.log.Add("사용자 임의 위치 클릭 : " + e.Item.Title); - switch (e.Item.Position) - { - - - - } - if (dlg != null) dlg.Dispose(); - } - private void demoRunToolStripMenuItem_Click(object sender, EventArgs e) { PUB.Result.JobEndTime = DateTime.Now; @@ -577,6 +510,7 @@ namespace Project } VAR.BOOL[eVarBool.FLAG_SETUP] = false;// VAR.BOOL[eVarBool.FLAG_SETUP] = false;//VAR.BOOL[eVarBool.FLAG_SETUP] = false; + if (popmsg) PUB.popup.Visible = true; } @@ -681,7 +615,10 @@ namespace Project if (dlg == DialogResult.Yes) { PUB.sm.ClearRunStep(); - PUB.sm.SetNewRunStep(ERunStep.GOHOME); + //대상노드를 충전기로하고 + PUB._virtualAGV.StartNode = null; + PUB._virtualAGV.TargetNode = null; + PUB.sm.SetNewRunStep(ERunStep.GOTO); PUB.sm.SetNewStep(eSMStep.RUN); PUB.log.Add("사용자 충전 해제"); } @@ -720,26 +657,23 @@ namespace Project } private void brHome_Click(object sender, EventArgs e) { - var bCharge = PUB.sm.Step == eSMStep.RUN && - (PUB.sm.RunStep == ERunStep.GOHOME); - if (PUB.CheckManualChargeMode() == false) return; - if (bCharge == true) + var bHome = PUB.sm.Step == eSMStep.RUN && (PUB.sm.RunStep == ERunStep.GOHOME); + if (bHome == true) { - var dlg = UTIL.MsgQ("홈(QC) 이동을 취소 할까요?"); + var dlg = UTIL.MsgQ("홈 이동을 취소 할까요?"); if (dlg == DialogResult.Yes) { PUB.sm.ClearRunStep(); PUB.sm.SetNewStep(eSMStep.IDLE); PUB.AGV.AGVMoveStop("user home cancle", arDev.Narumi.eStopOpt.Stop); - //PUB.AGV.AddCommand(arDev.Narumi.eAgvCmd.MoveStop);//.Move(Device.PLC.Rundirection.Stop, "사용자 홈 이동 취소"); PUB.log.Add("사용자 홈 이동 취소"); } } else { - var dlg = UTIL.MsgQ("홈(QC) 이동을 실행 할까요?"); + var dlg = UTIL.MsgQ("홈 이동을 실행 할까요?"); if (dlg == DialogResult.Yes) { PUB.sm.ClearRunStep(); @@ -748,7 +682,6 @@ namespace Project PUB.log.Add("사용자 홈 이동 실행"); } } - } @@ -869,6 +802,7 @@ namespace Project { var _mapCanvas = PUB._mapCanvas; PUB._mapNodes = result.Nodes; + PUB.log.Add($"Set _mapNodes"); // 맵 캔버스에 데이터 설정 _mapCanvas.Nodes = result.Nodes; diff --git a/Cs_HMI/Project/fSetup.Designer.cs b/Cs_HMI/Project/fSetup.Designer.cs index 2313378..a03ab1e 100644 --- a/Cs_HMI/Project/fSetup.Designer.cs +++ b/Cs_HMI/Project/fSetup.Designer.cs @@ -175,7 +175,6 @@ this.tbMCID = new System.Windows.Forms.TextBox(); this.label4 = new System.Windows.Forms.Label(); this.chkDetectManualCharge = new System.Windows.Forms.CheckBox(); - this.chkAGVDirBack = new System.Windows.Forms.CheckBox(); this.chkFullScreen = new System.Windows.Forms.CheckBox(); this.nudMusicVol = new System.Windows.Forms.NumericUpDown(); this.label22 = new System.Windows.Forms.Label(); @@ -251,7 +250,7 @@ this.tabControl1.Multiline = true; this.tabControl1.Name = "tabControl1"; this.tabControl1.SelectedIndex = 0; - this.tabControl1.Size = new System.Drawing.Size(1270, 598); + this.tabControl1.Size = new System.Drawing.Size(1270, 578); this.tabControl1.TabIndex = 14; // // tabPage6 @@ -259,7 +258,7 @@ this.tabPage6.Controls.Add(this.panel1); this.tabPage6.Location = new System.Drawing.Point(4, 4); this.tabPage6.Name = "tabPage6"; - this.tabPage6.Size = new System.Drawing.Size(1244, 590); + this.tabPage6.Size = new System.Drawing.Size(1244, 570); this.tabPage6.TabIndex = 6; this.tabPage6.Text = "일반"; this.tabPage6.UseVisualStyleBackColor = true; @@ -276,19 +275,21 @@ // // tableLayoutPanel1 // + this.tableLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.tableLayoutPanel1.ColumnCount = 2; this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); - this.tableLayoutPanel1.Controls.Add(this.btMusic, 0, 1); this.tableLayoutPanel1.Controls.Add(this.btAutoCharge, 1, 0); this.tableLayoutPanel1.Controls.Add(this.btSpeaker, 0, 0); - this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; - this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 0); + this.tableLayoutPanel1.Controls.Add(this.btMusic, 0, 1); + this.tableLayoutPanel1.Location = new System.Drawing.Point(17, 17); this.tableLayoutPanel1.Name = "tableLayoutPanel1"; this.tableLayoutPanel1.RowCount = 2; this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); - this.tableLayoutPanel1.Size = new System.Drawing.Size(1238, 648); + this.tableLayoutPanel1.Size = new System.Drawing.Size(1227, 550); this.tableLayoutPanel1.TabIndex = 24; // // btMusic @@ -308,7 +309,7 @@ this.btMusic.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical; this.btMusic.GradientRepeatBG = false; this.btMusic.isButton = true; - this.btMusic.Location = new System.Drawing.Point(3, 327); + this.btMusic.Location = new System.Drawing.Point(3, 278); this.btMusic.MouseDownColor = System.Drawing.Color.Yellow; this.btMusic.MouseOverColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); this.btMusic.msg = null; @@ -328,7 +329,7 @@ this.btMusic.SignAlign = System.Drawing.ContentAlignment.BottomRight; this.btMusic.SignColor = System.Drawing.Color.Yellow; this.btMusic.SignFont = new System.Drawing.Font("Consolas", 7F, System.Drawing.FontStyle.Italic); - this.btMusic.Size = new System.Drawing.Size(613, 318); + this.btMusic.Size = new System.Drawing.Size(607, 269); this.btMusic.TabIndex = 23; this.btMusic.Tag = "2"; this.btMusic.Text = "배경음악"; @@ -354,7 +355,7 @@ this.btAutoCharge.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical; this.btAutoCharge.GradientRepeatBG = false; this.btAutoCharge.isButton = true; - this.btAutoCharge.Location = new System.Drawing.Point(622, 3); + this.btAutoCharge.Location = new System.Drawing.Point(616, 3); this.btAutoCharge.MouseDownColor = System.Drawing.Color.Yellow; this.btAutoCharge.MouseOverColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); this.btAutoCharge.msg = null; @@ -374,7 +375,7 @@ this.btAutoCharge.SignAlign = System.Drawing.ContentAlignment.BottomRight; this.btAutoCharge.SignColor = System.Drawing.Color.Yellow; this.btAutoCharge.SignFont = new System.Drawing.Font("Consolas", 7F, System.Drawing.FontStyle.Italic); - this.btAutoCharge.Size = new System.Drawing.Size(613, 318); + this.btAutoCharge.Size = new System.Drawing.Size(608, 269); this.btAutoCharge.TabIndex = 20; this.btAutoCharge.Tag = "1"; this.btAutoCharge.Text = "자동충전"; @@ -420,7 +421,7 @@ this.btSpeaker.SignAlign = System.Drawing.ContentAlignment.BottomRight; this.btSpeaker.SignColor = System.Drawing.Color.Yellow; this.btSpeaker.SignFont = new System.Drawing.Font("Consolas", 7F, System.Drawing.FontStyle.Italic); - this.btSpeaker.Size = new System.Drawing.Size(613, 318); + this.btSpeaker.Size = new System.Drawing.Size(607, 269); this.btSpeaker.TabIndex = 11; this.btSpeaker.Tag = "0"; this.btSpeaker.Text = "음성지원"; @@ -481,7 +482,7 @@ this.tabPage1.Location = new System.Drawing.Point(4, 4); this.tabPage1.Name = "tabPage1"; this.tabPage1.Padding = new System.Windows.Forms.Padding(3); - this.tabPage1.Size = new System.Drawing.Size(1244, 590); + this.tabPage1.Size = new System.Drawing.Size(1244, 570); this.tabPage1.TabIndex = 0; this.tabPage1.Text = "AGV"; // @@ -1640,7 +1641,7 @@ this.label44.AutoSize = true; this.label44.Font = new System.Drawing.Font("궁서체", 18F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129))); this.label44.ForeColor = System.Drawing.Color.WhiteSmoke; - this.label44.Location = new System.Drawing.Point(473, 546); + this.label44.Location = new System.Drawing.Point(1152, 201); this.label44.Name = "label44"; this.label44.Size = new System.Drawing.Size(49, 24); this.label44.TabIndex = 64; @@ -1651,7 +1652,7 @@ this.label29.AutoSize = true; this.label29.Font = new System.Drawing.Font("궁서체", 18F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129))); this.label29.ForeColor = System.Drawing.Color.SkyBlue; - this.label29.Location = new System.Drawing.Point(51, 546); + this.label29.Location = new System.Drawing.Point(730, 201); this.label29.Name = "label29"; this.label29.Size = new System.Drawing.Size(211, 24); this.label29.TabIndex = 62; @@ -1706,7 +1707,7 @@ this.label28.AutoSize = true; this.label28.Font = new System.Drawing.Font("궁서체", 18F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129))); this.label28.ForeColor = System.Drawing.Color.SkyBlue; - this.label28.Location = new System.Drawing.Point(138, 503); + this.label28.Location = new System.Drawing.Point(817, 158); this.label28.Name = "label28"; this.label28.Size = new System.Drawing.Size(124, 24); this.label28.TabIndex = 29; @@ -1913,7 +1914,7 @@ this.vcChargeWaitSec.FontSideButton = new System.Drawing.Font("Consolas", 15F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.vcChargeWaitSec.ForeColor = System.Drawing.Color.WhiteSmoke; this.vcChargeWaitSec.ForeColorButton = System.Drawing.Color.Black; - this.vcChargeWaitSec.Location = new System.Drawing.Point(270, 540); + this.vcChargeWaitSec.Location = new System.Drawing.Point(949, 195); this.vcChargeWaitSec.MaxValue = 999999D; this.vcChargeWaitSec.MinValue = 0D; this.vcChargeWaitSec.Name = "vcChargeWaitSec"; @@ -1937,7 +1938,7 @@ this.tbChargerID.FontSideButton = new System.Drawing.Font("Consolas", 15F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.tbChargerID.ForeColor = System.Drawing.Color.WhiteSmoke; this.tbChargerID.ForeColorButton = System.Drawing.Color.Black; - this.tbChargerID.Location = new System.Drawing.Point(270, 497); + this.tbChargerID.Location = new System.Drawing.Point(949, 152); this.tbChargerID.MaxValue = 999999D; this.tbChargerID.MinValue = 0D; this.tbChargerID.Name = "tbChargerID"; @@ -2729,7 +2730,6 @@ this.groupBox3.Controls.Add(this.propertyGrid1); this.groupBox3.Controls.Add(this.groupBox1); this.groupBox3.Controls.Add(this.chkDetectManualCharge); - this.groupBox3.Controls.Add(this.chkAGVDirBack); this.groupBox3.Controls.Add(this.chkFullScreen); this.groupBox3.Controls.Add(this.nudMusicVol); this.groupBox3.Controls.Add(this.label22); @@ -2765,7 +2765,7 @@ this.propertyGrid1.Font = new System.Drawing.Font("맑은 고딕", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129))); this.propertyGrid1.Location = new System.Drawing.Point(678, 109); this.propertyGrid1.Name = "propertyGrid1"; - this.propertyGrid1.Size = new System.Drawing.Size(538, 448); + this.propertyGrid1.Size = new System.Drawing.Size(538, 426); this.propertyGrid1.TabIndex = 11; // // groupBox1 @@ -2806,18 +2806,6 @@ this.chkDetectManualCharge.Text = "수동 충전 감지"; this.chkDetectManualCharge.UseVisualStyleBackColor = true; // - // chkAGVDirBack - // - this.chkAGVDirBack.AutoSize = true; - this.chkAGVDirBack.Font = new System.Drawing.Font("궁서체", 20F, System.Drawing.FontStyle.Bold); - this.chkAGVDirBack.ForeColor = System.Drawing.Color.Red; - this.chkAGVDirBack.Location = new System.Drawing.Point(27, 72); - this.chkAGVDirBack.Name = "chkAGVDirBack"; - this.chkAGVDirBack.Size = new System.Drawing.Size(619, 31); - this.chkAGVDirBack.TabIndex = 8; - this.chkAGVDirBack.Text = "FVI 이동시 Backward 방향으로 이동 합니다"; - this.chkAGVDirBack.UseVisualStyleBackColor = true; - // // chkFullScreen // this.chkFullScreen.AutoSize = true; @@ -3374,13 +3362,13 @@ this.btSave.ColorTheme = arCtl.arLabel.eColorTheme.Custom; this.btSave.Cursor = System.Windows.Forms.Cursors.Hand; this.btSave.Dock = System.Windows.Forms.DockStyle.Bottom; - this.btSave.Font = new System.Drawing.Font("궁서체", 21.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129))); + this.btSave.Font = new System.Drawing.Font("궁서체", 30F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129))); this.btSave.ForeColor = System.Drawing.Color.White; this.btSave.GradientEnable = true; this.btSave.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.ForwardDiagonal; this.btSave.GradientRepeatBG = false; this.btSave.isButton = true; - this.btSave.Location = new System.Drawing.Point(5, 740); + this.btSave.Location = new System.Drawing.Point(5, 720); this.btSave.MouseDownColor = System.Drawing.Color.Yellow; this.btSave.MouseOverColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); this.btSave.msg = null; @@ -3400,7 +3388,7 @@ this.btSave.SignAlign = System.Drawing.ContentAlignment.BottomRight; this.btSave.SignColor = System.Drawing.Color.Yellow; this.btSave.SignFont = new System.Drawing.Font("Consolas", 7F, System.Drawing.FontStyle.Italic); - this.btSave.Size = new System.Drawing.Size(1270, 55); + this.btSave.Size = new System.Drawing.Size(1270, 75); this.btSave.TabIndex = 8; this.btSave.Text = "저장"; this.btSave.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; @@ -3569,7 +3557,6 @@ private AGVControl.ValueSelect vcChargeStartLevel; private AGVControl.ValueSelect vcChargeMaxLevel; private System.Windows.Forms.GroupBox groupBox3; - private System.Windows.Forms.CheckBox chkAGVDirBack; private System.Windows.Forms.CheckBox chkFullScreen; private System.Windows.Forms.NumericUpDown nudMusicVol; private System.Windows.Forms.Label label22; diff --git a/Cs_HMI/Project/fSetup.cs b/Cs_HMI/Project/fSetup.cs index ba3abc7..98521c8 100644 --- a/Cs_HMI/Project/fSetup.cs +++ b/Cs_HMI/Project/fSetup.cs @@ -116,10 +116,7 @@ namespace Project SetColorValue(btSpeaker, PUB.setting.Enable_Speak); SetColorValue(btAutoCharge, PUB.setting.Enable_AutoCharge); SetColorValue(btMusic, PUB.setting.Enable_Music); - - nudDoorSoundTerm.Value = PUB.setting.doorSoundTerm; - chkAGVDirBack.Checked = PUB.setting.AGV_Direction_FVI_Backward; - + nudDoorSoundTerm.Value = PUB.setting.alarmSoundTerm; chkClear1.Checked = PUB.setting.datetime_Check_1; chkClear2.Checked = PUB.setting.datetime_Check_2; cleartime1.Value = DateTime.Parse("1982-11-23 " + PUB.setting.datetime_Reset_1 + ":00"); @@ -299,7 +296,6 @@ namespace Project PUB.setting.ChargeMaxTime = (int)vcChargeMaxTime.Value; //Pub.setting.ChargeIdleInterval = (int)nudChargeIdleInterval.Value; PUB.setting.ChargeRetryTerm = (int)vcChargeRetryTerm.Value; - PUB.setting.AGV_Direction_FVI_Backward = chkAGVDirBack.Checked; //초기화시간 PUB.setting.datetime_Check_1 = chkClear1.Checked; @@ -340,8 +336,8 @@ namespace Project PUB.SetVolume((int)nudMusicVol.Value); PUB.setting.ChargeSearchTime = (int)vcChargeSearchTime.Value; - PUB.setting.doorSoundTerm = (int)nudDoorSoundTerm.Value; - if (PUB.setting.doorSoundTerm < 1) PUB.setting.doorSoundTerm = 15; //기본값 15초 + PUB.setting.alarmSoundTerm = (int)nudDoorSoundTerm.Value; + if (PUB.setting.alarmSoundTerm < 1) PUB.setting.alarmSoundTerm = 15; //기본값 15초 ////핀설정 //var baL = new System.Collections.BitArray(new byte[] { PUB.setting.PinReverse_DI_Low }); diff --git a/Cs_HMI/CLAUDE.md b/Cs_HMI/README.md similarity index 78% rename from Cs_HMI/CLAUDE.md rename to Cs_HMI/README.md index 6d5b480..4d08d3a 100644 --- a/Cs_HMI/CLAUDE.md +++ b/Cs_HMI/README.md @@ -1,4 +1,74 @@ -# CLAUDE.md +# ENIG AGV Control System Documentation + +## 개요 +이 문서는 ENIG AGV (Automated Guided Vehicle) 제어 소프트웨어의 동작 및 기능에 대한 기술 문서입니다. 본 시스템은 C# 기반의 상태 머신(State Machine) 아키텍처를 사용하여 AGV의 주행, 충전, 자재 이송 등의 작업을 제어합니다. + +> **참고**: 현재 기능 개발이 진행 중이며, 일부 시퀀스는 변경될 수 있습니다. + +## 핵심 기능 (Core Functionality) + +### 1. 대기 및 준비 (IDLE / READY) +- **상태 파일**: `_SM_RUN_READY.cs` +- **기능**: + - AGV가 작업을 수행하지 않을 때의 기본 상태입니다. + - **자동 충전 모니터링**: 배터리 레벨을 지속적으로 확인하여 설정된 임계값 이하로 떨어지거나, 유휴 시간이 길어지면 자동으로 충전 시퀀스로 전환합니다. + - **충전 완료 체크**: 충전 중일 경우 최대 충전 시간 또는 목표 전압에 도달하면 충전을 중단하고 대기 상태로 복귀합니다. + - **정차 유지**: 대기 모드에서 AGV가 움직이지 않도록 지속적으로 정지 명령을 수행합니다. + +### 2. 목적지 이동 (GOTO) +- **상태 파일**: `_SM_RUN_GOTO.cs` +- **기능**: + - 지정된 RFID 태그(노드)로 이동하는 주행 로직입니다. + - **경로 예측 (Prediction)**: 현재 위치에서 목적지까지의 경로를 계산하고, 필요한 회전(Turn)이나 분기 동작을 결정합니다. + - **속도 제어**: 직선 구간, 코너, 정지 전 감속 등 상황에 맞춰 속도(High, Mid, Low)를 조절합니다. + - **장애물 감지**: 주행 중 전방 장애물이 감지되면 즉시 정지하거나 감속합니다. + +### 3. 충전 시퀀스 (CHARGE) +- **상태 파일**: `_SM_RUN_GOCHARGE.cs`, `_SM_RUN_GOCHARGECHECK.cs` +- **기능**: + - **충전기 이동**: 충전 스테이션의 RFID 위치를 찾아 이동합니다. + - **정밀 도킹**: 충전기 앞에서 정밀하게 위치를 조정하여 도킹합니다. + - **충전 시작/종료**: BMS(Battery Management System)와 통신하여 충전을 시작하고 상태를 모니터링합니다. + +## 특수 시퀀스 (Special Sequences) + +버퍼(Buffer) 스테이션에서의 자재 로딩/언로딩을 위한 특수 동작 시퀀스입니다. + +### 1. 버퍼 진입 (BUFFER IN) +- **상태 파일**: `_SM_RUN_BUFFER_IN.cs` +- **동작 순서**: + 1. **진입 전 확인**: 하드웨어 상태 및 위치 확인. + 2. **회전 (Turn)**: 버퍼 진입을 위해 필요한 각도로 회전 (주로 180도 턴). + 3. **리프트 다운 (Lift Down)**: 자재 적재를 위해 리프트를 하강 (코드상 확인 필요). + 4. **후진 진입**: 저속으로 후진하여 버퍼 스테이션에 진입. + 5. **마크 감지 정지**: 정지 마크를 감지하여 정확한 위치에 정차. + +### 2. 버퍼 이탈 (BUFFER OUT) +- **상태 파일**: `_SM_RUN_BUFFER_OUT.cs` +- **동작 순서**: + 1. **전진 이동**: 저속으로 전진하여 버퍼 스테이션을 빠져나옵니다. + 2. **마크 스톱**: 이탈 완료 지점의 마크를 감지하여 정지합니다. + 3. **회전 (Turn)**: 주행 방향으로 복귀하기 위해 우측 180도 회전을 수행합니다. + +### 3. 동기화 (SYNC) +- **상태 파일**: `_SM_RUN_SYNC.cs` +- **기능**: + - 프로그램 시작 시 또는 연결 복구 시 AGV 하드웨어와 소프트웨어 간의 설정을 동기화합니다. + - 속도 PID 제어값, 주행 파라미터 등을 장비로 전송하고 확인(ACK) 받습니다. + - **UI 표시**: 동기화 진행률을 화면에 표시하여 사용자가 상태를 알 수 있게 합니다. + +## 안전 기능 (Safety Features) +- **장애물 감지**: LiDAR 또는 센서를 통해 전방 물체 감지 시 음성 안내("전방에 물체가 감지되었습니다")와 함께 정지. +- **통신 타임아웃**: 하드웨어(AGV, BMS, XBee)와의 통신이 끊기면 에러 상태로 전환하거나 재연결을 시도. +- **비상 정지**: 소프트웨어적 비상 정지 및 하드웨어 E-Stop 상태 감지. + +## 개발 상태 +- 현재 기본 주행 및 충전 기능은 구현되어 있으나, 버퍼 시퀀스 및 예외 처리에 대한 고도화 작업이 진행 중입니다. +- 맵 에디터(`UnifiedAGVCanvas`)와 연동하여 실시간 모니터링 및 시뮬레이션 기능을 강화하고 있습니다. + +--- + +# 기존 CLAUDE.md 내용 (참고용) 이 파일은 이 저장소의 코드로 작업할 때 Claude Code (claude.ai/code)를 위한 지침을 제공합니다. 맵데이터는 C:\Data\Source\(5613#) ENIG AGV\Source\Cs_HMI\Data\NewMap.agvmap 파일을 기준으로 사용 @@ -343,4 +413,4 @@ AGVNavigationCore/ ### 🚨 알려진 이슈 - **빌드 환경**: MSBuild 2022가 설치되지 않은 환경에서 빌드 불가 -- **좌표 시스템**: 줌/팬 상태에서 좌표 변환 정확성 지속 모니터링 필요 \ No newline at end of file +- **좌표 시스템**: 줌/팬 상태에서 좌표 변환 정확성 지속 모니터링 필요 diff --git a/Cs_HMI/StateMachine/EnumStruct.cs b/Cs_HMI/StateMachine/EnumStruct.cs index 475b635..f792428 100644 --- a/Cs_HMI/StateMachine/EnumStruct.cs +++ b/Cs_HMI/StateMachine/EnumStruct.cs @@ -45,17 +45,13 @@ namespace Project.StateMachine /// public enum ERunStep : byte { - /// /// 자동모드 대기상태 /// READY = 0, - /// - /// 홈(QC)로 이동합니다 - /// GOHOME, - + /// /// 충전을 해제 함 /// @@ -66,7 +62,6 @@ namespace Project.StateMachine /// GOCHARGE, - /// /// 충전중 /// diff --git a/Cs_HMI/SubProject/AGV/EnumData.cs b/Cs_HMI/SubProject/AGV/EnumData.cs index 1e57b04..bd7ca92 100644 --- a/Cs_HMI/SubProject/AGV/EnumData.cs +++ b/Cs_HMI/SubProject/AGV/EnumData.cs @@ -15,7 +15,7 @@ namespace arDev public enum eMoveSpd { High, - Middle, + Mid, Low, } public enum eSetPIDSpeed @@ -73,12 +73,12 @@ namespace arDev else if (bunki == 'R') Bunki = eBunki.Right; if (speed == 'H') this.Speed = eMoveSpd.High; - else if (speed == 'M') this.Speed = eMoveSpd.Middle; + else if (speed == 'M') this.Speed = eMoveSpd.Mid; else if (speed == 'L') this.Speed = eMoveSpd.Low; } public eMoveDir Direction { get; set; } = eMoveDir.Forward; public eBunki Bunki { get; set; } = eBunki.Strate; - public eMoveSpd Speed { get; set; } = eMoveSpd.Middle; + public eMoveSpd Speed { get; set; } = eMoveSpd.Mid; public int PBSSensor { get; set; } = 1; public override string ToString() { diff --git a/Cs_HMI/SubProject/CommData/Enum.cs b/Cs_HMI/SubProject/CommData/Enum.cs index f95025f..c67c696 100644 --- a/Cs_HMI/SubProject/CommData/Enum.cs +++ b/Cs_HMI/SubProject/CommData/Enum.cs @@ -12,7 +12,7 @@ namespace COMM LPickOnCount, SumQty, ChargeWaitSec, - + SyncItemCount, } public enum eVarUInt32 { @@ -68,7 +68,7 @@ namespace COMM /// /// AGV 진행방향(UP = backward, DOWN = forward) /// - AGVDIR_UP, + AGVDIR_BACK, /// /// 마크센서가 감지되면 활성화됨 @@ -112,10 +112,7 @@ namespace COMM /// 충전시작명령을 전송했다 /// WAIT_CHARGEACK, - - MARKSTOP_ON, - - + //agv area start ( 64 ~ 95) @@ -177,6 +174,7 @@ namespace COMM /// ReadyStart, + MarkSensorOn, MarkSensorOff, /// @@ -209,5 +207,10 @@ namespace COMM /// 마지막으로 턴 명령을 전송한 시간 /// LastTurnCommandTime, + + /// + /// 마지막을 실행 명령을 전송한 시간 + /// + LastRunCommandTime, } } \ No newline at end of file diff --git a/Cs_HMI/docs/GOHOME_Analysis.md b/Cs_HMI/docs/GOHOME_Analysis.md new file mode 100644 index 0000000..cdc159d --- /dev/null +++ b/Cs_HMI/docs/GOHOME_Analysis.md @@ -0,0 +1,63 @@ +# GOHOME 상태 머신 분석 + +## 개요 +`GOHOME` 상태 머신(`_SM_RUN_GOHOME`)은 AGV를 현재 위치에서 미리 정의된 "Home" 노드로 이동시키는 역할을 합니다. 이 과정은 `_Util.cs`와 `VirtualAGV.cs`에 정의된 공유 경로 탐색 및 이동 로직을 활용합니다. + +## 로직 흐름 + +### 1. 초기화 및 안전 점검 +- **하드웨어 확인:** `PUB.AGV.IsOpen`을 확인합니다. 연결이 끊겨 있으면 에러 상태로 설정합니다. +- **충전 해제:** `_SM_RUN_CHGOFF`를 호출하여 AGV가 물리적으로 충전기에 연결되어 있지 않은지 확인합니다. + - *잠재적 문제:* 충전 센서가 고착(stuck)된 경우, 이 단계에서 무한 대기할 수 있습니다. +- **Lidar 안전:** `PUB.AGV.system1.stop_by_front_detect`를 확인합니다. 장애물이 감지되면 제거될 때까지 실행을 일시 중지(false 반환)합니다. + +### 2. 1단계: 목적지 설정 +- **홈 위치 조회:** `PUB.setting.NodeMAP_RFID_Home`에서 홈 노드 ID를 가져옵니다. +- **유효성 검사:** 맵에서 홈 노드를 찾을 수 없는 경우, 에러를 기록하고 `READY` 상태로 초기화합니다. +- **타겟 할당:** `PUB._virtualAGV.TargetNode`를 홈 노드로 설정합니다. + +### 3. 2단계: 이동 실행 +- **위임:** `_Util.cs`의 `UpdateMotionPositionForMark("_SM_RUN_GOHOME")`를 호출합니다. +- **경로 탐색:** + - 경로가 없거나 현재 경로가 유효하지 않은 경우, `_Util.cs`가 `CurrentNode`에서 `TargetNode`까지의 새로운 경로를 계산합니다. +- **예측 및 제어:** + - `VirtualAGV.Predict()`가 현재 노드와 경로를 기반으로 다음 행동을 결정합니다. + - **정지 조건:** `Predict()`가 `Stop`을 반환하는 경우: + - `IsPositionConfirmed`가 true인지 확인합니다. + - `CurrentNodeId`가 `TargetNode.NodeId`와 일치하는지 확인합니다. + - 둘 다 true이면 `true`(도착)를 반환합니다. + - **이동 조건:** `Predict()`가 이동 명령을 반환하는 경우: + - 논리적 명령(좌/우/직진, 전진/후진, 속도)을 하드웨어 명령(`AGVMoveSet`)으로 변환합니다. + - **최적화:** 상태가 변경된 경우에만 명령을 전송합니다 (최근 `_Util.cs` 업데이트에 구현됨). + - AGV가 구동 중인지 확인합니다 (`AGVMoveRun`). + +### 4. 3단계: 완료 +- **알림:** "홈 검색 완료" 음성을 출력합니다. +- **로깅:** 데이터베이스에 기록을 추가합니다. +- **전환:** 시퀀스를 업데이트하여 `GOHOME` 상태를 사실상 종료합니다. + +## 잠재적 문제 및 위험 요소 + +### 1. 충전 센서에 의한 무한 대기 +- **위험:** 충전 신호가 활성화되어 있는 한 `_SM_RUN_CHGOFF` 호출은 계속 `false`를 반환합니다. +- **시나리오:** 센서가 고장 나거나 시스템이 모르는 사이에 AGV가 수동으로 충전기에 밀려 올라간 경우, 여기서 멈출 수 있습니다. +- **완화:** `_SM_RUN_CHGOFF` 확인에 타임아웃이나 수동 오버라이드 기능을 추가해야 합니다 (현재 스니펫에서는 보이지 않음). + +### 2. 위치 상실 복구 +- **위험:** `_SM_RUN_POSCHK`(`UpdateMotionPositionForMark`에서 호출됨)가 태그를 찾지 못하면, AGV가 무한히 기어갈(crawl) 수 있거나 멈출 수 있습니다. +- **메커니즘:** `_SM_RUN_POSCHK`는 태그를 찾기 위해 저속 전진 명령을 내립니다. +- **시나리오:** AGV가 경로를 벗어났거나 데드존에 있는 경우, Lidar가 감지하지 못하면 충돌하거나 배회할 수 있습니다. + +### 3. 경로 재계산 루프 (확인됨: 안전함) +- **분석:** `_Util.cs` 코드를 확인한 결과, `CalcPath`가 실패하여 경로가 생성되지 않으면(`PathResult.result == null`) 즉시 `PUB.sm.SetNewRunStep(ERunStep.READY)`를 호출합니다. +- **결론:** 경로 계산 실패 시 상태 머신이 `READY` 상태로 전환되므로, 무한 루프나 반복적인 재계산 시도는 발생하지 않습니다. 안전하게 정지합니다. + +### 4. 통신 폭주 (해결됨) +- **이전 위험:** 동일한 이동 명령의 지속적인 전송. +- **해결:** 최근 `_Util.cs` 업데이트에서 `PUB.AGV.data`를 새 명령과 비교하여 변경 시에만 전송하도록 수정되었습니다. + +## 권장 사항 +1. **충전 해제 타임아웃:** 센서 고장 시 무한 대기를 방지하기 위해 `_SM_RUN_CHGOFF` 확인에 타임아웃을 추가하십시오. +2. **경로 실패 처리:** `CalcPath`가 null/empty를 반환하는지 명시적으로 확인하고, 무한 재시도 대신 에러와 함께 `GOHOME` 시퀀스를 중단하십시오. +3. **도착 확인:** `_Util.cs`의 "도착" 확인이 "거의 도착" 시나리오(예: 태그 약간 앞에서 정지)에 대해 견고한지 확인하십시오. 현재 로직은 `CurrentNodeId` 업데이트에 의존하며, 이는 양호해 보입니다. +