Skip to main content

Chapter 6: Gazebo Simulation

Welcome to Module 2! In this chapter, we transition from understanding robot descriptions (URDF) to bringing robots to life in a physics-accurate simulation environment. Gazebo is the industry-standard simulator that enables you to test robot behaviors without risking expensive hardware.


Learning Objectivesโ€‹

By the end of this chapter, you will be able to:

  • Explain the role of simulation in robotics development
  • Install and configure Gazebo for ROS 2
  • Create and customize simulation worlds
  • Spawn URDF robots into Gazebo environments
  • Configure physics engines and simulation parameters
  • Add sensors to simulated robots and visualize their output

Why Simulation Mattersโ€‹

The Cost of Physical Testingโ€‹

Developing robots in the real world is expensive and risky:

ChallengeReal WorldSimulation
Hardware Cost$10,000 - $1,000,000+$0 (software)
Testing TimeHours per iterationSeconds per iteration
Safety RiskPotential damageZero risk
Environment ControlLimitedComplete control
ReproducibilityDifficultPerfect repeatability
ParallelizationOne robotThousands of instances

The Digital Twin Conceptโ€‹

A digital twin is a virtual replica of a physical system that mirrors its real-world counterpart in real-time. In robotics, this means:

  1. Design Phase: Test robot designs before manufacturing
  2. Development Phase: Develop and debug algorithms safely
  3. Deployment Phase: Validate behaviors before real-world execution
  4. Operation Phase: Monitor and predict real robot behavior
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Digital Twin Workflow โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ Design โ”‚โ”€โ”€โ”€โ–ถโ”‚ Simulate โ”‚โ”€โ”€โ”€โ–ถโ”‚ Validate in Real โ”‚ โ”‚
โ”‚ โ”‚ (URDF) โ”‚ โ”‚ (Gazebo) โ”‚ โ”‚ World โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚ โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ โ”‚ โ–ผ โ”‚ โ”‚
โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถโ”‚ Refine โ”‚โ—€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Introduction to Gazeboโ€‹

What is Gazebo?โ€‹

Gazebo is an open-source 3D robotics simulator that provides:

  • Physics Simulation: Accurate rigid body dynamics, collision detection
  • Sensor Simulation: LIDAR, cameras, IMUs, GPS, force/torque sensors
  • Environment Modeling: Indoor/outdoor worlds with lighting and terrain
  • Robot Models: Library of pre-built robots and objects
  • ROS 2 Integration: Seamless communication with ROS 2 nodes

Gazebo Classic vs Gazebo (Ignition)โ€‹

The Gazebo ecosystem has evolved significantly:

FeatureGazebo ClassicGazebo (Modern)
VersionGazebo 11 (EOL 2025)Gazebo Harmonic (2024+)
ArchitectureMonolithicModular (Ignition libraries)
RenderingOGRE 1.xOGRE 2.x (PBR support)
PhysicsODE defaultMultiple engines (DART, Bullet, TPE)
ROS 2 Supportros_gazeboros_gz (native)
RecommendationLegacy projectsNew projects
Recommendation

For new ROS 2 projects, use Gazebo Harmonic or later. This textbook focuses on the modern Gazebo (formerly Ignition Gazebo).

Gazebo Architectureโ€‹

Modern Gazebo is built on a collection of Ignition libraries:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Gazebo Architecture โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ gz-sim โ”‚ โ”‚ gz-gui โ”‚ โ”‚ gz-transport โ”‚ โ”‚
โ”‚ โ”‚ (Simulator) โ”‚ โ”‚ (Interface) โ”‚ โ”‚ (Communication) โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚ โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ gz-physics โ”‚ โ”‚ gz-renderingโ”‚ โ”‚ gz-msgs โ”‚ โ”‚
โ”‚ โ”‚ (Dynamics) โ”‚ โ”‚ (Graphics) โ”‚ โ”‚ (Messages) โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚ โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ gz-math โ”‚ โ”‚ gz-sensors โ”‚ โ”‚ gz-plugin โ”‚ โ”‚
โ”‚ โ”‚ (Utilities) โ”‚ โ”‚ (Sensors) โ”‚ โ”‚ (Extensions) โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Installing Gazebo for ROS 2โ€‹

Prerequisitesโ€‹

Ensure you have ROS 2 Humble (or later) installed. Then install Gazebo:

# Install Gazebo Harmonic (for ROS 2 Humble/Iron/Jazzy)
sudo apt-get update
sudo apt-get install ros-humble-ros-gz

# Verify installation
gz sim --version

ROS-Gazebo Bridgeโ€‹

The ros_gz package provides bidirectional communication between ROS 2 and Gazebo:

# Install the bridge packages
sudo apt-get install ros-humble-ros-gz-bridge
sudo apt-get install ros-humble-ros-gz-sim
sudo apt-get install ros-humble-ros-gz-image

Testing the Installationโ€‹

Launch a simple world to verify everything works:

# Terminal 1: Launch Gazebo with an empty world
ros2 launch ros_gz_sim gz_sim.launch.py gz_args:="empty.sdf"

# Terminal 2: List Gazebo topics visible in ROS 2
ros2 topic list

Understanding SDF World Filesโ€‹

What is SDF?โ€‹

Simulation Description Format (SDF) is an XML format for describing:

  • Simulation worlds (environments)
  • Robot models (alternative to URDF)
  • Lights, physics, and plugins

While URDF describes robots, SDF describes entire simulation scenarios.

Basic World Structureโ€‹

<?xml version="1.0" ?>
<sdf version="1.8">
<world name="my_first_world">

<!-- Physics Configuration -->
<physics name="1ms" type="dart">
<max_step_size>0.001</max_step_size>
<real_time_factor>1.0</real_time_factor>
</physics>

<!-- Lighting -->
<light type="directional" name="sun">
<cast_shadows>true</cast_shadows>
<pose>0 0 10 0 0 0</pose>
<diffuse>0.8 0.8 0.8 1</diffuse>
<specular>0.2 0.2 0.2 1</specular>
<direction>-0.5 0.1 -0.9</direction>
</light>

<!-- Ground Plane -->
<model name="ground_plane">
<static>true</static>
<link name="link">
<collision name="collision">
<geometry>
<plane>
<normal>0 0 1</normal>
<size>100 100</size>
</plane>
</geometry>
</collision>
<visual name="visual">
<geometry>
<plane>
<normal>0 0 1</normal>
<size>100 100</size>
</plane>
</geometry>
<material>
<ambient>0.8 0.8 0.8 1</ambient>
</material>
</visual>
</link>
</model>

</world>
</sdf>

Key World Elementsโ€‹

ElementPurposeExample
<physics>Simulation stepping and engineDART, Bullet, ODE
<light>Scene illuminationSun, point lights, spotlights
<model>Objects in the worldGround, obstacles, robots
<plugin>Extend functionalitySensors, controllers
<scene>Rendering settingsAmbient light, shadows, sky

Creating Your First Simulation Worldโ€‹

Step 1: Create a Package for Worldsโ€‹

cd ~/ros2_ws/src
ros2 pkg create --build-type ament_cmake my_robot_simulation \
--dependencies ros_gz_sim

# Create directories
mkdir -p my_robot_simulation/worlds
mkdir -p my_robot_simulation/launch
mkdir -p my_robot_simulation/models

Step 2: Create a Custom Worldโ€‹

Create worlds/warehouse.sdf:

<?xml version="1.0" ?>
<sdf version="1.8">
<world name="warehouse">

<!-- Physics: 1kHz simulation rate -->
<physics name="1kHz" type="dart">
<max_step_size>0.001</max_step_size>
<real_time_factor>1.0</real_time_factor>
<real_time_update_rate>1000</real_time_update_rate>
</physics>

<!-- Plugins for ROS 2 integration -->
<plugin
filename="gz-sim-physics-system"
name="gz::sim::systems::Physics">
</plugin>
<plugin
filename="gz-sim-sensors-system"
name="gz::sim::systems::Sensors">
<render_engine>ogre2</render_engine>
</plugin>
<plugin
filename="gz-sim-scene-broadcaster-system"
name="gz::sim::systems::SceneBroadcaster">
</plugin>
<plugin
filename="gz-sim-user-commands-system"
name="gz::sim::systems::UserCommands">
</plugin>

<!-- Sunlight -->
<light type="directional" name="sun">
<cast_shadows>true</cast_shadows>
<pose>0 0 10 0 0 0</pose>
<diffuse>1 1 1 1</diffuse>
<specular>0.5 0.5 0.5 1</specular>
<attenuation>
<range>1000</range>
<constant>0.9</constant>
<linear>0.01</linear>
<quadratic>0.001</quadratic>
</attenuation>
<direction>-0.5 0.1 -0.9</direction>
</light>

<!-- Ground Plane -->
<model name="ground_plane">
<static>true</static>
<link name="link">
<collision name="collision">
<geometry>
<plane>
<normal>0 0 1</normal>
<size>50 50</size>
</plane>
</geometry>
<surface>
<friction>
<ode>
<mu>100</mu>
<mu2>50</mu2>
</ode>
</friction>
</surface>
</collision>
<visual name="visual">
<geometry>
<plane>
<normal>0 0 1</normal>
<size>50 50</size>
</plane>
</geometry>
<material>
<ambient>0.5 0.5 0.5 1</ambient>
<diffuse>0.5 0.5 0.5 1</diffuse>
</material>
</visual>
</link>
</model>

<!-- Warehouse Walls -->
<model name="wall_north">
<static>true</static>
<pose>0 10 1 0 0 0</pose>
<link name="link">
<collision name="collision">
<geometry>
<box><size>20 0.2 2</size></box>
</geometry>
</collision>
<visual name="visual">
<geometry>
<box><size>20 0.2 2</size></box>
</geometry>
<material>
<ambient>0.7 0.7 0.7 1</ambient>
</material>
</visual>
</link>
</model>

<!-- Obstacle: Box -->
<model name="obstacle_box">
<pose>3 2 0.5 0 0 0</pose>
<link name="link">
<inertial>
<mass>10</mass>
<inertia>
<ixx>0.167</ixx>
<iyy>0.167</iyy>
<izz>0.167</izz>
</inertia>
</inertial>
<collision name="collision">
<geometry>
<box><size>1 1 1</size></box>
</geometry>
</collision>
<visual name="visual">
<geometry>
<box><size>1 1 1</size></box>
</geometry>
<material>
<ambient>0.8 0.4 0.1 1</ambient>
<diffuse>0.8 0.4 0.1 1</diffuse>
</material>
</visual>
</link>
</model>

</world>
</sdf>

Step 3: Create a Launch Fileโ€‹

Create launch/warehouse.launch.py:

from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
from launch_ros.substitutions import FindPackageShare


def generate_launch_description():
# Paths
pkg_ros_gz_sim = FindPackageShare('ros_gz_sim')
pkg_my_simulation = FindPackageShare('my_robot_simulation')

# World file path
world_file = PathJoinSubstitution([
pkg_my_simulation, 'worlds', 'warehouse.sdf'
])

# Launch Gazebo
gz_sim = IncludeLaunchDescription(
PythonLaunchDescriptionSource([
PathJoinSubstitution([
pkg_ros_gz_sim, 'launch', 'gz_sim.launch.py'
])
]),
launch_arguments={
'gz_args': ['-r ', world_file],
}.items()
)

return LaunchDescription([
gz_sim,
])

Spawning Robots into Gazeboโ€‹

Converting URDF to Gazebo-Compatible Formatโ€‹

Your URDF from Chapter 5 needs additional Gazebo-specific elements:

<robot name="my_humanoid">
<!-- Standard URDF content -->
<link name="base_link">
<!-- ... -->
</link>

<!-- Gazebo-specific elements -->
<gazebo reference="base_link">
<material>Gazebo/Blue</material>
<mu1>0.2</mu1>
<mu2>0.2</mu2>
</gazebo>

<!-- Gazebo plugins for control -->
<gazebo>
<plugin filename="gz-sim-joint-state-publisher-system"
name="gz::sim::systems::JointStatePublisher">
</plugin>
</gazebo>
</robot>

Spawning with ros_gzโ€‹

Create a launch file to spawn your robot:

from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration, Command
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare
import os


def generate_launch_description():
# Get URDF file
urdf_file = os.path.join(
FindPackageShare('my_robot_description').find('my_robot_description'),
'urdf', 'robot.urdf.xacro'
)

robot_description = Command(['xacro ', urdf_file])

# Spawn robot in Gazebo
spawn_robot = Node(
package='ros_gz_sim',
executable='create',
arguments=[
'-name', 'my_robot',
'-topic', 'robot_description',
'-x', '0.0',
'-y', '0.0',
'-z', '0.5',
],
output='screen',
)

# Robot state publisher
robot_state_publisher = Node(
package='robot_state_publisher',
executable='robot_state_publisher',
parameters=[{'robot_description': robot_description}],
output='screen',
)

return LaunchDescription([
robot_state_publisher,
spawn_robot,
])

Physics Configurationโ€‹

Understanding Physics Enginesโ€‹

Gazebo supports multiple physics engines:

EngineStrengthsUse Cases
DARTAccurate dynamics, soft contactsHumanoids, manipulation
BulletFast, game-orientedLarge environments, many objects
ODEMature, well-testedGeneral robotics
TPETrivial physicsSensor testing without dynamics

Configuring Physics Parametersโ€‹

<physics name="high_accuracy" type="dart">
<!-- Simulation step size (seconds) -->
<max_step_size>0.001</max_step_size>

<!-- Real-time factor: 1.0 = real-time, 0.5 = half speed -->
<real_time_factor>1.0</real_time_factor>

<!-- Update rate (Hz) -->
<real_time_update_rate>1000</real_time_update_rate>

<!-- DART-specific settings -->
<dart>
<collision_detector>fcl</collision_detector>
<solver>
<solver_type>dantzig</solver_type>
</solver>
</dart>
</physics>

Tuning for Performance vs Accuracyโ€‹

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Physics Tuning Trade-offs โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ โ”‚
โ”‚ Accuracy โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ Speed โ”‚
โ”‚ โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ Small step size โ”‚ โ”‚ Large step size โ”‚ โ”‚
โ”‚ โ”‚ (0.0001s) โ”‚ โ”‚ (0.01s) โ”‚ โ”‚
โ”‚ โ”‚ More iterations โ”‚ โ”‚ Fewer iterationsโ”‚ โ”‚
โ”‚ โ”‚ Complex solver โ”‚ โ”‚ Simple solver โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚ โ”‚
โ”‚ Use for: Use for: โ”‚
โ”‚ - Contact-rich tasks - Path planning โ”‚
โ”‚ - Manipulation - Large-scale simulation โ”‚
โ”‚ - Humanoid balance - Sensor testing โ”‚
โ”‚ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Adding Sensors in Simulationโ€‹

Common Simulated Sensorsโ€‹

Gazebo can simulate all sensors we studied in Chapter 2:

<!-- LIDAR Sensor -->
<sensor name="lidar" type="gpu_lidar">
<pose>0 0 0.5 0 0 0</pose>
<topic>scan</topic>
<update_rate>10</update_rate>
<lidar>
<scan>
<horizontal>
<samples>640</samples>
<resolution>1</resolution>
<min_angle>-1.5708</min_angle>
<max_angle>1.5708</max_angle>
</horizontal>
<vertical>
<samples>16</samples>
<resolution>1</resolution>
<min_angle>-0.261799</min_angle>
<max_angle>0.261799</max_angle>
</vertical>
</scan>
<range>
<min>0.1</min>
<max>100</max>
</range>
</lidar>
</sensor>

<!-- RGB Camera -->
<sensor name="camera" type="camera">
<pose>0 0 0.3 0 0 0</pose>
<topic>image</topic>
<update_rate>30</update_rate>
<camera>
<horizontal_fov>1.047</horizontal_fov>
<image>
<width>640</width>
<height>480</height>
<format>R8G8B8</format>
</image>
<clip>
<near>0.1</near>
<far>100</far>
</clip>
</camera>
</sensor>

<!-- IMU Sensor -->
<sensor name="imu" type="imu">
<always_on>true</always_on>
<update_rate>100</update_rate>
<topic>imu</topic>
<imu>
<angular_velocity>
<x><noise type="gaussian"><mean>0</mean><stddev>0.01</stddev></noise></x>
<y><noise type="gaussian"><mean>0</mean><stddev>0.01</stddev></noise></y>
<z><noise type="gaussian"><mean>0</mean><stddev>0.01</stddev></noise></z>
</angular_velocity>
<linear_acceleration>
<x><noise type="gaussian"><mean>0</mean><stddev>0.1</stddev></noise></x>
<y><noise type="gaussian"><mean>0</mean><stddev>0.1</stddev></noise></y>
<z><noise type="gaussian"><mean>0</mean><stddev>0.1</stddev></noise></z>
</linear_acceleration>
</imu>
</sensor>

Bridging Sensor Data to ROS 2โ€‹

Use the ros_gz_bridge to expose Gazebo topics in ROS 2:

# In your launch file
bridge = Node(
package='ros_gz_bridge',
executable='parameter_bridge',
arguments=[
'/scan@sensor_msgs/msg/LaserScan@gz.msgs.LaserScan',
'/camera/image@sensor_msgs/msg/Image@gz.msgs.Image',
'/imu@sensor_msgs/msg/Imu@gz.msgs.IMU',
],
output='screen'
)

Practical Exercise: Complete Simulation Setupโ€‹

Goalโ€‹

Create a simulation with:

  1. A warehouse environment
  2. A mobile robot with LIDAR
  3. ROS 2 integration for sensor data

Step-by-Stepโ€‹

  1. Build the workspace:
cd ~/ros2_ws
colcon build --packages-select my_robot_simulation
source install/setup.bash
  1. Launch the simulation:
ros2 launch my_robot_simulation warehouse.launch.py
  1. Verify sensor data in ROS 2:
# List all topics
ros2 topic list

# Echo LIDAR data
ros2 topic echo /scan

# Visualize in RViz2
rviz2
  1. Control the robot:
# Send velocity commands
ros2 topic pub /cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.5}, angular: {z: 0.1}}"

Debugging Simulation Issuesโ€‹

Common Problems and Solutionsโ€‹

ProblemCauseSolution
Robot falls through groundMissing collisionAdd <collision> to all links
Robot explodes on spawnOverlapping linksCheck joint origins, spawn higher
No sensor dataMissing pluginAdd sensor system plugin to world
Slow simulationHigh real-time factorReduce step size or simplify models
Bridge not workingTopic mismatchVerify topic names and message types

Useful Debugging Commandsโ€‹

# List all Gazebo topics
gz topic -l

# Echo a Gazebo topic
gz topic -e -t /world/warehouse/model/my_robot/link/base_link/sensor/lidar/scan

# Check simulation statistics
gz stats

# Pause/unpause simulation
gz service -s /world/warehouse/control --reqtype gz.msgs.WorldControl \
--reptype gz.msgs.Boolean --req 'pause: true'

Summaryโ€‹

In this chapter, you learned:

  • Why simulation matters: Cost savings, safety, and accelerated development
  • Gazebo fundamentals: Architecture, SDF format, physics engines
  • World creation: Building custom environments with objects and lighting
  • Robot integration: Spawning URDF robots and configuring Gazebo plugins
  • Sensor simulation: Adding LIDAR, cameras, and IMUs with realistic noise
  • ROS 2 bridging: Connecting Gazebo to your ROS 2 nodes

Simulation is the foundation of modern robotics development. Before any algorithm touches real hardware, it should be thoroughly tested in simulation.


Further Readingโ€‹


Next Week Previewโ€‹

In Chapter 7, we'll explore Unity for Robotics - a powerful alternative for:

  • Photorealistic rendering and synthetic data generation
  • Machine learning training environments
  • Human-robot interaction scenarios
  • Cross-platform deployment