30代エンジニアの備忘録のカバー画像

30代エンジニアの備忘録

組み込み開発・信号処理・プログラミングの技術メモと短編小説

🦭 【ROS2入門⑪】Nav2入門 - 自律ナビゲーションスタックでロボットを自律移動させる

シリーズ この記事は「ROS2入門シリーズ」の一部です。 シリーズ目次を見る

2026年5月時点。ROS 2 入門の締めとして、自律移動スタック Nav2 公式ドキュメント を扱います。想定読者は Gazebo シミュまで終えた方で、ここではコンポーネントの並びと TurtleBot3 でよくある起動順を優先します。

Ubuntu 22.04 + ROS 2 Humble 想定です。SLAM 実装(Cartographer / slam_toolbox)や launch 名は環境で差が出るため、手元のパッケージ README と TurtleBot3 e-Manual が正です。細部パラメータはプロジェクト側の yaml に従ってください。

本記事を読み終えると、地図作成→map_server→Nav2 goal までの流れを説明でき、失敗時に use_sim_time や初期姿勢を疑える状態になります。


Nav2(Navigation 2)の構成はどうなっている?

Nav2 はプランナ・コントローラ・コストマップ・行動ツリーなどが協調する自律移動スタックです。全体像は Nav2 公式ドキュメント の Architecture を参照し、下表は教材としての役割整理です。

Nav2スタック全体像
Nav2スタック全体像
主要コンポーネント
コンポーネント 役割
BT Navigator ビヘイビアツリーでナビゲーション処理を制御
Planner Server ゴールまでのグローバルパスを計算(A*等)
Controller Server ローカル障害物回避とモーター指令
Costmap 2D 障害の膨張(インフレーション)と通行可能領域のコストを管理
SLAM / 自己位置まわり Cartographer や slam_toolbox など。実際の構成はメタパッケージ側の前提に従う

SLAM で地図はどう作る?

SLAM(Simultaneous Localization and Mapping)は、移動しながら地図を溜めつつ自己位置を推定する処理の総称です。下は Cartographer 系 launch がある前提の例です。apt で入れるパッケージ名は launch と揃え、slam_toolbox と Cartographer を取り違えないでください(TurtleBot3 e-Manual)。

# SLAM 用パッケージは、使う launch に合わせて入れる(例のためコメントのみ)
# sudo apt install ros-humble-turtlebot3-cartographer
# または slam_toolbox 版なら、その launch に対応したパッケージを選択

# ターミナル1: Gazebo起動
export TURTLEBOT3_MODEL=burger
ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py

# ターミナル2: SLAM(Cartographer 前提の一例。自分の環境の launch に差し替え)
ros2 launch turtlebot3_cartographer cartographer.launch.py use_sim_time:=True

# ターミナル3: teleopでロボットを動かして地図を作成
ros2 run turtlebot3_teleop teleop_keyboard

# 地図を保存
ros2 run nav2_map_server map_saver_cli -f ~/map
SLAM地図作成→Nav2自律移動の流れ
SLAM地図作成→Nav2自律移動の流れ

Nav2 で自律移動はどう試す?

# 保存した地図を使ってNav2を起動
# ターミナル1: Gazebo
export TURTLEBOT3_MODEL=burger
ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py

# ターミナル2: Nav2起動
ros2 launch turtlebot3_navigation2 navigation2.launch.py \
  use_sim_time:=True \
  map:=$HOME/map.yaml

RViz2 が開いたら、環境により次のような流れになります:

  1. 2D Pose Estimate で初期姿勢の目安を与える(地図座標との整合)
  2. Nav2 Goal でゴールを指定
  3. プランナ/コントローラが通れると、cmd_vel など経由で移動指令が流れる(パラメータやコストマップ次第で止まることもあります)

Python から Nav2 にゴールはどう送る?

import rclpy
from rclpy.node import Node
from nav2_msgs.action import NavigateToPose
from rclpy.action import ActionClient


class NavGoalSender(Node):

    def __init__(self):
        super().__init__('nav_goal_sender')
        self._client = ActionClient(
            self, NavigateToPose, 'navigate_to_pose')

    def send_goal(self, x, y):
        goal = NavigateToPose.Goal()
        goal.pose.header.frame_id = 'map'
        goal.pose.header.stamp = self.get_clock().now().to_msg()
        goal.pose.pose.position.x = x
        goal.pose.pose.position.y = y
        goal.pose.pose.orientation.w = 1.0

        self._client.wait_for_server()
        future = self._client.send_goal_async(goal)
        self.get_logger().info(f'Goal sent: ({x}, {y})')
        return future

コストマップとは何か?

コストマップ = 「そのマスへ進むコスト」を敷いたレイヤーのイメージ

  0   … 問題なく通行しやすい
  100 … 致命的な障害として扱う(通れない判定になりやすい)
  -1  … まだよく見えない(未知)な領域

検出されている障害の周りにはしばしば「避けやすい」コストが積まれ、パスが脇へ寄る。

Nav2 試行でつまずきやすい点は?

  • use_sim_time:=True をシミュと揃え忘れると、TF や地図の時刻まわりで挙動がおかしくなりやすい
  • 地図ファイルの map.yaml と .pgm のパスがズレると map_server が落ちる
  • 初期姿勢(Pose Estimate)が大きく外れていると、局所プランナがすぐ異常終了することがある(RViz で微調整)
  • navigate_to_pose の frame_id(例: map)と TF が繋がっているかを、tf2_tools/RViz で先に確認する

ROS 2 入門シリーズの振り返りは?

ROS 2 入門シリーズ(①〜⑪)ひとまとめです。自分のワークスペースで 再現できた項目から復習すると定着しやすいです。

① ROS 2 の全体像・よくある用語
② Ubuntu 22.04 と ROS 2 Humble の導入
③ ノード/トピック/サービス/アクションの概念
④ Python で Pub/Sub
⑤ カスタム .msg /.srv /.action(インターフェース用パッケージ)
⑥ Python でサービス・アクション(例題ベース)
⑦ `colcon`・パッケージひな型・launch
⑧ RViz2・rqt
⑨ TF2(フレームと変換)
⑩ Gazebo と ros_gz まわり(シミュ環境依存に注意)
⑪ 本記事: Nav2(自律移動スタックの入口)
このあと広げやすいトピック
  • 実機への載せ替え:センサ・オドメ・安全停止を含めて差分前提
  • MoveIt 2:アームなどの経路計画
  • micro-ROS:マイコンと ROS 2 の接続
  • ROS 2 とセキュリティ:DDS/ネットワーク方針