Gazebo 설치와 기본 환경 세팅
Gazebo란 무엇인가?
Gazebo는 로봇 시뮬레이션을 위한 오픈 소스 소프트웨어로서, 실제 물리엔진(ODE, Bullet, DART 등)을 활용하여 3D 환경에서 로봇의 동작을 시뮬레이션한다. 센서, 물리 특성, 여러 형태의 월드(world) 환경을 재현할 수 있어, 하드웨어를 실물로 제작하기 전에 가상 환경에서 테스트할 수 있게 한다.
기본적으로 Gazebo는 크게 두 가지 버전 계열이 존재한다. 하나는 고전적으로 많이 사용되어 온 “Gazebo Classic”이며, 다른 하나는 “Ignition Gazebo(이후 Gazebo Fortress, Garden 등)” 계열이다. ROS2 Humble에서는 여전히 Gazebo Classic을 활용하는 경우가 많고, 필요에 따라 Ignition 계열을 함께 쓸 수도 있다. 다만 본문에서는 Humble과 호환이 널리 알려진 Gazebo Classic 환경 설치 및 세팅 위주로 살펴본다.
Gazebo Classic과 Ignition Gazebo(신버전) 차이
Gazebo Classic:
오랫동안 유지되어 온 안정된 버전.
ROS1부터 이어진 자료와 예제가 풍부.
기존 ros-gazebo 플러그인(gazebo_ros_pkgs 등)이 가장 많이 호환.
Ignition Gazebo(이후 Fortress, Garden, Citadel 등):
코드 구조가 모듈화되어 있으며, 향상된 UI나 물리엔진 확장성을 제공.
앞으로의 Gazebo 주요 버전으로 발전 예정.
ROS2 Humble과 연동 시 ignition-ros 패키지를 통해 사용 가능.
ROS2 Humble에서는 두 가지 버전을 모두 설치할 수도 있지만, 일반적으로 첫 입문 단계에서는 Gazebo Classic이 예제나 참고 자료가 많기 때문에 학습 곡선이 더 낮은 편이다.
Ubuntu에서 Gazebo 설치하기
ROS2 Humble과 함께 사용하는 환경은 Ubuntu 22.04(Jammy) 기준으로 가정한다. 배포본에 따라 패키지 명이나 버전이 다를 수 있으나, 대표적으로 다음과 같은 방법으로 Gazebo를 설치할 수 있다.
sudo apt update
sudo apt install gazebo11 # Gazebo Classic 11 버전설치 후 다음 명령어를 통해 Gazebo가 제대로 설치되었는지 확인할 수 있다.
Ubuntu 22.04 환경에서 gazebo11이 설치되었다면, 설치가 완료된 것이다.
ROS2 Humble용 Gazebo ROS 패키지 설치
ROS2와 Gazebo를 연동하기 위해서는 별도의 ROS 인터페이스 패키지가 필요하다. ROS2 Humble을 설치한 후, 다음과 같이 gazebo_ros_pkgs를 설치한다.
이렇게 하면 Gazebo에서 ROS2 토픽, 서비스, 액션 등을 활용할 수 있도록 하는 여러 플러그인이 함께 설치된다. 이를테면 센서 데이터가 ROS2 토픽으로 퍼블리시(publish)되거나, ROS2 명령을 Gazebo 환경에 전달하는 식의 연동이 가능해진다.
Gazebo 실행 및 기본 테스트
설치가 완료되었다면 우선 gazebo 명령어를 통해 기본 UI를 실행해 볼 수 있다. 만약 설치한 터미널에서 바로 실행되지 않는다면, ROS2 환경 변수를 설정해주어야 한다.
GUI가 뜨면서 기본 세계(default world)가 로드되는 것을 확인할 수 있다. 기본 환경에서 카메라, 조명 등이 생성되어 있으며, 물리엔진이 실행 중이다. 상단 혹은 사이드바를 이용해 간단한 모델(박스, 원통, 구 등)을 드래그 앤 드롭하여 월드에 배치할 수 있다.
Gazebo 플러그인(plugin) 구조
Gazebo에서 ROS2와 상호작용하기 위해서는 플러그인을 로드해서 토픽/서비스/액션을 주고받을 수 있도록 해야 한다. Gazebo Classic의 플러그인은 주로 C++로 작성되어 있으며, 로봇 모델의 URDF(Xacro)나 SDF 파일 안에서 <plugin> 태그를 활용해 명시한다.
예를 들어, 로봇 모델의 URDF 안에 아래와 같이 플러그인을 삽입할 수 있다.
이를 통해 Gazebo가 로봇 모델을 로드할 때 ROS2 컨트롤 관련 플러그인을 함께 구동하게 된다.
Gazebo 환경 변수 설정
Gazebo를 단독으로 사용한다면 별도의 환경 변수 설정이 크게 필요하지 않다. 하지만 ROS2 Humble과의 연동을 고려한다면, ROS2 작업공간(workspace)나 각종 패키지 위치를 Gazebo가 인식하도록 관련 환경 변수를 잡아줄 필요가 있다.
GAZEBO_MODEL_PATH Gazebo에서 로드할 로봇 모델이나 월드(world) 파일이 있는 디렉터리를 등록한다. 예를 들어,
$HOME/ros2_ws/src/my_robot/models디렉터리를 Gazebo 모델 경로에 추가하려면 다음과 같이 설정한다.GAZEBO_PLUGIN_PATH Gazebo에서 사용할 플러그인(예:
.so파일)이 위치한 경로를 등록한다. 보통 ROS2 설치로 인해 자동 설정되지만, 사용자 정의 플러그인을 직접 빌드하는 경우 다음과 같이 추가 경로를 설정할 수 있다.LD_LIBRARY_PATH 동적으로 로드되는 라이브러리 경로가 Gazebo 구동 시 반영되도록 해야 한다. 로컬 workspace를 통해 빌드된
.so파일을 찾도록 하기 위해 아래와 같이 설정할 수 있다.
이러한 환경 변수들은 개발 편의를 위해 보통 ~/.bashrc나 ~/.zshrc 등에 추가한다. 단, 너무 과도하게 설정하면 예기치 못한 충돌이 발생할 수 있으므로, 필요한 경로만 깔끔하게 정리하는 것이 중요하다.
ROS2 패키지와 Gazebo 모델/월드 파일 구조
ROS2에서 사용하는 Gazebo 모델 또는 월드 파일을 배치할 때, 보통 패키지 디렉터리 구조를 다음과 같이 구성한다.
urdf/또는sdf/디렉터리에 로봇 관련 파일을 모아놓고,worlds/디렉터리에 시뮬레이션 환경의 월드 파일(확장자는.world)을 둔다.models/디렉터리에는 Gazebo에서 로드 가능한 모델(config, sdf 파일)들을 배치한다.
이렇게 구조화해두면 $GAZEBO_MODEL_PATH나 ROS2의 패키지 경로에서 모델과 월드 파일을 쉽게 찾을 수 있다.
Gazebo Classic의 주요 GUI 기능
Gazebo를 실행하면 기본 GUI 화면이 나타난다. 상단 메뉴바와 사이드 도구를 통해 다양한 작업이 가능하다.
Insert 탭 박스(Box), 구(Sphere), 원통(Cylinder), 조명(Light) 등 기본 오브젝트를 마우스로 드래그 앤 드롭하여 월드에 삽입할 수 있다.
World 탭 현재 월드에 추가된 모델과 요소들을 트리 구조로 확인하고, 각종 파라미터(위치, 회전, 물리 속성 등)를 수정할 수 있다.
Visual/Physics 설정 상단 메뉴에서 Scene 또는 Physics 설정을 열어 환경의 조명, 그라운드 평면, 물리 엔진(ODE, Bullet 등) 파라미터를 조정할 수 있다.
ROS2 연동 시 이러한 시뮬레이션 요소들이 ROS 토픽, 서비스, 액션 등의 형태로 노출된다. 예를 들어, 로봇 팔(arm)을 시뮬레이션한다면, 조인트(Joint) 상태가 ROS2 토픽으로 퍼블리시되고, 명령을 액션/서비스로 전달할 수 있다.
Gazebo GUI 없이 Headless 모드 실행
시뮬레이션 자원이 제한된 환경(예: CI 서버, 임베디드 보드)에서 GUI 없이 Gazebo를 구동하고 싶을 때는 다음과 같이 명령어에 -s나 --headless-rendering 옵션을 붙여 사용할 수 있다.
또는 ROS2 런치 파일에서 <arg name="gui" default="false" />와 같은 옵션으로 제어할 수도 있다.
GUI를 띄우지 않으면 시뮬레이션을 가볍게 실행할 수 있지만, 시각적인 디버깅이 어려울 수 있다. 따라서 개발 초기에는 GUI로 테스트하고, 완성 단계에서 성능 최적화가 필요할 때 Headless 모드를 활용하는 편이 좋다.
ROS2 Launch 파일로 Gazebo 실행하기
ROS2에서는 .launch.py 파일을 통해 노드를 실행하는 방식이 일반적이다. Gazebo 역시 launch 파일을 만들어 두면 프로젝트 단위로 편리하게 시뮬레이션 환경을 로드할 수 있다.
--verbose: Gazebo 실행 로그를 자세히 출력한다.-s libgazebo_ros_factory.so: ROS2와의 상호작용을 위한 factory 플러그인을 로드한다.
위 예시에서 단순히 Gazebo를 실행하기만 하는 구조이지만, 실제 프로젝트에서는 월드 파일 경로 혹은 로봇 모델 스폰(spawn) 명령을 함께 넣어 종합적인 시뮬레이션 환경을 구성할 수 있다.
Gazebo 로그(Logs) 확인
Gazebo 실행 중 오류나 경고가 발생하면, 보통 터미널에 메시지가 나타난다. 추가로 Gazebo의 로그 디렉터리는 기본적으로 $HOME/.gazebo/log에 생성되며, 해당 경로에 날짜별 폴더가 생긴다. 로컬에서 시뮬레이션을 여러 번 실행해보고 문제가 생긴다면, 여기에 기록되는 로그 파일을 확인해보는 것이 도움이 된다.
URDF와 SDF 파일 구조의 차이
Gazebo에서 로봇 모델을 정의할 때는 URDF나 SDF 형식을 모두 지원한다. URDF(Unified Robot Description Format)는 ROS에서 오래전부터 사용되어 온 XML 기반 형식이고, SDF(Simulation Description Format)는 Gazebo 시뮬레이션에 특화된 형식이다.
URDF
주로 ROS에서 사용되는 형식으로, 로봇의 링크(link), 조인트(joint), 조인트 한계(joint limit) 정보 등을 정의한다.
구조가 단순하고 XML로 작성하기 때문에 비교적 이해하기 쉽다.
Gazebo와 연동하기 위해서는 URDF 내에
<gazebo>태그를 추가하여 물리 정보(마찰력, 관성, 센서 등)를 정의하거나, 로봇 플러그인을 명시해야 한다.
SDF
Gazebo에서 로봇이나 월드(world)를 정의하는 데 사용하는 표준 형식으로, URDF보다 확장성이 높다.
로봇뿐만 아니라 복잡한 환경, 물리 파라미터, 센서, 플러그인 등을 더욱 세밀하게 정의할 수 있다.
ROS 측면에서 보면, URDF+Xacro를 통해 구현할 수 없는 일부 Gazebo 기능을 바로 SDF로 작성할 수 있다는 장점이 있다.
ROS2 환경에서는 URDF나 SDF를 모두 활용할 수 있으나, 기존 ROS 패키지나 예제 코드 대부분이 URDF 기반이므로 URDF를 우선 학습하고, SDF가 필요한 경우 선택적으로 사용하면 된다.
관성(inertia) 파라미터 설정
시뮬레이션에서 물리 엔진이 현실적으로 동작하려면 링크(link)의 질량, 관성 모멘트(inertia), 질량중심(center of mass) 등의 물리 파라미터가 올바르게 설정되어야 한다. 예를 들어, 어떤 링크의 질량이 $m$이고, 3x3 관성 행렬이 $\mathbf{I}$라면, URDF 내에서는 다음과 같이 표현한다.
위에서 ixx, iyy, izz 등은 대각성분이며, ixy, ixz, iyz 등은 비대각성분이다. 이 행렬을 수식으로 나타내면 다음과 같다.
시뮬레이션 정확도를 높이기 위해 실제 로봇의 CAD 모델로부터 관성 정보를 추출하거나, 대략적인 추정값이라도 넣어주어야 한다.
충돌(Collision)과 시각(Visual) 요소 분리
Gazebo에서는 한 링크에 대해 충돌(collision) 요소와 시각(visual) 요소를 각각 정의할 수 있다.
Collision: 물리 시뮬레이션에 사용되는 형상(geometry). 실제 충돌 판정을 위해 단순한 형태(박스, 구 등)로 구성하는 것이 일반적이다.
Visual: 시각적으로 보여주는 형상. 충돌 요소와 달리 정교한 3D 메시(mesh)나 텍스처(texture)를 적용할 수 있다.
예를 들어, URDF에서는 다음과 같이 명시한다.
이렇게 충돌 요소를 단순화하여 시뮬레이션 계산량을 줄이되, 시각적 표현은 실제 모델과 유사한 정밀 메시를 사용할 수 있다.
좌표계(좌표 프레임)와 변환
Gazebo 시뮬레이션에서 각 링크, 월드, 센서 등은 각각 고유의 좌표계(프레임)를 가진다. 어떤 좌표계에서 다른 좌표계로 변환을 하고자 할 때는 변환 행렬 $\mathbf{T}$을 적용한다. 2차원 회전 예시를 보면,
이와 유사하게 3차원 변환은 회전 행렬과 평행이동 벡터를 합쳐서 4x4 형태의 동차(homogeneous) 좌표계로 표현한다.
Gazebo 상에서 예를 들어, 월드 좌표계($\mathrm{world}$)에서 로봇 베이스링크($\mathrm{base_link}$)까지의 변환을 $^{\mathrm{world}}\mathbf{T}_{\mathrm{base}}$라 하면, 실제 URDF/SDF에서는 <origin xyz="x y z" rpy="roll pitch yaw"/>와 같이 정의된다.
센서(Sensor) 플러그인
Gazebo 시뮬레이션은 다양한 센서를 가상으로 구현할 수 있다. 예: 카메라, 레이저(LiDAR), IMU, GPS, Depth 카메라 등. 이를 위해서는 센서 플러그인을 로봇 모델의 URDF 또는 SDF 파일에 추가하면 된다.
이렇게 하면 Gazebo가 카메라 센서를 시뮬레이션해, ROS2 토픽(/my_robot/image_raw)으로 이미지를 퍼블리시한다.
Gazebo 플러그인 개발 개요
Gazebo에서 동작하는 로직(물리 제어, 센서 모델, 월드 동적 변화 등)을 유연하게 확장하기 위해서는 플러그인(Plugin)을 개발할 수 있다. Gazebo Classic 기준으로 C++로 작성된 동적 라이브러리(.so)를 만들어 로드하는 방식이며, 원하는 이벤트(초기화, 시뮬레이션 주기, 충돌 판정 등)에 맞춰 함수를 실행할 수 있다.
Gazebo 플러그인은 크게 다음 유형이 있다.
World Plugin: 월드 전체에 대한 이벤트를 처리한다. 예를 들어 월드가 로드되었을 때 특정 오브젝트를 생성하거나, 시간에 따라 월드를 동적으로 업데이트하는 로직 등을 구현한다.
Model Plugin: 특정 모델(로봇 등)에 직접 바인딩되어, 모델 상태나 조인트, 링크 정보 등을 주기적으로 읽어 제어 로직을 적용한다.
Sensor Plugin: 센서 데이터를 생성하거나 시뮬레이션 중 센서의 동작을 커스터마이징한다. 예: 카메라, LiDAR, IMU 등에 사용자 정의 효과를 부여.
System Plugin: Gazebo의 전역 시스템 레벨에서 동작한다. UI를 확장하거나, 프로파일링, 디버깅 툴을 추가하는 등의 작업을 할 수 있다.
ROS2 연동 시에는 “gazebo_ros_pkgs”에서 제공하는 ROS 플러그인들을 자주 활용하지만, 더 세밀한 동작이 필요하거나 특정 로직을 직접 제어하고 싶다면 사용자 정의 플러그인을 만들어야 한다.
사용자 정의 플러그인 작성 예시 (Model Plugin)
여기서는 Model Plugin 예시를 들어, 특정 로봇 모델이 매 시뮬레이션 업데이트 때마다 로그를 출력하는 단순 기능을 살펴보겠다.
플러그인 C++ 코드 작성 패키지 디렉터리에
src/simple_model_plugin.cpp파일을 하나 만든다고 가정하자.CMakeLists.txt 설정 플러그인 코드를 컴파일하기 위해
CMakeLists.txt에서 Gazebo 관련 의존성과 컴파일 옵션을 설정해야 한다. 예시:빌드 및 설치 ROS2 워크스페이스 내에 패키지를 배치해둔 경우, 다음과 같이
colcon build를 실행한다.빌드가 정상적으로 완료되면,
install/simple_model_plugin/lib/libsimple_model_plugin.so등의 경로에 동적 라이브러리가 생성된다.플러그인 로드하기 Gazebo에서 해당 플러그인을 불러오기 위해서는 SDF나 URDF 내부에서
<plugin>태그를 추가하거나, Gazebo 명령줄에서-s옵션으로 로드할 수도 있다.SDF 예시
URDF 예시
명령줄 로드 예시
실제로 Gazebo를 실행하면, 플러그인이 로드될 때 “
[SimpleModelPlugin] Loaded!” 메시지가 출력되고, 시뮬레이션 업데이트마다 모델의 위치가 로그로 확인될 것이다.
ROS2 통신을 활용한 플러그인 확장
사용자 정의 Gazebo 플러그인에 ROS2 rclcpp 노드를 직접 포함시켜, 토픽/서비스/액션 통신을 구현할 수도 있다. 이를 위해서는 다음과 같은 작업이 필요하다.
ROS2 종속성 추가
CMakeLists.txt에서find_package(rclcpp REQUIRED)등 ROS2 관련 의존성을 찾고, 빌드 타겟에 링크한다.rclcpp::Node 생성 플러그인의
Load()함수 내에서 ROS2 노드를 초기화하고, 퍼블리셔/서브스크라이버 등을 생성한다.ROS2 이벤트 처리
OnUpdate()에서 Gazebo 모델 상태를 읽고, ROS2 토픽으로 퍼블리시하거나, ROS2로부터 들어오는 제어 명령(서브스크립션/서비스 등)을 처리할 수 있다.
이렇게 하면 Gazebo 시뮬레이션과 ROS2 노드가 한 프로세스 안에서 동시에 동작하므로, 보다 직접적인 연동이 가능해진다. 하지만 이때 ROS2 스레드 처리나 rclcpp::spin 관련 사항을 주의 깊게 다뤄야 하며, Gazebo 이벤트 루프와 충돌하지 않도록 신경써야 한다.
플러그인 디버깅 팁
GDB를 통한 디버깅: Gazebo 실행 시 GDB를 붙여서 브레이크포인트를 걸고 디버깅할 수 있다.
로그 메시지: 표준출력(std::cout) 혹은 ROS2 로그 매크로(RCLCPP_INFO 등)를 통해 적절히 로그를 기록한다.
환경 변수 확인: $GAZEBO_PLUGIN_PATH, $LD_LIBRARY_PATH 등이 제대로 설정되지 않으면 플러그인이 로드되지 않는다.
플러그인 버전 호환성: Gazebo Classic 11 버전에서 빌드된 플러그인이 Gazebo 9 등 다른 버전에서 작동하지 않을 수 있으므로 버전을 맞춰야 한다.
모델별 Plugin 삽입 주의사항
하나의 모델에 여러 개의 플러그인을 삽입할 수도 있다. 예: 제어 플러그인, 센서 플러그인 등. 이때 다음 사항에 유의한다.
플러그인 간 리소스 충돌(예: 동일 링크를 동시에 제어)
업데이트 순서(어떤 플러그인이 먼저 Load되고 OnUpdate되는지)
ROS2 네임스페이스나 토픽 이름이 중복되지 않도록 설계
이를 프로젝트 규모에 맞춰 체계적으로 구조화하고, URDF/Xacro/SDF의 계층 구조를 깔끔하게 유지하는 것이 중요하다.
시뮬레이션 시간(공시성과 실시간)
Gazebo에서는 실제 시간(real-time)과 시뮬레이션 시간(simulation time)을 구분하여 다룬다. 시뮬레이션이 무거울수록(복잡한 물리엔진 연산, 다수의 센서나 복잡한 메시 등) 실제 시간 대비 시뮬레이션 시간이 느려지거나, 스텝(step) 단위로 끊기는 현상이 생길 수 있다.
Real Time Factor(RTF) Gazebo GUI 하단에서 확인할 수 있는 값으로, 시뮬레이션 시간 대비 실제 시간의 비율이다. 가령 RTF가 0.5라면 시뮬레이션 1초가 실제 2초만에 진행됨을 의미한다.
Physics Update Rate 시뮬레이션의 기본 물리 업데이트 주기(초당 스텝 수). 너무 높이면 계산량이 급증해 RTF가 낮아질 수 있으므로, 모델 복잡도에 맞춰 적절히 조정해야 한다.
ROS2와의 시간 동기 Gazebo에서 사용하는 “시뮬레이션 시간”을 ROS2의 “/clock” 토픽으로 퍼블리시할 수 있다. ROS2 노드에서는 파라미터 설정(예: use_sim_time=true)을 통해, /clock 토픽을 기반으로 한 가상 시간을 사용하게 된다.
Gazebo 물리엔진 설정
Gazebo Classic 11 기준, 기본 물리엔진은 ODE(Open Dynamics Engine)이며, 선택적으로 Bullet, DART, Simbody 등을 사용 가능하다. 물리엔진마다 마찰, 관성 해석, 조인트 제약 처리 등의 구현 방식이 다소 차이가 있으므로, 프로젝트 특성에 따라 적절한 엔진을 고를 수 있다.
ODE
오랜 역사를 지닌 물리엔진으로, Gazebo에서 기본값으로 사용.
충돌 감지, 조인트 제약 처리 등이 간단하고 안정적이나, 고도로 정밀한 물리 현상 구현에는 다소 제한이 있을 수 있음.
Bullet
게임 엔진 등에서 널리 사용되는 물리엔진. 충돌 감지, 강체(rigid body) 시뮬레이션에 강점.
DART
다물체 동역학(Multi-body dynamics)에 특화된 물리엔진으로, 조인트 움직임이 많은 로봇 암(arm) 시뮬레이션에 유리.
Simbody
생체역학 등에서 사용되는 정확한 역학 모델에 강점.
Physics 파라미터 Gazebo GUI 상단 메뉴(Physics)나 SDF 파일에서 물리 파라미터를 세부 설정할 수 있다. 예: max_step_size, real_time_update_rate, gravity, solver_iterations 등.
Gazebo의 Seed Randomness와 재현성
시뮬레이션 환경에서 무작위(random) 요소가 있는 경우(센서 노이즈, 모델 초기 자세 무작위 설정 등), Gazebo는 내부적으로 난수 발생기(random seed)를 사용한다.
재현성(reproducibility)을 위해, 실험마다 고정된 seed를 설정할 수 있다.
특정 실험 시나리오에서 다양한 초기 조건을 반복적으로 부여하고 싶다면, seed를 변경해가며 시뮬레이션을 돌려볼 수 있다.
SDF 파일에서 <seed> 태그나, 명령줄 옵션을 통해 Gazebo 실행 시 seed 값을 지정할 수도 있다.
이렇게 하면 시뮬레이션에 포함된 무작위 노이즈나 물리 현상이 동일 seed 값을 기준으로 반복된다.
Gazebo 월드(World) 파일 확장
ROS2 프로젝트에서 반복적으로 사용할 월드를 구성할 때는, SDF 형식의 .world 파일을 커스터마이징해두는 것이 편리하다. 예를 들어 “warehouse.world”라는 파일을 만들어, 내부에 박스형 창고 구조물, 조명, 지면 등 필요한 요소를 배치할 수 있다.
이렇게 준비한 .world 파일을 직접 로드하거나, ROS2 launch 파일에서 인자로 받아 Gazebo를 실행하면 된다.
복합 시나리오(여러 로봇, 여러 센서) 구성
하나의 Gazebo 월드 안에 여러 로봇을 동시에 배치할 수 있다. 이때 각각의 로봇이 같은 URDF/SDF를 공유하거나, 서로 다른 모델을 섞어서 사용할 수도 있다.
네임스페이스(namespace) 로봇 A와 로봇 B가 같은 토픽 이름(예:
/scan)을 사용하면 충돌이 생길 수 있다. URDF 내에서<robotNamespace>를 다르게 설정하거나, spawn 명령 시-x옵션 등을 통해 네임스페이스를 지정해주면 편리하다.센서 충돌 한 시뮬레이션 안에 많은 센서(카메라, LiDAR 등)를 동시에 구동하면 CPU/GPU 부담이 커진다. 필요한 센서만 활성화하거나, 해상도/프레임레이트를 조정하여 성능을 최적화해야 한다.
통신 충돌 ROS2 QoS 설정, 토픽 우선순위 등에 따라 네트워크나 메시 처리 병목이 생길 수 있다. ROS2의
BEST_EFFORT,RELIABLEQoS를 적절히 설정하여 트래픽을 조절할 수 있다.
Docker를 통한 Gazebo 실행
Gazebo 환경을 좀 더 이식성 있게 관리하기 위해 Docker 이미지를 사용하는 경우도 많다. 특히 CI(Continuous Integration)나 클라우드 서버에서 시뮬레이션 테스트를 할 때 유용하다.
기본 Ubuntu + ROS2 + Gazebo Dockerfile에서 Ubuntu 22.04 이미지를 기반으로 ROS2 Humble, Gazebo11 등을 설치한 후, 필요한 패키지를 모두 세팅한다.
GUI Forwarding 로컬 환경에서 Docker 컨테이너 안의 Gazebo GUI를 띄우려면 X11 forwarding이나 VNC 등을 활용한다.
Headless GUI 없이 테스트하려면
--headless-rendering옵션을 주거나, XVFB(가상 디스플레이) 기반으로 실행할 수 있다.
GPU 가속 렌더링과 호환성
Gazebo 환경에서는 GPU 가속을 활용해 3D 렌더링 성능을 높일 수 있다. 특히 지형(terrain), 여러 개의 3D 모델, 복잡한 텍스처가 들어간 환경에서 CPU만으로 렌더링하기에는 한계가 있으므로, 가능하다면 GPU를 활용하는 편이 좋다.
NVIDIA 드라이버 & CUDA
엔비디아 GPU를 사용하는 경우, 호환되는 드라이버를 제대로 설치해야 한다.
리눅스 환경(특히 Ubuntu)에서
nvidia-driver-XXX형태로 패키지를 설치하고,nvidia-smi명령으로 GPU 인식 여부를 확인한다.
OpenGL 버전
Gazebo Classic은 OpenGL 3.x 이상을 요구한다. 가상 머신 환경에서는 OpenGL을 완전 지원하지 못해, 3D GUI가 일부 깨질 수 있다.
Intel/AMD 내장 그래픽
별도 GPU가 없는 PC에서 내장 그래픽을 쓰는 경우, 드라이버 버전에 따라 성능이나 렌더링 호환성에 이슈가 발생할 수 있다.
일부 저사양 환경에서는 Gazebo를 Headless 모드로 사용하고, RViz 또는 다른 툴로 시각화하는 방식을 고민해야 한다.
ROS2 Launch 파일에서 Gazebo와 RViz 동시 실행
ROS2 프로젝트에서 시뮬레이션과 시각화를 동시에 구동하려면, Launch 파일에서 Gazebo와 RViz 노드를 함께 띄울 수 있다. 예시로 bringup_sim.launch.py라는 파일을 만들 수 있다.
이렇게 구성해두면 $ ros2 launch my_robot_description bringup_sim.launch.py 명령으로 Gazebo와 RViz가 함께 구동된다.
Gazebo: 시뮬레이션 물리 및 3D 환경
RViz: 센서 데이터, TF(좌표 변환), 로봇 모델 상태 등을 시각화
두 툴을 동시에 실행하면 시스템 자원 소모가 커질 수 있으므로, 개발 환경에 맞춰 필요한 시점에만 함께 구동하는 것이 좋다.
시뮬레이션 성능 최적화 요령
복잡한 로봇 모델, 고해상도 센서, 여러 로봇 동시 시뮬레이션 등이 겹치면 Gazebo가 매우 느려질 수 있다. 다음은 성능 튜닝을 위한 대표적 방법들이다.
Collision Geometry 단순화
복잡한 메시 대신, 박스나 구 등 단순 도형으로 충돌(컬리전) 형상을 구성한다.
시각(Visual) 메시와 충돌(Collision) 메시를 분리하여, 충돌은 가볍게 처리한다.
Physics Update Rate / Max Step Size 조정
물리 업데이트 횟수를 줄이거나(예: 1000 → 300), 최대 스텝 크기를 늘려서 시뮬레이션 부하를 줄인다.
RTF(Real Time Factor)가 너무 낮아지지 않도록 적절한 타협점을 찾는다.
센서 해상도/주파수 조정
카메라 해상도를 1920×1080 대신 640×480으로 낮추고, 프레임레이트도 필요한 범위로 제한한다(30fps → 15fps).
LiDAR 역시 스캔 범위나 각 해상도를 낮춰 시뮬레이션 연산량을 절감한다.
Headless Rendering
GUI가 필요 없는 상황에서는
--headless-rendering옵션으로 실행해 CPU/GPU 부하를 줄이고, 물리엔진만 동작시키도록 한다.
GPU/드라이버 업데이트
OS 환경에서 최신 드라이버 및 Gazebo 버전을 사용하는 것만으로도 성능이 향상될 수 있다.
멀티 스레드 / 멀티코어 활용
Gazebo Classic 자체가 물리엔진, 렌더링, 센서 업데이트를 다중 스레드로 처리하긴 하지만, 일정 부분은 싱글 스레드 병목이 생길 수 있다.
필요에 따라 OS나 CPU 코어 할당, RT(실시간) 우선순위 설정 등을 조절해볼 수 있다.
Gazebo 커맨드 라인 유틸리티
Gazebo Classic에는 다양한 커맨드 라인 도구가 있으며, 그중 ROS2와 함께 자주 쓰이는 것은 다음과 같다.
gz topic list, gz topic echo, gz topic info 등 Gazebo에서 사용하는 자체 토픽(예: ~/factory, ~/world/...) 목록 확인, 에코, 인포.
gz model: 시뮬레이션 중 동적으로 모델을 삽입하거나 삭제, 포즈(위치) 이동 등 할 수 있다.
gz physics: 현재 물리 설정 조회나, 엔진 종류를 변경할 수도 있다(실시간 수정은 제한적).
주의: gz 명령어는 Ignition 계열(지금은 Gazebo Fortress, Garden 등)에서 주로 사용되는 CLI 툴이지만, Gazebo Classic 11 이후 버전과도 일부 호환되는 명령이 있다. 서로 버전 차이를 인지하고 사용해야 한다.
Gazebo와 TF(Transform) 관점
ROS 환경에서는 로봇 링크 간 변환을 tf2 프레임워크로 관리한다. Gazebo 물리엔진 내부 좌표계는 별개이므로, URDF/SDF에서 정의된 링크/조인트 구조를 바탕으로 ROS2 측에서 TF를 퍼블리시한다.
로봇 디스크립션에서
<joint>나<link>가 연결된 구조가tf2트리로 매핑되어, RViz나 rqt_tf_tree 등에서 확인할 수 있다.Gazebo에서 링크가 물리적으로 움직이면, ROS2 컨트롤 또는 각종 플러그인을 통해 TF가 자동 갱신된다(예:
joint_state_publisher,robot_state_publisher).실제 로봇과 시뮬레이션 로봇을 동시 관측하려면, TF 프레임이 충돌나지 않도록 네임스페이스를 구분하거나, TF 리맵핑이 필요할 수 있다.
에러 트러블슈팅(자주 발생하는 문제)
설치 충돌
ROS2 apt 패키지와 Gazebo apt 패키지가 버전 호환 문제로 충돌할 수 있음.
$ sudo apt update && sudo apt upgrade후 종종 깨지는 경우가 있으므로, 호환표나 공식 문서를 참고해 설치한다.
플러그인 로드 실패
$GAZEBO_PLUGIN_PATH,$LD_LIBRARY_PATH설정 누락, 혹은 라이브러리 빌드 시 Gazebo 버전 mismatch.
X11 Forwarding 실패
Docker나 원격 SSH 환경에서 Gazebo GUI가 뜨지 않는 경우,
DISPLAY환경 변수나 xhost 권한 설정을 확인해야 함.
시간 동기 오류
ROS2 노드가
use_sim_time=true로 세팅되었으나 /clock 토픽이 퍼블리시되지 않는 경우, Gazebo 플러그인이 로드되었는지 등 확인이 필요.
Last updated