From 1a4b8a6a5489d7068567ec00d5f305c15cb48a0b Mon Sep 17 00:00:00 2001 From: backuppc Date: Tue, 3 Mar 2026 13:00:13 +0900 Subject: [PATCH] =?UTF-8?q?=EB=AA=A8=EB=93=A0=20=EA=B2=BD=EB=A1=9C?= =?UTF-8?q?=EB=A5=BC=20=EC=A0=84=EC=B2=B4=20=EC=A0=95=EC=9D=98=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=A0=84=20=EB=B0=B1=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PathFinding/Planning/AGVPathfinder.cs | 151 ++++++++++++++++-- AGVLogic/AGVSimulator/AGVSimulator.csproj | 22 +-- ...lock.통신 프로토콜_AGV_V350_LF_25.01.10_r2.xlsx# | 1 - 3 files changed, 153 insertions(+), 21 deletions(-) delete mode 100644 Document/통신프로토콜/.~lock.통신 프로토콜_AGV_V350_LF_25.01.10_r2.xlsx# diff --git a/AGVLogic/AGVNavigationCore/PathFinding/Planning/AGVPathfinder.cs b/AGVLogic/AGVNavigationCore/PathFinding/Planning/AGVPathfinder.cs index f02c1f5..31e0e5d 100644 --- a/AGVLogic/AGVNavigationCore/PathFinding/Planning/AGVPathfinder.cs +++ b/AGVLogic/AGVNavigationCore/PathFinding/Planning/AGVPathfinder.cs @@ -651,6 +651,28 @@ namespace AGVNavigationCore.PathFinding.Planning Path = new List { "7B", "11B", "3T", "3B", "11B", "7B", "8B", "9B", "20B", "34B", "33B", "32B", "31B", "35B", "36B" } }); + + //일반노드를 포함하여 모든 노드를 정의하자 + + /* 예시 + *retval.Add(new MapZonePathData { NodeSta = StationType.Plating, NodeEnd = StationType.Loader, Monitor = MapZoneMonitor.RightBtm, Path = new List { "72F", "11F", "3B", "71B" } }); + //retval.Add(new MapZonePathData { NodeSta = StationType.Plating, NodeEnd = StationType.Loader, Monitor = MapZoneMonitor.LeftTop, Path = new List { "72B", "11B", "3T", "3B", "71B" } }); + //retval.Add(new MapZonePathData { NodeSta = StationType.Plating, NodeEnd = StationType.Charger, Monitor = MapZoneMonitor.RightBtm, Path = new List { "72F", "11F", "3T", "3F", "11F", "7B", "10B", "6B", "73B" } }); + //retval.Add(new MapZonePathData { NodeSta = StationType.Plating, NodeEnd = StationType.Charger, Monitor = MapZoneMonitor.LeftTop, Path = new List { "72B", "11B", "3F", "11F", "7B", "10B", "6B", "73B" } }); + //retval.Add(new MapZonePathData { NodeSta = StationType.Plating, NodeEnd = StationType.Cleaner, Monitor = MapZoneMonitor.RightBtm, Path = new List { "72F", "11F", "3T", "3B", "70B" } }); + //retval.Add(new MapZonePathData { NodeSta = StationType.Plating, NodeEnd = StationType.Cleaner, Monitor = MapZoneMonitor.LeftTop, Path = new List { "72B", "11B", "3B", "70B" } }); + //retval.Add(new MapZonePathData { NodeSta = StationType.Plating, NodeEnd = StationType.Buffer, Monitor = MapZoneMonitor.RightBtm, Path = new List { "72F", "11B", "7B", "8B", "9B", "20B", "34B", "33B", "32B", "31B", "35B", "36B" } }); + //retval.Add(new MapZonePathData { NodeSta = StationType.Plating, NodeEnd = StationType.Buffer, Monitor = MapZoneMonitor.LeftTop, Path = new List { "72B", "11B", "3T", "3B", "11B", "7B", "8B", "9B", "20B", "34B", "33B", "32B", "31B", "35B", "36B" } }); + */ + + // 일반노드 6 -> + // 일반노드 10 -> + // 일반노드 11 -> + // 일반노드 8 -> + // 일반노드 9 -> + // 일반노드 20 -> + + return retval; } /// @@ -686,6 +708,14 @@ namespace AGVNavigationCore.PathFinding.Planning public AGVPathResult CalculateScriptedPath(MapNode startNode, MapNode targetNode, MapNode prevNode, AgvDirection prevDir) { + // 태그 내 숫자로 정확히 매칭하기 위한 람다 (예: 3을 찾을 때 "36"이 매칭되지 않도록) + Func matchNode = (tag, rfid) => + { + string idStr = ""; + foreach (char c in tag) if (char.IsDigit(c)) idStr += c; + return idStr == rfid.ToString(); + }; + var startZone = GetMapZone(startNode); var targetZone = GetMapZone(targetNode); @@ -855,14 +885,8 @@ namespace AGVNavigationCore.PathFinding.Planning { //위치는 현재위치이나 모니터방향이 일치하지 않으므로 턴을 한후 경로를 다시 찾아야한다. - // 태그 내 숫자로 정확히 매칭하기 위한 람다 (예: 3을 찾을 때 "36"이 매칭되지 않도록) - Func matchNode = (tag, rfid) => - { - string idStr = ""; - foreach (char c in tag) if (char.IsDigit(c)) idStr += c; - return idStr == rfid.ToString(); - }; - + //버퍼는 턴포인트까지는 항상B로 이동해야한다. + startTag = startNode.RfidId + "B"; // 1.현재위치에서 턴포인트(3)까지 이동하는 경로를 찾는다. var path1Candidate = zonepath.FirstOrDefault(d => { @@ -1018,11 +1042,108 @@ namespace AGVNavigationCore.PathFinding.Planning } } } + else if (startZone == MapZone.Loader && targetZone == MapZone.Loader) + { + //모니터가 아래에 있다면 방향이 일치하지 않으므로 턴(3)을 해야 한후 목표까지 이동해야한다 + if (monitorMode == MapZoneMonitor.RightBtm) + { + var newpath = new List { "71B", "3T", "3B", "71B" }; + int startIndex = newpath.FindIndex(p => matchNode(p, startNode.RfidId)); + if (startIndex != -1) newpath = newpath.Skip(startIndex).ToList(); + return ConvertHardcodedPathToResult(newpath, startNode, prevNode, prevDir); + } + else if (startNode.RfidId.Equals(targetNode.RfidId)) //시작과 목표가 같을경우 + { + var result = new AGVPathResult { Success = true }; + result.Path = new List { startNode }; + result.DetailedPath = new List { new NodeMotorInfo(1, startNode.Id, startNode.RfidId, prevDir, null, MagnetDirection.Straight, false) }; + result.TotalDistance = 0; + return result; + } + else + { + //시작과 목표가 다른경우이므로 현재위치에서 목표까지 단순경로 생성해서 반환하면 된다. + return this.FindBasicPath(startNode, targetNode, prevNode, prevDir); + } + } + else if (startZone == MapZone.Cleaner && targetZone == MapZone.Cleaner) + { + //모니터가 위에 있다면 방향이 일치하지 않으므로 턴(3)을 해야 한후 목표까지 이동해야한다 + if (monitorMode == MapZoneMonitor.LeftTop) + { + var newpath = new List { "70B", "3T", "3B", "70B" }; + int startIndex = newpath.FindIndex(p => matchNode(p, startNode.RfidId)); + if (startIndex != -1) newpath = newpath.Skip(startIndex).ToList(); + return ConvertHardcodedPathToResult(newpath, startNode, prevNode, prevDir); + } + else if (startNode.RfidId.Equals(targetNode.RfidId)) //시작과 목표가 같을경우 + { + var result = new AGVPathResult { Success = true }; + result.Path = new List { startNode }; + result.DetailedPath = new List { new NodeMotorInfo(1, startNode.Id, startNode.RfidId, prevDir, null, MagnetDirection.Straight, false) }; + result.TotalDistance = 0; + return result; + } + else + { + //시작과 목표가 다른경우이므로 현재위치에서 목표까지 단순경로 생성해서 반환하면 된다. + return this.FindBasicPath(startNode, targetNode, prevNode, prevDir); + } + } + else if (startZone == MapZone.Plating && targetZone == MapZone.Plating) + { + //모티너가 좌측에 있다면 방향이 일치하지 않으므로 턴(3)을 해야 한후 목표까지 이동해야한다. + if (monitorMode == MapZoneMonitor.LeftTop) + { + var newpath = new List { "72B", "11B", "3T", "3B", "11B", "72B" }; + int startIndex = newpath.FindIndex(p => matchNode(p, startNode.RfidId)); + if (startIndex != -1) newpath = newpath.Skip(startIndex).ToList(); + return ConvertHardcodedPathToResult(newpath, startNode, prevNode, prevDir); + } + else if (startNode.RfidId.Equals(targetNode.RfidId)) //시작과 목표가 같을경우 + { + var result = new AGVPathResult { Success = true }; + result.Path = new List { startNode }; + result.DetailedPath = new List { new NodeMotorInfo(1, startNode.Id, startNode.RfidId, prevDir, null, MagnetDirection.Straight, false) }; + result.TotalDistance = 0; + return result; + } + else + { + //시작과 목표가 다른경우이므로 현재위치에서 목표까지 단순경로 생성해서 반환하면 된다. + return this.FindBasicPath(startNode, targetNode, prevNode, prevDir); + } + } + else if (startZone == MapZone.Charger && targetZone == MapZone.Charger) + { + //모니터가 위에 있다면 방향이 일치하지 않으므로 턴(3)을 해야 한후 목표까지 이동해야한다 + if (monitorMode == MapZoneMonitor.LeftTop) + { + var newpath = new List { "73B", "6B", "10B", "7F", "11F", "3T", "3F", "11F", "7B", "10B", "6B", "73B" }; + int startIndex = newpath.FindIndex(p => matchNode(p, startNode.RfidId)); + if (startIndex != -1) newpath = newpath.Skip(startIndex).ToList(); + return ConvertHardcodedPathToResult(newpath, startNode, prevNode, prevDir); + } + else if (startNode.RfidId.Equals(targetNode.RfidId)) //시작과 목표가 같을경우 + { + var result = new AGVPathResult { Success = true }; + result.Path = new List { startNode }; + result.DetailedPath = new List { new NodeMotorInfo(1, startNode.Id, startNode.RfidId, prevDir, null, MagnetDirection.Straight, false) }; + result.TotalDistance = 0; + return result; + } + else + { + //시작과 목표가 다른경우이므로 현재위치에서 목표까지 단순경로 생성해서 반환하면 된다. + return this.FindBasicPath(startNode, targetNode, prevNode, prevDir); + } + } else { - //다른경우는 아직 처리하지 않는다 + // } + return AGVPathResult.CreateFailure("경로를 계산할 수 없습니다"); } @@ -1141,11 +1262,23 @@ namespace AGVNavigationCore.PathFinding.Planning { if (prevNode.RfidId == 20) return MapZoneMonitor.LeftTop; + else + { + int bdx = startNode.Position.X - prevNode.Position.X; + if (bdx < 0) return MapZoneMonitor.LeftTop; + else return MapZoneMonitor.RightBtm; + } } else if (prevDir == AgvDirection.Backward) { if (prevNode.RfidId == 20) return MapZoneMonitor.RightBtm; + else + { + int bdx = startNode.Position.X - prevNode.Position.X; + if (bdx < 0) return MapZoneMonitor.RightBtm; + else return MapZoneMonitor.LeftTop; + } } } diff --git a/AGVLogic/AGVSimulator/AGVSimulator.csproj b/AGVLogic/AGVSimulator/AGVSimulator.csproj index d1ec161..1155c05 100644 --- a/AGVLogic/AGVSimulator/AGVSimulator.csproj +++ b/AGVLogic/AGVSimulator/AGVSimulator.csproj @@ -45,6 +45,12 @@ + + Form + + + fMain.cs + @@ -56,20 +62,9 @@ - - Form - - - SimulatorForm.cs - - - - SimulatorForm.cs - - @@ -84,5 +79,10 @@ AGVMapEditor + + + fMain.cs + + \ No newline at end of file diff --git a/Document/통신프로토콜/.~lock.통신 프로토콜_AGV_V350_LF_25.01.10_r2.xlsx# b/Document/통신프로토콜/.~lock.통신 프로토콜_AGV_V350_LF_25.01.10_r2.xlsx# deleted file mode 100644 index 64e8f9a..0000000 --- a/Document/통신프로토콜/.~lock.통신 프로토콜_AGV_V350_LF_25.01.10_r2.xlsx# +++ /dev/null @@ -1 +0,0 @@ -,BACKUPPC/1,backuppc,26.02.2026 11:12,file:///C:/Users/1/AppData/Roaming/LibreOffice/4; \ No newline at end of file