# How to Configure Joint Limits and Motor Constraints in DART

> Learn to configure DART joint limits and motor constraints. Set position and velocity limits, assign actuator types, and add constraint objects for precise control.

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

---

**To configure joint limits and motor constraints in DART, set limits on each **DegreeOfFreedom** using `setPositionLimits()` and `setVelocityLimits()`, assign an **actuator type** (`SERVO`, `FORCE`, or `MIMIC`) to the Joint, and add the corresponding constraint object (`JointLimitConstraint`, `ServoMotorConstraint`, or `MimicMotorConstraint`) to the World.**

This guide covers the complete workflow for configuring joint limits and motor constraints in DART (Dynamic Animation and Robotics Toolkit). The `dartsim/dart` repository uses a two-level architecture where **Degrees of Freedom (DoFs)** store raw limits while **Joints** manage actuator behavior, requiring specific constraint objects to bridge the gap between configuration and physics simulation.

## Understanding the DART Joint Architecture

In DART, a **joint** is a collection of one or more **degrees of freedom** (DoFs). Hard limits—position, velocity, acceleration, and force—are stored on each individual `DegreeOfFreedom` object, while motor-type behavior (servo, force, velocity, mimic) is stored on the joint itself as an **actuator type**. The physics engine enforces limits through the `JointLimitConstraint` class and executes motor commands through `ServoMotorConstraint` (for position/velocity servo) or `MimicMotorConstraint` (for coupled joints).

## Step-by-Step Configuration Workflow

Follow this sequence to properly configure limits and motors:

1. **Obtain the joint** via `Skeleton::getJoint()` or through a `BodyNode` pointer.
2. **Set DoF limits** using the APIs in `dart::dynamics::DegreeOfFreedom` (defined in [`dart/dynamics/degree_of_freedom.hpp`](https://github.com/dartsim/dart/blob/main/dart/dynamics/degree_of_freedom.hpp)).
3. **Choose an actuator type** on the joint with `Joint::setActuatorType()` (defined in [`dart/dynamics/joint.hpp`](https://github.com/dartsim/dart/blob/main/dart/dynamics/joint.hpp)).
4. **Create the appropriate constraint** (`JointLimitConstraint`, `ServoMotorConstraint`, or `MimicMotorConstraint`) and add it to the world or a `ConstrainedGroup`.
5. **Step the simulation**—the constraint solver automatically applies limits and motor commands each timestep.

## Setting Joint Limits on Degrees of Freedom

Individual DoFs store their own limits. Access each DoF via `joint->getDof(index)` and configure bounds before adding constraints.

```cpp
auto* joint = skel->getJoint("elbow");

// Configure limits on each DoF
for (std::size_t i = 0; i < joint->getNumDofs(); ++i) {
  // Position limits: +/- 90 degrees in radians
  joint->getDof(i)->setPositionLimits(-M_PI_2, M_PI_2);
  
  // Velocity limits: +/- 5 rad/s
  joint->getDof(i)->setVelocityLimits(-5.0, 5.0);
}

// Add constraint to enforce these limits
auto limitConstraint = std::make_shared<dart::constraint::JointLimitConstraint>(joint);
world->addConstraint(limitConstraint);

```

The `JointLimitConstraint` (defined in [`dart/constraint/joint_limit_constraint.hpp`](https://github.com/dartsim/dart/blob/main/dart/constraint/joint_limit_constraint.hpp)) reads these limits each timestep and applies corrective impulses to prevent violations.

## Implementing Motor Constraints

Motor behavior depends on the joint's actuator type and the specific constraint class added to the world.

### Position and Velocity Control with ServoMotorConstraint

For position or velocity servo control, set the actuator type to `Joint::SERVO` and add a `ServoMotorConstraint` (defined in [`dart/constraint/servo_motor_constraint.hpp`](https://github.com/dartsim/dart/blob/main/dart/constraint/servo_motor_constraint.hpp)):

```cpp
// Set actuator type
joint->setActuatorType(dart::dynamics::Joint::SERVO);

// Create servo constraint
auto servo = std::make_shared<dart::constraint::ServoMotorConstraint>(joint);
world->addConstraint(servo);

// Command the desired position (in radians)
joint->getDof(0)->setCommand(desiredAngle);

```

The constraint generates forces to drive the joint toward the command value each simulation step.

### Direct Force Control

For direct force or torque control without a servo loop, use `Joint::FORCE`. This mode applies generalized forces directly to the DoFs and does not require a motor constraint object, though you must still add a `JointLimitConstraint` if you want to enforce position/velocity limits.

### Mimic Joints with MimicMotorConstraint

To make one joint copy another's motion (useful for coupled joints like gripper fingers), use `Joint::MIMIC` and `MimicMotorConstraint` (defined in [`dart/constraint/mimic_motor_constraint.hpp`](https://github.com/dartsim/dart/blob/main/dart/constraint/mimic_motor_constraint.hpp)):

```cpp
auto* leader = skel->getJoint("shoulder");
auto* follower = skel->getJoint("elbow");

// Configure actuator types
leader->setActuatorType(dart::dynamics::Joint::FORCE);
follower->setActuatorType(dart::dynamics::Joint::MIMIC);

// follower = leader * multiplier + offset
follower->setMimicJoint(leader, 1.0, 0.0);

// Add mimic constraint for the follower
auto mimic = std::make_shared<dart::constraint::MimicMotorConstraint>(follower);
world->addConstraint(mimic);

```

The `MimicMotorConstraint` reads the leader joint's generalized forces and applies a scaled copy to the follower.

## Tuning Global Constraint Parameters

All constraint instances share global **error reduction parameter (ERP)** and **constraint force mixing (CFM)** settings that affect stability and responsiveness. Tune these static setters before creating constraints:

```cpp
// Joint limit tuning: fast error correction with slight softness
dart::constraint::JointLimitConstraint::setErrorReductionParameter(0.02);
dart::constraint::JointLimitConstraint::setConstraintForceMixing(1e-6);

// Servo motor tuning
dart::constraint::ServoMotorConstraint::setConstraintForceMixing(1e-5);

```

These parameters affect every instance of the respective constraint type in the simulation.

## Summary

- **Limits live on DoFs**: Use `DegreeOfFreedom::setPositionLimits()` and `setVelocityLimits()` (from [`dart/dynamics/degree_of_freedom.hpp`](https://github.com/dartsim/dart/blob/main/dart/dynamics/degree_of_freedom.hpp)) to define bounds.
- **Actuator types live on Joints**: Use `Joint::setActuatorType()` (from [`dart/dynamics/joint.hpp`](https://github.com/dartsim/dart/blob/main/dart/dynamics/joint.hpp)) to select `SERVO`, `FORCE`, or `MIMIC` behavior.
- **Constraints enforce behavior**: You must instantiate `JointLimitConstraint`, `ServoMotorConstraint`, or `MimicMotorConstraint` and add them to the `World` for the limits and motors to take effect.
- **Global tuning**: Adjust ERP and CFM via static setters on constraint classes to control solver behavior across all instances.

## Frequently Asked Questions

### Where are joint limits physically stored in DART?

Joint limits are stored on individual **DegreeOfFreedom** objects, not on the Joint itself. Access them via `joint->getDof(index)` and call `setPositionLimits()` or `setVelocityLimits()`. The `JointLimitConstraint` reads these stored values each frame to calculate constraint forces.

### What is the difference between `Joint::SERVO` and `Joint::FORCE` actuator types?

`Joint::SERVO` enables closed-loop position or velocity control through the `ServoMotorConstraint`, which generates forces to reach the target set via `setCommand()`. `Joint::FORCE` applies direct generalized forces to the DoFs without a feedback loop, giving you raw torque control but requiring you to handle stabilization manually.

### How do I make one joint automatically follow another joint's movement?

Set the follower joint's actuator type to `Joint::MIMIC` using `setActuatorType()`, define the relationship with `setMimicJoint(leader, multiplier, offset)`, and add a `MimicMotorConstraint` to the world. This constraint copies forces from the leader joint to the follower based on the scaling factor you specify.

### Why are my joint limits not being enforced during simulation?

You likely forgot to add a `JointLimitConstraint` to the world. Setting limits on the `DegreeOfFreedom` only stores the boundary values; the physics engine requires an active constraint object to apply corrective impulses. Create the constraint with `std::make_shared<dart::constraint::JointLimitConstraint>(joint)` and call `world->addConstraint()` to enable enforcement.