fix: Add motor direction parameter to magnet direction calculation in pathfinding

- Fixed critical issue in ConvertToDetailedPath where motor direction was not passed to GetRequiredMagnetDirection
- Motor direction is essential for backward movement as Left/Right directions must be inverted
- Modified AGVPathfinder.cs line 280 to pass currentDirection parameter
- Ensures backward motor direction properly inverts magnet sensor directions

feat: Add waypoint support to pathfinding system

- Added FindPath overload with params string[] waypointNodeIds in AStarPathfinder
- Supports sequential traversal through multiple intermediate nodes
- Validates waypoints and prevents duplicates in sequence
- Returns combined path result with aggregated metrics

feat: Implement path result merging with DetailedPath preservation

- Added CombineResults method in AStarPathfinder for intelligent path merging
- Automatically deduplicates nodes when last of previous path equals first of current
- Preserves DetailedPath information including motor and magnet directions
- Essential for multi-segment path operations

feat: Integrate magnet direction with motor direction awareness

- Modified JunctionAnalyzer.GetRequiredMagnetDirection to accept AgvDirection parameter
- Inverts Left/Right magnet directions when moving Backward
- Properly handles motor direction context throughout pathfinding

feat: Add automatic start node selection in simulator

- Added SetStartNodeToCombo method to SimulatorForm
- Automatically selects start node combo box when AGV position is set via RFID
- Improves UI usability and workflow efficiency

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
backuppc
2025-10-24 15:46:16 +09:00
parent 3ddecf63ed
commit d932b8d332
47 changed files with 7473 additions and 1088 deletions

View File

@@ -0,0 +1,276 @@
# AGV 방향 정보 저장 위치 분석
## 개요
AGV의 이동 방향을 계산하기 위해 **이전 RFID 위치 정보**와 **현재 모터 방향(전/후진)**을 함께 저장하고 관리하는 시스템
---
## 📍 저장 위치: VirtualAGV.cs (AGVSimulator\Models\VirtualAGV.cs)
### 핵심 필드 (Field) 구조
#### 현재 상태 (Current State)
```csharp
private Point _currentPosition; // 현재 AGV 위치 (픽셀 좌표)
private MapNode _currentNode; // 현재 노드 (RFID ID 포함)
private AgvDirection _currentDirection; // 현재 모터 방향 (Forward/Backward)
```
#### 이전 상태 (Previous State - 리프트 방향 계산용)
```csharp
private Point _targetPosition; // 이전 위치 (previousPos 역할)
private MapNode _targetNode; // 이전 노드 (이전 RFID)
private AgvDirection _targetDirection; // 이전 모터 방향
```
### 데이터 구조 시각화
```
이전 상태 (n-1) 현재 상태 (n)
────────────────────────────────────
_targetPosition ─────→ _currentPosition (좌표 이동)
_targetNode ─────→ _currentNode (RFID 이동)
_targetDirection ─────→ _currentDirection (모터 방향)
```
---
## 🔄 SetPosition() 메서드 - 위치 및 방향 업데이트
### 위치: VirtualAGV.cs 305~322행
```csharp
/// <summary>
/// AGV 위치 직접 설정 (시뮬레이터용)
/// TargetPosition을 이전 위치로 저장하여 리프트 방향 계산이 가능하도록 함
/// </summary>
/// <param name="node">현재 RFID 노드</param>
/// <param name="newPosition">새로운 위치</param>
/// <param name="motorDirection">모터이동방향 (Forward/Backward)</param>
public void SetPosition(MapNode node, Point newPosition, AgvDirection motorDirection)
{
// 현재 위치를 이전 위치로 저장 (리프트 방향 계산용)
if (_currentPosition != Point.Empty)
{
_targetPosition = _currentPosition; // ← 이전 위치 저장
_targetDirection = _currentDirection; // ← 이전 방향 저장
_targetNode = node; // ← 이전 노드(RFID) 저장
}
// 새로운 위치 설정
_currentPosition = newPosition; // 현재 위치 설정
_currentDirection = motorDirection; // 현재 모터방향 설정
_currentNode = node; // 현재 노드(RFID) 설정
// 위치 변경 이벤트 발생
PositionChanged?.Invoke(this, (_currentPosition, _currentDirection, _currentNode));
}
```
### SetPosition() 실행 흐름
| 단계 | 동작 | 데이터 |
|------|------|--------|
| **1단계: 이전 상태 백업** | 현재 위치 → 이전 위치로 저장 | _currentPosition → _targetPosition |
| | 현재 방향 → 이전 방향으로 저장 | _currentDirection → _targetDirection |
| | 현재 노드 → 이전 노드로 저장 | _currentNode → _targetNode |
| **2단계: 새 상태 설정** | 새 좌표 저장 | newPosition → _currentPosition |
| | 새 모터방향 저장 | motorDirection → _currentDirection |
| | 새 노드(RFID) 저장 | node → _currentNode |
| **3단계: 이벤트 발생** | 위치 변경 알림 | PositionChanged 이벤트 발생 |
---
## 🧭 리프트 방향 계산에 사용되는 정보
### 필요한 정보
1. **이전 위치**: _targetPosition
2. **현재 위치**: _currentPosition
3. **현재 모터 방향**: _currentDirection (Forward/Backward)
### 리프트 방향 계산 로직
**파일**: `AGVNavigationCore\Utils\LiftCalculator.cs`
**메서드**: `CalculateLiftAngleRadians(Point currentPos, Point targetPos, AgvDirection motorDirection)`
#### 계산식 (모터 방향 고려)
```csharp
if (motorDirection == AgvDirection.Forward)
{
// 전진: 현재→목표 벡터 (리프트가 목표 방향 향함)
var dx = targetPos.X - currentPos.X;
var dy = targetPos.Y - currentPos.Y;
}
else if (motorDirection == AgvDirection.Backward)
{
// 후진: 현재→목표 벡터 반대 (리프트가 이동 방향 향함)
var dx = currentPos.X - targetPos.X;
var dy = currentPos.Y - targetPos.Y;
}
// 각도 계산
var angle = Math.Atan2(dy, dx);
```
### 계산 예시
#### 상황 1: 전진 모드 (Forward)
```
위치: 006 (100, 100) → 005 (150, 100) 이동 중
_targetPosition = (100, 100) // 이전 위치 (006)
_currentPosition = (150, 100) // 현재 위치 (005)
_currentDirection = Forward // 전진
벡터: (150-100, 100-100) = (50, 0) ⇒ 오른쪽(0°)
리프트 방향: 오른쪽(0°)으로 회전
```
#### 상황 2: 후진 모드 (Backward)
```
위치: 006 (100, 100) → 005 (150, 100) 이동 중 (후진)
_targetPosition = (100, 100) // 이전 위치 (006)
_currentPosition = (150, 100) // 현재 위치 (005)
_currentDirection = Backward // 후진
벡터: (100-150, 100-100) = (-50, 0) ⇒ 왼쪽(180°)
리프트 방향: 왼쪽(180°)으로 회전 (이동 방향 반대)
```
---
## 📊 저장된 정보 요약
### VirtualAGV가 저장하는 RFID/방향 정보
| 정보 | 필드명 | 타입 | 설명 |
|------|--------|------|------|
| **이전 위치** | _targetPosition | Point | 이전 RFID 감지 위치 |
| **이전 RFID** | _targetNode | MapNode | 이전 RFID 정보 (RfidId 포함) |
| **이전 방향** | _targetDirection | AgvDirection | 이전 모터 방향 |
| **현재 위치** | _currentPosition | Point | 현재 RFID 감지 위치 |
| **현재 RFID** | _currentNode | MapNode | 현재 RFID 정보 (RfidId 포함) |
| **현재 방향** | _currentDirection | AgvDirection | 현재 모터 방향 (Forward/Backward) |
### MapNode에 포함된 RFID 정보
```csharp
public class MapNode
{
public string RfidId { get; set; } // 물리적 RFID ID
public string RfidStatus { get; set; } // RFID 상태
public string RfidDescription { get; set; } // RFID 설명
// ... 기타 노드 정보
}
```
---
## 🔍 호출 흐름: SetPosition() 언제 호출되는가?
### 호출 위치들
#### 1. **AGV 시뮬레이션에서의 자동 위치 업데이트**
**시나리오**: AGV가 경로를 따라 이동 중
```csharp
// VirtualAGV.cs의 경로 실행 중
ProcessNextNode()
SetPosition(nextNode, nextPosition, motorDirection)
_targetPosition
_currentPosition
```
#### 2. **시뮬레이터 UI에서의 수동 위치 설정**
**시나리오**: 사용자가 시뮬레이터에서 AGV를 수동으로 배치
```csharp
// SimulatorForm에서 사용자 클릭
userClicksOnCanvas()
SetPosition(selectedNode, clickPosition, currentDirection)
VirtualAGV
```
---
## 💾 이 정보가 사용되는 곳들
### 1. **리프트 방향 계산** (LiftCalculator.cs)
```csharp
var liftAngle = CalculateLiftAngleRadians(
_targetPosition, // 이전 위치
_currentPosition, // 현재 위치
_currentDirection // 현재 모터 방향
);
```
### 2. **경로 방향 검증** (DirectionChangePlanner.cs)
```csharp
// 현재 방향이 목표 도킹 방향과 일치하는지 확인
bool needDirectionChange = (_currentDirection != requiredDockingDirection);
```
### 3. **UI 렌더링** (UnifiedAGVCanvas.cs)
```csharp
// AGV 리프트 그리기 시 방향 정보 사용
DrawAGVLiftAdvanced(graphics, agv);
agv.CurrentDirection ( )
agv.TargetPosition ( )
```
### 4. **위치 변경 이벤트 발생**
```csharp
PositionChanged?.Invoke(this,
(_currentPosition, _currentDirection, _currentNode)
);
```
---
## 🎯 요약: AGV 방향 계산 데이터 흐름
```
입력: RFID 감지 + 모터 방향 정보
SetPosition(node, newPos, direction) 호출
[이전 상태 백업]
_targetPosition = 이전 위치
_targetDirection = 이전 방향
_targetNode = 이전 RFID
[현재 상태 설정]
_currentPosition = 새 위치
_currentDirection = 현재 방향
_currentNode = 현재 RFID
[리프트 방향 계산에 사용]
LiftCalculator.CalculateLiftAngleRadians(
이전위치, 현재위치, 현재방향
)
결과: AGV의 정확한 리프트 방향 결정
```
---
## 📌 중요 포인트
**이전 위치 보존**: SetPosition() 호출 시 기존 현재 위치를 이전 위치로 저장
**방향 정보 포함**: 이전/현재 방향 모두 저장하여 리프트 회전 계산
**RFID 매핑**: MapNode에 RfidId 포함하여 물리적 RFID와 논리적 위치 연계
**이벤트 발행**: 위치 변경 시 자동으로 PositionChanged 이벤트 발생
**파라미터 분리**: motorDirection을 별도 파라미터로 받아 명확한 방향 제어
---
## 🔧 현재 상태: 시뮬레이터에서만 구현
현재 이 저장 메커니즘은 **VirtualAGV.cs에 전체 주석처리**되어 있습니다.
실제 운영 시스템에서는 이와 유사한 메커니즘이 **실제 AGV 하드웨어 제어 모듈**에서 구현될 것으로 예상됩니다.