이번 강의에서는 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 |
출력으로는 다음 데이터를 제공합니다.
| /map | nav_msgs/OccupancyGrid 형식의 2D 점유 격자 지도 |
| /pose | 지도 기준 로봇 추정 위치 |
| map -> odom TF | 지도 좌표계와 오도메트리 좌표계의 관계 |
| /slam_toolbox/pose_graph | pose graph 정보 |
| /slam_toolbox/new_node_event | pose 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 | 오도메트리 |
| /scan | 2D 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_topic | LiDAR 스캔 토픽 |
| resolution | 지도 해상도 |
| map_update_interval | 지도 업데이트 주기 |
| minimum_travel_distance | 새 스캔을 처리하기 위한 최소 이동 거리 |
| minimum_travel_heading | 새 스캔을 처리하기 위한 최소 회전량 |
| do_loop_closing | loop closure 사용 여부 |
| mode | mapping 또는 localization 모드 |
| use_scan_matching | scan 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 기반 모바일 로봇 학습에서 실용성이 높습니다.