Your Gazebo World Is Slow — Start With the Physics Engine, Not the Hardware
A slow Gazebo world usually means physics is eating your CPU. Here's how to treat the physics engine as a real engineering decision — and benchmark it properly.
24 Feb 2026, 05:25 UTC

You've stacked some boxes, dropped in a mobile manipulator, attached a camera and a lidar — and the simulation crawls along at half real time. Before you reach for a faster machine, look at the two levers that usually dominate CPU cost in Gazebo (gz-sim): which physics engine is solving your contacts, and how big a step it takes.
The thesis of this post is simple: the physics engine is a first-class engineering decision, not a config afterthought. Each backend trades solver quality, throughput, and feature coverage differently, and the right choice depends on the world you actually run.
How engine selection actually works
In modern Gazebo, physics is bound to a world through two pieces of SDF (Simulation Description Format). First, the <physics> element inside your world file sets parameters like max_step_size, real_time_factor, and real_time_update_rate. Second, a physics system plugin declared in the world binds the engine implementation — the shared library that actually integrates dynamics and resolves contacts.
DART is the default backend and a sound starting point. Its constraint solver and articulated-body dynamics handle robots with many joints and contacts well, and it has the broadest feature coverage of the available engines. The alternatives exist for good reasons:
- Bullet Featherstone targets performance in many-body scenes, but has historically covered fewer Gazebo features than DART.
- TPE (Trivial Physics Engine) is an experimental engine aimed at mesh-heavy scenes where full rigid-body accuracy isn't needed.
- ODE is the legacy engine from the Gazebo Classic era, still available via its plugin.
Exact plugin filenames vary across releases (Fortress, Garden, Harmonic, and later), so check the example worlds shipped with your installed version rather than copying strings from a blog — including this one.
A worked example: swapping engines on a contact-rich world
Take a world with a pile of boxes and a manipulator nudging them. With the DART plugin loaded, launch it headless and note the real-time factor (RTF) — the ratio of simulated time to wall-clock time. You can read it from the GUI's stats panel or from the gz stats topic:
# Run from a shell on the machine running the sim; no special permissions needed
gz sim -r -s your_world.sdf # -s = headless server, -r = run immediately
# In a second terminal:
gz topic -e -t /stats | grep real_time_factorNow change exactly one thing: the physics system plugin entry in the world SDF, pointing it at the Bullet Featherstone plugin instead of DART. Relaunch, confirm the world still behaves (boxes settle, joints move), and read the RTF again. Because the world, seed, and step size are identical, the difference is attributable to the engine — that's the whole point of the harness.
The second lever is max_step_size. If contacts look jittery or stacked objects drift apart, tightening the step from 0.002 to 0.001 seconds often stabilizes them — at roughly double the physics CPU cost, since the solver runs twice as many iterations per simulated second. The trade cuts both ways: if your world is stable and slow, increasing the step size is free throughput.
The trade-offs worth respecting
A few caveats before you commit to a non-default engine:
- Feature coverage. Some sensors, joint types, or collision features may be unsupported or behave differently outside DART. After any swap, re-validate your world's behavior, not just its speed.
- RTF is a cap, not a promise. Setting
real_time_factorto 1.0 asks Gazebo not to run faster than real time; it cannot make an overloaded machine keep up. - Results are hardware- and world-dependent. An engine that wins on a box-stacking scene may lose on a single dexterous arm. Don't quote anyone's benchmark numbers — including mine — as universal.
- Release drift. Plugin names, defaults, and engine maturity change between Gazebo releases. Verify against your installed version's example worlds and console output (the log tells you which physics plugin actually loaded).
Make it a habit, not a one-off
The actionable takeaway: build a tiny benchmark harness. Fix a representative world, a step size, and a fixed simulated duration; run headless; record wall-clock time and RTF; change only the engine. Re-run it whenever your world changes significantly — new sensors, more bodies, different contact geometry — because the right engine for last month's world may be wrong for this month's. Physics is usually the dominant cost in a slow Gazebo sim, which means it's also your cheapest win.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.