feat: Implement AGV command prediction system for real-time control

- Add motor/magnet/speed enums and AGVCommand class for AGV control
- Implement Predict() method for next action prediction based on path and state
- Add RFID position tracking (requires 2 RFIDs for position confirmation)
- Add SetPath() method to VirtualAGV for path management
- Implement GetCommandFromPath() to extract motor/magnet/speed from DetailedPath
- Add real-time prediction display in SimulatorForm (timer1_Tick)
- Support automatic forward movement at low speed when position unconfirmed
- Support stop command when destination reached or no destination set

Key Features:
- Position unconfirmed (RFID < 2): Forward + Straight + Low speed
- Position confirmed + no destination: Stop (position found)
- Position confirmed + destination reached: Stop (arrived)
- Path execution: Motor/Magnet/Speed from DetailedPath NodeMotorInfo
- Rotation nodes: Automatic low speed
- Junction handling: Magnet direction (Left/Right/Straight)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
backuppc
2025-11-03 17:34:35 +09:00
parent c3f8c7117d
commit 3712c290c9
7 changed files with 555 additions and 25 deletions

View File

@@ -111,7 +111,7 @@ namespace AGVNavigationCore.PathFinding.Planning
return null;
}
public AGVPathResult FindPath_test(MapNode startNode, MapNode targetNode,
public AGVPathResult FindPath(MapNode startNode, MapNode targetNode,
MapNode prevNode, AgvDirection prevDirection, AgvDirection currentDirection, bool crossignore = false)
{
// 입력 검증
@@ -154,6 +154,8 @@ namespace AGVNavigationCore.PathFinding.Planning
{
MakeDetailData(pathResult, currentDirection);
MakeMagnetDirection(pathResult);
for (int i = 0; i < pathResult.DetailedPath.Count; i++)
pathResult.DetailedPath[i].seq = i + 1;
return pathResult;
}
}
@@ -182,6 +184,8 @@ namespace AGVNavigationCore.PathFinding.Planning
{
MakeDetailData(pathResult, ReverseDirection);
MakeMagnetDirection(pathResult);
for (int i = 0; i < pathResult.DetailedPath.Count; i++)
pathResult.DetailedPath[i].seq = i + 1;
return pathResult;
}
}
@@ -196,6 +200,8 @@ namespace AGVNavigationCore.PathFinding.Planning
{
MakeDetailData(pathResult, currentDirection);
MakeMagnetDirection(pathResult);
for (int i = 0; i < pathResult.DetailedPath.Count; i++)
pathResult.DetailedPath[i].seq = i + 1;
return pathResult;
}
@@ -220,7 +226,7 @@ namespace AGVNavigationCore.PathFinding.Planning
Path0.PrevDirection = prevDirection;
MakeDetailData(Path0, prevDirection);
var Path1 = FindPath_test(nextNodeForward, targetNode, startNode, prevDirection, currentDirection, true);
var Path1 = FindPath(nextNodeForward, targetNode, startNode, prevDirection, currentDirection, true);
Path1.PrevNode = startNode;
Path1.PrevDirection = prevDirection;
//MakeDetailData(Path1, ReverseDirection);
@@ -228,6 +234,9 @@ namespace AGVNavigationCore.PathFinding.Planning
var combinedResult0 = Path0;
combinedResult0 = _basicPathfinder.CombineResults(combinedResult0, Path1);
MakeMagnetDirection(combinedResult0);
for (int i = 0; i < combinedResult0.DetailedPath.Count; i++)
combinedResult0.DetailedPath[i].seq = i + 1;
return combinedResult0;
}
else if (nextNodeBackward != null)
@@ -404,6 +413,8 @@ namespace AGVNavigationCore.PathFinding.Planning
MakeMagnetDirection(combinedResult);
for (int i = 0; i < combinedResult.DetailedPath.Count; i++)
combinedResult.DetailedPath[i].seq = i + 1;
return combinedResult;
@@ -427,7 +438,7 @@ namespace AGVNavigationCore.PathFinding.Planning
string nextNodeId = (i + 1 < path1.Path.Count) ? path1.Path[i + 1].NodeId : null;
// 노드 정보 생성 (현재 방향 유지)
var nodeInfo = new NodeMotorInfo(
var nodeInfo = new NodeMotorInfo(i+1,
nodeId, RfidId,
currentDirection,
nextNodeId,

View File

@@ -28,6 +28,10 @@ namespace AGVNavigationCore.PathFinding.Planning
/// </summary>
public class NodeMotorInfo
{
/// <summary>
/// 일련번호
/// </summary>
public int seq { get; set; }
/// <summary>
/// 노드 ID
/// </summary>
@@ -68,13 +72,19 @@ namespace AGVNavigationCore.PathFinding.Planning
/// </summary>
public bool RequiresSpecialAction { get; set; }
/// <summary>
/// 해당노드가 인식되면 이 값이 셋팅됩니다.
/// </summary>
public bool IsPass { get; set; }
/// <summary>
/// 특수 동작 설명
/// </summary>
public string SpecialActionDescription { get; set; }
public NodeMotorInfo(string nodeId,string rfid, AgvDirection motorDirection, string nextNodeId = null, MagnetDirection magnetDirection = MagnetDirection.Straight)
public NodeMotorInfo(int seqno,string nodeId,string rfid, AgvDirection motorDirection, string nextNodeId = null, MagnetDirection magnetDirection = MagnetDirection.Straight)
{
seq = seqno;
NodeId = nodeId;
RfidId = rfid;
MotorDirection = motorDirection;
@@ -84,6 +94,7 @@ namespace AGVNavigationCore.PathFinding.Planning
IsDirectionChangePoint = false;
RequiresSpecialAction = false;
SpecialActionDescription = string.Empty;
IsPass = false;
}