Simulation and Digital Twins

Gazebo, Webots, CoppeliaSim, Isaac Sim and MuJoCo compared; URDF models, physics step size and stability, and closing the sim-to-real gap.

Why simulate

  • Safety and cost: a crash in simulation costs nothing, and a gripper that would break a part just resets.
  • Speed of iteration: test a change in minutes, run many cases in parallel, and run faster than real time.
  • Repeatability: the same scenario every time, with exact ground truth for every quantity, which a real robot never gives you.
  • Before the hardware exists: test the software, check reach and clearances, and size motors.
  • Automated testing: run the navigation stack against hundreds of maps on every code change (see Software Practice).
  • The limits: a simulation is a model, and it is wrong in ways you cannot predict. Treat it as a way to find bugs and bound behavior, not as proof that the real robot works.

The simulators compared

SimulatorStrengthsNotes
Gazebo (Harmonic and later)The standard with ROS 2; mobile robots, arms, sensors, worlds; plugin architectureOpen source; physics through DART, Bullet and others; many ready-made robot models and worlds
WebotsEasy to start; many built-in robots; runs on all major systems; good documentationOpen source; ROS 2 interface available
CoppeliaSimFlexible scene building, strong for arms, grippers and conveyors, many languages and enginesFree for education; commercial license for companies
NVIDIA Isaac SimPhoto-realistic sensors, synthetic data, GPU physics, large scenesNeeds a capable NVIDIA GPU; ROS 2 bridge
MuJoCo, PyBullet, Isaac Lab, GenesisFast, accurate contact physics for learning-based control; thousands of parallel environmentsUsually used from Python; see Machine Learning
Vendor offline programmersRobotStudio (ABB), ROBOGUIDE (FANUC), KUKA.Sim, RoboDK (many brands)Simulate a specific industrial robot and its controller; export real robot programs (see Industrial Robotics)
Unity and UnrealVisual realism, human interaction, VRWeak physics for robotics unless supplemented; useful for perception data

Describing the robot: URDF and SDF

A robot is described by links (rigid bodies, each with a shape, a mass and an inertia) joined by joints (fixed, revolute, continuous, prismatic) in a tree. The URDF (Unified Robot Description Format) is the ROS format; SDF is Gazebo’s richer format, which can describe whole worlds. Use xacro (XML with macros and parameters) so that a wheel is written once and used twice.

<robot name="diff_bot" xmlns:xacro="http://www.ros.org/wiki/xacro">
  <link name="base_link">
    <visual><geometry><box size="0.30 0.20 0.10"/></geometry></visual>
    <collision><geometry><box size="0.30 0.20 0.10"/></geometry></collision>     <!-- simple shapes: fast and stable -->
    <inertial>
      <mass value="5.0"/>
      <inertia ixx="0.0208" iyy="0.0417" izz="0.0542" ixy="0" ixz="0" iyz="0"/>
    </inertial>
  </link>

  <xacro:macro name="wheel" params="name y">
    <link name="${name}_wheel">
      <collision><geometry><cylinder radius="0.05" length="0.03"/></geometry></collision>
      <inertial><mass value="0.5"/><inertia ixx="0.00035" iyy="0.00035" izz="0.000625" ixy="0" ixz="0" iyz="0"/></inertial>
    </link>
    <joint name="${name}_wheel_joint" type="continuous">
      <parent link="base_link"/><child link="${name}_wheel"/>
      <origin xyz="0 ${y} -0.03" rpy="-1.5708 0 0"/><axis xyz="0 0 1"/>
    </joint>
  </xacro:macro>
  <xacro:wheel name="left"  y=" 0.10"/>
  <xacro:wheel name="right" y="-0.10"/>
</robot>
  • Separate visual and collision shapes: a detailed mesh for looks, a few boxes, cylinders and spheres for collisions (fast and stable).
  • Units are SI, and angles are radians; frames follow REP 103 (see Frames, Transforms and Arm Kinematics).
  • Check it: check_urdf, urdf_to_graphviz and RViz show the tree and the frames; move each joint by hand with joint_state_publisher_gui.
  • One description for everything: RViz, the simulator, the planner and the real robot’s robot_state_publisher all read the same file.

Mass and inertia: the numbers that matter

The simulator needs each link’s mass and inertia tensor, and wrong values make a robot behave like a toy. Use the textbook formulas for simple shapes, or read them from CAD:

Shape (mass m)IxxIyyIzz
Box (x × y × z)m (y² + z²) ÷ 12m (x² + z²) ÷ 12m (x² + y²) ÷ 12
Solid cylinder (radius r, length h, axis z)m (3 r² + h²) ÷ 12m (3 r² + h²) ÷ 12m r² ÷ 2
Solid sphere (radius r)2 m r² ÷ 52 m r² ÷ 52 m r² ÷ 5

Worked example: the diff-bot in the URDF

  • Body: a 5 kg box 0.30 × 0.20 × 0.10 m: Ixx = 5 × (0.20² + 0.10²) ÷ 12 = 0.0208, Iyy = 0.0417 and Izz = 0.0542 kg·m².
  • Wheel: a 0.5 kg solid cylinder, r = 0.05 m, h = 0.03 m: Izz (about the axle) = 0.5 × 0.05² ÷ 2 = 0.000625, and Ixx = Iyy = 0.5 × (3 × 0.05² + 0.03²) ÷ 12 = 0.000350 kg·m².
  • Why it matters: the wheel’s Izz sets how fast the motor can accelerate it; an inertia ten times too large makes the simulated robot sluggish, one that is zero crashes the solver.
  • Common mistakes: mass in grams instead of kilograms, an inertia copied from a different body, center of mass off-center, and a tiny mass on a link that carries a heavy one (the solver oscillates).

Physics engines: step size, contact and stability

A physics engine advances the world in small time steps: it computes forces, integrates the motion, detects collisions and resolves the contacts. The step size is a trade between accuracy, speed and stability. Stiff things (contacts, high-gain controllers, springs) force small steps.

Worked example: a stiff contact and the step size

  • A wheel resting on the ground is modeled as a spring: k = 1.00e+5 N/m under m = 1 kg. Its natural frequency is ω = √(k ÷ m) = 316 rad/s (50.3 Hz).
  • An explicit integrator (semi-implicit Euler, as in most engines) is stable only if the step is below 2 ÷ ω = 6.3 ms. Starting with a 1 cm compression and simulating one second:
StepSteps per secondLargest displacementResult
1.0 ms1 000 steps/s1.01e-2 mstable
3.0 ms333 steps/s1.14e-2 mstable
6.0 ms167 steps/s3.16e-2 mstable
6.5 ms154 steps/s7.25e+29 munstable: grows without bound
10.0 ms100 steps/s4.71e+87 munstable: grows without bound

Beyond 6.3 ms the motion explodes, which is how a robot “shakes itself apart” in a simulator. Real engines add damping and constraint-based contacts (soft constraints) to allow larger steps, but the rule stands: the step must be small compared with the fastest dynamics, and a stiffer model needs a smaller step.

  • Typical step sizes: 1 ms for robots with stiff joints and contacts; 2 to 5 ms for mobile robots and light arms; the controller loop must be an exact multiple of the physics step.
  • Collision shapes: primitives and convex hulls are fast and stable; triangle meshes are slow and can snag. Leave a small margin (a few millimeters) so that resting contacts do not jitter.
  • Friction and restitution matter more than anything for wheels and grasps: rubber on concrete is about 0.8 to 1.0, plastic on metal 0.2 to 0.4. Check them against a measurement.
  • Joint limits, damping and friction in the URDF reflect the real joint; an undamped simulated joint swings far longer than a real one.
  • Engines differ: the same robot can behave differently in two engines; try another before blaming your controller.

Simulation speed: the real-time factor

Worked example: real-time factor

The real-time factor (RTF) is simulated time divided by wall-clock time. With a 1 ms step costing 0.4 ms of computing, RTF = 1 ÷ 0.4 = 2.5: the simulation runs 2.5 times faster than real time. With a heavy scene at 2.5 ms per step the RTF is 0.40: a 60 s test takes 150 s. For a test suite, headless (no graphics) and as fast as possible; for development, near 1.0 so that you can watch.

  • Run headless in CI (gz sim -s -r), and in parallel containers.
  • Use simulation time (use_sim_time:=true) in every node, so that a slow simulation does not break timeouts; the simulator publishes /clock.
  • Fewer, simpler objects and lower sensor rates (a lidar at 10 Hz, a camera at 15 Hz) raise the RTF the most; cameras and 3D lidar are the expensive sensors.
  • Determinism: fix the random seeds so that a failure can be repeated.

Simulated sensors and noise

A simulated sensor returns perfect data unless you add the imperfections of the real one. The usual models are: Gaussian noise on each measurement, a slowly varying bias (an IMU’s gyroscope drifts), quantization, dropouts, latency and a limited range and field of view.

SensorWhat to modelTypical values
2D lidarRange noise, dropouts on dark or shiny surfaces, minimum and maximum range, scan rateσ = 0.01 m (0.2 % at 5 m), 5 to 15 Hz, 0.15 to 12 m
CameraResolution, field of view, exposure, motion blur, lens distortion, noise, rolling shutter640×480 to 1920×1080, 15 to 60 fps
Depth cameraNoise growing with distance squared, holes at edges, range limitsSee Perception
IMUGyroscope and accelerometer noise density and bias random walkGyro bias 1 to 10 °/h (good) up to hundreds (cheap MEMS)
Wheel encodersQuantization, slip, backlash360 to 4 096 counts per revolution
GNSSPosition noise, jumps, outages near buildings1 to 3 m (standard), 2 cm with RTK

Closing the gap between simulation and reality

  • Identify and measure the real robot: wheel diameter, track width, mass, center of mass, motor constants, friction and latency; put them in the model.
  • Add delay and noise to the simulation so that controllers tuned there are not tuned for an ideal world: a controller that works only without delay will fail on hardware.
  • Domain randomization: randomize the parameters you are unsure about, within a range, every run. If friction is 0.8 ± 40 % (here 0.48 to 1.12), a controller that works across the range is robust to the real value.
  • Use the same interfaces, topics, message types and frame names, so the code is unchanged between simulation and hardware.
  • Retune on the real robot at low speed, and compare logs of the same maneuver: where the simulation and the bag disagree, the model is wrong.
  • Validate the simulation against reality, not only the robot against the simulation: drive a known path in both and compare.
  • Do not tune to the simulator’s quirks: a trick that exploits a simulation artifact will fail outside it.

Simulation for testing and learning

Worked example: a parameter sweep

A navigation test with 3 × 4 × 3 × 5 values of four parameters (map, start pose, obstacle layout, noise level) has 180 cases. At 2 s each in a headless simulator that is 6 minutes of computing, about 0.8 minutes on eight parallel workers. Run it on every change and fail the build if the success rate drops: the cheapest regression test a robot can have.

  • Scenario files: maps, start and goal poses and events written as data, so that tests are repeatable and reviewed.
  • Pass-fail metrics: reached the goal, time, path length, minimum distance to obstacles, collisions, emergency stops.
  • Replay bags into perception and localization code to test them on real data (see ROS 2 in Practice).
  • Learning-based control: reinforcement learning needs millions of trials: use GPU-parallel engines (Isaac Lab, MuJoCo, Genesis) and randomization, and expect the policy to need adaptation on hardware.
  • Synthetic data: a simulated camera renders labeled images for training detectors: 108 000 frames (an hour at 30 fps) of 640 × 480 color is 99.5 GB raw, so store compressed.

Digital twins

A digital twin is a simulation kept in step with a real machine by live data: it mirrors the real state, so that you can monitor it, predict what comes next, test a change on the twin before applying it, and replay a failure. For a robot cell that means the CAD-accurate model, the real I/O and joint states streamed into it, and the same program running on both. The value depends on how well the model is validated, so start with a narrow question (does the new tool collide? what is the cycle time?) and measure the twin against the machine.

Related

FAQ

Which simulator should I start with?

Gazebo if you use ROS 2 for a mobile robot or arm; Webots for the gentlest start; MuJoCo or Isaac Lab for reinforcement learning; the maker’s tool (RobotStudio, ROBOGUIDE, RoboDK) for an industrial robot.

Why does my robot jitter or explode in the simulator?

Usually a step that is too large for a stiff contact or joint, wrong inertia (too small or zero), colliding shapes that overlap at the start, or an over-aggressive controller. Reduce the step, check the inertias and simplify the collision geometry.

How accurate must the simulation be?

Accurate enough to answer the question you ask it. Navigation logic needs approximate dynamics and realistic sensors; grasping and contact-rich tasks need careful friction and geometry; a controller’s final tuning is always done on the real robot.

Can I trust a controller tuned in simulation?

As a starting point, yes. Expect to retune on hardware: friction, delay, backlash and noise are worse in reality, and add them to the simulation to narrow the gap.

References

  • Gazebo, Webots, CoppeliaSim and MuJoCo documentation; the URDF and SDF specifications; REP 103.
  • Tobin, J. et al., “Domain randomization for transferring deep neural networks from simulation to the real world”, IROS, 2017.
  • Featherstone, R., Rigid Body Dynamics Algorithms; Murray, R. M., Li, Z. and Sastry, S. S., A Mathematical Introduction to Robotic Manipulation.

Last reviewed: October 2026. Stability limits and timings are computed in the page builder for the example values: your engine and model will differ.