Finger¶
A two-DoF planar finger interacting with a free-rotating spinner body. The family covers two task styles: continuously spinning the body, and rotating it to a target angle.
FingerSpin¶

| Property | Value |
|---|---|
| Canonical ID | mjx/finger_spin-v0 |
| Action space | Box(-1.0, 1.0, (2,), float32) |
| Observation space | Box(-inf, inf, (9,), float32) |
| Episode length | 1000 |
| Config | {"ctrl_dt": 0.02, "sim_dt": 0.005, "naconmax": 25_000, "njmax": 50} |
Description¶
The finger has to keep the spinner rotating around its hinge. There's no target angle — only the spinner's instantaneous angular velocity matters. The challenge is producing a coordinated finger motion that builds and sustains spinner momentum without snagging.
Rewards¶
Uses a sparse reward that fires only when the spinner is rotating fast enough in the negative direction:
| Python | |
|---|---|
1 | |
The threshold gives a clean binary signal:
1.0when the spinner is rotating at or faster thanSPIN_VELOCITYin the negative direction.0.0otherwise.
Starting state¶
1 | |
(finger joint positions, spinner orientation, and joint velocities — finger initialised at a default configuration with the spinner at rest.)
Termination¶
Episode ends when step >= max_steps (default 1000). No early termination.
Usage¶
| Python | |
|---|---|
1 2 | |
Reference¶
Upstream: mujoco_playground/_src/dm_control_suite/finger.py.
FingerTurnEasy¶

| Property | Value |
|---|---|
| Canonical ID | mjx/finger_turn_easy-v0 |
| Action space | Box(-1.0, 1.0, (2,), float32) |
| Observation space | Box(-inf, inf, (12,), float32) |
| Episode length | 1000 |
| Config | {"ctrl_dt": 0.02, "sim_dt": 0.005, "naconmax": 25_000, "njmax": 50} |
Description¶
The finger has to rotate the spinner to a randomised target angle and hold it there. The "easy" variant uses a generous EASY_TARGET_SIZE tolerance around the target, so the agent has a wide acceptance band to find — useful for bootstrapping a controller before tightening the criterion in FingerTurnHard.
Rewards¶
Uses a sparse reward that fires once the spinner has rotated to within tolerance of the target angle:
| Python | |
|---|---|
1 2 | |
dist_to_target is signed — negative inside the band, positive outside — so the comparison gives a clean binary signal:
1.0when the spinner sits withinEASY_TARGET_SIZEof the target angle.0.0otherwise.
Starting state¶
1 2 | |
(finger and spinner state plus the target's position fields appended at the end.)
Termination¶
Episode ends when step >= max_steps (default 1000). No early termination.
Usage¶
| Python | |
|---|---|
1 2 | |
Reference¶
Upstream: mujoco_playground/_src/dm_control_suite/finger.py.
FingerTurnHard¶

| Property | Value |
|---|---|
| Canonical ID | mjx/finger_turn_hard-v0 |
| Action space | Box(-1.0, 1.0, (2,), float32) |
| Observation space | Box(-inf, inf, (12,), float32) |
| Episode length | 1000 |
| Config | {"ctrl_dt": 0.02, "sim_dt": 0.005, "naconmax": 25_000, "njmax": 50} |
Description¶
The same target-rotation task as FingerTurnEasy, but the tolerance shrinks to HARD_TARGET_SIZE. With the smaller acceptance band, random exploration almost never lands inside the target — the variant doubles as a sparse-exploration benchmark on top of the manipulation task itself.
Rewards¶
Uses a sparse reward that fires once the spinner has rotated to within the tighter tolerance band:
| Python | |
|---|---|
1 2 | |
dist_to_target is signed — negative inside the band, positive outside — so the comparison gives a clean binary signal:
1.0when the spinner sits withinHARD_TARGET_SIZEof the target angle.0.0otherwise.
Starting state¶
1 2 | |
Termination¶
Episode ends when step >= max_steps (default 1000). No early termination.
Usage¶
| Python | |
|---|---|
1 2 | |
Reference¶
Upstream: mujoco_playground/_src/dm_control_suite/finger.py.