copilot file backup

This commit is contained in:
ChiKyun Kim
2025-09-18 17:25:14 +09:00
parent c5f2dbc477
commit 9a9ca4cf32
29 changed files with 7513 additions and 109 deletions

View File

@@ -0,0 +1,636 @@
# AGV 경로 계산 알고리즘 설계 문서
## 1. 시스템 개요
### 1.1 AGV 하드웨어 특성
- **구조**: 리프트 - 몸체 - 모니터 (가로 직사각형)
- **이동**: 전진/후진만 가능, 제자리 회전 불가
- **제어**: 마그넷 라인 트레이서 (magnet left/right/straight)
- **도킹**: 전진 도킹(충전기), 후진 도킹(버퍼, 로더 등)
### 1.2 핵심 제약사항
1. **제자리 회전 불가**: 방향 전환을 위해서는 갈림길 이용 필수
2. **갈림길 조건**: 인접 노드 3개 이상 필요
3. **도킹 조건**: AGV 방향과 목적지 도킹 방향이 일치해야 함
4. **상태 의존성**: 이전 이동 정보 없이는 현재 방향 판단 불가
5. **인접노드 경유 필수**: 갈림길에서 방향전환시 반드시 인접노드를 경유해야 함
## 2. 경로 계산 알고리즘 아키텍처
### 2.1 다단계 경로 계산 방식
```
1단계: 기본 최단 경로 계산
2단계: 방향 호환성 검증
3단계: 방향 전환 경로 생성 (필요시)
4단계: 최종 경로 최적화
```
### 2.2 핵심 클래스 구조
```
AGVPathCalculator (메인 경로 계산기)
├── BasicPathFinder (기본 최단 경로)
├── DirectionAnalyzer (방향 분석 및 호환성 검증)
├── TurnAroundPlanner (방향 전환 경로 계획)
└── PathOptimizer (경로 최적화)
```
## 3. 세부 알고리즘 설계
### 3.1 AGV 상태 모델
```csharp
public class AgvState
{
public string CurrentNodeId { get; set; } // 현재 위치 (RFID)
public string PreviousNodeId { get; set; } // 이전 위치 (방향 판단용)
public AgvDirection MotorDirection { get; set; } // 현재 모터 방향
public AgvDirection LiftDirection { get; set; } // 리프트가 향하는 방향
public AgvDirection MonitorDirection { get; set; } // 모니터가 향하는 방향
}
```
### 3.2 방향 판단 알고리즘
#### 3.2.1 현재 AGV 방향 계산
```
IF 이전노드 → 현재노드 이동 시 모터방향이 전진:
리프트 방향 = 이전노드 방향
모니터 방향 = 현재노드에서 이전노드 반대 방향
IF 이전노드 → 현재노드 이동 시 모터방향이 후진:
리프트 방향 = 현재노드에서 이전노드 반대 방향
모니터 방향 = 이전노드 방향
```
#### 3.2.2 도킹 호환성 검증
```
FOR 목적지 노드:
IF 목적지.도킹타입 == 전진도킹 (충전기):
RETURN 모니터방향 == 목적지방향
IF 목적지.도킹타입 == 후진도킹 (버퍼, 로더):
RETURN 리프트방향 == 목적지방향
```
### 3.3 기본 경로 계산 (1단계)
#### 3.3.1 단순 최단 경로 알고리즘
- **알고리즘**: Dijkstra 또는 BFS (AGV 특성상 가중치가 단순)
- **목적**: 방향 고려 없이 순수한 최단 거리 경로
- **출력**: 노드 시퀀스 [시작 → ... → 목적지]
```
기본경로 = BFS_최단경로(시작노드, 목적지노드)
예시: 003 → 002 → 001 (언로더)
```
### 3.4 방향 호환성 검증 (2단계)
#### 3.4.1 경로상 방향 시뮬레이션
```
FOR 각 경로 단계:
현재_AGV_방향 = 시뮬레이션_이동(이전노드, 현재노드, 모터방향)
IF 현재노드 == 목적지:
도킹_가능 = 검증_도킹_호환성(현재_AGV_방향, 목적지_도킹타입)
IF 도킹_가능:
RETURN 기본경로 (방향 전환 불필요)
ELSE:
PROCEED TO 3단계 (방향 전환 필요)
```
### 3.5 방향 전환 경로 계획 (3단계)
#### 3.5.1 갈림길 탐색 알고리즘
```
갈림길_후보 = []
FOR 기본경로상의 각 노드:
IF 노드.인접노드수 >= 3:
갈림길_후보.ADD(노드)
IF 갈림길_후보 == 빈목록:
// 기본경로에 갈림길 없음 → 외부 갈림길 탐색
가장_가까운_갈림길 = BFS_갈림길_탐색(현재위치)
갈림길_후보.ADD(가장_가까운_갈림길)
```
#### 3.5.2 방향 전환 시퀀스 계획
```
선택된_갈림길 = 갈림길_후보[0] // 가장 가까운 갈림길
// Phase 1: 갈림길까지 이동 (현재 모터 방향 유지)
Phase1_경로 = 현재위치 → 선택된_갈림길
// Phase 2: 갈림길에서 우회 (인접 노드 경유 필수)
우회_노드 = 계산_우회_방향(선택된_갈림길, 현재_진입_방향)
Phase2_경로 = 선택된_갈림길 → 우회_노드
// 중요: AGV는 갈림길에서 직접 되돌아갈 수 없으므로 반드시 인접노드 방문
// Phase 3: 모터 방향 전환 + 갈림길 재진입
모터방향 = 반전(현재_모터방향)
Phase3_경로 = 우회_노드 → 선택된_갈림길
// 우회노드에서 모터방향 전환 후 갈림길로 복귀
// Phase 4: 목적지까지 이동 (전환된 방향으로)
Phase4_경로 = 선택된_갈림길 → 목적지
```
#### 3.5.3 갈림길 방향 선택 우선순위
```
FOR 갈림길의 각 인접노드 (진입방향 제외):
방향타입 = 계산_마그넷_방향(진입방향, 인접노드방향)
우선순위:
1. Straight (직진)
2. Left (왼쪽)
3. Right (오른쪽)
선택된_방향 = 우선순위가_가장_높은_방향
```
### 3.6 최종 경로 최적화 (4단계)
#### 3.6.1 경로 검증
```
FOR 최종경로의 각 단계:
1. 연결성 검증 (모든 인접 노드가 실제 연결되어 있는가)
2. 마그넷 방향 일관성 검증
3. 도킹 방향 최종 검증
```
#### 3.6.2 경로 최적화
```
IF 여러 갈림길 옵션 존재:
각_옵션별_총거리 = 계산_총_이동거리(옵션)
최적_경로 = MIN(각_옵션별_총거리)
```
## 4. 데이터 구조 설계
### 4.1 입력 데이터
```csharp
public class PathRequest
{
public AgvState CurrentState { get; set; } // 현재 AGV 상태
public string TargetRfidId { get; set; } // 목적지 RFID
public MapData MapData { get; set; } // 맵 데이터
}
```
### 4.2 출력 데이터
```csharp
public class PathResult
{
public bool Success { get; set; }
public List<PathStep> Steps { get; set; } // 단계별 상세 경로
public string ErrorMessage { get; set; }
public PathMetrics Metrics { get; set; } // 성능 지표
}
public class PathStep
{
public string RfidId { get; set; } // UI 표시용 RFID
public string NodeId { get; set; } // 내부 처리용 NodeID
public AgvDirection MotorDirection { get; set; }
public MagnetDirection MagnetDirection { get; set; }
public string Action { get; set; } // "이동", "방향전환", "도킹" 등
public string Description { get; set; } // 사용자 친화적 설명
}
```
## 5. 예외 상황 처리
### 5.1 불가능한 경로
- **갈림길 없음**: 방향 전환이 불가능한 맵 구조
- **고립된 노드**: 연결이 끊어진 노드
- **순환 참조**: 무한 루프 방지
### 5.2 복구 전략
```
IF 방향전환_불가능:
RETURN 오류 "목적지 도킹 불가능 - 갈림길 부족"
IF 경로_없음:
RETURN 오류 "목적지 접근 불가능 - 맵 연결 확인 필요"
IF 계산시간_초과:
RETURN 오류 "경로 계산 시간 초과 - 맵 복잡도 점검 필요"
```
## 6. 성능 최적화 전략
### 6.1 캐싱 전략
- **맵 구조 캐싱**: 갈림길 노드, 인접 노드 정보
- **거리 매트릭스**: 자주 사용되는 노드 간 거리
- **방향 전환 패턴**: 성공한 방향 전환 시퀀스
### 6.2 알고리즘 최적화
- **조기 종료**: 방향 호환 시 3-4단계 건너뛰기
- **휴리스틱**: 갈림길 선택 시 목적지 방향 고려
- **병렬 처리**: 여러 갈림길 옵션 동시 계산
## 7. 테스트 시나리오
### 7.1 기본 시나리오
1. **직선 경로**: 003 → 002 → 001 (방향 호환)
2. **방향 전환**: 003(후진) → 001(언로더) 도킹
3. **복잡한 갈림길**: 여러 갈림길이 있는 경우
### 7.3 실제 맵 검증 시나리오 (NewMap.agvmap 기반)
**시나리오**: AGV가 034→033 (전진) 상태에서 040(BUF2, 후진도킹) 목적지
- **기본경로**: 033 → 032 → 040
- **방향호환성**: 전진 ≠ 후진 → 방향전환 필요
- **갈림길**: 032 (3개 연결: 031, 033, 040)
- **4단계 시퀀스**:
1. 033 → 032 (전진, magnet right)
2. 032 → 031 (전진, magnet left) - 인접노드 경유
3. 031 → 032 (후진, magnet right) - 모터방향 전환
4. 032 → 040 (후진, magnet straight) - 도킹성공
**검증포인트**:
- 032는 Position(148,545)를 중심으로 031(서쪽), 033(동쪽), 040(남쪽) 연결
- 마그넷 방향 계산시 실제 좌표 기반 방향 확인 필수
- 040에서 032로의 복귀는 인접노드(031) 경유 없이 불가능
### 7.2 경계 조건
1. **동일 위치**: 시작 = 목적지
2. **인접 노드**: 한 번만 이동하면 되는 경우
3. **최대 거리**: 맵에서 가장 먼 두 지점
## 8. 구현 우선순위
### Phase 1: 기본 기능
1. AgvState 및 PathStep 데이터 모델
2. 기본 최단 경로 계산
3. 방향 판단 로직
### Phase 2: 고급 기능
1. 방향 호환성 검증
2. 갈림길 탐색 및 방향 전환
3. 최종 경로 최적화
### Phase 3: 최적화
1. 성능 최적화 및 캐싱
2. 예외 처리 강화
3. 테스트 케이스 완성
## 9. 핵심 알고리즘 의사코드
### 9.1 메인 경로 계산 함수
```
FUNCTION CalculatePath(currentState, targetRfidId, mapData):
// 1단계: 기본 최단 경로
basicPath = FindShortestPath(currentState.CurrentNodeId, targetRfidId)
// 2단계: 방향 호환성 검증
IF IsDirectionCompatible(currentState, basicPath, targetRfidId):
RETURN CreateSuccessResult(basicPath)
// 3단계: 방향 전환 필요
turnAroundPath = PlanTurnAround(currentState, basicPath, targetRfidId)
// 4단계: 최적화
optimizedPath = OptimizePath(turnAroundPath)
RETURN CreateSuccessResult(optimizedPath)
```
### 9.2 방향 전환 계획 함수
```
FUNCTION PlanTurnAround(currentState, basicPath, targetRfidId):
// 갈림길 찾기
junctions = FindJunctionsInPath(basicPath)
IF junctions.IsEmpty():
junctions = FindNearestJunctions(currentState.CurrentNodeId)
bestJunction = SelectBestJunction(junctions, targetRfidId)
// 4단계 경로 생성 (인접노드 경유 필수)
phase1 = PathToJunction(currentState, bestJunction)
phase2 = DetourToAdjacentNode(bestJunction, currentState.MotorDirection)
phase3 = ReturnToJunctionWithReversedMotor(phase2.EndNode, bestJunction)
phase4 = PathFromJunctionToTarget(bestJunction, targetRfidId, !currentState.MotorDirection)
RETURN CombinePaths(phase1, phase2, phase3, phase4)
```
### 9.3 마그넷 방향 계산 함수
```
FUNCTION CalculateMagnetDirection(fromNodeId, toNodeId, junctionNodeId):
fromPos = GetNodePosition(fromNodeId)
toPos = GetNodePosition(toNodeId)
junctionPos = GetNodePosition(junctionNodeId)
// 갈림길 진입 방향 벡터
entryVector = Normalize(junctionPos - fromPos)
// 갈림길 진출 방향 벡터
exitVector = Normalize(toPos - junctionPos)
// 외적을 이용한 방향 판단
crossProduct = CrossProduct(entryVector, exitVector)
dotProduct = DotProduct(entryVector, exitVector)
IF Abs(dotProduct) > 0.8: // 직진 허용 오차
RETURN MagnetDirection.Straight
ELSE IF crossProduct > 0:
RETURN MagnetDirection.Left
ELSE:
RETURN MagnetDirection.Right
```
## 10. 핵심 설계 원칙 요약
### 10.1 AGV 하드웨어 제약사항 핵심
1. **방향전환 불가**: 제자리 회전 기능 없음 → 갈림길 필수 활용
2. **인접노드 경유**: 갈림길에서 직접 복귀 불가 → 반드시 인접노드 방문
3. **양방향 연결**: 맵 연결 정보는 단방향 저장, 실제는 양방향 해석
4. **좌표 기반 마그넷**: 노드 Position 좌표로 실제 마그넷 방향 계산
### 10.2 알고리즘 핵심 검증점
1. **갈림길 조건**: 인접노드 3개 이상 (진입방향 제외시 2개 선택지)
2. **방향 호환성**: 현재 AGV 방향 ≠ 목적지 도킹 방향 → 4단계 전환
3. **마그넷 정확성**: 벡터 외적/내적 기반 좌/우/직진 판단
4. **경로 유효성**: 모든 연결이 실제 맵에서 존재하는지 검증
### 10.3 실제 구현시 주의사항
- **RFID vs NodeID**: 사용자 인터페이스는 RFID, 내부 로직은 NodeID
- **좌표계 정확성**: Position 문자열 파싱시 정수 변환 검증
- **양방향 탐색**: ConnectedNodes 뿐만 아니라 역방향 연결도 고려
- **에러 처리**: 갈림길 부족, 경로 없음, 순환참조 등 예외 상황
## 11. NewMap.agvmap 갈림길 데이터 (참조용)
### 11.1 확인된 갈림길 노드 목록
**주요 갈림길 (3개 이상 연결)**:
| RFID | NodeId | Position | 연결 노드 | 연결 RFID | 용도 |
|------|--------|----------|-----------|-----------|------|
| 004 | N004 | 380,340 | N003, N022, N031 | 003, 012, 030 | 서쪽 주요 갈림길 |
| 005 | N011 | 460,420 | N012, N004, N015 | 006, 004, 037 | 중앙 주요 갈림길 |
| 012 | N022 | 459,279 | N004, N023, N006 | 004, 016, 013 | 중앙-북쪽 갈림길 |
| 032 | N020 | 148,545 | N021, N005, N028 | 031, 033, 040 | 남쪽 갈림길 |
### 11.2 갈림길별 방향전환 전략
**RFID 005 (중앙 갈림길)**:
- **동쪽에서 진입** (006 → 005): 서쪽(004) 또는 남쪽(037)으로 우회 가능
- **서쪽에서 진입** (004 → 005): 동쪽(006) 또는 남쪽(037)으로 우회 가능
- **남쪽에서 진입** (037 → 005): 동쪽(006) 또는 서쪽(004)으로 우회 가능
**RFID 004 (서쪽 갈림길)**:
- **동쪽에서 진입** (005 → 004): 서쪽(003) 또는 남쪽(030)으로 우회 가능
- **서쪽에서 진입** (003 → 004): 동쪽(005) 또는 남쪽(030)으로 우회 가능
- **남쪽에서 진입** (030 → 004): 동쪽(005) 또는 서쪽(003)으로 우회 가능
**RFID 012 (중앙-북쪽 갈림길)**:
- **서쪽에서 진입** (004 → 012): 동쪽(013) 또는 북쪽(016)으로 우회 가능
- **동쪽에서 진입** (013 → 012): 서쪽(004) 또는 북쪽(016)으로 우회 가능
- **북쪽에서 진입** (016 → 012): 서쪽(004) 또는 동쪽(013)으로 우회 가능
**RFID 032 (남쪽 갈림길)**:
- **동쪽에서 진입** (033 → 032): 서쪽(031) 또는 남쪽(040)으로 우회 가능
- **서쪽에서 진입** (031 → 032): 동쪽(033) 또는 남쪽(040)으로 우회 가능
- **남쪽에서 진입** (040 → 032): 동쪽(033) 또는 서쪽(031)으로 우회 가능
### 11.3 경로 계산시 갈림길 활용 지침
1. **갈림길 우선순위**: 목적지와 가까운 갈림길 우선 선택
2. **우회 방향 선택**: 막다른 길 < 2개 연결 < 3개 이상 연결 순서로 우선순위
3. **마그넷 방향 계산**: 실제 좌표 기반 벡터 계산으로 정확한 left/right/straight 판단
4. **방향전환 검증**: 갈림길에서 최소 1회 인접노드 경유 후 모터방향 전환
### 11.4 실제 활용 예시
**007→006 전진모터 → 011(TOPS) 경로**:
- **기본경로**: 006 → 005 → 004 → 030 → 009 → 010 → 011
- **방향전환**: 005 갈림길 활용 (006 → 005 → 037 → 005 → 004...)
- **결과**: 후진 도킹으로 TOPS 접근 성공
**034→033 전진모터 → 041(BUF1) 경로****검증됨**:
- **기본경로**: 033 → 032 → 031 → 041
- **방향호환성**: 전진 ≠ 후진 → 방향전환 필요
- **4단계 시퀀스**:
1. 033 → 032 (전진, left)
2. 032 → 040 (전진, straight) - 인접노드 경유
3. 040 → 032 (후진, straight) - 모터방향 전환
4. 032 → 031 → 041 (후진, right → straight) - 도킹성공
## 12. 구현을 위한 핵심 알고리즘 요약
### 12.1 필수 구현 클래스
```csharp
// 1. 메인 경로 계산기
public class AGVPathCalculator
{
public PathResult CalculatePath(AgvState currentState, string targetRfidId, MapData mapData)
// 핵심 의존성 클래스들
private BasicPathFinder _basicPathFinder;
private DirectionAnalyzer _directionAnalyzer;
private TurnAroundPlanner _turnAroundPlanner;
private JunctionFinder _junctionFinder;
}
// 2. 갈림길 탐색기 (중요!)
public class JunctionFinder
{
public List<string> FindJunctionsInPath(List<string> path, MapData mapData)
public List<string> FindNearestJunctions(string nodeId, MapData mapData)
public bool IsJunction(string nodeId, MapData mapData) // 3개 이상 연결 확인
}
// 3. 방향 전환 계획기
public class TurnAroundPlanner
{
public PathResult PlanTurnAroundPath(AgvState state, List<string> basicPath, string targetId)
public string SelectBestDetourNode(string junctionId, string entryDirection, MapData mapData)
}
// 4. 마그넷 방향 계산기
public class MagnetDirectionCalculator
{
public MagnetDirection CalculateDirection(string fromNodeId, string toNodeId, string junctionId, MapData mapData)
// 벡터 외적/내적 기반 left/right/straight 판단
}
```
### 12.2 핵심 알고리즘 단계별 체크리스트
**1단계: 기본 최단 경로**
- [ ] BFS/Dijkstra로 최단 경로 계산
- [ ] 양방향 연결 해석 (ConnectedNodes + 역방향 탐색)
- [ ] RFID ↔ NodeID 매핑 처리
**2단계: 방향 호환성 검증**
- [ ] 현재 AGV 방향 계산 (이전노드 → 현재노드 + 모터방향)
- [ ] 목적지 도킹 방향 요구사항 확인 (Type + DockDirection)
- [ ] 최종 도착 시 AGV 방향 시뮬레이션
**3단계: 방향 전환 (필요시)**
- [ ] 경로상 갈림길 탐색 (3개 이상 연결 노드)
- [ ] 가장 가까운 갈림길 선택
- [ ] 4단계 시퀀스 생성:
- Phase1: 갈림길까지 이동
- Phase2: 인접노드 경유 (필수!)
- Phase3: 모터방향 전환 후 갈림길 복귀
- Phase4: 목적지까지 이동
**4단계: 최적화 및 검증**
- [ ] 마그넷 방향 정확성 검증 (좌표 기반 벡터 계산)
- [ ] 연결성 검증 (모든 단계가 실제 연결되어 있는지)
- [ ] 최종 도킹 방향 재검증
### 12.3 검증된 테스트 케이스
1. **034→033→041**: 방향전환 성공 (032 갈림길, 040 인접노드) ✅
2. **034→033→040**: 이전 분석에서 방향전환 성공 ✅
3. **007→006→019**: 직선 경로, 방향호환 ✅
4. **007→006→001**: 방향전환 필요 (004 갈림길) ✅
5. **007→006→011**: 방향전환 성공 (005 갈림길) ✅
6. **031→032→001**: 방향전환 필요 (004 갈림길, 030 인접노드) ✅
7. **014→015→019**: 방향전환 필요 (012 갈림길, 004 인접노드) ✅
8. **018→019→015**: 직선 경로, 방향호환 (막다른 길 시작) ✅
### 12.4 구현 우선순위
**Phase 1 (핵심 기능)**:
1. MapData, AgvState, PathResult 모델 구현
2. BasicPathFinder (BFS 기반)
3. JunctionFinder (갈림길 탐색)
4. DirectionAnalyzer (방향 호환성)
**Phase 2 (고급 기능)**:
1. TurnAroundPlanner (4단계 방향전환)
2. MagnetDirectionCalculator (벡터 기반)
3. PathOptimizer (경로 최적화)
**Phase 3 (완성)**:
1. 예외 처리 강화
2. 성능 최적화
3. 테스트 케이스 완성
## 13. 중요한 구현 주의사항 및 함정
### 13.1 AGV 방향성 함정 (매우 중요!)
**함정 1: 막다른 길에서의 방향 전환 불가**
- ❌ 잘못된 분석: "010에서 009로 후진 → 009에서 010으로 후진"
- ✅ 올바른 이해: 010(막다른 길)에서는 들어온 방향으로만 되돌아갈 수 있음
- **교훈**: 갈림길에서만 방향전환 가능, 막다른 길/편도에서는 불가능
**함정 2: 입구 방향과 출구 방향 혼동**
- ❌ 잘못된 분석: "015→014 전진 후 014→015 전진"
- ✅ 올바른 이해: 014→015 전진으로 왔으면 015→014는 후진만 가능
- **교훈**: AGV는 들어온 방향의 반대로만 되돌아갈 수 있음
**함정 3: 가짜 갈림길 식별**
- ❌ 잘못된 분석: "015-014-013-012는 갈림길"
- ✅ 올바른 이해: 이것은 편도 1차선, 진짜 갈림길은 3개 이상 연결
- **교훈**: 연결 개수와 실제 구조를 정확히 파악해야 함
### 13.2 경로 계산 알고리즘 핵심 원칙
**원칙 1: 막다른 길 우선순위**
- 막다른 길에서 시작 → 방향 자동 결정 → 가장 간단한 케이스
- 예: 018→019→015 (후진→전진, 방향호환)
**원칙 2: 가장 가까운 갈림길 활용**
- 경로상 갈림길 없음 → 더 먼 갈림길 탐색
- 예: 014→015→019 (012 갈림길 활용, 004까지 갈 필요 없음)
**원칙 3: 인접노드 경유 필수**
- 갈림길에서 직접 되돌아가기 불가능
- 반드시 인접노드 방문 후 모터방향 전환
### 13.3 디버깅 체크리스트
**방향 계산 검증**:
- [ ] 현재 AGV 방향 정확히 계산 (이전→현재 + 모터방향)
- [ ] 목적지 도킹 방향 요구사항 확인
- [ ] 최종 도착 시 AGV 방향 시뮬레이션
**갈림길 검증**:
- [ ] 3개 이상 연결 확인 (편도 vs 진짜 갈림길)
- [ ] 양방향 연결 해석 (ConnectedNodes + 역방향)
- [ ] 인접노드 경유 가능성 확인
**경로 유효성 검증**:
- [ ] 모든 연결이 실제 존재하는지 확인
- [ ] 마그넷 방향 계산 정확성
- [ ] 막다른 길에서 방향전환 시도하지 않는지
### 13.4 성공 패턴
1. **직선 경로 (방향호환)**: 034→033→040, 018→019→015
2. **단일 갈림길 방향전환**: 034→033→041 (032 갈림길)
3. **원거리 갈림길 활용**: 014→015→019 (012 갈림길)
4. **복합 경로**: 031→032→001 (004 갈림길, 030 인접노드)
이 설계 문서를 바탕으로 단계별로 구현을 진행하면, AGV의 복잡한 방향 전환 요구사항을 체계적으로 해결할 수 있습니다.
### 테스트 예제 (각 목표별 답안계산 : 경유 노드의 RFID도 모두 포함)
Q1-1.033->032(전진) : 목표 040,041,008,001,011,019,015
040 : 032 ->(F) 031 ->(R) 032 -> 040
041 : 032 ->(F) 040 ->(R) 032 -> 031 -> 041
008 : 032 ->(B) 033 -> 034 -> 035 -> 036 -> 037 -> 005 -> 006 -> 007 -> 008
001 : 032 ->(B) 033 -> 034 -> 035 -> 036 -> 037 -> 005 -> 004 -> 003 -> 002 -> 001
011 : 032 ->(B) 033 -> 034 -> 035 -> 036 -> 037 -> 005 -> 004 -> 030 -> 009 -> 010 -> 011
019 : 032 ->(B) 033 -> 034 -> 035 -> 036 -> 037 -> 005 -> 004 -> 012 -> 013 ->(F) -> 012 -> 016 -> 017 -> 018 -> 019
015 : 032 ->(B) 033 -> 034 -> 035 -> 036 -> 037 -> 005 -> 004 -> 012 -> 016 ->(F) -> 012 -> 013 -> 014 -> 015
Q1-2.033->032(후진) : 목표 040,041,008,001,011,019,015
040 : 032 ->(F) 033 ->(R) 032 -> 040
041 : 032 ->(R) 031 -> 041
008 : 032 ->(F) 033 -> 034 -> 035 -> 036 -> 037 -> 005 -> 004 ->(B) -> 005 -> 006 -> 007 -> 008
001 : 032 ->(F) 033 -> 034 -> 035 -> 036 -> 037 -> 005 -> 006 ->(B) -> 004 -> 003 -> 002 -> 001
011 : 032 ->(F) 033 -> 034 -> 035 -> 036 -> 037 -> 005 -> 004 -> 003 ->(B) -> 004 -> 030 -> 009 -> 010 -> 011
032 ->(F) 033 -> 034 -> 035 -> 036 -> 037 -> 005 -> 004 -> 012 ->(B) -> 004 -> 030 -> 009 -> 010 -> 011
019 : 032 ->(F) 033 -> 034 -> 035 -> 036 -> 037 -> 005 -> 004 -> 012 -> 016 -> 017 -> 018 -> 019
015 : 032 ->(F) 033 -> 034 -> 035 -> 036 -> 037 -> 005 -> 004 -> 012 -> 013 -> 014 -> 015
Q2-1.006->007(전진) : 목표 040,041,008,001,011,019,015
040 : 007 ->(B) 006 -> 005 -> 037 -> 036 -> 035 -> 034 -> 033 -> 032 -> 040
041 : 007 ->(B) 006 -> 005 -> 037 -> 036 -> 035 -> 034 -> 033 -> 032 -> 031 -> 041
008 : 007 ->(F) 006 -> 005 -> 037 ->(B) 005 -> 006 -> 007 -> 008
001 : 007 ->(B) 006 -> 005 -> 004 -> 003 -> 002 -> 001
011 : 007 ->(B) 006 -> 005 -> 004 -> 030 -> 009 -> 010 -> 011
019 : 007 ->(B) 006 -> 005 -> 004 -> 012 -> 013 ->(F) 012 -> 016 -> 017 -> 018 -> 019
015 : 007 ->(B) 006 -> 005 -> 004 -> 012 -> 016 ->(F) 012 -> 013 -> 014 -> 015
Q2-2.006->007(후진) : 목표 040,041,008,001,011,019,015
040 : 007 ->(F) 006 -> 005 -> 004 ->(B) 005 -> 037 -> 036 -> 035 -> 034 -> 033 -> 032 -> 040
041 : 007 ->(F) 006 -> 005 -> 004 ->(B) 005 -> 037 -> 036 -> 035 -> 034 -> 033 -> 032 -> 031 -> 041
008 : 007 ->(B) 008
001 : 007 ->(F) 006 -> 005 -> 004 -> 030 ->(B) 004 -> 003 -> 002 -> 001
: 007 ->(F) 006 -> 005 -> 004 -> 012 ->(B) 004 -> 003 -> 002 -> 001
011 : 007 ->(F) 006 -> 005 -> 004 -> 003 ->(B) 004 -> 030 -> 009 -> 010 -> 011
007 ->(F) 006 -> 005 -> 004 -> 012 ->(B) 004 -> 030 -> 009 -> 010 -> 011
019 : 007 ->(F) 006 -> 005 -> 004 -> 012 -> 016 -> 017 -> 018 -> 019
015 : 007 ->(F) 006 -> 005 -> 004 -> 012 -> 013 -> 014 -> 015
Q3-1.009->010(전진) : 목표 040,041,008,001,011,019,015
Q3-2.009->010(후진) : 목표 040,041,008,001,011,019,015
Q4-1.013->014(전진) : 목표 040,041,008,001,011,019,015
Q4-2.013->014(후진) : 목표 040,041,008,001,011,019,015
Q5-1.033->032(전진) : 목표 040,041,008,001,011,019,015
Q5-2.033->032(후진) : 목표 040,041,008,001,011,019,015
Q6-1.006->007(전진) : 목표 040,041,008,001,011,019,015
Q6-2.006->007(후진) : 목표 040,041,008,001,011,019,015
Q7-1.009->010(전진) : 목표 040,041,008,001,011,019,015
Q7-2.009->010(후진) : 목표 040,041,008,001,011,019,015
Q8-1.013->014(전진) : 목표 040,041,008,001,011,019,015
Q8-2.013->014(후진) : 목표 040,041,008,001,011,019,015