# How to Fix Simulation Instability in DART: Common Causes and Solutions

> Fix simulation instability in DART by understanding common causes like large timesteps and stiff controllers. Learn solutions including timestep reduction and parameter tuning.

- Repository: [DART: Dynamic Animation and Robotics Toolkit/dart](https://github.com/dartsim/dart)
- Tags: how-to-guide
- Published: 2026-02-28

---

**Simulation instability in DART typically stems from oversized timesteps, stiff explicit controllers, or aggressive contact handling, and can be resolved by reducing the timestep, adding implicit damping, and tuning constraint solver parameters.**

The Dynamic Animation and Robotics Toolkit (DART) is a popular open-source physics engine for robotics and biomechanics simulation. Despite its robust constraint solver, users frequently encounter **simulation instability in DART** when configuring complex contact scenarios or high-gain controllers. This guide examines the root causes of these instabilities and provides concrete fixes using the actual `dartsim/dart` source code.

## Common Symptoms and Root Causes of Simulation Instability in DART

Understanding the symptom pattern helps identify whether you are facing a numerical stability issue or a modeling error.

### Explosive Velocity Divergence

When joint velocities rapidly approach infinity within a few simulation steps, the root cause is typically an **oversized timestep** (`dt`) relative to the system stiffness. In [`dart/simulation/world.hpp`](https://github.com/dartsim/dart/blob/main/dart/simulation/world.hpp), the `World::setTimeStep()` method sets this parameter, and values above 0.01 seconds often trigger instability with stiff springs or high-gain PD controllers.

### High-Frequency Jitter in Contact Stacks

Rapid oscillations or vibration when objects are in contact usually indicate **insufficient damping** or overly aggressive contact constraints. This occurs in the constraint solver phase, where large timesteps combined with high-friction contacts can push the Linear Complementarity Problem (LCP) solver out of its convergence region.

### Slow Positional Drift

Gradual deviation from expected trajectories without velocity explosions typically stems from **discretization error** or energy injection through contacts. This accumulates when the semi-implicit Euler integrator used in `World::step()` operates with inadequate damping.

## First-Line Fixes for DART Simulation Stability

Before adjusting complex solver parameters, apply these four fixes in order:

1. **Reduce the timestep** – Call `World::setTimeStep(dt)` with a smaller value (start with 0.001s). This is the most effective single change for resolving explosive instability.

2. **Lower controller stiffness** – Decrease PD gains or replace explicit torque control with implicit joint stiffness via `DegreeOfFreedom::setSpringStiffness()`.

3. **Add damping** – Apply velocity-dependent damping through `DegreeOfFreedom::setDampingCoefficient()` or moderate `Kd` gains in your controller.

4. **Clamp actuation** – Saturate torque commands to realistic bounds before calling `Joint::setCommand()` to prevent impulsive force spikes.

## Advanced Stabilization Techniques

When basic fixes prove insufficient, target specific subsystems using DART's deeper configuration APIs.

### Optimizing Timestep Settings

In [`dart/simulation/world.hpp`](https://github.com/dartsim/dart/blob/main/dart/simulation/world.hpp), the `World::setTimeStep(double)` method (line 191) controls the integration period. For systems with stiff springs or high-frequency contact dynamics, reduce `dt` to 0.001 seconds or smaller. The semi-implicit Euler integrator in `World::step()` is only conditionally stable, and stability improves linearly with smaller timesteps.

### Configuring Implicit Joint Springs and Damping

Rather than simulating springs through high-gain PD control, use DART's built-in implicit spring and damping models in [`dart/dynamics/degree_of_freedom.hpp`](https://github.com/dartsim/dart/blob/main/dart/dynamics/degree_of_freedom.hpp). The `DegreeOfFreedom::setSpringStiffness(double)` method (line 330) adds stiffness to the joint dynamics matrix solved implicitly during the LCP step, remaining stable at larger timesteps than explicit controllers. Similarly, `DegreeOfFreedom::setDampingCoefficient(double)` adds velocity-dependent dissipation directly to the dynamics.

### Tuning Constraint Solver Parameters

For contact-related jitter, adjust the constraint solver settings in [`dart/constraint/constraint_solver.hpp`](https://github.com/dartsim/dart/blob/main/dart/constraint/constraint_solver.hpp). Access the solver via `World::getConstraintSolver()` and modify:

- `setIterationLimit(int)` – Increase from default (usually 20) to 50-200 for complex contact stacks.
- `setTolerance(double)` – Tighten to 1e-6 for better convergence.
- Time step consistency – Ensure `ConstraintSolver::setTimeStep()` matches the world timestep.

### Collision Detector Selection

If instability persists with specific geometry types, experiment with different collision detectors. In `dart/collision/`, switch between FCL, Bullet, or ODE backends:

```cpp
auto detector = dart::collision::FCLCollisionDetector::create();
world->getConstraintSolver()->setCollisionDetector(detector);

```

Different detectors handle edge-case contacts (thin objects, high-speed collisions) with varying stability characteristics.

## Code Examples for Stabilizing DART Simulations

**1. Reduce Timestep and Verify**

```cpp
// Create world and set a safe timestep
dart::simulation::WorldPtr world = dart::simulation::World::create();
world->setTimeStep(0.001);   // 1 ms – start small and increase as needed

```

*Source*: `World::setTimeStep` definition in [`dart/simulation/world.hpp`](https://github.com/dartsim/dart/blob/main/dart/simulation/world.hpp) (line 191).

**2. Use Implicit Joint Stiffness & Damping**

```cpp
// Assume you have a pointer to a joint or a DoF
auto* dof = joint->getDof(0);

// Set spring stiffness (implicit)
dof->setSpringStiffness(500.0);   // N·m/rad

// Set damping coefficient (implicit)
dof->setDampingCoefficient(5.0); // N·m·s/rad

```

*Source*: `DegreeOfFreedom::setSpringStiffness` in [`dart/dynamics/degree_of_freedom.hpp`](https://github.com/dartsim/dart/blob/main/dart/dynamics/degree_of_freedom.hpp) (line 330); `setDampingCoefficient` is analogous.

**3. Clamp Controller Commands**

```cpp
double rawTorque = controller.computeTorque(...);
double maxTorque = 100.0;          // realistic limit
double torque = std::clamp(rawTorque, -maxTorque, maxTorque);
joint->setCommand(torque);

```

**4. Adjust Constraint Solver Settings**

```cpp
auto* solver = world->getConstraintSolver();
solver->setIterationLimit(200);   // increase if contacts jitter
solver->setTolerance(1e-6);      // tighter convergence

```

*Source*: `ConstraintSolver` API in [`dart/constraint/constraint_solver.hpp`](https://github.com/dartsim/dart/blob/main/dart/constraint/constraint_solver.hpp) (line 144).

**5. Switch Collision Detector**

```cpp
auto detector = dart::collision::FCLCollisionDetector::create();
world->getConstraintSolver()->setCollisionDetector(detector);

```

## Summary

- **Simulation instability in DART** most often originates from oversized timesteps, stiff explicit controllers, or aggressive contact configurations rather than solver bugs.
- **Reduce the timestep** using `World::setTimeStep()` as the first and most effective intervention.
- **Prefer implicit joint springs and damping** via `DegreeOfFreedom::setSpringStiffness()` and `setDampingCoefficient()` over high-gain PD control for stiff behaviors.
- **Tune the constraint solver** by increasing iteration limits and tightening tolerances through `World::getConstraintSolver()` when dealing with complex contact stacks.
- **Clamp actuation forces** and verify mass properties to prevent numerical explosions from unrealistic force spikes or extreme inertia ratios.

## Frequently Asked Questions

### What is the most common cause of simulation instability in DART?

The most common cause is an **oversized timestep** relative to the system stiffness. DART uses a semi-implicit Euler integrator that is only conditionally stable. When the timestep is too large for stiff springs, high-gain controllers, or rapid contact events, the integration error accumulates exponentially, causing velocities to diverge toward infinity within a few steps.

### How do I fix exploding velocities in my DART simulation?

Start by reducing the timestep via `World::setTimeStep(0.001)` or smaller. Next, replace any high-gain PD controllers with **implicit joint springs** using `DegreeOfFreedom::setSpringStiffness()`, which remains stable at larger timesteps. Finally, add damping via `DegreeOfFreedom::setDampingCoefficient()` or clamp your torque commands to prevent impulsive force spikes that trigger numerical explosions.

### What timestep should I use for stable DART simulations?

Begin with **1 ms (0.001 s)** for systems involving contacts, stiff springs, or high-gain control. You can increase the timestep gradually up to 0.01 s only after verifying stability with implicit damping and moderate controller gains. For extremely stiff systems or high-speed collisions, you may need to reduce the timestep to 0.0005 s or smaller.

### Can switching collision detectors fix simulation jitter?

Yes, different collision detectors handle edge-case contacts with varying stability characteristics. If you experience jitter with thin objects or high-speed collisions, experiment with alternative backends such as **FCL**, **Bullet**, or **ODE** by creating the detector and passing it to `World::getConstraintSolver()->setCollisionDetector()`. This can resolve instability arising from specific geometric configurations without requiring a smaller global timestep.