SLAM Toolbox

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. 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오도메트리
/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 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_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 등이 주요 설정값입니다.

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

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_rangemax_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_coarseloop_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_penaltyminimum_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 Modepose graph node를 RViz에서 직접 움직일 수 있게 함
Save Changes수동으로 움직인 node 변경사항 반영
Clear Changes수동 변경사항 취소
Pausescan 처리 일시정지
Clear Queue대기 중인 scan queue 삭제
Start At Dock저장된 graph의 첫 node 근처에서 시작
Start At Pose지정한 pose에서 pose graph 시작
Generate Mapsubmap/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 Modepose 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가 “이 위치는 아까 지나간 곳과 같다”고 판단할 가능성이 높아집니다.

Leave a Comment