Gazebo is a powerful robotics simulation tool that provides a 3D environment for simulating robots, sensors, and objects. It is widely used in the ROS ecosystem for testing and developing robotics algorithms in a realistic virtual environment before deploying them to real hardware.
Gazebo integrates tightly with ROS, enabling simulation and control of robots using ROS topics, services, and actions. In ROS2 with the latest Gazebo releases the integration is facilitated by ros_gz.
Key Features of Gazebo:
Besides Gazebo, there are many alternative simulation environments for ROS, but usually the setup of these simulators are more complicated and less documented. Certain simulators also have very high requirements for the GPU.
| Simulator | Best For | Advantages | Disadvantages |
|---|---|---|---|
| Gazebo | General robotics simulation in ROS | Free, accurate physics, ROS support | Moderate visuals, resource-heavy |
| Unity | High-fidelity visuals and AI/ML tasks | Realistic graphics, AI tools | Steep learning curve, not robotics-specific |
| Webots | Beginner-friendly robotics simulation | Easy setup, cross-platform | Limited graphics, less customizable |
| Isaac Sim | High-end AI and robotics simulation | High-fidelity physics, AI support | GPU-intensive, complex setup |
Before we install Gazebo we have to understand the compatibility between Gazebo versions and ROS distributions.
| ROS Distribution | Gazebo Citadel (LTS) | Gazebo Fortress (LTS) | Gazebo Garden | Gazebo Harmonic (LTS) | Gazebo Ionic |
|---|---|---|---|---|---|
| ROS 2 Rolling | ❌ | ❌ | ⚡ | ⚡ | ✅ |
| ROS 2 Jazzy (LTS) | ❌ | ❌ | ⚡ | ✅ | ❌ |
| ROS 2 Iron | ❌ | ✅ | ⚡ | ⚡ | ❌ |
| ROS 2 Humble (LTS) | ❌ | ✅ | ⚡ | ⚡ | ❌ |
| ROS 2 Foxy (LTS) | ✅ | ❌ | ❌ | ❌ | ❌ |
| ROS 1 Noetic (LTS) | ✅ | ⚡ | ❌ | ❌ | ❌ |
Since we use the latest LTS ROS2 distribution, Jazzy, we need Gazebo Harmonic.
To install Gazebo Harmonic binaries on Ubuntu 24.04 simply follow the steps on this link.
Once it's installed we can try it with the following command:
gz sim shapes.sdf
If everything works well you should see the following screen:

If you have a problem with opening this example shapes.sdf there might be various reasons that requires some debugging skills with Gazebo and Linux.
If you see a Segmentation fault (Address not mapped to object [(nil)]) due to problems with Qt you can try to set the following environmental variable to force Qt to use X11 instead of Wayland. Link
bash
export QT_QPA_PLATFORM=xcb
If you run Gazebo in WSL2 or virtual machine the most common problem is with the 3D acceleration with the OGRE2 rendering engine of Gazebo. You can either try disabling HW acceleration (not recommended) or you can switch the older OGRE rendering engine with the following arguments. Link
bash
gz sim shapes.sdf --render-engine ogre
If you run Ubuntu natively on a machine with an integrated Intel GPU and a discrete GPU you can check this troubleshooting guide.
After Gazebo successfully starts we can install the Gazebo ROS integration with the following command:
sudo apt install ros-jazzy-ros-gz
You can find the official install guide here.
Let's start again the gz sim shapes.sdf example again and let's see what is important on the Gazebo GUI:

-r when you start Gazebo it automatically starts the simulation.4. some parameters can be changed most of them are read only.Resource Spawner, Visualize Lidar, Image Display, etc.Gazebo has an online model database available here, you can browse and download models from here. Normally this online model library is accessible within Gazebo although there might be issues in WSL2 or in virtual machines, so I prepared an offline model library with some basic models.
You can download this offline model library from Google Drive.
After download unzip it and place it in the home folder of your user. To let Gazebo know about the offline model library we have to set the GZ_SIM_RESOURCE_PATH environmental variable, the best is to add it to the .bashrc:
export GZ_SIM_RESOURCE_PATH=~/gazebo_models
After setting up the offline model library let's open the empty.sdf in Gazebo and add a few models through the Resource Spawner within the plug-in browser:

From now, every lesson has a starter package that you can donwload from GitHub. To download the starter package clone the following git repo with the right branch (with the -b branch flag) to your colcon workspace:
git clone -b starter-branch https://github.com/MOGI-ROS/Week-3-4-Gazebo-basics.git
Let's see what's inside the bme_gazebo_basics package with the tree command!
.
├── CMakeLists.txt
├── package.xml
├── meshes
│ ├── mecanum_wheel_left.STL
│ ├── mecanum_wheel_right.STL
│ ├── mogi_bot.blend
│ ├── mogi_bot.dae
│ ├── mogi_bot.SLDPRT
│ ├── mogi_bot.STEP
│ ├── mogi_bot.STL
│ ├── wheel.blend
│ ├── wheel.dae
│ ├── wheel.SLDPRT
│ ├── wheel.STEP
│ └── wheel.STL
├── rviz
│ ├── rviz.rviz
│ └── urdf.rviz
├── urdf
│ └──materials.xacro
└── worlds
├── empty.sdf
└── world.sdf
There are a few folders that we didn't met before:
- meshes: this folder contains the 3D models in dae format (collada mesh) that we'll use later for our robot's body and wheels. In this lesson it also includes the SolidWorks and Blender models as reference, but it's not needed for the simulation.
- rviz: pre-configured RViz2 layouts that we can use to display the robot's model and the environment
- urdf: URDF = Universal Robot Description Format. We'll create the model of our robots in this folder. It already has a file with color codes and names.
- worlds: we'll store the Gazebo worlds that we use in the simulation. In the next chapter we learn how to create a Gazebo world.
Before we create a new world, let's see how can we open the example world.sdf. Let's navigate to the worlds folder and run the following command:
gz sim world.sdf
In case you have problem with the default OGRE2 rendering engine you can switch to OGRE:
bash gz sim world.sdf --render-engine ogre
And it should open the example world I created for this package.

Now let's switch to the empty template:
gz sim empty.sdf
Build a world you like using the resource spawner and in the end save it into the worlds folder with sdf extension.

After we created the new world file, let's see how can we launch Gazebo and load the world using ROS. First, let's create a launch folder within the package. Inside this folder let's create a new launch file world.launch.py.
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution, TextSubstitution
def generate_launch_description():
world_arg = DeclareLaunchArgument(
'world', default_value='world.sdf',
description='Name of the Gazebo world file to load'
)
pkg_bme_gazebo_basics = get_package_share_directory('bme_gazebo_basics')
pkg_ros_gz_sim = get_package_share_directory('ros_gz_sim')
# Add your own gazebo library path here
gazebo_models_path = "/home/david/gazebo_models"
os.environ["GZ_SIM_RESOURCE_PATH"] += os.pathsep + gazebo_models_path
gazebo_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(pkg_ros_gz_sim, 'launch', 'gz_sim.launch.py'),
),
launch_arguments={'gz_args': [PathJoinSubstitution([
pkg_bme_gazebo_basics,
'worlds',
LaunchConfiguration('world')
]),
#TextSubstitution(text=' -r -v -v1 --render-engine ogre')],
TextSubstitution(text=' -r -v -v1')],
'on_exit_shutdown': 'true'}.items()
)
launchDescriptionObject = LaunchDescription()
launchDescriptionObject.add_action(world_arg)
launchDescriptionObject.add_action(gazebo_launch)
return launchDescriptionObject
This launch file has one argument, the world file's name - you can change the default value to your new world. It also ensures that the offline Gazebo model folder is added to the environmental variable, and finally it launches Gazebo through the ros_gz_sim with the right arguments (note that the simulation will start automatically because of the -r flag).
In case you have problem with the default
$ claude mcp add Week-3-4-Gazebo-basics \
-- python -m otcore.mcp_server <graph>