AMR 경로 계획과 미션 실행 완벽 가이드 | 코스트맵부터 액추에이터 물리 검증까지
이 글의 핵심
AMR이 목적지까지 어떻게 경로를 계산하고(A*·DWA·Nav2), 그 경로 끝에서 실제로 픽업·리프트·컨베이어 이송 같은 물리 동작을 어떻게 수행하며 검증하는지를 소프트웨어와 하드웨어 양쪽 관점에서 다룹니다. amr-basics-guide.md에서 개념적으로만 소개했던 경로 계획과 미션 실행 단계를 실제 알고리즘, 하드웨어 제약, 안전 인터록 수준까지 파고듭니다.
이 글의 핵심
amr-basics-guide.md에서는 AMR의 소프트웨어 파이프라인을 “인지 → 측위 → 지도작성 → 경로 계획 → 모션 제어”라는 개념 수준에서 소개했습니다. 이 글은 그중에서도 경로 계획이 내부적으로 어떻게 동작하는지, 그리고 계획된 경로 끝에서 미션이 어떻게 실제 물리 동작으로 실행되고 검증되는지를 파고드는 심화 후속편입니다. A*와 Dijkstra의 실제 차이, DWA가 매 제어 주기마다 속도를 고르는 방식, ROS2 Nav2가 이를 어떻게 하나의 스택으로 묶는지, 그리고 VDA5050 오더가 리프트 모터·컨베이어·그리퍼 같은 실제 액추에이터 명령으로 바뀌고 리미트 스위치와 로드셀로 검증되는 과정까지 소프트웨어와 하드웨어 양쪽 관점에서 설명합니다.
왜 이 글을 쓰는가: “경로 계획”과 “미션 실행”은 AMR 코드베이스에서 가장 버그가 자주 발생하고, 동시에 가장 이해하기 어려운 두 영역입니다. 알고리즘 이름만 아는 것과, 왜 그 알고리즘을 쓰는지·하드웨어 제약이 어떻게 소프트웨어 설계를 강제하는지·물리적 검증이 왜 필수인지를 이해하는 것 사이에는 큰 차이가 있습니다.
1. 전역 경로 계획 — 코스트맵 위에서 최단 경로 찾기
1.1 점유 격자와 인플레이션 레이어
전역 경로 계획의 출발점은 코스트맵(Costmap) 입니다. 코스트맵은 지도를 일정 크기(보통 5~10cm)의 격자로 나누고, 각 칸에 “이 칸을 지나가는 것이 얼마나 위험한가”를 숫자로 저장한 자료구조입니다. 가장 아래 레이어가 점유 격자 지도(Occupancy Grid Map) 로, SLAM으로 만든 정적 지도를 기반으로 각 칸을 비어 있음(free), 차 있음(occupied), 미확인(unknown) 세 값 중 하나로 표시합니다.
여기에 인플레이션 레이어(Inflation Layer) 가 덧씌워집니다. 벽이나 선반처럼 실제로 점유된 칸 바로 옆을 로봇 중심이 지나가면, 로봇의 실제 몸체 폭 때문에 충돌이 일어납니다. 인플레이션 레이어는 점유된 칸을 중심으로 로봇의 반경만큼 비용을 방사형으로 감쇠시키며 퍼뜨려서, 장애물에 가까울수록 높은 비용이, 멀어질수록 낮은 비용이 매겨지도록 만듭니다.
비용 = 장애물까지 거리가 로봇 반경보다 가까우면 → 치명적 비용(통과 불가)
장애물까지 거리가 인플레이션 반경 이내면 → 거리에 반비례하는 감쇠 비용
그 외 → 0(자유 공간)
이 레이어가 없다면 경로 계획 알고리즘은 로봇을 점(point)으로 취급해서, 벽에 완전히 붙어 지나가는 “수학적으로는 맞지만 물리적으로는 충돌하는” 경로를 최적 경로로 골라버릴 수 있습니다. 인플레이션 레이어는 로봇의 물리적 크기를 경로 계획 알고리즘이 이해할 수 있는 숫자 비용으로 번역해주는 역할을 합니다.
1.2 Dijkstra와 A* — 같은 문제, 다른 효율
코스트맵이라는 그래프가 준비되면, 시작 칸에서 목적지 칸까지 가장 비용이 낮은 경로를 찾는 문제로 귀결됩니다. 가장 기본적인 해법이 Dijkstra 알고리즘입니다.
함수 DIJKSTRA(시작, 목적지, 코스트맵):
dist[모든 노드] = 무한대
dist[시작] = 0
우선순위_큐 = {(0, 시작)}
반복 우선순위_큐가 비어있지 않은 동안:
(현재_거리, 현재) = 우선순위_큐에서 거리가 가장 작은 항목 꺼내기
만약 현재 == 목적지:
경로 재구성 후 반환
각 이웃 in 현재의 인접 칸:
새_거리 = 현재_거리 + 이동비용(현재, 이웃)
만약 새_거리 < dist[이웃]:
dist[이웃] = 새_거리
우선순위_큐에 (새_거리, 이웃) 추가
반환 실패
Dijkstra는 목적지가 어느 방향에 있는지 전혀 모른 채로, 시작점을 중심으로 동심원처럼 사방으로 균등하게 탐색을 넓혀갑니다. 그 결과 최단 경로를 반드시 찾아내는 것은 보장되지만, 목적지와 정반대 방향의 노드까지 불필요하게 많이 방문하게 되어 큰 지도에서는 계산 비용이 빠르게 커집니다.
A* 알고리즘은 여기에 “이 노드에서 목적지까지 대략 얼마나 남았는가”를 추정하는 휴리스틱 함수를 더합니다.
함수 A_STAR(시작, 목적지, 코스트맵):
open_set = {시작}
g_cost[시작] = 0 # 시작부터 실제로 이동한 비용
f_cost[시작] = 휴리스틱(시작, 목적지) # g_cost + 추정 남은 거리
반복 open_set이 비어있지 않은 동안:
현재 = open_set에서 f_cost가 가장 작은 노드
만약 현재 == 목적지:
경로 재구성 후 반환
open_set에서 현재 제거
각 이웃 in 현재의 인접 칸:
새_g = g_cost[현재] + 이동비용(현재, 이웃)
만약 새_g < g_cost.get(이웃, 무한대):
g_cost[이웃] = 새_g
f_cost[이웃] = 새_g + 휴리스틱(이웃, 목적지)
open_set에 이웃 추가
반환 실패
두 알고리즘의 코드 구조는 거의 동일합니다. 차이는 단 한 줄, f_cost 계산에 휴리스틱 항을 더했는지 여부뿐입니다. 하지만 이 한 줄이 만드는 실무적 차이는 큽니다. 휴리스틱이 실제 남은 거리를 과대평가하지 않는 성질(admissible heuristic, 보통 유클리드 거리나 맨해튼 거리를 사용)을 만족하면, A는 여전히 최적 경로를 보장하면서도 목적지 방향으로 탐색을 집중시켜 방문 노드 수를 극적으로 줄입니다. 이것이 실무 AMR 전역 계획기 대부분이 순수 Dijkstra 대신 A, 혹은 그 변형(D* Lite, Hybrid A* 등)을 기본값으로 채택하는 이유입니다.
주의할 점은, 휴리스틱을 과도하게 크게 잡으면(실제 거리보다 훨씬 크게 추정하면) 탐색은 더 빨라지지만 더 이상 최적 경로를 보장하지 않게 된다는 것입니다. 실무에서 “경로가 이상하게 돌아간다”는 버그의 상당수가 이 admissibility 조건이 튜닝 과정에서 깨진 경우입니다.
2. 지역 경로 계획 — 매 제어 주기마다 속도를 고르는 문제
2.1 DWA(Dynamic Window Approach)의 핵심 아이디어
전역 계획이 만든 경로는 정적 지도 기준의 “큰 그림”일 뿐입니다. 사람이 갑자기 통로에 들어서거나 다른 로봇이 교차하는 상황까지 반영하려면, 훨씬 짧은 시간 창 안에서 반복적으로 재계산하는 지역 계획(Local Planning) 이 필요합니다. 이 영역에서 가장 널리 쓰이는 알고리즘이 DWA(Dynamic Window Approach) 입니다.
DWA의 핵심 아이디어는 “로봇이 다음 제어 주기 동안 물리적으로 낼 수 있는 속도의 범위는 제한되어 있다”는 사실에서 출발합니다. 로봇은 순간적으로 아무 속도나 낼 수 없습니다. 현재 속도에서 가속도 한계 안에서만 다음 속도로 전이할 수 있습니다. 이 제약이 만드는 실행 가능한 속도 조합의 집합을 동적 윈도우(Dynamic Window) 라고 부릅니다.
함수 DWA(현재_속도, 코스트맵, 목표_방향, dt):
후보_집합 = {}
# 1단계: 이번 제어 주기에서 물리적으로 도달 가능한 (v, w) 조합만 샘플링
for v in 범위(v_min, v_max, 샘플_간격):
for w in 범위(w_min, w_max, 샘플_간격):
# 가속도 한계를 벗어나는 조합은 애초에 제외
만약 abs(v - 현재_속도.v) > 최대가속도 * dt:
continue
만약 abs(w - 현재_속도.w) > 최대각가속도 * dt:
continue
후보_집합에 (v, w) 추가
최고_점수 = -무한대
최선의_후보 = None
# 2단계: 각 후보를 짧은 시간(dt) 동안 굴려보고 점수 매기기
for (v, w) in 후보_집합:
궤적 = 시뮬레이션(현재_위치, v, w, 시간_구간)
만약 궤적이 코스트맵상 장애물과 충돌:
continue # 충돌 궤적은 즉시 제외
점수 = (
가중치_클리어런스 * 장애물까지_최소거리(궤적, 코스트맵)
+ 가중치_방향 * 목표방향_정렬도(궤적, 목표_방향)
+ 가중치_속도 * 전진속도(v)
)
만약 점수 > 최고_점수:
최고_점수 = 점수
최선의_후보 = (v, w)
반환 최선의_후보 # 이번 주기에 실제로 내보낼 (선속도, 각속도)
DWA는 이렇게 걸러진 후보 각각을 짧은 시간 동안 앞으로 굴려보는 시뮬레이션을 수행하고, 세 가지 기준 — 장애물과의 클리어런스(얼마나 안전한가), 목표 방향과의 정렬도(얼마나 효율적인가), 전진 속도(얼마나 빠른가) — 를 가중합해 점수를 매깁니다. 가장 점수가 높은 (v, ω) 조합이 이번 제어 주기의 실제 모터 명령이 됩니다. 이 전체 과정이 매 제어 주기(통상 1020Hz, 즉 50100밀리초마다)마다 처음부터 다시 반복됩니다.
DWA가 실무에서 널리 채택된 이유는 계산이 비교적 가볍고, 로봇의 실제 가감속 한계를 계획 단계에서부터 명시적으로 반영하기 때문에 “계획대로 가라고 명령했는데 로봇이 물리적으로 그 명령을 따라갈 수 없는” 상황이 원천적으로 줄어든다는 데 있습니다.
2.2 TEB — 시간축까지 최적화하는 대안
DWA는 매 주기마다 짧은 시간 구간만 보고 독립적으로 최선의 속도를 고르는 반면, TEB(Timed Elastic Band) 는 경로 전체를 시간 축을 포함한 하나의 궤적으로 놓고, 장애물 회피·시간 최적성·동역학 제약을 동시에 만족하도록 탄성 밴드처럼 궤적 전체를 반복적으로 변형시켜 최적화합니다. DWA보다 계산량은 크지만, 좁은 통로에서의 회전이나 동적 장애물을 앞질러 피하는 것 같은 복잡한 기동에서 더 매끄러운 궤적을 만들어낼 수 있어, 연산 자원이 넉넉한 플랫폼에서 DWA의 대안으로 채택되곤 합니다.
3. ROS2 Nav2 — 전역과 지역 계획을 하나의 스택으로 묶기
지금까지 설명한 A*(또는 그 변형)와 DWA(또는 TEB)는 실무에서 대부분 처음부터 직접 구현하지 않고, ROS2의 표준 내비게이션 스택인 Nav2 위에서 플러그인 형태로 조합해 사용합니다. Nav2는 전역 계획기, 지역 계획기, 코스트맵, 회복 행동(recovery behavior)을 각각 교체 가능한 플러그인으로 구성한 프레임워크입니다.
# nav2_params.yaml (개념 예시 — 실제 배포 설정은 로봇마다 다름)
planner_server:
ros__parameters:
planner_plugins: ["GridBased"]
GridBased:
plugin: "nav2_navfn_planner/NavfnPlanner" # 내부적으로 A* 기반 탐색
use_astar: true
controller_server:
ros__parameters:
controller_plugins: ["FollowPath"]
FollowPath:
plugin: "dwb_core::DWBLocalPlanner" # DWA 계열 지역 계획기
local_costmap:
local_costmap:
ros__parameters:
plugins: ["obstacle_layer", "inflation_layer"]
inflation_layer:
plugin: "nav2_costmap_2d::InflationLayer"
inflation_radius: 0.55 # 인플레이션 반경(m)
이 설정 파일은 실제 배포 튜토리얼이 아니라, Nav2가 “어떤 전역 계획기 플러그인을, 어떤 지역 계획기 플러그인을, 어떤 코스트맵 레이어 구성으로 쓸 것인가”를 선언적으로 조합한다는 구조를 보여주기 위한 예시입니다. 실무 엔지니어가 Nav2 위에서 하는 작업의 상당 부분은 이 파라미터들 — 인플레이션 반경, 속도/가속도 한계, 샘플링 해상도, 각 점수 항목의 가중치 — 을 로봇의 실제 물리 사양과 운영 환경에 맞춰 튜닝하는 일입니다. 코드를 바닥부터 새로 작성하기보다, “왜 로봇이 이 모퉁이에서 멈칫거리는가”를 로그와 파라미터로 추적하고 조정하는 디버깅 역량이 훨씬 자주 요구됩니다.
4. 하드웨어 의존 체인 — 왜 제어 루프는 10~20Hz인가
경로 계획 알고리즘이 아무리 정교해도, 그 성능은 결국 아래에 깔린 하드웨어 체인의 가장 느린 고리에 의해 제한됩니다. 이 체인을 순서대로 따라가 보면 다음과 같습니다.
[LiDAR 스캔 주기]
통상 10~15Hz, 즉 66~100ms마다 새 스캔 데이터 도착
↓
[코스트맵 갱신]
새 스캔이 도착할 때마다 인플레이션 레이어 재계산
격자 해상도가 촘촘할수록, 갱신 반경이 넓을수록 연산량 증가
↓
[컴퓨트 자원 제약]
Jetson Orin, Intel NUC 등 임베디드 PC의 CPU/GPU 성능이
코스트맵 갱신 + DWA 후보 시뮬레이션을 얼마나 빨리 끝낼 수 있는지 결정
↓
[지역 계획기 재계산 주기]
위 두 단계가 끝나야 다음 (v, ω) 명령을 계산할 수 있음
↓
[모터 드라이버 명령 갱신 주기]
계산된 속도 명령이 실제 모터 컨트롤러로 전달되는 주기
(CAN 버스, RS485 등 통신 방식에 따라 자체 지연 존재)
이 체인의 각 단계는 서로 다른 하드웨어 부품에 의해 상한이 걸립니다. LiDAR가 아무리 빨리 스캔을 내보내도 컴퓨트가 코스트맵 갱신을 그 속도로 따라가지 못하면 의미가 없고, 계획이 아무리 빨리 끝나도 모터 드라이버가 그만큼 빠른 명령 갱신을 받아들이지 못하면 역시 병목이 됩니다. 실무에서 AMR의 제어 루프가 대체로 10~20Hz(50~100ms 주기)로 수렴하는 이유가 여기에 있습니다. 이 값은 이론적 최적치가 아니라, LiDAR 스캔 주기·임베디드 컴퓨트 성능·모터 드라이버 통신 지연이라는 세 하드웨어 제약이 동시에 감당할 수 있는 현실적인 균형점입니다.
4.1 제어 루프가 목표 주기를 못 맞추면 벌어지는 일
만약 코스트맵 갱신이나 DWA 시뮬레이션이 목표 주기(예: 10Hz, 즉 100ms) 안에 끝나지 않으면 어떤 일이 벌어질까요.
- 오래된 데이터로 계산한 명령을 반복 전송: 새 센서 데이터가 아직 반영되지 않은 채로 이전 주기의 계획 결과를 다시 내보내게 되어, 실제로는 이미 지나간 장애물 정보를 기준으로 판단하게 됩니다.
- 진동(oscillation): 계획 주기가 불규칙해지면 로봇이 “이쪽으로 가려다 저쪽으로” 하는 식으로 짧은 시간에 방향을 자주 바꾸는 떨림 현상이 나타나기 쉽습니다. 이는 각 주기의 점수 계산이 서로 다른 시점의 코스트맵을 기준으로 이루어지면서 일관성이 깨지기 때문입니다.
- 충돌 위험 증가: 가장 심각한 경우, 동적 장애물(사람, 다른 로봇)의 위치가 실제보다 오래된 값으로 남아 있는 상태에서 속도 명령이 나가면, 그 사이 장애물이 이동한 거리만큼 안전 마진이 잠식되어 실제 충돌 위험이 커집니다.
이 때문에 실무에서는 목표 제어 주기를 지키지 못하는 상황(연산 지연, 스레드 스케줄링 지연 등)을 감지하면 즉시 속도를 낮추거나 정지하는 워치독(watchdog) 로직을 지역 계획기 바깥에 별도로 두는 경우가 많습니다. 계획 알고리즘 자체의 정교함보다, “제때 계획하지 못했을 때 안전하게 실패하는” 설계가 실제 배포 환경에서는 더 중요하게 다뤄집니다.
5. 미션 실행 — 오더가 물리적 동작으로 바뀌기까지
경로 계획이 로봇을 목적지까지 이동시키는 문제를 풀었다면, 그다음은 “도착해서 무엇을 할 것인가”라는 전혀 다른 문제입니다. VDA5050 기반 플릿 관리 프로토콜에서 오더는 노드(node)와 엣지(edge)의 연속, 그리고 특정 노드에 도달했을 때 실행할 액션(action)으로 구성됩니다. 이 프로토콜 자체의 메시지 구조와 상태 필드에 대한 상세한 설명은 이미 vda5050-order-action-pick-handling.md에서 다루었으므로, 여기서는 이 오더가 로봇 내부에서 어떻게 상태 머신으로 소비되고, 최종적으로 어떤 물리적 동작으로 이어지는지에 집중합니다.
5.1 로봇 내부 상태 머신 개념도
[오더 수신]
↓
DRIVING ── (경로 계획 + 모션 제어로 다음 노드까지 이동)
↓
노드 도착 (도착 반경 이내 + 정지 완료 확인)
↓
해당 노드에 액션이 정의되어 있는가?
│
├─ 없음 → 다음 엣지로 즉시 DRIVING 재개
│
└─ 있음 → 액션 상태 머신 진입
ACTION_INITIALIZING (액추에이터 초기화, 안전 조건 확인)
↓
ACTION_RUNNING (실제 물리 동작 수행 중)
↓
ACTION_FINISHED (물리적 완료 신호 확인 후에만 전이)
↓
다음 엣지로 DRIVING 재개, 또는 오더 종료
이 상태 머신에서 실무적으로 가장 중요한 지점은 ACTION_RUNNING에서 ACTION_FINISHED로의 전이 조건입니다. 이 전이를 “모터에 명령을 보냈다”나 “정해진 시간이 지났다”만으로 판단하는지, 아니면 5.3절에서 다룰 물리적 확인 신호까지 요구하는지가 시스템의 신뢰성을 크게 좌우합니다.
5.2 물리적 액션 메커니즘 — AMR마다 다른 액추에이터
VDA5050의 액션 정의는 프로토콜 레벨에서는 추상적인 actionType 문자열(pick, drop, lift 등)에 불과하지만, 실제로 이를 수행하는 하드웨어는 AMR의 폼팩터에 따라 완전히 다릅니다.
- 리프트/스크류 구동 선반형 AMR: 창고에서 흔히 쓰이는 형태로, 선반 전체를 들어 올리는 방식입니다. 서보 모터가 리드 스크류(lead screw) 를 회전시켜 상판을 수직으로 밀어 올리며, 부하가 큰 만큼 위치 피드백을 위한 엔코더와 과부하 방지를 위한 전류 모니터링이 함께 구성됩니다.
- 컨베이어 이송형 AMR: 상판 자체가 소형 벨트 컨베이어로 되어 있어, 로봇이 스테이션에 도착하면 벨트 모터를 구동해 화물을 로봇 안팎으로 밀어 넣거나 빼냅니다. 스테이션 쪽 컨베이어와 로봇 쪽 컨베이어의 속도·타이밍을 맞추는 동기화가 중요합니다.
- 협동로봇 팔 탑재형 AMR: 이동 플랫폼 위에 소형 협동로봇(cobot) 팔을 얹어, 도착 후 팔이 직접 물건을 집습니다. 그리퍼는 공압식(pneumatic) 또는 전동식(electric) 으로 구현되며, 공압식은 힘 제어가 단순하고 빠른 반면 별도의 압축 공기 공급계가 필요하고, 전동식은 정밀한 힘·위치 제어가 가능하지만 상대적으로 느립니다.
세 방식 모두 “액션을 수행한다”는 소프트웨어 상태 전이는 동일하게 ACTION_RUNNING이지만, 그 아래에서 실제로 구동되는 것은 리드 스크류를 돌리는 서보, 벨트를 돌리는 모터, 그리퍼를 여닫는 공압 밸브로 전혀 다른 물리 시스템이라는 점이 실무에서 중요합니다.
5.3 물리적 완료 검증 — 왜 “명령을 보냈다”가 “완료했다”와 다른가
소프트웨어가 액추에이터에 동작 명령을 내리는 것과, 그 동작이 실제로 의도한 대로 완료되었는지를 확인하는 것은 서로 다른 문제입니다. 이 간극을 메우는 것이 물리적 센서를 통한 검증입니다.
- 리미트 스위치(Limit Switch): 리프트가 완전히 상승했는지, 그리퍼가 완전히 닫혔는지를 기계적 접점으로 확인합니다. 전류 기반 추정보다 훨씬 단순하고 신뢰도가 높아, 위치 확인의 1차 수단으로 널리 쓰입니다.
- 로드셀(Load Cell): 실제로 화물의 무게가 실렸는지를 확인합니다. 리프트가 끝까지 올라갔더라도 선반 위에 화물이 없거나 예상 무게와 다르다면, 로드셀 값이 이 불일치를 즉시 드러냅니다.
- 근접 센서(Proximity Sensor): 컨베이어 이송이나 그리퍼 파지에서, 물체가 실제로 지정된 위치에 존재하는지를 비접촉으로 확인합니다.
이 확인 과정이 중요한 이유는, 소프트웨어의 “액션 완료” 메시지가 물리적 사실과 다를 수 있는 실패 모드가 실제로 존재하기 때문입니다. 예를 들어 리프트 모터에 정해진 시간만큼 전류를 흘려보낸 뒤 타이머 만료로 완료를 판단하는 설계라면, 화물이 걸려 실제로는 절반만 상승했거나 아예 움직이지 않았는데도 소프트웨어는 성공 상태를 상위 플릿 관리 시스템에 보고할 수 있습니다. 이 상태로 다음 엣지로 이동하면, 화물이 로봇 밖으로 떨어지거나 이후 하역 지점에서 예상과 다른 결과가 나타나는 등 안전·운영 양쪽에서 문제가 발생합니다. 그래서 신뢰성 있는 AMR 설계에서는 ACTION_FINISHED 전이 조건에 반드시 하나 이상의 물리적 확인 신호를 포함시키는 것을 원칙으로 삼습니다.
5.4 안전 하드웨어의 개입 — 미션 실행 중 인터럽트
미션이 DRIVING이든 액션 실행 중이든, 안전 관련 하드웨어는 이 상태 머신과 독립적인 우선순위로 개입합니다.
- 안전 등급 LiDAR(Safety-rated LiDAR)의 감속/정지 구역: 정의된 구역 안에 장애물이 들어오면, 일반 내비게이션 스택을 거치지 않고 하드웨어에 가까운 레벨에서 즉시 속도를 제한하거나 정지시킵니다. 이 신호는 소프트웨어 상태 머신 관점에서 DRIVING 또는 ACTION_RUNNING을 일시 정지(PAUSED) 상태로 강제 전이시키는 형태로 반영됩니다.
- 물리적 비상 정지(E-Stop): 버튼이 눌리면 모터 전원 자체가 차단되며, 이는 소프트웨어의 어떤 상태 전이 로직보다도 우선합니다. 소프트웨어는 이 이벤트를 감지해 현재 진행 중이던 오더를
FAILED나PAUSED로 기록하고, 재개 시 안전 조건을 다시 확인하는 절차를 거칩니다. - 워치독 타이머: 통신이 두절되거나 제어 루프가 목표 주기를 벗어나면, 별도의 워치독이 자동으로 정지 명령을 발동합니다.
이 안전 계층이 상위 미션 로직과 의도적으로 분리되어 설계된다는 점이 중요합니다. 경로 계획이나 액션 상태 머신에 소프트웨어 버그가 있어도, 안전 하드웨어 인터록은 그 버그와 무관하게 동작해야 하기 때문입니다. VDA5050 기반 플릿 시스템에서는 이런 안전 이벤트가 발생했을 때 오더 상태를 어떻게 갱신하고 플릿 관리자에게 어떻게 보고하는지가 프로토콜 레벨의 세부 사항인데, 이 부분의 구체적인 메시지 구조와 C++ 구현 패턴은 vda5050-order-action-pick-handling.md와 vda5050-protocol-cpp-guide.md에서 자세히 다루고 있으니 함께 참고하시기 바랍니다. 여러 대의 AMR이 이런 인터럽트 상황에서도 서로 충돌 없이 조율되는 플릿 게이트웨이 아키텍처는 agv-fleet-gateway-development-guide.md에서 다룹니다.
6. 마치며 — 경로 계획과 미션 실행은 결국 하나의 신뢰성 문제
이 글에서 다룬 두 축 — 경로 계획(A*, DWA, Nav2)과 미션 실행(상태 머신, 액추에이터, 물리적 검증) — 은 서로 다른 알고리즘과 하드웨어를 다루지만 본질적으로 같은 질문에 답하고 있습니다. 소프트웨어가 계산한 결과를 물리 세계가 실제로 따라갈 수 있는가, 그리고 물리 세계의 결과를 소프트웨어가 정확히 확인할 수 있는가라는 질문입니다.
경로 계획에서는 이 질문이 “코스트맵의 인플레이션 반경이 로봇의 실제 몸체 크기를 정확히 반영하는가”, “DWA가 고른 속도가 로봇의 실제 가감속 한계 안에 있는가”, “제어 루프가 하드웨어 체인이 감당할 수 있는 주기를 지키는가”의 형태로 나타납니다. 미션 실행에서는 “액션 완료 보고가 리미트 스위치나 로드셀 같은 물리적 신호에 근거하는가”, “안전 하드웨어의 개입이 상위 로직과 독립적으로 동작하는가”의 형태로 나타납니다. 두 영역 모두에서, 알고리즘의 정교함보다 소프트웨어와 하드웨어 사이의 이 간극을 얼마나 촘촘하게 메웠는가가 실제 배포 환경에서의 신뢰성을 결정합니다.