DART 7 · in development You are reading the documentation for DART 7, an in-progress redesign that is not yet recommended for production use. Looking for the current stable release? See the DART 6 LTS documentation.

The simulation loop

Every DART program is a loop around world.step(). This page explains what a step is, how time and gravity work, and how to read results back out.

Time steps

A World advances in fixed increments called the time step. Set it when you create the world, or change it later through the time_step property:

import dartpy as dart

world = dart.World(time_step=1.0 / 1000.0)   # 1 ms per step
print(world.time_step)                       # -> 0.001

Each call to world.step() advances simulated time by exactly one time step and updates world.time:

world.enter_simulation_mode()
for _ in range(500):
    world.step()
print(f"simulated {world.time:.3f} seconds")   # -> 0.500 seconds

Smaller time steps are more accurate and more stable but cost more per second of simulated time. A common starting point is 1/1000 s for contact-rich scenes and 1/2401/120 s for lighter ones. To advance a fixed amount of wall-clock behavior, choose the time step first, then loop the right number of steps.

Gravity

Gravity is a world-level vector in metres per second squared. DART pulls along −Z by default; set it explicitly when you want a different magnitude or direction:

import numpy as np

world.gravity = np.array([0.0, 0.0, -9.81])   # Earth, −Z is "down"
world.gravity = np.array([0.0, 0.0, -1.62])   # the Moon
world.gravity = np.array([0.0, 0.0, 0.0])     # free space

Reading state during the loop

After each step, body and joint state is fresh, so you can read it directly. Handles returned by add_rigid_body expose the body’s current pose and motion:

world.enter_simulation_mode()
for step in range(1000):
    world.step()
    position = np.asarray(box.translation)        # world-frame xyz
    velocity = np.asarray(box.linear_velocity)    # world-frame linear velocity
    if step % 100 == 0:
        speed = float(np.linalg.norm(velocity))
        print(f"t={world.time:5.3f}  z={position[2]:.3f}  speed={speed:.3f}")

This is also where a controller belongs: read state at the top of the loop, compute a command, apply it, then step. Keeping read → decide → act → step in that order makes the loop deterministic and easy to test.

A note on determinism

world.step() is synchronous and deterministic: when it returns, the step is complete and every output it produced is fresh. The same world, built the same way and stepped the same number of times, produces the same result. That predictability is deliberate — it keeps simulations reproducible for research, testing, and controller development.

Next

You now know the loop. The next section looks at the central object it revolves around: the World.