← BlogAMR 내비게이션 입문· 9/12

Recovery Behavior — 막혔을 때 로봇이 스스로 빠져나오는 행동들

경로 추종이 실패하거나 로봇이 막혔을 때 spin·backup 같은 복구 행동이 어떻게 트리거되고, Behavior Tree의 복구 분기로 이어지는지. 그리고 플릿 차원의 STOP 처리.

약 3분
Nav2recoverybehavior-treestuckAMR

Recovery Behavior

아무리 좋은 경로 계획기와 컨트롤러가 있어도, 로봇은 막힙니다. 사람이 갑자기 앞을 막거나, 좁은 모서리에 끼거나, 경로가 잠깐 사라지거나. 이때 로봇이 멈춰서 굳어버리지 않고 스스로 빠져나오게 하는 게 recovery behavior(복구 행동)입니다.

막히면 트리의 복구 가지로 빠진다

Behavior Tree에서 봤듯, 경로 추종(FollowPath)이 실패하면 BT는 곧장 복구 분기로 넘어갑니다.

도식 렌더링 중…

각 복구 행동의 쓸모는 명확합니다.

  • Spin — 제자리에서 회전해 LiDAR로 주변을 다시 스캔. 갇힌 줄 알았는데 사실 길이 있던 경우 효과적.
  • BackUp — 0.5m쯤 후진. 모서리에 코를 박은 끼임 상태를 푸는 데 유용.
  • Wait — 사람·다른 로봇이 지나가길 잠깐 기다림.

복구가 끝나면 다시 경로를 계획해 재시도합니다. "성공할 때까지 같은 자리에서 우기는" 대신, 상황을 바꿔 보고 다시 도전하는 구조입니다.

언제 "막혔다"고 판단하나

복구는 아무 때나 트리거되면 안 됩니다. 진행이 멈췄는지(progress) 를 감시하는 검사기가 일정 시간(예: 30초) 동안 전진이 없으면 stuck으로 판정해 복구를 부릅니다.

💡 복구도 실패할 수 있다 — local costmap이 깨져 "Off Grid" 상태면 spin·backup조차 실패합니다. 복구가 안 먹으면 복구 자체가 아니라 costmap 범위를 의심하세요.

우리 런에서 실제로 발화한 복구

여기까지가 교과서입니다. 그런데 저희 창고 런 로그를 뒤져 보면 Nav2 의 spin·backup·wait 은 한 번도 발화하지 않았습니다. 대신 그 위층에 저희가 얹은 로직이 막힘을 풀었습니다.

[PASS-GATE]   HO_A: 앞 구간 폭 1.10m, 교행필요 1.97m, HO_B 가 먼저 → 진입 전 정지(중심선 유지)
[PASS-ALIGN]  HO_A: 앞 구간 중심선 횡오차 +0.61m → 정렬 후 진입 (허용 0.10m)
[PASS-RESUME] HO_A: 같은 목표 재발행 1/4 · 9.2s 정지(이동 0.05m) · 통로 비었음

왼쪽은 교과서의 복구 분기(FollowPath 실패 → spin·backup·wait → 재시도)이고, 저희 창고 런에서 이 가지는 0회 발화했습니다. 오른쪽이 실제로 막힘을 푼 경로입니다 — 9.2초 동안 0.05m 밖에 못 움직인 것을 「막혔다」로 판정하고(임계 8초·0.25m), 통로가 비었는지 확인한 뒤, 같은 목표를 다시 발행합니다(최대 4회).왼쪽은 교과서의 복구 분기(FollowPath 실패 → spin·backup·wait → 재시도)이고, 저희 창고 런에서 이 가지는 0회 발화했습니다. 오른쪽이 실제로 막힘을 푼 경로입니다 — 9.2초 동안 0.05m 밖에 못 움직인 것을 「막혔다」로 판정하고(임계 8초·0.25m), 통로가 비었는지 확인한 뒤, 같은 목표를 다시 발행합니다(최대 4회).

차이는 무엇을 보고 「막혔다」고 판정하느냐에 있습니다. Nav2 의 복구는 FollowPath 라는 행동의 실패를 신호로 삼습니다. 위 로그는 그 대신 결과를 봅니다 — 시간이 지났는데 움직인 거리가 없으면 막힌 것으로 봅니다. 경로 추종이 「성공 중」이라고 보고하면서도 로봇이 제자리인 경우가 있는데, 이때 앞의 신호는 침묵하고 뒤의 신호는 울립니다.

⚠️ 복구 로직이 두 겹이면 어느 겹이 돌았는지 로그로 구분해 두어야 합니다 — 「복구가 됐다」만 보고 Nav2 의 복구가 정상이라고 읽으면, 실제로는 한 번도 안 돌아간 기능을 검증했다고 착각하게 됩니다. 저희도 이 글을 쓰면서 로그를 뒤져 보고서야 발화 0회를 확인했습니다.

플릿 차원의 멈춤 — 충돌 회피로서의 STOP

다중 로봇에서는 한 단계 위의 복구도 있습니다. 충돌 위험을 감지하면 플릿 관리자가 특정 로봇에 STOP을 내리는데, 이때 단순히 바퀴를 멈추는 게 아니라 Nav2의 목표(goal)를 취소해야 합니다.

⚠️ 바퀴만 멈추고 goal을 살려두면, Nav2가 "왜 안 가지?" 하며 계속 미는 명령을 냅니다. 충돌 회피로 멈출 땐 goal을 취소해 컨트롤러가 미는 것 자체를 멈춰야 합니다.

한 줄 정리

📌 Recovery는 막혔을 때 spin(다시 보기)·backup(끼임 탈출)·wait(양보) 로 상황을 바꿔 재시도하는 행동이며, Behavior Tree의 복구 분기로 실행된다. 복구가 안 먹으면 costmap을, 플릿 STOP은 바퀴가 아니라 goal 취소로 처리한다.