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 |
출력으로는 다음 데이터를 제공합니다.
| /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. SLAM Toolbox 사용
1) 터미널 기본 준비
TurtleBot3 모델을 지정합니다.
export TURTLEBOT3_MODEL=burger
사용 중인 모델이 waffle 또는 waffle_pi라면 다음처럼 바꿉니다.
export TURTLEBOT3_MODEL=waffle
또는
export TURTLEBOT3_MODEL=waffle
확인합니다.
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 use_sim_time:=true
정상 실행되면 /map 토픽이 생성됩니다.
확인합니다.
ros2 topic list | grep map
예상 출력:
/map
/map_metadata
/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 |
| MarkerArray | /slam_toolbox/graph_visualization |
Map의 Topic은 /map으로 설정합니다.
LaserScan의 Topic은 /scan으로 설정합니다.
MarkerArray는 By topic에서 /slam_toolbox/graph_visualization으로 설정합니다.
정상이라면 로봇 주변의 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) 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 "{}"
출력이 길게 나오면 정상입니다.
10) 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를 사용할 때 중요합니다.
5. 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 등이 주요 설정값입니다.
기본 파라미터 파일을 직접 수정하지 말고, 내 패키지로 복사해서 사용합니다.
mkdir -p ~/ros2_study/slamtoolbox_config
cp /opt/ros/humble/share/slam_toolbox/config/mapper_params_online_async.yaml \
~/ros2_study/slamtoolbox_config/my_mapper_params_online_async.yaml
파일을 엽니다.
gedit ~/ros2_study/slamtoolbox_config/my_mapper_params_online_async.yaml
아래 항목들의 설정값을 확인합니다.
slam_toolbox:
ros__parameters:
# Plugin params
solver_plugin: solver_plugins::CeresSolver
ceres_linear_solver: SPARSE_NORMAL_CHOLESKY
ceres_preconditioner: SCHUR_JACOBI
ceres_trust_strategy: LEVENBERG_MARQUARDT
ceres_dogleg_type: TRADITIONAL_DOGLEG
ceres_loss_function: None
# ROS Parameters
odom_frame: odom
map_frame: map
base_frame: base_footprint
scan_topic: /scan
use_map_saver: true
mode: mapping #localization
# if you'd like to immediately start continuing a map at a given pose
# or at the dock, but they are mutually exclusive, if pose is given
# will use pose
#map_file_name: test_steve
# map_start_pose: [0.0, 0.0, 0.0]
#map_start_at_dock: true
debug_logging: false
throttle_scans: 1
transform_publish_period: 0.02 #if 0 never publishes odometry
map_update_interval: 5.0
resolution: 0.05
min_laser_range: 0.0 #for rastering images
max_laser_range: 20.0 #for rastering images
minimum_time_interval: 0.5
transform_timeout: 0.2
tf_buffer_duration: 30.
stack_size_to_use: 40000000 #// program needs a larger stack size to serialize large maps
enable_interactive_mode: true
# General Parameters
use_scan_matching: true
use_scan_barycenter: true
minimum_travel_distance: 0.5
minimum_travel_heading: 0.5
scan_buffer_size: 10
scan_buffer_maximum_scan_distance: 10.0
link_match_minimum_response_fine: 0.1
link_scan_maximum_distance: 1.5
loop_search_maximum_distance: 3.0
do_loop_closing: true
loop_match_minimum_chain_size: 10
loop_match_maximum_variance_coarse: 3.0
loop_match_minimum_response_coarse: 0.35
loop_match_minimum_response_fine: 0.45
# Correlation Parameters - Correlation Parameters
correlation_search_space_dimension: 0.5
correlation_search_space_resolution: 0.01
correlation_search_space_smear_deviation: 0.1
# Correlation Parameters - Loop Closure Parameters
loop_search_space_dimension: 8.0
loop_search_space_resolution: 0.05
loop_search_space_smear_deviation: 0.03
# Scan Matcher Parameters
distance_variance_penalty: 0.5
angle_variance_penalty: 1.0
fine_search_angle_offset: 0.00349
coarse_search_angle_offset: 0.349
coarse_angle_resolution: 0.0349
minimum_angle_penalty: 0.9
minimum_distance_penalty: 0.5
use_response_expansion: true
min_pass_through: 2
occupancy_threshold: 0.1
a. ROS 프레임 및 토픽 설정
odom_frame: odom
map_frame: map
base_frame: base_footprint
scan_topic: /scan
이 항목들은 SLAM에서 사용되는 좌표계와 LiDAR 토픽을 정의합니다.
map_frame은 SLAM을 통해 생성되는 전역 지도 좌표계입니다.
odom_frame은 로봇의 오도메트리 좌표계이며, 휠 엔코더나 IMU 기반으로 연속적인 이동 추정을 담당합니다.
base_frame은 로봇 본체의 기준 좌표계입니다. 일반적으로 모바일 로봇에서는 base_link 또는 base_footprint를 사용합니다.
scan_topic은 LiDAR 스캔 데이터가 입력되는 토픽입니다. 이 설정에서는 /scan 토픽의 sensor_msgs/LaserScan 데이터를 사용합니다.
SLAM이 정상적으로 동작하려면 다음과 같은 TF 관계가 올바르게 구성되어 있어야 합니다.
map → odom → base_footprint → laser
b. SLAM 모드 및 지도 저장 설정
use_map_saver: true
mode: mapping
mode는 SLAM의 동작 방식을 지정합니다.
현재 설정은 mapping 모드로 되어 있으며, 이는 로봇이 주행하면서 새로운 지도를 생성하는 모드입니다.
이미 생성된 지도를 기반으로 위치 추정만 수행하려면 다음과 같이 변경하시면 됩니다.
mode: localization
use_map_saver: true는 지도 저장 기능을 사용할 수 있도록 설정하는 항목입니다. SLAM 수행 후 생성된 지도를 저장할 때 사용됩니다.
c. 지도 해상도 및 업데이트 설정
map_update_interval: 5.0
resolution: 0.05
resolution은 지도 셀 하나의 크기를 의미합니다.
현재 설정값 0.05는 한 셀이 실제 공간에서 5cm를 의미합니다.
값이 작을수록 지도가 정밀해지지만, 메모리 사용량과 계산량이 증가합니다.
실내 모바일 로봇에서는 보통 0.03 ~ 0.05m 정도를 많이 사용합니다.
map_update_interval은 지도를 갱신하는 주기입니다.
현재 설정은 5초마다 지도를 업데이트하도록 되어 있습니다.
값을 줄이면 지도 반영은 빨라지지만 CPU 부하가 증가할 수 있습니다.
d. LiDAR 거리 범위 설정
min_laser_range: 0.0
max_laser_range: 20.0
min_laser_range와 max_laser_range는 SLAM에 사용할 LiDAR 거리 범위를 지정합니다.
max_laser_range: 20.0은 최대 20m까지의 스캔 데이터를 사용한다는 의미입니다.
하지만 실제 사용 시에는 사용하는 LiDAR의 유효 거리와 환경 조건을 고려하셔야 합니다.
너무 먼 거리의 데이터는 노이즈가 많을 수 있으므로, 실내 환경에서는 LiDAR 성능에 따라 8.0 ~ 15.0m 정도로 제한하는 것이 더 안정적일 수 있습니다.
e. TF 및 시간 관련 설정
transform_publish_period: 0.02
transform_timeout: 0.2
tf_buffer_duration: 30.
minimum_time_interval: 0.5
transform_publish_period는 SLAM 결과로 계산된 TF를 발행하는 주기입니다.
현재 설정값 0.02는 0.02초, 즉 약 50Hz로 TF를 발행한다는 의미입니다.
transform_timeout은 TF 조회 시 기다리는 최대 시간입니다.
TF가 늦게 들어오거나 시스템 부하가 큰 경우 이 값이 너무 작으면 TF 오류가 발생할 수 있습니다.
tf_buffer_duration은 TF 데이터를 버퍼에 저장하는 시간입니다.
현재는 30초로 설정되어 있어 비교적 넉넉한 편입니다.
minimum_time_interval은 스캔 처리 최소 시간 간격입니다.
현재 0.5초로 설정되어 있으므로, 너무 짧은 시간 간격으로 들어오는 스캔은 처리하지 않도록 제한합니다.
f. 스캔 매칭 기본 설정
use_scan_matching: true
use_scan_barycenter: true
minimum_travel_distance: 0.5
minimum_travel_heading: 0.5
use_scan_matching은 LiDAR 스캔 데이터를 이용해 로봇의 위치를 보정하는 기능입니다.
이 값은 일반적으로 true로 사용하는 것이 좋습니다.
minimum_travel_distance는 새로운 스캔을 SLAM 그래프에 추가하기 위한 최소 이동 거리입니다.
현재 설정값은 0.5m입니다. 로봇이 0.5m 이상 이동해야 새로운 노드가 추가됩니다.
minimum_travel_heading은 새로운 스캔을 추가하기 위한 최소 회전 각도입니다.
현재 설정값은 0.5rad로, 약 28.6도입니다.
이 두 값이 너무 작으면 노드가 지나치게 많이 생성되어 계산량이 증가합니다.
반대로 너무 크면 지도 정밀도가 떨어질 수 있습니다.
g. 스캔 버퍼 설정
scan_buffer_size: 10
scan_buffer_maximum_scan_distance: 10.0
scan_buffer_size는 스캔 매칭에 사용할 과거 스캔 데이터의 개수입니다.
현재는 최근 10개의 스캔을 사용합니다.
scan_buffer_maximum_scan_distance는 버퍼에 포함할 수 있는 최대 스캔 거리 조건입니다.
현재 설정은 10m입니다.
이 값들은 스캔 매칭의 안정성과 계산량에 영향을 줍니다.
버퍼 크기가 커지면 매칭 안정성은 좋아질 수 있지만, 계산 부하가 증가합니다.
h. 루프 클로징 설정
do_loop_closing: true
loop_search_maximum_distance: 3.0
loop_match_minimum_chain_size: 10
loop_match_maximum_variance_coarse: 3.0
loop_match_minimum_response_coarse: 0.35
loop_match_minimum_response_fine: 0.45
루프 클로징은 로봇이 이전에 지나갔던 위치로 다시 돌아왔을 때, 누적된 오차를 보정하는 기능입니다.
장거리 주행이나 복도형 환경에서는 오도메트리 오차가 누적되기 때문에 루프 클로징이 매우 중요합니다.
do_loop_closing: true는 루프 클로징 기능을 활성화합니다.
loop_search_maximum_distance는 루프 후보를 찾을 최대 거리입니다.
현재 설정은 3m 이내에서 루프 후보를 탐색합니다.
loop_match_minimum_chain_size는 루프 클로징을 수행하기 위해 필요한 최소 연결 스캔 수입니다.
값이 클수록 더 확실한 루프만 인정하게 됩니다.
loop_match_minimum_response_coarse와 loop_match_minimum_response_fine은 각각 거친 매칭과 정밀 매칭에서 요구되는 최소 응답값입니다.
값이 높을수록 더 엄격하게 루프를 인정하므로 잘못된 루프 클로징을 줄일 수 있지만, 루프 검출률은 낮아질 수 있습니다.
i. Correlation Search 설정
correlation_search_space_dimension: 0.5
correlation_search_space_resolution: 0.01
correlation_search_space_smear_deviation: 0.1
Correlation Search는 스캔 매칭 시 현재 스캔이 어느 위치에서 가장 잘 맞는지 탐색하는 영역을 의미합니다.
correlation_search_space_dimension은 탐색 공간의 크기입니다.
현재 값은 0.5m로, 현재 추정 위치 주변 0.5m 범위에서 스캔 매칭을 수행합니다.
correlation_search_space_resolution은 탐색 해상도입니다.
현재 값은 0.01m로, 1cm 단위로 후보 위치를 탐색합니다.
해상도가 작을수록 정밀하지만 계산량이 증가합니다.
실시간성이 부족한 경우 이 값을 약간 키우는 방식으로 부하를 줄일 수 있습니다.
j. Loop Closure Search 설정
loop_search_space_dimension: 8.0
loop_search_space_resolution: 0.05
loop_search_space_smear_deviation: 0.03
루프 클로징 탐색 공간은 일반 스캔 매칭보다 넓게 설정됩니다.
현재 loop_search_space_dimension은 8m로 설정되어 있으며, 이는 루프 후보를 비교적 넓은 범위에서 찾겠다는 의미입니다.
loop_search_space_resolution은 0.05m로, 루프 탐색 시 5cm 단위로 후보 위치를 탐색합니다.
루프 탐색 공간이 너무 작으면 루프를 놓칠 수 있고, 너무 크면 잘못된 루프 클로징 가능성과 계산량이 증가합니다.
k. Scan Matcher 패널티 설정
distance_variance_penalty: 0.5
angle_variance_penalty: 1.0
minimum_angle_penalty: 0.9
minimum_distance_penalty: 0.5
이 항목들은 스캔 매칭 결과를 평가할 때 거리와 각도 변화에 대한 패널티를 지정합니다.
distance_variance_penalty는 위치 변화에 대한 패널티입니다.
angle_variance_penalty는 회전 변화에 대한 패널티입니다.
값이 높을수록 큰 위치 변화나 회전 변화에 대해 더 보수적으로 판단합니다.
즉, 스캔 매칭 결과가 오도메트리 추정값에서 크게 벗어나는 것을 억제합니다.
minimum_angle_penalty와 minimum_distance_penalty는 각도 및 거리 패널티의 최소값을 의미합니다.
l. 각도 탐색 설정
fine_search_angle_offset: 0.00349
coarse_search_angle_offset: 0.349
coarse_angle_resolution: 0.0349
이 항목들은 스캔 매칭 시 회전 방향 탐색 범위를 설정합니다.
fine_search_angle_offset은 정밀 탐색 시 사용하는 각도 범위입니다.
0.00349rad는 약 0.2도입니다.
coarse_search_angle_offset은 거친 탐색 시 사용하는 각도 범위입니다.
0.349rad는 약 20도입니다.
coarse_angle_resolution은 거친 탐색의 각도 해상도입니다.
0.0349rad는 약 2도입니다.
즉, 먼저 넓은 각도 범위에서 대략적인 방향을 찾고, 이후 좁은 범위에서 정밀하게 보정하는 구조입니다.
m. Occupancy Threshold 설정
occupancy_threshold: 0.1
occupancy_threshold는 특정 셀을 장애물로 판단할 확률 임계값입니다.
값이 낮으면 장애물로 판단되는 셀이 많아지고, 값이 높으면 더 확실한 장애물만 지도에 표시됩니다.
현재 값 0.1은 비교적 낮은 편이므로, 장애물이 적극적으로 지도에 반영될 수 있습니다.
노이즈가 많은 LiDAR 환경에서는 이 값을 너무 낮게 설정하면 잘못된 장애물이 생길 수 있습니다.
n. 커스텀 파라미터로 SLAM 실행
ros2 launch slam_toolbox online_async_launch.py \
params_file:=/home/sjyong/ros2_study/slamtoolbox_config/my_mapper_params_online_async.yaml\
use_sim_time:=true
정상 실행되면 기존과 동일하게 /map이 생성됩니다.
6. RViz2에서 slam_toolbox GUI plugin 켜기
먼저 Gazebo World와 slam_toolbox를 실행해야 합니다.
RViz2 실행:
rviz2
상단 메뉴에서 다음 순서로 들어갑니다.
Panels → Add New Panel
목록에서 아래 항목을 찾습니다.

SlamToolboxPlugin
또는 비슷하게 표시될 수 있습니다.
slam_toolbox/SlamToolboxPlugin
추가하면 RViz2 하단 또는 측면에 slam_toolbox 제어 패널이 생깁니다.
/media/sf_shared/Screenshot from 2026-06-12 13-29-56.png

7. RViz2 GUI plugin 주요 기능
slam_toolbox RViz plugin은 내부적으로 ROS service를 호출하는 GUI입니다.
주요 버튼은 대략 다음 의미입니다.
| GUI 기능 | 의미 |
|---|---|
| Save Map | .pgm, .yaml 형태의 일반 2D map 저장 |
| Serialize Map | .posegraph, .data 형태로 pose graph 저장 |
| Deserialize Map | 저장된 pose graph 불러오기 |
| Interactive Mode | pose graph node를 RViz에서 직접 움직일 수 있게 함 |
| Save Changes | 수동으로 움직인 node 변경사항 반영 |
| Clear Changes | 수동 변경사항 취소 |
| Pause | scan 처리 일시정지 |
| Clear Queue | 대기 중인 scan queue 삭제 |
| Start At Dock | 저장된 graph의 첫 node 근처에서 시작 |
| Start At Pose | 지정한 pose에서 pose graph 시작 |
| Generate Map | submap/posegraph 병합 후 /map 생성 |
8. Save Map과 Serialize Map 차이
Save Map
Save Map = navigation용 지도 저장
결과:
map.yaml
map.pgm
용도:
Nav2
AMCL
map_server
일반 localization
명령어로 하면:
ros2 run nav2_map_server map_saver_cli-f ~/maps/my_map
또는 slam_toolbox service:
ros2service call /slam_toolbox/save_map slam_toolbox/srv/SaveMap"{name: {data: '/home/ubuntu/maps/my_map'}}"
Serialize Map
Serialize Map = pose graph까지 저장
결과:
map.posegraph
map.data
용도:
나중에 이어서 mapping
lifelong mapping
localization mode
pose graph 수정
map merging
serialization/deserialization은 pose graph와 metadata를 저장하고 다시 불러와 계속 mapping하거나 localization에 쓰는 기능입니다.
명령어로 하면:
ros2service call /slam_toolbox/serialize_map slam_toolbox/srv/SerializePoseGraph"{filename: '/home/ubuntu/maps/my_map'}"
주의할 점:
확장자는 쓰지 않습니다.
9. RViz2 GUI로 pose graph 저장하기
절차:
1. slam_toolbox 실행
2. rviz2 실행
3. Panels → Add New Panel → SlamToolboxPlugin
4. 지도 작성
5. Serialize Map 입력칸에 경로 입력
6. Serialize Map 버튼 클릭
예를 들어 입력칸에:
/home/ubuntu/maps/warehouse_01
그러면 보통 다음 파일이 생깁니다.
/home/ubuntu/maps/warehouse_01.posegraph
/home/ubuntu/maps/warehouse_01.data
이 파일이 있어야 나중에 pose graph를 다시 불러와 이어서 mapping할 수 있습니다.
10. RViz2 GUI로 저장된 pose graph 불러오기
절차:
1. slam_toolbox 실행
2. rviz2 실행
3. SlamToolboxPlugin 열기
4. Deserialize Map 입력칸에 파일 경로 입력
5. Deserialize Map 클릭
입력 예:
/home/ubuntu/maps/warehouse_01
여기도 확장자는 빼는 게 안전합니다.
맞음: /home/ubuntu/maps/warehouse_01
피함: /home/ubuntu/maps/warehouse_01.posegraph
불러온 뒤 시작 위치 옵션을 선택할 수 있습니다.
| RViz2 옵션 | 정확한 의미 | 언제 사용하나 |
|---|---|---|
| Start At Dock | 저장된 pose graph의 첫 번째 노드, 즉 처음 mapping을 시작했던 위치 근처에서 시작한다고 가정합니다. 로봇이 dock 또는 원래 시작점 근처에 있을 때 scan matching으로 초기 위치를 잡습니다. | 로봇을 항상 같은 dock, 출발점, 충전 스테이션 근처에서 시작할 때 |
| Start At Pose Est. | 아래 입력칸의 X, Y, θ 값을 사용해서 map frame 기준 시작 pose를 직접 지정합니다. 즉, 사용자가 수치로 초기 위치를 넣는 방식입니다. | 로봇의 대략적인 map 좌표를 알고 있을 때 |
| Start At Curr. Odom | 현재 로봇의 odometry pose를 기준으로 pose graph를 시작합니다. 이전 실행 후 로봇을 거의 움직이지 않았거나, 잠깐 멈췄다가 다시 이어서 실행할 때 적합합니다. | slam_toolbox를 재시작했지만 로봇이 거의 이동하지 않았을 때 |
| Localize | 새 지도를 계속 확장하기보다, 불러온 serialized pose graph 안에서 localization 용도로 동작하게 합니다. RViz2의 2D Pose Estimate 도구와 /initialpose를 이용해 AMCL처럼 초기 위치를 다시 줄 수 있습니다. | 이미 만든 .posegraph/.data 맵에서 위치 추정만 하고 싶을 때 |
slam_toolbox localization mode는 /initialpose도 받을 수 있어 RViz2의 2D Pose Estimate 도구와 연동됩니다.
버튼별 기능은 아래와 같습니다.
| 항목 | 의미 |
|---|---|
| Interactive Mode | pose graph node를 RViz2에서 마우스로 선택하고 이동/회전할 수 있게 하는 모드 |
| Save Changes | 사용자가 손으로 옮긴 node 위치를 slam_toolbox에 반영하고 pose graph optimization 수행 |
| Clear Changes | 아직 저장하지 않은 수동 변경사항을 취소 |
| Accept New Scans | 새로 들어오는 LiDAR scan을 계속 SLAM에 반영할지 여부 |
| Create Map Tool | 지도 생성/수정 도구 관련 기능을 활성화하는 영역 |
11. CLI로 같은 기능 호출하기
GUI가 안 뜨거나 자동화하고 싶으면 service로 호출하면 됩니다.
1) service 목록 확인
ros2service list |grep slam_toolbox
대표 service:
/slam_toolbox/save_map
/slam_toolbox/serialize_map
/slam_toolbox/deserialize_map
/slam_toolbox/pause_new_measurements
/slam_toolbox/toggle_interactive_mode
/slam_toolbox/manual_loop_closure
/slam_toolbox/clear_changes
/slam_toolbox/reset
slam_toolbox 문서에도 save_map, serialize_map, deserialize_map, toggle_interactive_mode, manual_loop_closure 등의 service가 노출된다고 되어 있습니다.
2) pose graph 저장
ros2service call /slam_toolbox/serialize_map \
slam_toolbox/srv/SerializePoseGraph \
"{filename: '/home/ubuntu/maps/my_map'}"
3) 일반 map 저장
ros2service call /slam_toolbox/save_map \
slam_toolbox/srv/SaveMap \
"{name: {data: '/home/ubuntu/maps/my_map'}}"
4) interactive mode 켜기/끄기
ros2service call /slam_toolbox/toggle_interactive_mode \
slam_toolbox/srv/ToggleInteractive \
"{}"
5) 수동 loop closure / 변경 반영
ros2service call /slam_toolbox/manual_loop_closure \
slam_toolbox/srv/LoopClosure \
"{}"
6) 변경 취소
ros2service call /slam_toolbox/clear_changes \
slam_toolbox/srv/Clear \
"{}"
12. 지도 품질을 높이는 실전 운용법
SLAM은 명령어만 실행한다고 좋은 지도가 나오지 않습니다. 로봇을 어떻게 움직이는지가 중요합니다.
a. 좋은 지도 작성 방법
좋은 방식:
천천히 전진
천천히 회전
벽과 일정 거리 유지
복도를 왕복
출발 지점 근처로 다시 돌아오기
넓은 공간보다 벽 특징이 많은 곳부터 주행
나쁜 방식:
너무 빠른 전진
급회전
벽에 너무 가까이 붙음
좁은 공간에서 반복 충돌
한 번도 되돌아오지 않는 긴 주행
LiDAR가 볼 특징이 적은 넓은 빈 공간만 주행
b. Loop Closure를 의식한 주행
Loop closure가 잘 일어나려면 로봇이 예전에 지나갔던 장소를 다시 지나가야 합니다.
추천 경로:
출발 → 복도 이동 → 방 한 바퀴 → 다시 복도 → 출발점 근처 복귀
이렇게 이동하면 SLAM Toolbox가 “이 위치는 아까 지나간 곳과 같다”고 판단할 가능성이 높아집니다.