VFH+ 반응형 회피
Nav2의 planner→controller 파이프라인은 강력하지만, 무겁고 전역 지도에 의존합니다. 그런데 "지금 눈앞의 장애물을 빠르게 피하는" 단순한 반응이 필요할 때가 있습니다 — Nav2가 안 떠 있거나, 동적 장애물이 너무 많을 때. 그때 쓰는 가벼운 방법이 VFH+(Vector Field Histogram) 입니다.
3단계로 데이터를 줄인다
VFH의 핵심은 복잡한 환경을 점점 단순한 형태로 줄여, 마지막엔 "어느 방향으로 갈지" 하나만 남기는 것입니다.
도식 렌더링 중…
- Occupancy Grid — 로봇 주변의 장애물 격자. (앞 글의 점유 격자와 같은 개념)
- Polar Histogram — 격자를 로봇 중심의 방향별 막대그래프로 변환. 각 방향(sector)에 장애물이 얼마나 빽빽한지.
- Steering Valley — 막대가 낮은(=비어 있는) 골짜기를 찾아, 목표 방향에 가장 가까운 골짜기로 핸들을 꺾습니다.
극좌표 히스토그램으로 보면 이렇습니다.
방향: ← ↖ ↑ ↗ →
밀도: ███ █ · ·· ████
↑
여기가 valley (비었음) → 이 방향으로
데이터 축소를 코드로 보면 — 히스토그램에서 빈 골짜기를 고르는 것.
# 격자 → 방향별 장애물 밀도(polar histogram) → 가장 빈 골짜기
def steer_vfh(grid, goal_dir, threshold):
hist = [density(grid, s) for s in range(0, 360, 30)] # 12방향(30도)
valleys = [s for s, d in enumerate(hist) if d < threshold]
return min(valleys, key=lambda s: abs(s*30 - goal_dir)) # 목표에 가까운 골짜기
VFH+가 "+"인 이유 — 로봇 폭 보상
원래 VFH는 로봇을 점으로 봤지만, VFH+ 는 로봇의 폭을 보상합니다. 장애물까지 거리가 가까울수록, 그 장애물이 막는 각도를 넓혀 잡습니다.
💡 각도 확장 공식 — 장애물이 막는 각도를
enlargement_angle = arcsin((r_robot + r_safety) / d_obstacle)만큼 넓힙니다. Inflation이 costmap에서 장애물을 부풀린 것과 같은 발상을, 여기선 각도에서 합니다. 가까운 장애물일수록(d 작을수록) 더 넓게 막아 안전 여유를 확보합니다.
⚠️ 섹터 해상도의 한계 — 방향을 12개(30°)로만 나누면, 좁은 틈을 "막혔다"고 잘못 볼 수 있습니다. 해상도를 높이거나 VFH+의 보상을 쓰는 게 좁은 통로 통과의 관건입니다.
어디에 쓰나 — fallback 주행
VFH+는 전역 경로 계획기 없이도 도는 가벼움 덕분에, Nav2 스택이 가동되지 않는 상황의 fallback 주행으로 유용합니다. 순찰(patrol) 컨트롤러가 큰 경로를 주고, VFH+가 즉석 장애물을 피하는 식의 조합이 가능합니다. "무거운 전역 계획"과 "가벼운 반응 회피" 사이에서 상황에 맞게 고르는 것이죠.
한 줄 정리
📌 VFH+는 격자 → 방향별 polar histogram → 가장 빈 골짜기로 데이터를 줄여 "갈 방향"을 직접 고르는 가벼운 반응형 회피다. 로봇 폭을 각도 확장으로 보상하며, Nav2가 없을 때의 fallback 주행에 적합하다.
