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:
276
Cs_HMI/AGVLogic/ANALYSIS_AGV_Direction_Storage.md
Normal file
276
Cs_HMI/AGVLogic/ANALYSIS_AGV_Direction_Storage.md
Normal 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 하드웨어 제어 모듈**에서 구현될 것으로 예상됩니다.
|
||||
Reference in New Issue
Block a user