Skip to main content

Chapter 1: Simulating Physics, Gravity, and Collisions in Gazebo

Introduction

Physics simulation is the foundation of realistic robotic digital twins. When you drop a robot arm in Gazebo, it should fall with Earth-like gravity. When two robot links collide, they should bounce or stop based on material properties. This chapter will teach you how Gazebo calculates these behaviors and how to configure them for your robots.

By the end of this chapter, you'll understand how physics engines work, how to select and configure the right engine for your application, and how to tune gravity, friction, and collision parameters to match real-world physics.

Why this matters: Accurate physics simulation is critical for testing control algorithms, validating robot designs, and training AI models. Poor physics configuration leads to behaviors that don't transfer to real hardware - the so-called "reality gap."

Understanding Physics Engines

Gazebo doesn't simulate physics itself - it delegates this to specialized physics engines. Think of the physics engine as the mathematical calculator that computes forces, torques, velocities, and positions at every simulation step.

Supported Physics Engines

Gazebo Classic supports four physics engines:

  1. ODE (Open Dynamics Engine): The default engine. Fast, stable, and suitable for most robotics applications. Good balance between speed and accuracy.

  2. Bullet: Known for high-fidelity collision detection. Excellent for grasping, manipulation, and scenarios with many simultaneous contacts.

  3. Simbody: Highly accurate dynamics suitable for biomechanics and articulated systems. Slower than ODE but more precise for complex kinematic chains.

  4. DART (Dynamic Animation and Robotics Toolkit): Advanced features including constraint-based dynamics and precise contact handling.

Which to choose? Start with ODE (the default). Switch to Bullet if you need better collision handling for manipulation tasks. Use Simbody if accuracy is more important than speed.

Configuring the Physics Engine

You configure the physics engine in your Gazebo world file (.world extension):

<!-- File: my_world.world -->
<?xml version="1.0"?>
<sdf version="1.6">
<world name="default">

<!-- Physics engine configuration -->
<physics type="ode">
<!-- Maximum simulation step size in seconds -->
<max_step_size>0.001</max_step_size>

<!-- Real-time factor: 1.0 = real-time, >1 = faster, <1 = slower -->
<real_time_factor>1</real_time_factor>

<!-- Target update rate in Hz (1000 Hz = 1ms steps) -->
<real_time_update_rate>1000</real_time_update_rate>
</physics>

</world>
</sdf>

Key parameters explained:

  • max_step_size: How frequently physics is calculated. Smaller = more accurate but slower. 1ms (0.001s) is a good default.
  • real_time_factor: Simulation speed multiplier. Use 1.0 to match real-world time.
  • real_time_update_rate: How many times per second physics is computed. Should be 1 / max_step_size for consistency.

Switching Physics Engines

To use a different engine, just change the type attribute:

<!-- Use Bullet physics engine -->
<physics type="bullet">
<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>
<!-- Use Simbody physics engine -->
<physics type="simbody">
<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>

Gravity Configuration

Gravity is one of the most important physical forces in robotics. On Earth, gravity accelerates objects at 9.81 m/s² downward. In Gazebo, you specify gravity as a 3D vector.

Setting Gravity

<world name="default">
<physics type="ode">
<!-- Gravity vector: [x, y, z] in m/s² -->
<!-- Earth standard: -9.81 m/s² in the Z (vertical) direction -->
<gravity>0 0 -9.81</gravity>

<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>
</world>

Understanding the gravity vector:

  • [0, 0, -9.81]: Standard Earth gravity pulling down along the Z-axis
  • [0, 0, -1.62]: Moon gravity (useful for space robotics simulation)
  • [0, 0, -3.71]: Mars gravity
  • [0, 0, 0]: Zero gravity (space station simulation)

Why Negative Z?

In Gazebo's coordinate system, the Z-axis points upward. Gravity pulls downward, so we use a negative value: -9.81 instead of +9.81.

Testing Gravity

You can test gravity by spawning a simple box and watching it fall:

<world name="default">
<physics type="ode">
<gravity>0 0 -9.81</gravity>
<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>

<!-- A simple box suspended in mid-air -->
<model name="falling_box">
<pose>0 0 5 0 0 0</pose> <!-- Position: x=0, y=0, z=5 (5 meters up) -->
<link name="box_link">
<collision name="collision">
<geometry>
<box>
<size>1 1 1</size> <!-- 1m x 1m x 1m cube -->
</box>
</geometry>
</collision>
<visual name="visual">
<geometry>
<box>
<size>1 1 1</size>
</box>
</geometry>
</visual>
<!-- Mass: 1 kg -->
<inertial>
<mass>1.0</mass>
<inertia>
<ixx>0.166667</ixx>
<iyy>0.166667</iyy>
<izz>0.166667</izz>
</inertia>
</inertial>
</link>
</model>
</world>

When you run this world, the box will fall and accelerate at 9.81 m/s² until it hits the ground plane.

Friction Models

Friction determines how surfaces interact when sliding or rolling against each other. Without friction, a robot's wheels would slip infinitely on the ground. Too much friction, and wheels won't turn at all.

Surface Friction Parameters

Gazebo uses two friction coefficients:

  1. mu (μ): Coefficient of friction. Higher values = more grip.
  2. mu2 (μ2): Secondary friction coefficient for anisotropic surfaces (different friction in different directions).

Configuring Friction in URDF

When defining robot links or environment models, you specify friction in the <surface> element:

<!-- Wheel with high friction for good traction -->
<link name="wheel_link">
<collision name="collision">
<geometry>
<cylinder>
<radius>0.1</radius>
<length>0.05</length>
</cylinder>
</geometry>

<!-- Surface properties -->
<surface>
<friction>
<ode>
<!-- Primary friction coefficient (0-infinity, typically 0.5-1.5) -->
<mu>1.0</mu>

<!-- Secondary friction coefficient -->
<mu2>1.0</mu2>
</ode>
</friction>
</surface>
</collision>

<!-- Visual and inertial properties... -->
</link>

Friction Coefficient Examples

Surface CombinationTypical μ ValueUse Case
Rubber on concrete0.8 - 1.5Robot wheels on indoor floors
Metal on metal0.15 - 0.3Joints, sliding mechanisms
Ice on ice0.02 - 0.05Low-friction simulation
Rubber on ice0.15 - 0.25Challenging traction scenarios

Advanced Friction: Slip and Damping

For more realistic wheel behavior, you can add slip compliance and damping:

<surface>
<friction>
<ode>
<mu>1.0</mu>
<mu2>1.0</mu2>

<!-- Slip compliance: how much slip occurs before friction engages -->
<slip1>0.01</slip1>
<slip2>0.01</slip2>

<!-- Force-dependent slip (softness of contact) -->
<fdir1>1 0 0</fdir1> <!-- Friction direction vector -->
</ode>
</friction>

<!-- Contact damping and stiffness -->
<contact>
<ode>
<kp>1000000.0</kp> <!-- Contact stiffness (N/m) -->
<kd>1.0</kd> <!-- Contact damping (N*s/m) -->
</ode>
</contact>
</surface>

When to use advanced friction:

  • slip1/slip2: Simulate wheel slippage on loose terrain
  • kp (stiffness): Higher values make contacts "harder" (less penetration)
  • kd (damping): Prevents bouncing, adds energy dissipation

Collision Detection

Collision detection determines when objects in the simulation touch or intersect. Gazebo checks collisions between <collision> elements defined in your models.

Basic Collision Geometry

Every link that should participate in physics must have a <collision> element:

<link name="base_link">
<!-- Collision shape: defines physics boundaries -->
<collision name="base_collision">
<geometry>
<box>
<size>1 0.5 0.3</size> <!-- Width, Depth, Height in meters -->
</box>
</geometry>
</collision>

<!-- Visual shape: what you see (can be different from collision) -->
<visual name="base_visual">
<geometry>
<mesh>
<uri>model://my_robot/meshes/base.dae</uri>
</mesh>
</geometry>
</visual>

<!-- Mass properties... -->
</link>

Best practice: Use simple collision shapes (boxes, cylinders, spheres) for physics, and detailed meshes for visuals. This improves simulation speed without sacrificing visual quality.

Collision Shapes

Gazebo supports several collision primitives:

<!-- Box collision -->
<collision name="box_collision">
<geometry>
<box>
<size>1 1 1</size> <!-- X, Y, Z dimensions -->
</box>
</geometry>
</collision>

<!-- Cylinder collision (good for wheels, pillars) -->
<collision name="cylinder_collision">
<geometry>
<cylinder>
<radius>0.5</radius>
<length>2.0</length>
</cylinder>
</geometry>
</collision>

<!-- Sphere collision (fastest to compute) -->
<collision name="sphere_collision">
<geometry>
<sphere>
<radius>0.5</radius>
</sphere>
</geometry>
</collision>

<!-- Mesh collision (slow, use sparingly) -->
<collision name="mesh_collision">
<geometry>
<mesh>
<uri>model://my_robot/meshes/hull.stl</uri>
</mesh>
</geometry>
</collision>

Collision Performance Tips

  1. Prefer primitives over meshes: Boxes and cylinders are 10-100x faster than mesh collisions
  2. Simplify mesh colliders: Use low-polygon convex hulls for mesh collisions
  3. Use compound shapes: Combine multiple primitives to approximate complex shapes
  4. Disable unnecessary collisions: If two links can never collide, disable collision checking between them

Sometimes you want to prevent collision checking between specific parts (e.g., adjacent robot links):

<!-- In your robot URDF/SDF -->
<gazebo>
<self_collide>false</self_collide> <!-- Disable self-collision for entire model -->
</gazebo>

Or disable specific collision pairs:

<gazebo>
<disable_collision link1="link_a" link2="link_b"/>
</gazebo>

Contact Properties

You can tune how objects respond to collisions:

<collision name="bouncy_collision">
<geometry>
<sphere>
<radius>0.1</radius>
</sphere>
</geometry>

<surface>
<!-- Friction (covered earlier) -->
<friction>
<ode>
<mu>0.5</mu>
<mu2>0.5</mu2>
</ode>
</friction>

<!-- Contact mechanics -->
<contact>
<ode>
<!-- Stiffness: higher = harder contact, less penetration -->
<kp>1000000.0</kp>

<!-- Damping: higher = less bouncing -->
<kd>1.0</kd>

<!-- Max contact correction velocity (m/s) -->
<max_vel>0.01</max_vel>

<!-- Min penetration depth before correction (m) -->
<min_depth>0.001</min_depth>
</ode>
</contact>

<!-- Bounce (0 = no bounce, 1 = perfect elastic bounce) -->
<bounce>
<restitution_coefficient>0.8</restitution_coefficient>
<threshold>0.1</threshold> <!-- Min velocity for bouncing (m/s) -->
</bounce>
</surface>
</collision>

Practical Example: Configuring a Wheeled Robot

Let's put it all together with a complete example of a simple wheeled robot with proper physics configuration:

<?xml version="1.0"?>
<sdf version="1.6">
<world name="robot_test_world">

<!-- Physics configuration -->
<physics type="ode">
<gravity>0 0 -9.81</gravity>
<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>

<!-- Ground plane -->
<include>
<uri>model://ground_plane</uri>
</include>

<!-- Simple wheeled robot model -->
<model name="wheeled_robot">
<pose>0 0 0.2 0 0 0</pose>

<!-- Robot body -->
<link name="chassis">
<collision name="chassis_collision">
<geometry>
<box>
<size>0.6 0.4 0.2</size>
</box>
</geometry>
<surface>
<friction>
<ode>
<mu>0.3</mu> <!-- Moderate friction for chassis -->
<mu2>0.3</mu2>
</ode>
</friction>
</surface>
</collision>

<visual name="chassis_visual">
<geometry>
<box>
<size>0.6 0.4 0.2</size>
</box>
</geometry>
<material>
<ambient>0.3 0.3 0.8 1</ambient>
</material>
</visual>

<inertial>
<mass>10.0</mass>
<inertia>
<ixx>0.183</ixx>
<iyy>0.333</iyy>
<izz>0.45</izz>
</inertia>
</inertial>
</link>

<!-- Left wheel -->
<link name="left_wheel">
<pose>0.2 0.25 0 -1.5707 0 0</pose> <!-- Rotated 90° around X -->
<collision name="left_wheel_collision">
<geometry>
<cylinder>
<radius>0.15</radius>
<length>0.05</length>
</cylinder>
</geometry>
<surface>
<friction>
<ode>
<mu>1.2</mu> <!-- High friction for wheel traction -->
<mu2>1.2</mu2>
</ode>
</friction>
</surface>
</collision>

<visual name="left_wheel_visual">
<geometry>
<cylinder>
<radius>0.15</radius>
<length>0.05</length>
</cylinder>
</geometry>
<material>
<ambient>0.1 0.1 0.1 1</ambient>
</material>
</visual>

<inertial>
<mass>1.0</mass>
<inertia>
<ixx>0.0115</ixx>
<iyy>0.0115</iyy>
<izz>0.0225</izz>
</inertia>
</inertial>
</link>

<!-- Joint connecting left wheel to chassis -->
<joint name="left_wheel_joint" type="revolute">
<parent>chassis</parent>
<child>left_wheel</child>
<axis>
<xyz>0 1 0</xyz> <!-- Rotation axis -->
</axis>
</joint>

<!-- Right wheel (similar to left) -->
<!-- ... (code omitted for brevity) -->

</model>
</world>
</sdf>

Running the Simulation

Save the world file as robot_test.world and launch it:

gazebo robot_test.world

You should see the robot sitting on the ground with gravity pulling it down. The wheels will have high friction, preventing slipping, while the chassis has moderate friction.

Debugging Physics Issues

Common physics problems and solutions:

Problem: Robot falls through the ground

  • Cause: Missing collision geometry or ground plane
  • Fix: Ensure both robot and ground have <collision> elements

Problem: Robot behaves unrealistically (bounces, explodes)

  • Cause: Incorrect mass, inertia, or contact parameters
  • Fix: Check that mass is realistic (kg), inertia tensor is correct, and contact stiffness (kp) is appropriate (start with 1e6)

Problem: Simulation runs very slowly

  • Cause: Too many mesh collisions or too small step size
  • Fix: Replace mesh collisions with primitives, increase max_step_size to 0.002 or 0.005

Problem: Wheels slip excessively

  • Cause: Friction too low
  • Fix: Increase mu to 1.0-1.5 for wheel surfaces

Summary

In this chapter, you learned:

  • Gazebo uses physics engines (ODE, Bullet, Simbody, DART) to calculate forces and motion
  • Gravity is configured as a 3D vector (typically [0, 0, -9.81] for Earth)
  • Friction coefficients (mu, mu2) control surface grip and slippage
  • Collision detection uses simple shapes (box, cylinder, sphere) for performance
  • Contact properties (stiffness, damping, bounce) affect how objects interact
  • Practical physics configuration requires balancing accuracy and simulation speed

Next Steps: Now that you understand physics fundamentals, proceed to Chapter 2: Building Simulation Environments to learn how to create custom worlds and test scenarios for your robots.


Further Reading: