enhance: Display RFID values in path UI and improve AGV lift direction visualization
- Replace NodeID with RFID values in path display for better field mapping
- Add ComboBoxItem<T> class for {rfid} - [{node}] format in combo boxes
- Implement GetRfidByNodeId helper method for NodeID to RFID conversion
- Enhanced UpdatePathDebugInfo to show both RFID and NodeID information
- Improved path visualization with RFID-based route display
- Users can now easily match displayed paths with physical RFID tags
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AGVNavigationCore.Models;
|
||||
|
||||
namespace AGVNavigationCore.PathFinding
|
||||
@@ -24,6 +25,11 @@ namespace AGVNavigationCore.PathFinding
|
||||
/// </summary>
|
||||
public List<AgvDirection> Commands { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 노드별 모터방향 정보 목록
|
||||
/// </summary>
|
||||
public List<NodeMotorInfo> NodeMotorInfos { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 총 거리
|
||||
/// </summary>
|
||||
@@ -57,6 +63,7 @@ namespace AGVNavigationCore.PathFinding
|
||||
Success = false;
|
||||
Path = new List<string>();
|
||||
Commands = new List<AgvDirection>();
|
||||
NodeMotorInfos = new List<NodeMotorInfo>();
|
||||
TotalDistance = 0;
|
||||
CalculationTimeMs = 0;
|
||||
EstimatedTimeSeconds = 0;
|
||||
@@ -87,6 +94,31 @@ namespace AGVNavigationCore.PathFinding
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 성공 결과 생성 (노드별 모터방향 정보 포함)
|
||||
/// </summary>
|
||||
/// <param name="path">경로</param>
|
||||
/// <param name="commands">AGV 명령어 목록</param>
|
||||
/// <param name="nodeMotorInfos">노드별 모터방향 정보</param>
|
||||
/// <param name="totalDistance">총 거리</param>
|
||||
/// <param name="calculationTimeMs">계산 시간</param>
|
||||
/// <returns>성공 결과</returns>
|
||||
public static AGVPathResult CreateSuccess(List<string> path, List<AgvDirection> commands, List<NodeMotorInfo> nodeMotorInfos, float totalDistance, long calculationTimeMs)
|
||||
{
|
||||
var result = new AGVPathResult
|
||||
{
|
||||
Success = true,
|
||||
Path = new List<string>(path),
|
||||
Commands = new List<AgvDirection>(commands),
|
||||
NodeMotorInfos = new List<NodeMotorInfo>(nodeMotorInfos),
|
||||
TotalDistance = totalDistance,
|
||||
CalculationTimeMs = calculationTimeMs
|
||||
};
|
||||
|
||||
result.CalculateMetrics();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 실패 결과 생성
|
||||
/// </summary>
|
||||
|
||||
@@ -159,7 +159,8 @@ namespace AGVNavigationCore.PathFinding
|
||||
}
|
||||
|
||||
var agvCommands = GenerateAGVCommands(result.Path, targetDirection ?? AgvDirection.Forward);
|
||||
return AGVPathResult.CreateSuccess(result.Path, agvCommands, result.TotalDistance, stopwatch.ElapsedMilliseconds);
|
||||
var nodeMotorInfos = GenerateNodeMotorInfos(result.Path);
|
||||
return AGVPathResult.CreateSuccess(result.Path, agvCommands, nodeMotorInfos, result.TotalDistance, stopwatch.ElapsedMilliseconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -182,7 +183,8 @@ namespace AGVNavigationCore.PathFinding
|
||||
}
|
||||
|
||||
var agvCommands = GenerateAGVCommands(result.Path, actualTargetDirection);
|
||||
return AGVPathResult.CreateSuccess(result.Path, agvCommands, result.TotalDistance, stopwatch.ElapsedMilliseconds);
|
||||
var nodeMotorInfos = GenerateNodeMotorInfos(result.Path);
|
||||
return AGVPathResult.CreateSuccess(result.Path, agvCommands, nodeMotorInfos, result.TotalDistance, stopwatch.ElapsedMilliseconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -264,6 +266,92 @@ namespace AGVNavigationCore.PathFinding
|
||||
return AgvDirection.Right;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 노드별 모터방향 정보 생성
|
||||
/// </summary>
|
||||
/// <param name="path">경로 노드 목록</param>
|
||||
/// <returns>노드별 모터방향 정보 목록</returns>
|
||||
private List<NodeMotorInfo> GenerateNodeMotorInfos(List<string> path)
|
||||
{
|
||||
var nodeMotorInfos = new List<NodeMotorInfo>();
|
||||
if (path.Count < 2) return nodeMotorInfos;
|
||||
|
||||
for (int i = 0; i < path.Count; i++)
|
||||
{
|
||||
var currentNodeId = path[i];
|
||||
string nextNodeId = i < path.Count - 1 ? path[i + 1] : null;
|
||||
|
||||
AgvDirection motorDirection;
|
||||
|
||||
if (i == path.Count - 1)
|
||||
{
|
||||
// 마지막 노드: 도킹/충전 노드 타입에 따라 결정
|
||||
if (_nodeMap.ContainsKey(currentNodeId))
|
||||
{
|
||||
var currentNode = _nodeMap[currentNodeId];
|
||||
motorDirection = GetRequiredDirectionForNode(currentNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
motorDirection = AgvDirection.Forward;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 중간 노드: 다음 노드와의 관계를 고려한 모터방향 결정
|
||||
motorDirection = CalculateMotorDirection(currentNodeId, nextNodeId);
|
||||
}
|
||||
|
||||
nodeMotorInfos.Add(new NodeMotorInfo(currentNodeId, motorDirection, nextNodeId));
|
||||
}
|
||||
|
||||
return nodeMotorInfos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 현재 노드에서 다음 노드로 이동할 때의 모터방향 계산
|
||||
/// </summary>
|
||||
/// <param name="currentNodeId">현재 노드 ID</param>
|
||||
/// <param name="nextNodeId">다음 노드 ID</param>
|
||||
/// <returns>모터방향</returns>
|
||||
private AgvDirection CalculateMotorDirection(string currentNodeId, string nextNodeId)
|
||||
{
|
||||
if (!_nodeMap.ContainsKey(currentNodeId) || !_nodeMap.ContainsKey(nextNodeId))
|
||||
{
|
||||
return AgvDirection.Forward;
|
||||
}
|
||||
|
||||
var currentNode = _nodeMap[currentNodeId];
|
||||
var nextNode = _nodeMap[nextNodeId];
|
||||
|
||||
// 현재 노드와 다음 노드의 위치를 기반으로 이동 방향 계산
|
||||
var dx = nextNode.Position.X - currentNode.Position.X;
|
||||
var dy = nextNode.Position.Y - currentNode.Position.Y;
|
||||
var moveAngle = Math.Atan2(dy, dx);
|
||||
|
||||
// AGV의 구조: 리프트 ↔ AGV 몸체 ↔ 모니터
|
||||
// 전진: 모니터 방향으로 이동 (리프트에서 멀어짐)
|
||||
// 후진: 리프트 방향으로 이동 (리프트에 가까워짐)
|
||||
|
||||
// 다음 노드가 특수 노드인지 확인
|
||||
if (nextNode.Type == NodeType.Charging)
|
||||
{
|
||||
// 충전기: 전진으로 도킹
|
||||
return AgvDirection.Forward;
|
||||
}
|
||||
else if (nextNode.Type == NodeType.Docking)
|
||||
{
|
||||
// 도킹 스테이션: 후진으로 도킹
|
||||
return AgvDirection.Backward;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 일반 이동: 기본적으로 전진
|
||||
// 향후 경로 패턴 분석을 통해 더 정확한 방향 결정 가능
|
||||
return AgvDirection.Forward;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 경로 유효성 검증
|
||||
/// </summary>
|
||||
|
||||
32
Cs_HMI/AGVNavigationCore/PathFinding/NodeMotorInfo.cs
Normal file
32
Cs_HMI/AGVNavigationCore/PathFinding/NodeMotorInfo.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using AGVNavigationCore.Models;
|
||||
|
||||
namespace AGVNavigationCore.PathFinding
|
||||
{
|
||||
/// <summary>
|
||||
/// 노드별 모터방향 정보
|
||||
/// </summary>
|
||||
public class NodeMotorInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 노드 ID
|
||||
/// </summary>
|
||||
public string NodeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 해당 노드에서의 모터방향
|
||||
/// </summary>
|
||||
public AgvDirection MotorDirection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 다음 노드 ID (경로예측용)
|
||||
/// </summary>
|
||||
public string NextNodeId { get; set; }
|
||||
|
||||
public NodeMotorInfo(string nodeId, AgvDirection motorDirection, string nextNodeId = null)
|
||||
{
|
||||
NodeId = nodeId;
|
||||
MotorDirection = motorDirection;
|
||||
NextNodeId = nextNodeId;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user