TurtleBot3 시뮬레이션으로 배우는 SLAM Toolbox

이번 강의에서는 ROS 2 Humble 환경에서 SLAM Toolbox를 사용해 모바일 로봇의 2D 지도를 작성하고 저장하는 방법을 실습합니다.

1. SLAM의 등장 배경

모바일 로봇이 실내에서 자율주행을 하려면 두 가지 정보가 필요합니다.

첫째, 내가 어디에 있는가?

둘째, 주변 환경이 어떻게 생겼는가?

사람은 방 안을 걸어 다니면서 벽, 문, 책상 위치를 자연스럽게 기억합니다. 하지만 로봇은 센서 데이터만 보고 판단해야 합니다. 특히 실내에서는 GPS를 사용할 수 없거나 정확도가 매우 떨어지기 때문에, 로봇은 바퀴 엔코더, IMU, LiDAR 같은 센서를 이용해 자기 위치와 지도를 동시에 추정해야 합니다.

이 문제를 해결하는 기술이 SLAM입니다.

SLAM은 Simultaneous Localization and Mapping의 약자입니다.

한국어로는 동시적 위치추정 및 지도작성이라고 부릅니다.

로봇이 이동하면서 센서 데이터를 이용해 지도를 만들고, 동시에 그 지도 안에서 자신의 위치를 추정하는 기술입니다.

2D 모바일 로봇에서는 보통 LiDAR의 LaserScan 데이터와 로봇의 오도메트리, TF 정보를 이용합니다. SLAM Toolbox도 /scan 토픽과 odom_frame에서 base_frame으로 이어지는 TF를 사용하고, 결과로 /map과 map -> odom TF를 제공합니다.

2. SLAM Toolbox 개요

SLAM Toolbox는 ROS 환경에서 2D SLAM을 수행하기 위한 패키지입니다.

개발자는 Steve Macenski이며, 프로젝트 설명에 따르면 Simbe Robotics 시절에 개발되었고 이후 Samsung Research 등에서 유지·관리되었습니다.

SLAM Toolbox는 단순히 지도를 한 번 만들고 끝나는 패키지가 아닙니다. 일반적인 2D SLAM, 저장된 pose graph를 다시 불러와 이어서 매핑하는 기능, lifelong mapping, localization mode, synchronous/asynchronous mapping, pose graph 기반 최적화, RViz 플러그인 등을 제공합니다.

3. SLAM Toolbox의 핵심 특징

1) 2D LiDAR 기반 SLAM

SLAM Toolbox는 2D LiDAR 기반 모바일 로봇에서 많이 사용됩니다. 입력으로는 주로 다음 데이터를 사용합니다.

LiDAR 스캔/scan, sensor_msgs/LaserScan
로봇 좌표 변환/tf, /tf_static
오도메트리 기준 프레임odom
로봇 기준 프레임base_footprint 또는 base_link
지도 프레임map

출력으로는 다음 데이터를 제공합니다.

/mapnav_msgs/OccupancyGrid 형식의 2D 점유 격자 지도
/pose지도 기준 로봇 추정 위치
map -> odom TF지도 좌표계와 오도메트리 좌표계의 관계
/slam_toolbox/pose_graphpose graph 정보
/slam_toolbox/new_node_eventpose graph에 새 노드가 추가될 때 발생하는 이벤트

2) Online Async 모드

ROS 2 실습에서는 보통 다음 실행 파일을 많이 사용합니다.

ros2 launch slam_toolbox online_async_launch.py

online_async는 로봇이 움직이는 동안 실시간으로 센서 데이터를 받아 지도를 갱신합니다.

Nav2 공식 튜토리얼에서도 SLAM Toolbox를 실행할 때 online_async_launch.py를 사용하는 예제가 제시되어 있습니다.

3) Pose Graph 기반 지도 작성

SLAM Toolbox는 단순히 현재 스캔을 누적하는 방식이 아니라, 로봇의 이동 경로와 스캔 정보를 pose graph 형태로 관리합니다.

쉽게 말하면 다음과 같습니다.

로봇 위치 1 ---- 로봇 위치 2 ---- 로봇 위치 3 ---- 로봇 위치 4
    |              |              |              |
  scan1          scan2          scan3          scan4

로봇이 이동할 때마다 위치 노드가 생기고, 각 위치에서 LiDAR 스캔이 연결됩니다. 로봇이 다시 예전에 지나갔던 장소로 돌아오면 loop closure가 발생할 수 있습니다.

Loop closure는 “여기 예전에 왔던 곳이네?”라고 판단하는 과정입니다. 이 과정이 잘 되면 전체 지도의 뒤틀림이 줄어듭니다.

4) 지도 저장 방식

SLAM Toolbox에서는 지도를 두 가지 관점으로 저장할 수 있습니다.

첫 번째는 일반적인 지도 저장입니다.

ros2 run nav2_map_server map_saver_cli -f ~/map

이 명령은 다음 파일을 만듭니다.

~/map.pgm
~/map.yaml

Nav2 공식 튜토리얼에서도 SLAM 중 생성된 지도를 저장할 때 map_saver_cli를 사용합니다.

두 번째는 SLAM Toolbox의 pose graph 직렬화입니다.

ros2 service call /slam_toolbox/serialize_map slam_toolbox/srv/SerializePoseGraph "{filename: 'my_map'}"

일반 .pgm, .yaml 지도는 Navigation에서 쓰기 좋습니다. 반면 serialized pose graph는 나중에 다시 불러와서 이어서 매핑하거나, SLAM Toolbox localization에 사용할 수 있습니다. SLAM Toolbox는 /slam_toolbox/serialize_map, /slam_toolbox/deserialize_map, /slam_toolbox/save_map 등의 서비스를 제공합니다.

4. 실습 전체 구조

이번 실습은 다음 순서로 진행합니다.

1. TurtleBot3 시뮬레이션 실행
2. SLAM Toolbox 실행
3. RViz에서 /map, /scan, /tf 확인
4. 키보드로 로봇 조종
5. 지도 저장
6. 저장된 지도 확인
7. Python 노드로 SLAM 상태 모니터링

1) 터미널 기본 준비

TurtleBot3 모델을 지정합니다.

export TURTLEBOT3_MODEL=burger

사용 중인 모델이 waffle 또는 waffle_pi라면 다음처럼 바꿉니다.

export TURTLEBOT3_MODEL=waffle

또는

export TURTLEBOT3_MODEL=waffle_pi

확인합니다.

echo $TURTLEBOT3_MODEL

출력 예:

burger

2) TurtleBot3 시뮬레이션 실행

터미널 1에서 Gazebo 시뮬레이션을 실행합니다.

ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py

정상 실행되면 Gazebo에 TurtleBot3와 실습용 월드가 나타납니다.

다른 월드를 쓰고 싶다면 예를 들어 다음처럼 실행할 수 있습니다.

ros2 launch turtlebot3_gazebo turtlebot3_house.launch.py

3) 현재 토픽 확인

터미널 2를 열고 토픽 목록을 확인합니다.

source /opt/ros/humble/setup.bash
source ~/ros2_study/install/setup.bash

ros2 topic list

중요하게 볼 토픽은 다음입니다.

/cmd_vel
/odom
/scan
/tf
/tf_static

각 토픽의 의미는 다음과 같습니다.

/cmd_vel로봇 속도 명령
/odom오도메트리
/scan2D LiDAR 스캔
/tf좌표계 변환
/tf_static고정 좌표계 변환

/scan이 나오는지 확인합니다.

ros2 topic echo /scan --once

출력 일부 예:

header:
  frame_id: base_scan
angle_min: ...
angle_max: ...
ranges:
- ...

frame_id가 보통 base_scan으로 나옵니다. 이 값은 SLAM Toolbox가 LiDAR 데이터의 좌표계를 이해하는 데 중요합니다.

4) TF 구조 확인

SLAM이 제대로 동작하려면 TF가 연결되어 있어야 합니다.

일반적으로 TurtleBot3에서는 다음 관계가 필요합니다.

map
 └── odom
      └── base_footprint
           └── base_link
                └── base_scan

SLAM 실행 전에는 보통 map -> odom이 없습니다.

왜냐하면 map -> odom은 SLAM Toolbox가 만들어주는 좌표 변환이기 때문입니다.

현재 TF를 확인합니다.

ros2 run tf2_tools view_frames

실행 후 현재 디렉터리에 다음 파일이 생성됩니다.

frames.pdf

확인합니다.

evince frames.pdf

5) SLAM Toolbox 실행

터미널 3에서 SLAM Toolbox를 실행합니다.

source /opt/ros/humble/setup.bash
source ~/ros2_study/install/setup.bash
export TURTLEBOT3_MODEL=burger

ros2 launch slam_toolbox online_async_launch.py

정상 실행되면 /map 토픽이 생성됩니다.

확인합니다.

ros2 topic list | grep map

예상 출력:

/map

/map 메시지를 한 번 확인합니다.

ros2 topic echo /map --once

초기에는 지도가 비어 있거나 작게 나올 수 있습니다. 로봇이 움직이면서 LiDAR 데이터가 누적되어야 지도가 커집니다.

6) RViz2 실행

터미널 4에서 RViz2를 실행합니다.

source /opt/ros/humble/setup.bash
source ~/ros2_study/install/setup.bash

rviz2

RViz에서 다음 설정을 합니다.

a. Fixed Frame 설정

왼쪽 상단 Global Options에서 Fixed Frame을 다음으로 설정합니다.

map

b. 표시 항목 추가

RViz 왼쪽 아래의 Add 버튼을 누르고 다음 항목을 추가합니다.

Map/map
LaserScan/scan
TF/tf
Odometry/odom

Map의 Topic은 /map으로 설정합니다.

LaserScan의 Topic은 /scan으로 설정합니다.

정상이라면 로봇 주변의 LiDAR 점과 점유 격자 지도가 보입니다.

7) 키보드로 로봇 움직이기

터미널 5에서 키보드 조종 노드를 실행합니다.

source /opt/ros/humble/setup.bash
source ~/ros2_study/install/setup.bash
export TURTLEBOT3_MODEL=burger

ros2 run turtlebot3_teleop teleop_keyboard

조작 키는 보통 다음과 같습니다.

        w
   a    s    d
        x
w전진
x후진
a좌회전
d우회전
s정지

지도 작성 팁은 다음과 같습니다.

  • 너무 빠르게 움직이지 않습니다.
  • 제자리 회전을 적절히 사용합니다.
  • 벽을 따라 천천히 이동합니다.
  • 같은 장소를 한 번 이상 다시 지나가면 loop closure에 유리합니다.
  • 좁은 복도에서는 급회전보다 천천히 회전합니다.
  • 로봇이 벽에 너무 가까이 붙지 않도록 합니다.

SLAM 품질은 로봇을 얼마나 잘 움직이느냐에 크게 영향을 받습니다.

8) SLAM 결과 확인

다음 명령으로 /map이 계속 갱신되는지 확인합니다.

ros2 topic hz /map

출력 예:

average rate: 1.0

/scan도 확인합니다.

ros2 topic hz /scan

출력 예:

average rate: 5.0

TF도 확인합니다.

ros2 run tf2_ros tf2_echo map odom

정상이라면 map에서 odom으로 가는 변환이 출력됩니다.

At time ...
- Translation: [...]
- Rotation: [...]

이 변환이 없으면 SLAM 결과가 RViz에서 제대로 표시되지 않을 수 있습니다.

9) 지도 저장하기

충분히 이동해서 지도가 만들어졌다면 지도를 저장합니다.

터미널 6에서 다음 명령을 실행합니다.

mkdir -p ~/ros2_study/maps
cd ~/ros2_study/maps

ros2 run nav2_map_server map_saver_cli -f turtlebot3_slam_map

정상 실행되면 다음 파일이 생깁니다.

~/ros2_study/maps/turtlebot3_slam_map.pgm
~/ros2_study/maps/turtlebot3_slam_map.yaml

확인합니다.

ls -al ~/ros2_study/maps

출력 예:

turtlebot3_slam_map.pgm
turtlebot3_slam_map.yaml

yaml 파일 내용을 확인합니다.

cat ~/ros2_study/maps/turtlebot3_slam_map.yaml

출력 예:

image: turtlebot3_slam_map.pgm
mode: trinary
resolution: 0.05
origin: [-10.0, -10.0, 0]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.25

각 항목의 의미는 다음과 같습니다.

image지도 이미지 파일
resolution한 픽셀이 실제 몇 m인지 의미
origin지도 원점
occupied_thresh장애물로 판단하는 임계값
free_thresh빈 공간으로 판단하는 임계값

10) 저장된 지도 이미지 확인

지도 이미지를 확인합니다. File 관리자를 실행하여 해당 위치로 이동한 후 더블클릭하시면 이미지 뷰어가 실행되면서 이미지가 추력됩니다.

또는 ImageMagick이 설치되어 있다면 PNG로 변환할 수 있습니다.

sudo apt install imagemagick
convert ~/ros2_study/maps/turtlebot3_slam_map.pgm ~/ros2_study/maps/turtlebot3_slam_map.png

확인합니다.

지도 색상은 보통 다음 의미를 가집니다.

흰색이동 가능한 빈 공간
검은색장애물
회색아직 모르는 영역

11) SLAM Toolbox 서비스 확인

SLAM Toolbox가 제공하는 서비스를 확인합니다.

ros2 service list | grep slam_toolbox

예상되는 서비스는 다음과 비슷합니다.

/slam_toolbox/clear_changes
/slam_toolbox/deserialize_map
/slam_toolbox/dynamic_map
/slam_toolbox/manual_loop_closure
/slam_toolbox/pause_new_measurements
/slam_toolbox/save_map
/slam_toolbox/serialize_map
/slam_toolbox/toggle_interactive_mode
/slam_toolbox/reset

SLAM Toolbox 공식 문서에서도 위와 같은 서비스들이 제공된다고 설명합니다.

현재 지도를 서비스로 요청할 수도 있습니다.

ros2 service call /slam_toolbox/dynamic_map nav_msgs/srv/GetMap "{}"

출력이 길게 나오면 정상입니다.

12) Pose Graph 저장하기

일반 지도 저장과 별도로 pose graph를 저장할 수 있습니다.

cd ~/ros2_study/maps

ros2 service call /slam_toolbox/serialize_map slam_toolbox/srv/SerializePoseGraph "{filename: 'turtlebot3_pose_graph'}"

저장 위치는 실행 환경에 따라 현재 디렉터리 또는 ~/.ros 아래가 될 수 있습니다.

확인합니다.

find ~ -name "*turtlebot3_pose_graph*"

pose graph 저장은 단순 이미지 저장보다 SLAM Toolbox의 고급 기능에 가깝습니다. 나중에 이어서 매핑하거나 localization mode를 사용할 때 중요합니다.

13) SLAM 실행용 Launch 파일 만들기

매번 여러 터미널을 열기 불편하므로, Python launch 파일을 만들어 SLAM Toolbox와 모니터 노드를 같이 실행해 보겠습니다.

a. launch 폴더 생성

cd ~/ros2_study/src/my_first_package
mkdir -p launch
touch launch/slam_monitor.launch.py

파일을 엽니다.

gedit launch/slam_monitor.launch.py

다음 코드를 입력합니다.

from launch import LaunchDescription
from launch_ros.actions import Node


def generate_launch_description():
    slam_monitor_node = Node(
        package='my_first_package',
        executable='slam_monitor_node',
        name='slam_monitor_node',
        output='screen'
    )

    return LaunchDescription([
        slam_monitor_node
    ])

b. setup.py에 launch 설치 설정 추가

setup.py 상단에 다음 import가 없다면 추가합니다.

import os
from glob import glob

data_files에 launch 파일 설치 설정을 추가합니다.

예:

data_files=[
    ('share/ament_index/resource_index/packages',
        ['resource/' + package_name]),
    ('share/' + package_name, ['package.xml']),
    (os.path.join('share', package_name, 'launch'), glob('launch/*.launch.py')),
],

c. 다시 빌드

cd ~/ros2_study
colcon build --packages-select my_first_package
source install/setup.bash

d. launch 실행

ros2 launch my_first_package slam_monitor.launch.py

이 launch 파일은 모니터 노드만 실행합니다.

전체 실습 실행 순서는 다음과 같이 유지합니다.

터미널 1: Gazebo
터미널 2: SLAM Toolbox
터미널 3: RViz2
터미널 4: teleop_keyboard
터미널 5: slam_monitor_node

강의 초반에는 터미널을 나누는 편이 좋습니다. 어떤 노드가 어떤 역할을 하는지 학생들이 보기 쉽습니다.

14) SLAM Toolbox 파라미터 이해

SLAM Toolbox의 주요 파라미터는 다음과 같습니다.

odom_frame오도메트리 프레임
map_frame지도 프레임
base_frame로봇 기준 프레임
scan_topicLiDAR 스캔 토픽
resolution지도 해상도
map_update_interval지도 업데이트 주기
minimum_travel_distance새 스캔을 처리하기 위한 최소 이동 거리
minimum_travel_heading새 스캔을 처리하기 위한 최소 회전량
do_loop_closingloop closure 사용 여부
modemapping 또는 localization 모드
use_scan_matchingscan matching 사용 여부

SLAM Toolbox 공식 문서에는 solver 관련 파라미터, toolbox 파라미터, matcher 파라미터가 자세히 정리되어 있습니다.

예를 들어 odom_frame, map_frame, base_frame, scan_topic, resolution, map_update_interval, minimum_travel_distance, minimum_travel_heading, do_loop_closing 등이 주요 설정값입니다.

a. 기본 파라미터 파일 복사

기본 파라미터 파일을 직접 수정하지 말고, 내 패키지로 복사해서 사용합니다. 

mkdir -p ~/ros2_study/src/my_first_package/config
cp /opt/ros/humble/share/slam_toolbox/config/mapper_params_online_async.yaml \
   ~/ros2_study/src/my_first_package/config/my_mapper_params_online_async.yaml

파일을 엽니다.

gedit ~/ros2_study/src/my_first_package/config/my_mapper_params_online_async.yaml

아래 항목들의 설정값을 확인합니다.

slam_toolbox:
  ros__parameters:

    odom_frame: odom
    map_frame: map
    base_frame: base_footprint
    scan_topic: /scan

    mode: mapping

    resolution: 0.05
    map_update_interval: 5.0

    minimum_travel_distance: 0.5
    minimum_travel_heading: 0.5

    do_loop_closing: true

TurtleBot3에서 base_frame은 환경에 따라 base_footprint 또는 base_link일 수 있습니다. TF 트리를 확인하고 맞춰야 합니다.

확인 명령:

ros2 run tf2_tools view_frames

b. 커스텀 파라미터로 SLAM 실행

ros2 launch slam_toolbox online_async_launch.py \
  params_file:=~/ros2_study/src/my_first_package/config/my_mapper_params_online_async.yaml

정상 실행되면 기존과 동일하게 /map이 생성됩니다.

15) 지도 품질을 높이는 실전 운용법

SLAM은 명령어만 실행한다고 좋은 지도가 나오지 않습니다. 로봇을 어떻게 움직이는지가 중요합니다.

a. 좋은 지도 작성 방법

좋은 방식:

천천히 전진
천천히 회전
벽과 일정 거리 유지
복도를 왕복
출발 지점 근처로 다시 돌아오기
넓은 공간보다 벽 특징이 많은 곳부터 주행

나쁜 방식:

너무 빠른 전진
급회전
벽에 너무 가까이 붙음
좁은 공간에서 반복 충돌
한 번도 되돌아오지 않는 긴 주행
LiDAR가 볼 특징이 적은 넓은 빈 공간만 주행

b. Loop Closure를 의식한 주행

Loop closure가 잘 일어나려면 로봇이 예전에 지나갔던 장소를 다시 지나가야 합니다.

추천 경로:

출발 → 복도 이동 → 방 한 바퀴 → 다시 복도 → 출발점 근처 복귀

이렇게 이동하면 SLAM Toolbox가 “이 위치는 아까 지나간 곳과 같다”고 판단할 가능성이 높아집니다.

16) 문제 해결

a.  /map이 안 나옵니다

확인합니다.

ros2 topic list | grep map

없다면 SLAM Toolbox가 제대로 실행되지 않은 것입니다.

다시 실행합니다.

ros2 launch slam_toolbox online_async_launch.py

b. /scan이 안 나옵니다

확인합니다.

ros2 topic list | grep scan

없다면 시뮬레이션 또는 로봇 센서 노드가 제대로 실행되지 않은 것입니다.

Gazebo를 다시 실행합니다.

ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py

c. RViz에서 Fixed Frame 오류가 납니다

RViz의 Fixed Frame을 확인합니다.

map

그래도 오류가 나면 TF를 확인합니다.

ros2 run tf2_ros tf2_echo map odom

map -> odom이 없으면 SLAM Toolbox가 아직 정상적으로 TF를 발행하지 못하고 있는 것입니다.

d. 지도가 삐뚤어집니다

가능한 원인은 다음입니다.

로봇을 너무 빠르게 움직임천천히 이동
회전을 너무 급하게 함제자리 회전 속도 낮추기
loop closure 부족출발점 근처로 복귀
LiDAR 데이터 부족/scan 확인
TF 문제view_frames 확인
odom 불안정시뮬레이션 상태 확인

e. 지도 저장이 안 됩니다

현재 /map이 있는지 확인합니다.

ros2 topic echo /map --once

nav2_map_server가 설치되어 있는지 확인합니다.

ros2 pkg list | grep nav2_map_server

없으면 설치합니다.

sudo apt update
sudo apt install ros-humble-nav2-map-server

다시 저장합니다.

ros2 run nav2_map_server map_saver_cli -f ~/ros2_study/maps/turtlebot3_slam_map

5. 정리

이번 강의에서는 ROS 2 Humble에서 SLAM Toolbox를 사용해 TurtleBot3 시뮬레이션 환경의 2D 지도를 작성했습니다.

핵심은 다음입니다.

/scan + /tf + /odom
        ↓
SLAM Toolbox
        ↓
/map + map->odom TF
        ↓
map_saver_cli
        ↓
.pgm + .yaml 지도 파일

SLAM Toolbox는 단순한 지도 작성 도구가 아니라, pose graph 기반으로 지도를 만들고 저장하며, 이어서 매핑하거나 localization mode로 확장할 수 있는 ROS 2용 2D SLAM 패키지입니다.

특히 ROS 2 Humble과 Nav2 기반 모바일 로봇 학습에서 실용성이 높습니다.

Leave a Comment