제8부 항법
8.5 플래너·컨트롤러 플러그인
8.5.1 이 장에서 배우는 것 / 선수 지식
8.1.7에서 "Nav2를 쓴다는 것은 플러그인을 고르는 것"이라고 했다. 그중 가장 중요한 선택이 플래너(전역 경로)와 컨트롤러(지역 제어)다.
이 선택이 중요한 이유는 명확하다. 로봇의 기구학이 다르면 갈 수 있는 경로가 다르다. 차동 구동 로봇은 제자리 회전이 되지만 자동차형은 안 되고, 전방향 로봇은 옆으로 갈 수 있다. 기구학을 모르는 플래너가 만든 경로는 로봇이 따라갈 수 없다.
배우는 것:
- 플래너와 컨트롤러의 역할 분담 — 무엇을 누가 하는가.
- 플래너 카탈로그 — NavFn·Smac 계열·기타.
- 기구학별 선택 — 차동·전방향·아커만.
- 컨트롤러 카탈로그 — DWB·RPP·MPPI.
- 보조 플러그인 — 목표 검사기·진척 검사기·평활기.
- 선택 가이드 — 로봇에서 플러그인으로.
- 튜닝 요점 — 각 컨트롤러의 핵심 파라미터.
선수 지식: 8.4(코스트맵), 8.1(Nav2 구조), 6.5.6(이동 로봇 컨트롤러·/cmd_vel), 5.1.7(프레임).
정직: 플러그인 목록·파라미터는 배포판마다 추가·변경되며, 특히 MPPI·Smac 계열은 비교적 새롭다. 아래는 개념과 선택 기준에 집중하며, 정확한 파라미터는 Nav2 문서가 정본이다
(확인 필요). 성능 비교 수치는 인용하지 않는다(3.6.1).실행 확인(2026-08-16): Nav2 1.3.12를 설치해 플러그인 등록 이름을 실물과 대조했다. 이 장이 대는 플러그인은 전부 실재하나 표기 형식에 오류가 있어 정정했다 — 아래 함정 참조. 파라미터 이름·기본값·동작은 여전히 미검증이다.
함정 —
pkg/Class가 아니라pkg::Class다(실행 확인). Nav2 플러그인 이름을"nav2_navfn_planner/NavfnPlanner"처럼 슬래시로 적은 자료가 인터넷에 아직 많고, 이 책도 그렇게 적고 있었다(정정함). 현재 Nav2(1.3.12)의 플러그인 XML은<class type="nav2_navfn_planner::NavfnPlanner" …>만 등록하며name=속성이 없다. pluginlib은name이 없으면type을 조회 이름으로 쓰므로, 슬래시 형태는 조회에 실패한다 — 증상은 "플러그인을 찾을 수 없다"는 기동 실패다.nav2_smac_planner::SmacPlannerHybrid·nav2_behaviors::Spin(8.7) 등 전부 같다. 오래된 튜토리얼을 복사할 때 가장 먼저 확인할 지점이며, 확실한 방법은 해당 패키지의plugins.xml을 직접 열어type을 보는 것이다.다만 이것을 ROS 2 전체의 규칙으로 일반화하지 말라(실행 확인). 같은 날 MoveIt 2(2.12.4)를 확인해 보니 정반대였다 — MoveIt의 플러그인 XML은
name="occupancy_map_monitor/PointCloudOctomapUpdater"처럼 슬래시 조회 이름을 그대로 유지한다. 패키지마다 다르다. 규칙은 하나뿐이다 — 그 패키지의 플러그인 XML을 열어name이 있으면 그것을, 없으면type을 쓴다.
8.5.2 역할 분담
| 축 | 플래너 | 컨트롤러 |
|---|---|---|
| 입력 | 전역 코스트맵 + 목표 | 경로 + 지역 코스트맵 |
| 출력 | 기하 경로 | 속도 명령 |
| 시야 | 지도 전체 | 로봇 주변 |
| 주기 | 낮음(1 Hz·이벤트) | 높음(20 Hz) |
| 고려 | 도달 가능성·거리 | 동역학·즉각 장애물 |
| 시간 | 대개 없음 | 있음(속도·가속) |
핵심 구분: 플래너는 "어디로", 컨트롤러는 "어떻게".
함정: 플래너가 만든 경로를 컨트롤러가 못 따라갈 수 있다. 차동 구동 로봇에 홀로노믹 경로를 주면, 컨트롤러가 근사해서 따라가려다 진동하거나 실패한다. 둘의 기구학 가정이 일치해야 한다 — 이것이 선택의 핵심이다.
8.5.3 플래너 카탈로그
| 플래너 | 기구학 | 특징 |
|---|---|---|
| NavFn | 홀로노믹 가정 | 다익스트라·A*, 빠름·검증됨 |
| Smac 2D | 홀로노믹 가정 | 격자 A*, NavFn 대안 |
| Smac Hybrid-A* | 아커만·차동 | 기구학 제약 반영, 후진 지원 |
| Smac State Lattice | 임의 기구학 | 사전 정의 모션 프리미티브 |
| Theta* | 홀로노믹 | 격자 제약 없는 직선 경로 |
실물 등록 이름(실행 확인, Nav2 1.3.12): nav2_navfn_planner::NavfnPlanner · nav2_smac_planner::SmacPlanner2D · nav2_smac_planner::SmacPlannerHybrid · nav2_smac_planner::SmacPlannerLattice · nav2_theta_star_planner(별도 패키지). 위 표의 다섯 항목이 전부 실재한다.
planner_server:
ros__parameters:
expected_planner_frequency: 1.0
planner_plugins: ["GridBased"]
GridBased:
plugin: "nav2_navfn_planner::NavfnPlanner"
tolerance: 0.5
use_astar: false
allow_unknown: true
Smac Hybrid-A* 예:
GridBased:
plugin: "nav2_smac_planner::SmacPlannerHybrid"
tolerance: 0.25
downsample_costmap: false
allow_unknown: true
max_iterations: 1000000
motion_model_for_search: "DUBIN" # 또는 "REEDS_SHEPP"(후진 허용)
angle_quantization_bins: 72
minimum_turning_radius: 0.4 # ★ 로봇 최소 회전 반경
reverse_penalty: 2.0
change_penalty: 0.0
non_straight_penalty: 1.2
cost_penalty: 2.0
analytic_expansion_ratio: 3.5
smooth_path: true
핵심 차이 — 기구학 반영:
| 플래너 | 만드는 경로 |
|---|---|
| NavFn·Smac 2D | 격자 위 자유 경로(제자리 회전 가정) |
| Smac Hybrid-A* | 최소 회전 반경을 지키는 곡선 |
| Smac Lattice | 정의된 모션 조합 |
견해: 차동 구동 실내 로봇에는 NavFn으로 시작해도 충분한 경우가 많다. 빠르고 검증됐고 튜닝이 단순하다. Smac Hybrid-A*는 아커만 조향이나 후진이 필요한 경우, 또는 좁은 공간에서 정밀한 기동이 필요할 때 값을 한다.
함정:
minimum_turning_radius를 로봇 실제 값보다 작게 설정하면 못 따라가는 경로가 나온다. 차동 구동은 0으로 둘 수 있지만, 아커만은 실측값을 넣어야 한다.
함정:
allow_unknown이 참이면 미지 영역을 통과하는 경로가 나온다(8.4.2). 탐사 로봇에는 맞지만, 안전이 중요하면 거짓으로 두는 것을 검토한다.
8.5.4 컨트롤러 카탈로그
| 컨트롤러 | 방식 | 특징 |
|---|---|---|
| DWB | 궤적 샘플링 + 평가 | 검증됨·플러그인 가능한 평가자(critic) |
| RPP(Regulated Pure Pursuit) | 기하학적 추종 | 단순·부드러움, 경로 추종 우선 |
| MPPI | 샘플링 기반 최적화 | 강력, 계산 비용 큼 |
| Rotation Shim | 보조 | 큰 각도 차이를 먼저 회전으로 |
Graceful(확인 필요) | 부드러운 자세 수렴 제어 | 실물에 nav2_graceful_controller::GracefulController로 실재(실행 확인). 이 책은 다루지 않는다 |
실물 등록 이름(실행 확인): dwb_core::DWBLocalPlanner · nav2_regulated_pure_pursuit_controller::RegulatedPurePursuitController · nav2_mppi_controller::MPPIController · nav2_rotation_shim_controller::RotationShimController · nav2_graceful_controller::GracefulController.
controller_server:
ros__parameters:
controller_frequency: 20.0
controller_plugins: ["FollowPath"]
FollowPath:
plugin: "nav2_regulated_pure_pursuit_controller::RegulatedPurePursuitController"
desired_linear_vel: 0.5
lookahead_dist: 0.6
min_lookahead_dist: 0.3
max_lookahead_dist: 0.9
use_velocity_scaled_lookahead_dist: true
# 규제(regulation) — 속도를 줄이는 조건
use_regulated_linear_velocity_scaling: true
regulated_linear_scaling_min_radius: 0.9 # 곡률이 크면 감속
use_cost_regulated_linear_velocity_scaling: true
# 충돌 검사
max_allowed_time_to_collision_up_to_carrot: 1.0
8.5.4.1 DWB
궤적을 여러 개 샘플링해 각각을 점수화한다.
FollowPath:
plugin: "dwb_core::DWBLocalPlanner"
max_vel_x: 0.5
max_vel_theta: 1.5
acc_lim_x: 2.5
acc_lim_theta: 3.2
vx_samples: 20
vtheta_samples: 40
sim_time: 1.7
critics: ["RotateToGoal", "Oscillation", "BaseObstacle",
"GoalAlign", "PathAlign", "PathDist", "GoalDist"]
PathAlign.scale: 32.0
GoalAlign.scale: 24.0
PathDist.scale: 32.0
GoalDist.scale: 24.0
BaseObstacle.scale: 0.02
평가자(critic)가 DWB의 핵심이다:
| Critic | 평가 |
|---|---|
PathDist | 경로와의 거리 |
PathAlign | 경로 방향 정렬 |
GoalDist | 목표와의 거리 |
GoalAlign | 목표 방향 정렬 |
BaseObstacle | 장애물 비용 |
Oscillation | 진동 방지 |
RotateToGoal | 목표 근처에서 방향 정렬 |
견해: DWB의 critic 스케일 튜닝은 상호작용이 복잡하다. 한 값을 높이면 다른 행동이 바뀌고, 조합이 많아 시행착오가 길어진다. 처음 쓴다면 RPP가 튜닝이 단순하다 — 파라미터가 적고 각각의 의미가 직관적이다.
8.5.4.2 RPP (Regulated Pure Pursuit)
경로 앞의 한 점(carrot)을 향해 조향한다.
| 파라미터 | 효과 |
|---|---|
lookahead_dist | 작으면 정밀 추종·진동 위험, 크면 부드럽지만 코너 절단 |
use_velocity_scaled_lookahead_dist | 속도에 비례해 조정 |
regulated_linear_scaling_min_radius | 급커브에서 감속 |
use_cost_regulated_... | 장애물 근처에서 감속 |
견해: RPP는 "경로를 잘 따라가는" 것을 우선한다. 플래너가 좋은 경로를 만들었다면 잘 동작하고, 결과가 부드럽다. 반면 경로에서 크게 벗어난 회피는 잘 못한다 — 그것이 필요하면 DWB나 MPPI를 검토한다.
8.5.4.3 MPPI
여러 궤적을 샘플링해 비용을 최소화하는 제어를 찾는다.
FollowPath:
plugin: "nav2_mppi_controller::MPPIController"
time_steps: 56
model_dt: 0.05
batch_size: 2000
vx_max: 0.5
wz_max: 1.9
motion_model: "DiffDrive" # 또는 Omni · Ackermann
critics: ["ConstraintCritic", "ObstaclesCritic", "GoalCritic",
"GoalAngleCritic", "PathAlignCritic", "PathFollowCritic",
"PathAngleCritic", "PreferForwardCritic"]
| 축 | 평가 |
|---|---|
| 회피 성능 | 강력 — 복잡한 상황 대응 |
| 부드러움 | 좋음 |
| 계산 비용 | 높음(배치 크기·시간 단계에 비례) |
| 기구학 | 모델 선택 가능 |
| 튜닝 | critic 다수 |
정직: MPPI의 계산 부하는 상당하며, 임베디드 보드에서 20 Hz를 유지할 수 있는지 확인이 필요하다
(확인 필요).batch_size·time_steps를 줄이면 부하가 줄지만 성능이 떨어진다. 도입 전에 목표 하드웨어에서 주기를 측정하라.
견해: MPPI는 "회피가 중요하고 계산 여유가 있을 때" 선택한다. 사람이 많은 환경, 동적 장애물이 잦은 곳에서 강점이 있다. 반대로 정적 환경에서 단순 경로를 따라가는 용도라면 RPP가 경량이고 충분하다.
8.5.5 기구학별 선택
| 로봇 | 플래너 | 컨트롤러 | 비고 |
|---|---|---|---|
| 차동 구동(실내) | NavFn·Smac 2D | RPP 또는 DWB | 가장 흔한 조합 |
| 차동 + 동적 환경 | NavFn | MPPI | 회피 강화 |
| 전방향(메카넘) | NavFn·Smac 2D | DWB(omni)·MPPI(Omni) | 측면 이동 활용 |
| 아커만(자동차형) | Smac Hybrid-A* | RPP·MPPI(Ackermann) | 최소 회전 반경 |
| 트랙터·견인 | Smac Lattice | 전용 | 특수 기구학 |
| 좁은 공간 정밀 | Smac Hybrid-A* | MPPI | 후진 활용 |
# 전방향 로봇 — DWB 설정 예
FollowPath:
plugin: "dwb_core::DWBLocalPlanner"
max_vel_x: 0.5
max_vel_y: 0.5 # ★ 측면 이동 허용
vy_samples: 10
함정: 전방향 로봇인데
max_vel_y: 0.0으로 두면 측면 이동을 안 쓴다. 반대로 차동 구동인데 y 속도를 허용하면 로봇이 따라갈 수 없는 명령이 나간다. 기구학과 설정이 일치해야 한다.
8.5.6 보조 플러그인
8.5.6.1 목표 검사기(Goal Checker)
"도착했다"를 판정한다.
controller_server:
ros__parameters:
goal_checker_plugins: ["general_goal_checker"]
general_goal_checker:
plugin: "nav2_controller::SimpleGoalChecker"
xy_goal_tolerance: 0.25
yaw_goal_tolerance: 0.25
stateful: true
| 파라미터 | 의미 |
|---|---|
xy_goal_tolerance | 위치 허용 오차 |
yaw_goal_tolerance | 방향 허용 오차 |
stateful | 위치를 먼저 만족하면 그 뒤 방향만 |
함정: 허용 오차가 너무 작으면 도착 판정을 못 해 계속 미세 조정한다. 측위 정확도(8.3)보다 작게 설정하면 원리적으로 불가능하다. 측위 오차의 2~3배가 현실적이다.
견해:
stateful: true가 유용하다. 위치에 도달한 뒤 제자리에서 방향만 맞추므로, 위치와 방향을 동시에 만족시키려 진동하는 것을 막는다.
8.5.6.2 진척 검사기(Progress Checker)
"진전이 없다"를 감지한다.
progress_checker_plugins: ["progress_checker"]
progress_checker:
plugin: "nav2_controller::SimpleProgressChecker"
required_movement_radius: 0.5
movement_time_allowance: 10.0
10초 안에 0.5 m를 못 움직이면 실패로 판정하고, BT가 복구를 시작한다(8.6·8.7).
함정: 이 값이 너무 엄격하면 정상적인 느린 기동(좁은 곳 정밀 조작)에서 실패한다. 반대로 너무 느슨하면 갇힌 것을 오래 못 알아챈다. 로봇 속도와 환경에 맞춰 조정한다.
8.5.6.3 평활기(Smoother)
smoother_server:
ros__parameters:
smoother_plugins: ["simple_smoother"]
simple_smoother:
plugin: "nav2_smoother::SimpleSmoother"
tolerance: 1.0e-10
max_its: 1000
do_refinement: true
격자 기반 플래너의 계단식 경로를 부드럽게 만든다. RPP처럼 경로를 충실히 따르는 컨트롤러에서 특히 효과가 있다.
8.5.6.4 Rotation Shim
목표 방향과 크게 다를 때 먼저 회전한다.
FollowPath:
plugin: "nav2_rotation_shim_controller::RotationShimController"
primary_controller: "nav2_regulated_pure_pursuit_controller::RegulatedPurePursuitController"
angular_dist_threshold: 0.785 # 45도
rotate_to_heading_angular_vel: 1.8
견해: 차동 구동 로봇에서 Rotation Shim이 유용하다. 경로가 뒤쪽을 향할 때 곡선으로 선회하는 대신 제자리 회전으로 정렬한 뒤 출발하므로, 동작이 자연스럽고 공간을 덜 쓴다.
8.5.7 선택 절차
견해: 속도·가속 한계를 실제 사양으로 설정하는 것(6단계)이 자주 누락된다. 기본값이 로봇보다 빠르면 컨트롤러가 불가능한 명령을 내고, 느리면 성능을 낭비한다.
max_vel_x·acc_lim_x등을 실측·사양으로 채우라 — 5.3.3에서 URDF의effort·velocity를 실제 값으로 넣으라고 한 것과 같은 논리다.
함정: 컨트롤러의 속도 한계와
velocity_smoother·컨트롤러(ros2_control)의 한계가 일관되어야 한다(6.5.6·8.7). 서로 다르면 예상치 못한 동작이 나온다.
8.5.8 튜닝 요점
컨트롤러별로 먼저 볼 파라미터가 다르다.
| 증상 | RPP | DWB | MPPI |
|---|---|---|---|
| 코너를 절단한다 | lookahead_dist ↓ | PathDist.scale ↑ | PathFollowCritic ↑ |
| 진동한다 | lookahead_dist ↑ | Oscillation 조정 | 샘플·시간 조정 |
| 장애물에 너무 가깝다 | 비용 규제 활성 | BaseObstacle.scale ↑ | ObstaclesCritic ↑ |
| 너무 느리다 | 규제 조건 완화 | 속도 한계 확인 | 속도 한계 |
| 목표 근처에서 수렴하지 못한다 | 목표 검사기 허용오차 | RotateToGoal | GoalAngleCritic |
정직: 위 표는 일반적 경향이며, 파라미터 상호작용 때문에 예외가 많다
(확인 필요). 한 번에 하나씩 바꾸고 결과를 관찰하는 것이 유일하게 확실한 방법이다.
견해: 튜닝 전에 경로 자체를 보라. 컨트롤러가 비정상적으로 움직이는 원인이 플래너의 부적절한 경로인 경우가 많다. RViz2에서
/plan을 표시해 경로가 합리적인지 먼저 확인하고, 그 다음 추종을 본다. 순서를 거꾸로 하면 컨트롤러 파라미터를 헛되이 조정한다.
8.5.9 함정 카탈로그
| # | 함정 | 증상 | 대처 |
|---|---|---|---|
| 1 | 기구학과 플래너 불일치 | 못 따라가는 경로 | 8.5.5 표 |
| 2 | minimum_turning_radius 부정확 | 아커만이 경로 이탈 | 실측값 |
| 3 | 전방향인데 max_vel_y: 0 | 측면 이동 미사용 | 설정 일치 |
| 4 | 차동인데 y 속도 허용 | 불가능한 명령 | 0으로 |
| 5 | 속도·가속 한계 기본값 방치 | 성능 낭비·불가능 명령 | 실제 사양 |
| 6 | 컨트롤러·smoother 한계 불일치 | 예상 밖 동작 | 일관 설정 |
| 7 | 목표 허용오차 < 측위 정확도 | 도착 판정 실패 | 2~3배로 |
| 8 | 진척 검사기 과엄격 | 정상 기동에서 실패 | 환경에 맞게 |
| 9 | MPPI를 계산 확인 없이 | 주기 미달 | 목표 하드웨어 측정 |
| 10 | DWB critic을 한꺼번에 조정 | 원인 불명 | 하나씩 |
| 11 | 경로 확인 없이 컨트롤러 튜닝 | 무익한 작업 | /plan 먼저 |
| 12 | allow_unknown 무의식적 참 | 미지 통과 경로 | 안전 요구 검토 |
8.5.10 체크포인트
- 플래너와 컨트롤러의 역할 분담을 여섯 축으로 비교할 수 있는가. "어디로"와 "어떻게"의 구분은?
- 플래너가 만든 경로를 컨트롤러가 못 따라가는 경우가 왜 생기는가.
- 플래너 다섯 가지와 각각의 기구학 가정을 말할 수 있는가. Smac Hybrid-A*가 필요한 경우는?
minimum_turning_radius를 잘못 설정하면 무슨 일이 생기는가.- DWB의 critic 구조와, 처음 쓰는 사람에게 RPP를 권하는 이유는?
- RPP의
lookahead_dist가 작을 때·클 때의 트레이드오프는? - MPPI의 강점과 대가는? 도입 전에 확인해야 할 것은?
- 기구학별 플래너·컨트롤러 조합을 여섯 가지 말할 수 있는가.
- 목표 검사기의 허용오차를 측위 정확도와 어떻게 연관지어야 하는가.
stateful의 이점은? - 진척 검사기가 하는 일과, 값이 극단적일 때의 각 문제는?
- Rotation Shim이 차동 구동에서 유용한 이유는?
- 선택 절차에서 자주 누락되는 단계는 무엇인가.
- 컨트롤러 튜닝 전에 무엇을 먼저 확인해야 하는가.
다음 장 8.6은 이 모든 것을 조율하는 행동 트리를 다룬다. 왜 상태 기계가 아니라 행동 트리인가, 그리고 기본 트리를 어떻게 읽고 고치는가.