Files
ENIG/Cs_HMI/docs/Predict_Function_Analysis.md

6.6 KiB

Predict() 함수 분석 보고서

1. 개요 (Overview)

AGVNavigationCore.Models.VirtualAGV 클래스의 Predict() 함수는 AGV의 현재 상태(위치, RFID 감지, 경로 등)를 기반으로 **다음 행동(이동, 정지, 속도 등)**을 결정하는 핵심 의사결정 함수입니다. 시스템은 이 함수를 주기적으로 호출하여 AGV가 경로를 이탈하지 않고 목적지까지 안전하게 이동하도록 제어합니다.

2. 논리 흐름 (Logic Flow)

Predict() 함수의 결정 로직은 다음 순서로 진행됩니다.

graph TD
    A[Start Predict] --> B{위치 확정 여부<br/>(RFID 2개 이상)}
    B -- No --> C[UnknownPosition<br/>(전진/저속/탐색)]
    B -- Yes --> D{현재 경로(Path) 존재?}
    D -- No --> E[NoPath<br/>(정지)]
    D -- Yes --> F{목적지 도착 임박?<br/>(이전 노드 모두 통과)}
    F -- Yes --> G{현재 노드 == 최종 노드?}
    G -- Yes --> H{최종 노드 완료(IsPass)?}
    H -- Yes --> I[Complete<br/>(정지/완료)]
    H -- No --> J[MarkStop<br/>(정지/마크센서대기)]
    G -- No --> K[Logic Continue]
    F -- No --> K
    K --> L{경로 이탈 확인<br/>(현재노드가 경로에 존재?)}
    L -- No --> M[PathOut<br/>(정지/재탐색요청)]
    L -- Yes --> N[GetCommandFromPath<br/>(다음 노드 이동 명령)]

단계별 상세 분석

  1. 위치 미확정 (Position Check)

    • 조건: !_isPositionConfirmed (감지된 RFID 개수 < 2)
    • 행동: UnknownPosition 리턴.
    • 명령: Forward (전진), SpeedLevel.L (저속).
    • 목적: RFID를 추가로 찾아 위치를 확정하기 위해 천천히 이동.
  2. 경로 없음 (Path Check)

    • 조건: _currentPath가 null이거나 비어있음.
    • 행동: NoPath 리턴.
    • 명령: Stop.
  3. 목적지 도착 확인 (Goal Check)

    • 조건: 경로상의 마지막 노드(lastNode) 이전의 모든 노드가 IsPass == true 상태인지 확인.
    • 분기:
      • 최종 완료: _currentNode가 마지막 노드이고, IsPass == true로 설정됨 -> Complete 리턴.
      • 도착 직전(MarkStop): _currentNode가 마지막 노드이지만, 아직 IsPass == false임 -> MarkStop 리턴. 이는 물리적인 정지(Mark Sensor 감지)를 기다리는 상태임.
  4. 경로 이탈 확인 (Deviation Check)

    • 로직: 현재 경로(DetailedPath) 중에서 _currentNode와 ID가 일치하고 아직 지나가지 않은(IsPass == false) 노드를 찾음.
    • 결과: 찾지 못하면 PathOut 리턴 (경로 이탈로 간주하여 정지).
  5. 이동 명령 생성 (Command Generation)

    • 함수: GetCommandFromPath(CurrentNodeId) 호출.
    • 로직: 현재 노드에 정의된 이동 지침(모터 방향, 마그넷 분기, 속도 등)을 가져옴.
    • 명령: 해당 지침대로 Normal 명령 리턴.

3. 주요 메커니즘 및 의존성

3.1. 자동 패스 (Auto-Pass) 메커니즘

AGV가 중간 노드의 RFID를 놓치고 다음 노드로 건너뛰었을 때, 로직이 깨지지 않게 하는 중요한 안전장치입니다.

  • 위치: SetPosition() 함수 내 (Line 583~593).
  • 동작: AGV가 새로운 노드(B)에 도착했다고 보고되면, 경로상에서 B보다 앞선 모든 노드(A)의 IsPass 속성을 강제로 true로 변경합니다.
  • 효과: Predict의 "목적지 도착 확인" 로직(All Previous Passed)이 올바르게 작동하도록 보장합니다.

3.2. MarkStop 및 완료 처리

  • AGV가 마지막 노드 RFID를 읽으면 PredictMarkStop을 리턴합니다 (아직 IsPass는 false).
  • _Util.cs 등 제어부는 이를 보고 감속/정지 준비를 합니다.
  • AGV가 물리적으로 마크 센서에 정지하면 _AGV.cs에서 SetCurrentNodeMarkStop()을 호출합니다.
  • 이때 비로소 마지막 노드의 IsPasstrue가 됩니다.
  • 다음 Predict 호출 시 Complete가 리턴되어 시퀀스가 종료됩니다.

4. 식별된 문제점 및 제안 사항 (Issues & Suggestions)

4.1. "Skipped Node" 시나리오의 잠재적 위험

  • 현상: SetPosition은 RFID 수신 시 호출되어 이전 노드들을 Auto-Pass 처리합니다. 하지만 만약 AGV가 경로를 이탈하여 엉뚱한 노드로 갔는데, 우연히 그 노드가 경로의 훨씬 뒤쪽 노드라면?
  • 위험: 중간의 모든 공정을 건너뛰고 바로 목적지 근처로 인식할 수 있습니다.
  • 제안: SetPosition에서 건너뛰는 노드의 개수가 너무 많거나(예: 3개 이상), 거리가 물리적으로 불가능할 정도로 멀다면 에러(PathJump)를 발생시키는 안전장치 추가 고려.

4.2. 하드코딩된 상수 (Magic Numbers)

  • 코드: DetectedRfidCount >= 2, BatteryLevel < 20.0f 등.
  • 제안: 이러한 값들을 const 또는 설정 파일(PUB.setting)로 관리하여 유지보수성을 높여야 합니다.

4.3. GetCommandFromPath의 Null 처리 불일치

  • 현상: Predict에서는 PathOut을 먼저 체크하지만, 기저에 있는 GetCommandFromPath에도 중복된 Null 체크/NoTarget 리턴 로직이 있음.
  • 제안: 로직의 일관성을 위해 검증 로직을 통일하거나, Predict에서 확실히 걸러낸 후 GetCommandFromPath는 데이터를 가져오는 역할만 하도록 단순화.

4.4. Predict의 "현재 노드 기준" 명령 생성

  • 현상: GetCommandFromPathCurrentNodeId를 인자로 받습니다. 즉, "현재 노드에서 수행해야 할 행동"을 반환합니다.
  • 의문: 만약 AGV가 노드와 노드 사이(Edge)에 있을 때, CurrentNodeId는 "지난 노드"입니다. 이때 "지난 노드"의 명령을 계속 수행하는 것이 맞는지(일반적으로는 맞음, Go Forward 등) 확인 필요.
  • 확인: 현재 로직은 맞습니다. 다음 RFID를 만날 때까지 이전 명령을 유지합니다.

5. 결론 (Conclusion)

Predict() 함수는 SetPosition(위치 업데이트 및 Auto-Pass) 및 MarkStop 처리 로직과 유기적으로 결합되어 있어 단독으로만 보면 이해하기 어려울 수 있습니다. 현재 로직은 RFID 누락(Skip)에 대한 복구 능력을 갖추고 있으며, 물리적 정지(MarkStop)와 논리적 완료(Complete)를 구분하여 정밀한 제어를 가능하게 설계되어 있습니다.

다만, 매직 넘버 사용과 일부 중복된 검증 로직은 리팩토링을 통해 개선할 여지가 있습니다.