Our benchmarks put a humanoid at a table and let a model drive its hands. That takes a controller for the Unitree R1 EDU and its two Dex3-1 hands that keeps the robot standing for hours, takes commands like “move this hand above that point”, refuses what it cannot do safely, and records what happened.
Spur is that controller. It runs on the robot’s backpack computer, between whatever makes the decisions (a model, a script, a person) and the motors. Spur 0.1.1, the version that ran our benchmark trials, is open source.
What exists today
Unitree’s SDK gives an R1 owner the motor channel: a target and gains for each joint, about 500 times a second. Everything above that is yours to write: balance, inverse kinematics, collision checks, grasp detection, logs. Unitree’s built-in controller balances and walks, and documents a channel for arm joint targets while it does, but it does not plan motions, check collisions or report a grasp.
The open-source humanoid controllers from research labs add balance with a learned policy, and share a shape we did not want to inherit:
- Nothing watches the policy. A policy computes joint targets 50 times a second and a writer sends them on. If the policy stalls, the writer replays its last targets: the joints hold stiff and nothing balances. None of the stacks we read checks that the policy is alive.
- A fault ends in a limp robot. The standard response is to damp every joint and accept the fall.
- Manipulation is left to you. Planning a reach around a table, checking it against the other arm and judging whether a grasp holds are the user’s problem.
- The simulator stops at the motors. Unitree’s MuJoCo bridge has no hands.
What Spur does differently
Spur separates what keeps the robot standing from everything else. The parts that must never wait are small C++ programs on their own processor cores; everything else may stall or crash without taking the balance with it.
- Nothing slow touches balance. r1rt, a real-time core, is the only process that commands the motors (500 Hz, the policy at 50 Hz). No files, network, memory allocation or Python on that path.
- A hot standby. r1guard reads the robot’s state on its own and computes the same balance action every cycle. If the core goes silent, it takes the motors in about 10 ms and keeps balancing.
- Never limp. A fault steps down a ladder (policy inline, the guard, a stiff standing freeze). Only a person can make the robot go limp.
- Plan, then move. Every arm goal is planned end to end against one model of the world (the table, the objects, the other arm) before anything moves. A refusal says why, in words a model can act on.
- Hands that know when they hold. The grip verdict needs opposing contacts, a finger gap that matches the object and a lift check, never force alone.
- Everything recorded. Every 2 ms tick is logged off the control path; a flight recorder keeps the 30 seconds before any fault or takeover.

How we tested it
In simulation first. r1sim, our MuJoCo model of the R1 and both hands, has its key parameters measured on a real robot: joint friction, command latency, and what the motor board does when commands stop. The real controller programs run against it over the robot’s own network protocol. The balance policy passed 400 of 400 runs on it, from standing still to pushes.
Then we broke it on purpose. We froze or killed the core while the simulated robot stood: upright in 23 of 23 runs, the guard taking over in 10 to 15 ms. Without a standby, the same freeze puts the robot on the floor in about a second.

Then on the real robot, in stages:
- On a stand: all 26 joints moved the way the model says; with the core frozen on purpose, the guard took over in 10.7 ms; Wi-Fi drops never interrupted the 500-a-second command stream.
- On the floor: Spur took the motors from Unitree’s controller in about 0.2 seconds with half a degree of tilt or less. In one 73-minute session the core sent all 2.1 million commands 1.7 to 2.3 ms apart.
- At a table: 20 of 20 scripted grasps held.

In use
Spur ran every scored trial of our first table-clearing benchmark. The model sees the robot’s cameras and acts through six tools (move a hand above a point, lower it, close it, open it, move it, finish); Spur turns each call into a planned, checked motion or refuses it and says why.
One rule keeps it fair: the robot measures, the model aims. Spur corrects the robot’s own errors the same way for every model, but never aims for the model or tells it what it is looking at.
Open for anyone with an R1
Spur is a general controller, not a benchmark rig: nothing in the public code knows about our tasks. The repository (Apache-2.0) has the core and the guard, the command service with its planner, the hands, the camera, the logger, install scripts for the robot and the simulator with a viewer. The 131 stand recordings behind the simulator (CC BY 4.0) and the policy’s training kit are downloads.
Try it without a robot: bash scripts/demo.sh runs Spur’s own core and guard balancing the simulated R1. Press S to freeze the core and watch the guard take over.
For an evaluation company, the layer between a model and a robot deserves the same scrutiny as the model. Opening Spur lets anyone check that layer, and build on it.
Robotics benchmarking & evaluations



