← Modules

Gazebo Simulation Launcher

This notebook demonstrates the pykal.gazebo module, which provides simple wrappers for launching and managing Gazebo simulations directly from Jupyter notebooks.

Overview

The pykal.gazebo module provides two main functions:

  • start_gazebo(): Launch a Gazebo simulation with a robot

  • stop_gazebo(): Cleanly shut down the simulation

These wrappers handle all the complexity of:

  • Process management

  • ROS2 environment setup

  • Robot spawning at specified positions

  • Cleanup and shutdown

This allows you to focus on control algorithms rather than infrastructure.

Learning Objectives

By the end of this notebook, you will understand:

  1. Basic API: How to start and stop Gazebo simulations

  2. Configuration Options: Robots, worlds, spawn positions, headless mode

  3. Lifecycle Management: Process status checking and cleanup

  4. Use Cases: When to use GUI vs headless mode

  5. Integration: How this fits into the pykal workflow

Let’s begin!

from pykal.gazebo import start_gazebo, stop_gazebo
import time

print("✓ Imports complete")

Part 1: Basic Usage

The simplest use case: launch Gazebo with default settings.

1.1 Start Gazebo with TurtleBot3

The start_gazebo() function launches a Gazebo simulation and spawns a robot. It returns a GazeboProcess object for lifecycle management.

# Launch Gazebo with TurtleBot3 Burger
gz = start_gazebo(
    robot='turtlebot3',      # Robot type
    world='turtlebot3_world', # World/environment
    headless=False,          # Show GUI (set True for faster simulation)
    x_pose=0.0,              # Spawn at origin
    y_pose=0.0,
    z_pose=0.0,
    yaw=0.0,                 # Facing forward (radians)
    model='burger'           # TurtleBot variant
)

print(f"\n{'='*60}")
print(f"Gazebo Process: {gz}")
print(f"{'='*60}")
print("\n✓ Gazebo launched successfully!")
print("  Check the Gazebo window to see your TurtleBot3.")
print("\n  The robot is ready to receive ROS2 commands.")

What just happened?

The start_gazebo() function:

  1. Launched the Gazebo simulator

  2. Loaded the turtlebot3_world environment

  3. Spawned a TurtleBot3 Burger at position (0, 0, 0)

  4. Set up all ROS2 topics for communication

You should now see a Gazebo window with a small robot in an environment with obstacles.

1.2 Let Simulation Run

The robot is now active in Gazebo. Let’s let it run for a few seconds so you can observe it.

print("Simulation running...")
print("(The robot is idle, waiting for velocity commands on /cmd_vel)")
time.sleep(5)
print("✓ Observation complete")
Simulation running...
(The robot is idle, waiting for velocity commands on /cmd_vel)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[1], line 3
      1 print("Simulation running...")
      2 print("(The robot is idle, waiting for velocity commands on /cmd_vel)")
----> 3 time.sleep(5)
      4 print("✓ Observation complete")

NameError: name 'time' is not defined

1.3 Stop Gazebo

Always cleanly shut down Gazebo when you’re done. This prevents zombie processes.

stop_gazebo(gz)

print("✓ Gazebo shut down successfully")
print("  The Gazebo window should now be closed.")

Part 2: Configuration Options

The start_gazebo() function accepts several parameters to customize the simulation.

2.1 Supported Robots

PyKal currently supports two robot platforms:

  1. turtlebot3: Ground robot with differential drive

    • Models: burger (default), waffle, waffle_pi

    • Good for: Navigation, SLAM, ground-based control

  2. crazyflie: Quadrotor UAV

    • Models: Standard Crazyflie 2.0

    • Good for: 3D control, aerial robotics

Let’s try launching a Crazyflie:

# Launch Crazyflie quadrotor
gz_cf = start_gazebo(
    robot='crazyflie',
    world='empty_world',  # Simple empty environment
    headless=False,
    x_pose=0.0,
    y_pose=0.0,
    z_pose=0.5,  # Spawn 0.5m above ground
    yaw=0.0
)

print("\n✓ Crazyflie spawned at z=0.5m")
print("  Look for a small quadrotor hovering in the Gazebo window.")

time.sleep(3)

# Clean shutdown
stop_gazebo(gz_cf)
print("\n✓ Crazyflie simulation stopped")

2.2 Spawn Position and Orientation

You can spawn robots at any position and orientation using the x_pose, y_pose, z_pose, and yaw parameters.

Coordinate System:

  • x: Forward/backward (meters)

  • y: Left/right (meters)

  • z: Up/down (meters)

  • yaw: Rotation around z-axis (radians, 0 = facing +x)

Let’s spawn a TurtleBot at position (2, 1, 0) facing 45 degrees:

import numpy as np

# Spawn at custom position
gz_custom = start_gazebo(
    robot='turtlebot3',
    world='turtlebot3_world',
    headless=False,
    x_pose=2.0,              # 2 meters forward
    y_pose=1.0,              # 1 meter to the left
    z_pose=0.0,              # On the ground
    yaw=np.pi/4,             # 45 degrees (π/4 radians)
    model='burger'
)

print(f"\n✓ TurtleBot spawned at position (2, 1, 0)")
print(f"  Orientation: 45° (π/4 rad)")
print(f"\n  In the Gazebo window, the robot should be:")
print(f"    - 2 meters forward from origin")
print(f"    - 1 meter to the left")
print(f"    - Rotated 45 degrees counterclockwise")

time.sleep(5)

stop_gazebo(gz_custom)
print("\n✓ Custom position simulation stopped")

2.3 Headless Mode (Faster Simulation)

When you don’t need visualization, use headless=True for significantly faster simulation. This is ideal for:

  • Automated testing

  • Parameter tuning

  • Large-scale experiments

  • CI/CD pipelines

Performance comparison:

  • GUI mode: ~1x real-time (limited by rendering)

  • Headless mode: 5-10x real-time (CPU-limited only)

# Launch in headless mode
gz_headless = start_gazebo(
    robot='turtlebot3',
    world='empty_world',
    headless=True,  # No GUI!
    x_pose=0.0,
    y_pose=0.0,
    z_pose=0.0,
    yaw=0.0,
    model='burger'
)

print("\n✓ Headless simulation started")
print("  No Gazebo window - simulation runs in background.")
print("  This is much faster for automated testing!")

# Simulate some work
print("\nRunning headless simulation for 3 seconds...")
time.sleep(3)

stop_gazebo(gz_headless)
print("\n✓ Headless simulation stopped")

2.4 Different Worlds

Gazebo supports different simulation environments (“worlds”). Common options:

For TurtleBot3:

  • turtlebot3_world: Environment with obstacles and landmarks

  • turtlebot3_house: Indoor house environment

  • empty_world: Minimal empty environment

For Crazyflie:

  • empty_world: Open space for flight testing

  • Custom worlds with obstacles for navigation

The world parameter affects available features (obstacles, lighting, etc.) but not the robot’s ROS2 interface.

# Launch in empty world (minimal)
gz_empty = start_gazebo(
    robot='turtlebot3',
    world='empty_world',  # Just a ground plane
    headless=False,
    x_pose=0.0,
    y_pose=0.0,
    z_pose=0.0,
    yaw=0.0,
    model='burger'
)

print("\n✓ Launched in empty_world")
print("  You should see just a ground plane - no obstacles.")
print("  This is useful for basic motion testing.")

time.sleep(3)

stop_gazebo(gz_empty)
print("\n✓ Empty world simulation stopped")

Part 3: Lifecycle Management

Understanding the GazeboProcess object and proper cleanup.

3.1 The GazeboProcess Object

The start_gazebo() function returns a GazeboProcess object that tracks the simulation process. This object is used for cleanup.

# Start simulation
gz_demo = start_gazebo(
    robot='turtlebot3',
    world='empty_world',
    headless=True,
    x_pose=0.0,
    y_pose=0.0,
    z_pose=0.0,
    yaw=0.0,
    model='burger'
)

# Inspect the GazeboProcess object
print(f"GazeboProcess object: {gz_demo}")
print(f"Type: {type(gz_demo)}")
print(f"\nThis object keeps track of:")
print(f"  - Process IDs")
print(f"  - Environment variables")
print(f"  - Cleanup requirements")

# Clean shutdown using the object
stop_gazebo(gz_demo)
print("\n✓ Simulation stopped using GazeboProcess object")

3.2 Always Use stop_gazebo()

Important: Always call stop_gazebo() to cleanly shut down the simulation. Not doing so can leave:

  • Zombie processes consuming CPU

  • ROS2 nodes still running

  • Port conflicts for future simulations

Best Practice Pattern:

try:
    gz = start_gazebo(...)
    
    # Your simulation code here
    
finally:
    stop_gazebo(gz)

3.3 Error Handling

Proper error handling ensures cleanup even if your simulation code fails.

# Example: Safe simulation with error handling
gz_safe = None

try:
    print("Starting simulation with error handling...")
    
    gz_safe = start_gazebo(
        robot='turtlebot3',
        world='empty_world',
        headless=True,
        x_pose=0.0,
        y_pose=0.0,
        z_pose=0.0,
        yaw=0.0,
        model='burger'
    )
    
    print("✓ Simulation started")
    
    # Simulate some work
    time.sleep(2)
    
    # If an error occurred here, cleanup would still happen
    print("✓ Work completed successfully")
    
finally:
    if gz_safe is not None:
        print("\nCleaning up...")
        stop_gazebo(gz_safe)
        print("✓ Cleanup complete (even if errors occurred)")

Part 4: Integration with ROS2

Once Gazebo is running, the robot automatically publishes sensor data and listens for commands on ROS2 topics.

4.1 Available ROS2 Topics

When you launch a robot in Gazebo, it automatically sets up ROS2 topics:

TurtleBot3 Topics:

  • /cmd_vel (Twist): Velocity commands (linear and angular)

  • /odom (Odometry): Position, velocity, and pose estimates

  • /scan (LaserScan): LIDAR data (if equipped)

  • /imu (Imu): IMU sensor data

  • /joint_states: Joint positions and velocities

Crazyflie Topics:

  • /cmd_vel (Twist): Velocity commands

  • /odom (Odometry): Position and velocity

  • /imu (Imu): IMU data

These topics are ready for use with ROSNode wrappers (covered in later tutorials).

4.2 Quick Topic Check

You can verify the topics are active by inspecting ROS2 while Gazebo is running.

Note: This requires ROS2 command-line tools. If not available, skip this cell.

# Optional: Check available ROS2 topics
# This requires ros2 CLI tools installed

try:
    import subprocess
    
    gz_check = start_gazebo(
        robot='turtlebot3',
        world='empty_world',
        headless=True,
        x_pose=0.0,
        y_pose=0.0,
        z_pose=0.0,
        yaw=0.0,
        model='burger'
    )
    
    print("Checking ROS2 topics...\n")
    time.sleep(3)  # Wait for topics to initialize
    
    result = subprocess.run(
        ['ros2', 'topic', 'list'],
        capture_output=True,
        text=True,
        timeout=5
    )
    
    topics = [t for t in result.stdout.split('\n') if t.strip()]
    
    print("Active ROS2 topics:")
    for topic in topics:
        if any(key in topic for key in ['cmd_vel', 'odom', 'scan', 'imu']):
            print(f"  ✓ {topic}")
    
    stop_gazebo(gz_check)
    
except Exception as e:
    print(f"Topic check skipped: {e}")
    print("(This is optional - ROS2 CLI tools may not be available)")
    try:
        stop_gazebo(gz_check)
    except:
        pass

Part 5: Common Use Cases

Practical examples for different scenarios.

5.1 Use Case: Interactive Development

Scenario: You’re developing a controller and want to see the robot’s behavior.

Configuration:

  • headless=False - Show GUI for visual feedback

  • world='turtlebot3_world' - Rich environment with obstacles

  • Default spawn position

print("Use Case: Interactive Development\n")

gz_dev = start_gazebo(
    robot='turtlebot3',
    world='turtlebot3_world',
    headless=False,  # Show GUI
    x_pose=0.0,
    y_pose=0.0,
    z_pose=0.0,
    yaw=0.0,
    model='burger'
)

print("✓ Interactive simulation ready")
print("  - GUI visible for debugging")
print("  - Rich environment with obstacles")
print("  - Ready for ROSNode control commands")

# In a real workflow, you'd connect ROSNode controllers here
time.sleep(3)

stop_gazebo(gz_dev)
print("\n✓ Development session complete")

5.2 Use Case: Automated Testing

Scenario: Running regression tests in CI/CD pipeline.

Configuration:

  • headless=True - Maximum speed, no GUI

  • world='empty_world' - Minimal complexity

  • Programmatic position setup for repeatable tests

print("Use Case: Automated Testing\n")

# Test configuration
test_positions = [
    (0.0, 0.0, 0.0),
    (1.0, 0.0, np.pi/2),
    (-1.0, 1.0, np.pi),
]

for i, (x, y, yaw) in enumerate(test_positions):
    print(f"Test {i+1}/3: Position ({x}, {y}), yaw={yaw:.2f} rad")
    
    gz_test = start_gazebo(
        robot='turtlebot3',
        world='empty_world',
        headless=True,  # Fast!
        x_pose=x,
        y_pose=y,
        z_pose=0.0,
        yaw=yaw,
        model='burger'
    )
    
    # Run test (placeholder)
    time.sleep(1)
    
    stop_gazebo(gz_test)
    print(f"  ✓ Test {i+1} passed\n")

print("✓ All automated tests complete")

5.3 Use Case: Multi-Robot Experiments

Scenario: Testing multi-agent coordination.

Note: This requires advanced Gazebo configuration. The basic pattern is:

  • Launch one simulation

  • Spawn additional robots using ROS2 spawn service

For simplicity, the start_gazebo() wrapper currently supports single-robot scenarios. Multi-robot setups require manual ROS2 service calls (covered in advanced tutorials).

Part 6: Best Practices

Guidelines for effective Gazebo usage in pykal workflows.

6.1 Development Workflow

Recommended progression:

  1. Pure Python (no Gazebo)

    • Develop DynamicalSystem components

    • Test with synthetic data

    • Validate algorithms

  2. Gazebo Simulation (this notebook)

    • Wrap components in ROSNode callbacks

    • Deploy to Gazebo for physics validation

    • Test with realistic sensor noise

  3. Hardware Deployment

    • Transfer validated code to robot

    • Minimal changes required

Why this order?

  • Faster iteration in early stages

  • Physics validation before hardware

  • Risk reduction (no robot damage during algorithm development)

6.2 Performance Considerations

When to use headless mode:

  • ✓ Automated testing

  • ✓ Parameter tuning loops

  • ✓ Long simulation runs

  • ✓ CI/CD pipelines

When to use GUI mode:

  • ✓ Algorithm debugging

  • ✓ Behavior verification

  • ✓ Demos and presentations

  • ✓ Initial development

Resource usage:

  • GUI mode: ~2-4 GB RAM, 50-100% CPU (one core)

  • Headless mode: ~1-2 GB RAM, 30-60% CPU (one core)

6.3 Troubleshooting

Common issues:

  1. “Gazebo won’t start”

    • Check ROS2 installation

    • Verify robot packages installed (e.g., ros-humble-turtlebot3-*)

    • Try headless=True to rule out graphics issues

  2. “Simulation is very slow”

    • Use headless=True

    • Close other applications

    • Use empty_world instead of complex environments

  3. “Topics not appearing”

    • Wait 2-3 seconds after start_gazebo() for initialization

    • Check robot model is correct

    • Verify ROS2 environment (echo $ROS_DOMAIN_ID)

  4. “Process won’t stop”

    • Always call stop_gazebo(gz)

    • If stuck, manually kill: pkill -9 gzserver

    • Restart notebook kernel if necessary

Summary

This notebook covered the pykal.gazebo module:

Key Functions

  • start_gazebo(): Launch simulation with configurable robots, worlds, and positions

  • stop_gazebo(): Clean shutdown

Configuration Options

  • Robots: turtlebot3, crazyflie

  • Worlds: turtlebot3_world, empty_world, etc.

  • Position: x_pose, y_pose, z_pose, yaw

  • Mode: headless=True/False

  • Variants: model='burger'/'waffle' for TurtleBot3

Best Practices

  • Always use stop_gazebo() for cleanup

  • Use error handling (try/finally) for robust cleanup

  • Choose headless vs GUI based on use case

  • Follow development workflow: Python → Gazebo → Hardware

Next Steps

Now that you understand the Gazebo launcher, proceed to:

Tip

The Gazebo launcher is designed for Jupyter notebook workflows. For production deployments, you may want to use native ROS2 launch files. However, for rapid prototyping and algorithm development, pykal.gazebo provides the fastest path from theory to simulation.

← Modules