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:
311
Cs_HMI/AGVLogic/IMPLEMENTATION_SUMMARY.md
Normal file
311
Cs_HMI/AGVLogic/IMPLEMENTATION_SUMMARY.md
Normal file
@@ -0,0 +1,311 @@
|
||||
# 방향 기반 경로 탐색 구현 완료 요약
|
||||
|
||||
## ✅ 구현 완료
|
||||
|
||||
사용자 요구사항에 따라 **이전 위치 + 현재 위치 + 진행 방향**을 기반으로 **다음 노드를 계산하는 시스템**을 완전히 구현했습니다.
|
||||
|
||||
---
|
||||
|
||||
## 📦 구현된 컴포넌트
|
||||
|
||||
### 1. **VirtualAGV.GetNextNodeId()** (핵심 메서드)
|
||||
**파일**: `AGVNavigationCore\Models\VirtualAGV.cs` (라인 613~823)
|
||||
|
||||
```csharp
|
||||
public string GetNextNodeId(AgvDirection direction, List<MapNode> allNodes)
|
||||
```
|
||||
|
||||
#### 특징:
|
||||
- ✅ VirtualAGV의 `_prevPosition`, `_currentPosition`, `_currentNode` 사용
|
||||
- ✅ 최소 2개 위치 히스토리 검증 (prev/current 모두 설정되어야 함)
|
||||
- ✅ 벡터 기반 방향 계산 (내적, 외적)
|
||||
- ✅ Forward/Backward/Left/Right 모든 방향 지원
|
||||
- ✅ Backward 시 좌우 방향 자동 반전
|
||||
|
||||
#### 동작 방식:
|
||||
```
|
||||
입력: direction (Forward/Backward/Left/Right), allNodes
|
||||
↓
|
||||
1️⃣ 히스토리 검증: _prevPosition, _currentPosition 확인
|
||||
2️⃣ 연결된 노드 필터링: currentNode의 ConnectedNodes에서 후보 선택
|
||||
3️⃣ 이동 벡터 계산: _currentPosition - _prevPosition
|
||||
4️⃣ 벡터 정규화: 길이를 1로 만듦
|
||||
5️⃣ 각 후보에 대해 점수 계산:
|
||||
- 내적: 진행 방향과의 유사도
|
||||
- 외적: 좌우 판별
|
||||
- direction에 따라 가중치 적용
|
||||
6️⃣ 최고 점수 노드 반환
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧮 방향 점수 계산 로직
|
||||
|
||||
### Forward (전진) 모드
|
||||
```
|
||||
내적 값 (dotProduct) 점수
|
||||
────────────────────────────
|
||||
> 0.9 (거의 같은 방향) 100
|
||||
0.5~0.9 (비슷한 방향) 80
|
||||
0~0.5 (약간 다른 방향) 50
|
||||
-0.5~0 (거의 반대) 20
|
||||
< -0.5 (완전 반대) 0
|
||||
```
|
||||
|
||||
### Backward (후진) 모드
|
||||
```
|
||||
내적 값 (dotProduct) 점수
|
||||
────────────────────────────
|
||||
< -0.9 (거의 반대) 100
|
||||
-0.5~-0.9 (비슷하게 반대) 80
|
||||
-0.5~0 (약간 다른) 50
|
||||
0~0.5 (거의 같은 방향) 20
|
||||
> 0.5 (완전 같은 방향) 0
|
||||
```
|
||||
|
||||
### Left (좌측) 모드
|
||||
```
|
||||
Forward 상태 (dotProduct > 0): Backward 상태 (dotProduct < 0):
|
||||
─────────────────────────────────────────────────────────────────────
|
||||
crossProduct > 0.5 → 100 (좌측) crossProduct < -0.5 → 100 (좌측 반전)
|
||||
0~0.5 → 70 -0.5~0 → 70
|
||||
-0.5~0 → 50 0~0.5 → 50
|
||||
< -0.5 → 30 > 0.5 → 30
|
||||
```
|
||||
|
||||
### Right (우측) 모드
|
||||
```
|
||||
Forward 상태 (dotProduct > 0): Backward 상태 (dotProduct < 0):
|
||||
─────────────────────────────────────────────────────────────────────
|
||||
crossProduct < -0.5 → 100 (우측) crossProduct > 0.5 → 100 (우측 반전)
|
||||
-0.5~0 → 70 0~0.5 → 70
|
||||
0~0.5 → 50 -0.5~0 → 50
|
||||
> 0.5 → 30 < -0.5 → 30
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 테스트 시나리오
|
||||
|
||||
### 시나리오 1: 직선 경로 전진
|
||||
```
|
||||
001 (65, 229) → 002 (206, 244) → GetNextNodeId(Forward)
|
||||
이동 벡터: (141, 15)
|
||||
002→003: (72, 34)
|
||||
내적: 0.939 → Forward 점수: 100 ✓
|
||||
결과: 003
|
||||
```
|
||||
|
||||
### 시나리오 2: 좌회전
|
||||
```
|
||||
002 (206, 244) → 003 (278, 278) → GetNextNodeId(Left)
|
||||
이동 벡터에 대해 Left 가중치 적용
|
||||
외적: crossProduct 양수 선호
|
||||
```
|
||||
|
||||
### 시나리오 3: 우회전
|
||||
```
|
||||
003 (278, 278) → 004 (380, 340) → GetNextNodeId(Right)
|
||||
이동 벡터에 대해 Right 가중치 적용
|
||||
외적: crossProduct 음수 선호
|
||||
결과: 030 또는 N022 (맵 구조에 따라)
|
||||
```
|
||||
|
||||
### 시나리오 4: 후진
|
||||
```
|
||||
004 → 003 → GetNextNodeId(Backward)
|
||||
역진 가중치 적용 (dotProduct < -0.9 = 100점)
|
||||
결과: 002
|
||||
```
|
||||
|
||||
### 시나리오 5: Backward 시 좌우 반전
|
||||
```
|
||||
004 → 003 (Backward) → GetNextNodeId(Left)
|
||||
Backward 상태에서 Left = 원래 Right 방향
|
||||
좌우 자동 반전으로 올바른 방향 계산
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 추가 구현 파일들
|
||||
|
||||
### 1. **DirectionalPathfinder.cs**
|
||||
**파일**: `PathFinding\Planning\DirectionalPathfinder.cs`
|
||||
- 독립적인 벡터 기반 경로 탐색 엔진
|
||||
- VirtualAGV와 분리된 재사용 가능한 컴포넌트
|
||||
- 방향 가중치 커스터마이징 지원
|
||||
|
||||
### 2. **AGVDirectionCalculator.cs**
|
||||
**파일**: `Utils\AGVDirectionCalculator.cs`
|
||||
- VirtualAGV와 실제 AGV 시스템을 위한 통합 인터페이스
|
||||
- RFID 위치 기반 계산
|
||||
- 선택된 방향 역추적 기능
|
||||
|
||||
### 3. **DirectionalPathfinderTest.cs**
|
||||
**파일**: `Utils\DirectionalPathfinderTest.cs`
|
||||
- NewMap.agvmap 파일 로드 및 파싱
|
||||
- 테스트 시나리오 실행
|
||||
- 결과 검증 및 출력
|
||||
|
||||
### 4. **TestRunner.cs**
|
||||
**파일**: `Utils\TestRunner.cs`
|
||||
- 전체 테스트 프로그램 실행
|
||||
- 모든 시나리오 자동 테스트
|
||||
|
||||
---
|
||||
|
||||
## 📊 .csproj 수정 사항
|
||||
|
||||
**파일**: `AGVNavigationCore\AGVNavigationCore.csproj`
|
||||
|
||||
추가된 항목:
|
||||
```xml
|
||||
<Compile Include="PathFinding\Planning\DirectionalPathfinder.cs" />
|
||||
<Compile Include="Utils\AGVDirectionCalculator.cs" />
|
||||
<Compile Include="Utils\DirectionalPathfinderTest.cs" />
|
||||
<Compile Include="Utils\TestRunner.cs" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 사용 방법
|
||||
|
||||
### 기본 사용 (VirtualAGV)
|
||||
|
||||
```csharp
|
||||
// VirtualAGV 인스턴스
|
||||
var agv = new VirtualAGV("AGV001");
|
||||
|
||||
// 위치 설정 (최소 2번)
|
||||
agv.SetPosition(node001, new Point(65, 229), AgvDirection.Forward);
|
||||
agv.SetPosition(node002, new Point(206, 244), AgvDirection.Forward);
|
||||
|
||||
// 다음 노드 계산
|
||||
string nextNodeId = agv.GetNextNodeId(AgvDirection.Forward, allNodes);
|
||||
Console.WriteLine($"다음 노드: {nextNodeId}"); // 003
|
||||
```
|
||||
|
||||
### 고급 사용 (독립적인 계산기)
|
||||
|
||||
```csharp
|
||||
var calculator = new AGVDirectionCalculator();
|
||||
|
||||
string nextNodeId = calculator.GetNextNodeId(
|
||||
previousRfidPos: new Point(206, 244),
|
||||
currentNode: node003,
|
||||
currentRfidPos: new Point(278, 278),
|
||||
direction: AgvDirection.Right,
|
||||
allNodes: allNodes
|
||||
);
|
||||
|
||||
// 실제 선택된 방향 분석
|
||||
AgvDirection selectedDir = calculator.AnalyzeSelectedDirection(
|
||||
new Point(206, 244),
|
||||
new Point(278, 278),
|
||||
selectedNextNode,
|
||||
connectedNodes
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 중요 주의사항
|
||||
|
||||
### 1. 2개 위치 히스토리 필수
|
||||
```csharp
|
||||
// ❌ 잘못된 사용 (처음 호출 시)
|
||||
string next = agv.GetNextNodeId(direction, allNodes); // null 반환
|
||||
|
||||
// ✅ 올바른 사용
|
||||
agv.SetPosition(node1, pos1, AgvDirection.Forward); // 첫 번째
|
||||
agv.SetPosition(node2, pos2, AgvDirection.Forward); // 두 번째
|
||||
string next = agv.GetNextNodeId(direction, allNodes); // 결과 반환
|
||||
```
|
||||
|
||||
### 2. 벡터 정규화
|
||||
- 매우 작은 이동(<0.001px)은 거리 0으로 간주
|
||||
- 이 경우 첫 번째 연결 노드 반환
|
||||
|
||||
### 3. 좌표계 유지
|
||||
- 모든 좌표는 맵 기준 (화면 좌표가 아님)
|
||||
- 줌/팬 상태에서는 별도 변환 필요
|
||||
|
||||
### 4. 내적/외적 이해
|
||||
```
|
||||
내적 (Dot Product):
|
||||
= v1.x * v2.x + v1.y * v2.y
|
||||
범위: -1 ~ 1
|
||||
1 = 같은 방향, 0 = 직각, -1 = 반대 방향
|
||||
|
||||
외적 (Cross Product):
|
||||
= v1.x * v2.y - v1.y * v2.x
|
||||
양수 = 좌측, 음수 = 우측
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 최종 파일 구조
|
||||
|
||||
```
|
||||
AGVNavigationCore/
|
||||
├── Models/
|
||||
│ └── VirtualAGV.cs ⭐ (GetNextNodeId 추가)
|
||||
├── PathFinding/
|
||||
│ └── Planning/
|
||||
│ ├── DirectionalPathfinder.cs (NEW)
|
||||
│ ├── AGVPathfinder.cs
|
||||
│ └── ...
|
||||
├── Utils/
|
||||
│ ├── AGVDirectionCalculator.cs (NEW)
|
||||
│ ├── DirectionalPathfinderTest.cs (NEW)
|
||||
│ ├── TestRunner.cs (NEW)
|
||||
│ └── ...
|
||||
└── AGVNavigationCore.csproj (MODIFIED)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 핵심 요구사항 검증
|
||||
|
||||
| 요구사항 | 상태 | 구현 위치 |
|
||||
|---------|------|----------|
|
||||
| GetNextNodeID(direction) 메서드 | ✅ 완료 | VirtualAGV:628 |
|
||||
| 2개 위치 히스토리 검증 | ✅ 완료 | VirtualAGV:630-634 |
|
||||
| Forward/Backward/Left/Right 지원 | ✅ 완료 | VirtualAGV:743-817 |
|
||||
| 좌우 반전 로직 | ✅ 완료 | VirtualAGV:780, 806 |
|
||||
| 벡터 기반 계산 | ✅ 완료 | VirtualAGV:658-678 |
|
||||
| NewMap.agvmap 테스트 지원 | ✅ 완료 | DirectionalPathfinderTest |
|
||||
|
||||
---
|
||||
|
||||
## 📝 다음 단계 (선택사항)
|
||||
|
||||
1. **실제 맵에서 테스트**
|
||||
- TestRunner로 NewMap.agvmap 검증
|
||||
- 실제 RFID 번호로 시나리오 테스트
|
||||
|
||||
2. **성능 최적화**
|
||||
- 벡터 계산 캐싱
|
||||
- 점수 계산 병렬화
|
||||
|
||||
3. **기능 확장**
|
||||
- 3D 좌표 지원
|
||||
- A* 알고리즘 통합
|
||||
- 동적 가중치 조정
|
||||
|
||||
4. **시뮬레이터 통합**
|
||||
- AGVSimulator에 GetNextNodeId 연결
|
||||
- 실시간 경로 변경 시연
|
||||
|
||||
---
|
||||
|
||||
## 📚 관련 문서
|
||||
|
||||
- `ANALYSIS_AGV_Direction_Storage.md` - VirtualAGV 필드 분석
|
||||
- `IMPLEMENTATION_DirectionalPathfinder.md` - 상세 구현 가이드
|
||||
|
||||
---
|
||||
|
||||
**완료 일시**: 2025-10-23
|
||||
**상태**: 🟢 구현 완료, 테스트 대기
|
||||
**다음 작업**: NewMap.agvmap으로 실제 테스트
|
||||
Reference in New Issue
Block a user