
A demo is one rollout. Turning it into a number you can defend takes fixed resets, enough attempts, failure codes and a confidence interval. Here is the full protocol.
The first time a fine-tuned policy picks up the cube, the instinct is to reach for the phone and film it. That clip is real. It is also one sample from a distribution nobody has measured. Run the same policy twenty more times, move the cube two centimetres, turn on the overhead light, and it stops being representative of anything.
This article is about the distance between those two states: a policy that works once, and a policy whose behaviour you can predict tomorrow morning. That distance is almost never closed by a better model. It is closed by a reset you perform the same way every time, a tally sheet, a confidence interval, a retry rule, and a log you actually read.
What you need to know
- •A demo is one rollout. A success rate is a number with an interval, and at 10 rollouts that interval is about 50 points wide.
- •8 of 10 is a 95 percent Clopper-Pearson interval of 44.4 to 97.5 percent. 40 of 50 is 66.3 to 90.0. Same point estimate, very different claim.
- •Published work runs 10 to 50 rollouts per task: ACT 25 and the TRI large behavior model study 50 on real hardware, Pi0.5 10 per task in real and mock homes, SmolVLA 10 per task in simulation.
- •The reset is part of the experiment. Place the object by eye and you are measuring your own hands.
- •Retry logic can beat a better checkpoint: Robot Utility Models went from 74.4 to 90 percent by restarting failed attempts.
- •AY-Robots gives you the arm, the dataset pipeline, the training run and a served policy. It does not score your rollouts.
The demo is one sample, and you chose it
Selection bias in robot demos is not dishonesty, it is convenience. The policy fails, you nudge the cube, it fails, you nudge again, it works, you film that one. The belief that follows, it works, is built from a single sample drawn after several unrecorded resets.
The failures that surface on attempt eleven are rarely new physics. They are the thin parts of your demonstration coverage, plus the environment drifting while you are not looking.
| What changed | Why the demo hid it | How it shows up |
|---|---|---|
| Object start pose | You placed it where the policy already worked | Approach misses, gripper closes on air |
| Arm start pose | The demo began wherever the last attempt ended | First action chunk is out of distribution, arm lurches |
| Lighting | One session, one time of day | Wrist camera exposure shifts, grasp timing changes |
| Camera mounting | Nothing had been bumped yet | The largest silent killer; 5 mm is a different task |
| Servo temperature | Cold arm, first run of the day | STS3215 behaviour drifts as the bus warms |
| Operator | You knew where to put the cube | A second person resets differently, the number drops |
None of these are model problems, which is why swapping ACT for SmolVLA rarely fixes them. They are measurement problems, and the failure mode index is a faster diagnostic than another training run.
One number, and the interval you left off it
Success rate is a binomial proportion. If you ran n attempts and k succeeded, the honest report is k/n plus an interval. Clopper-Pearson is the conservative choice and it is two lines of Python. At 95 percent:
| Observed | Point estimate | 95% Clopper-Pearson | Width |
|---|---|---|---|
| 8 / 10 | 80.0% | 44.4% to 97.5% | 53 pts |
| 16 / 20 | 80.0% | 56.3% to 94.3% | 38 pts |
| 24 / 30 | 80.0% | 61.4% to 92.3% | 31 pts |
| 40 / 50 | 80.0% | 66.3% to 90.0% | 24 pts |
| 80 / 100 | 80.0% | 70.8% to 87.3% | 17 pts |
| 10 / 10 | 100% | 69.2% to 100% | 31 pts |
| 20 / 20 | 100% | 83.2% to 100% | 17 pts |
from scipy.stats import beta
def clopper_pearson(k, n, alpha=0.05):
"""Exact two-sided binomial interval for k successes in n trials."""
lo = 0.0 if k == 0 else beta.ppf(alpha / 2, k, n - k + 1)
hi = 1.0 if k == n else beta.ppf(1 - alpha / 2, k + 1, n - k)
return lo, hi
print(clopper_pearson(24, 30)) # (0.6143, 0.9229)
print(clopper_pearson(8, 10)) # (0.4439, 0.9748)If every one of n attempts succeeded, the 95 percent upper bound on your failure rate is roughly 3/n. Ten perfect runs still permit a true failure rate near 30 percent; twenty permit about 17 percent. The honest sentence is zero failures in ten attempts, not 100 percent reliable.
The second table ends arguments. To claim policy A beats policy B, the attempts you need depend on how big the real gap is. Two-proportion sample sizes at alpha 0.05 and 80 percent power, per policy:
| Gap to detect | Rollouts per policy | Feasible on one arm? |
|---|---|---|
| 50% vs 80% | 39 | One afternoon |
| 70% vs 90% | 62 | One day |
| 60% vs 80% | 82 | Two days |
| 50% vs 70% | 93 | Two days |
| 80% vs 90% | 199 | No |
| 50% vs 60% | 388 | No |
Read the last two rows carefully. A 10 point improvement in an already good policy is beyond what one arm and one human can measure in a week. That is not a reason to give up, it is a reason to stop claiming it. If two checkpoints land at 82 and 88 percent over 30 attempts each, you cannot tell them apart.
What published work actually runs
The numbers behind the tables you compare yourself against are smaller than most people assume. All of the following was read from the papers themselves.
| Work | Rollouts per task | Protocol detail worth copying |
|---|---|---|
| ACT / ALOHA (2023), real hardware | 25, one seed | Object start varied along a 15 cm reference line, not by eye |
| ACT / ALOHA (2023), simulation | 50 per seed, 3 seeds | Averaged across seeds, not best seed |
| Diffusion Policy (2023), simulation | 50 initial conditions x 3 seeds | Reports best checkpoint and average of the last 10 |
| SmolVLA (2025), LIBERO | 10 per task | Binary in sim, subtask decomposition on real hardware |
| Pi0.5 (2025), real and mock homes | 10 per policy per task | Scored by task progress, not binary success |
| Robot Utility Models (2024) | 10 per environment, 25 environments | Fixed grid of start positions across all sites |
| Large Behavior Models (2025), real | 50 per task, policy and condition | Blind A/B, randomized order, 1,800 real trials |
The TRI large behavior model study says it directly: there is significant risk that many robotics papers are measuring statistical noise due to insufficient statistical power. They also found a mundane choice like data normalization often dominated architectural changes. If that holds for a lab running 1,800 controlled real trials, assume it holds for your eight.

The reset is the experiment
The highest-leverage change most people can make is to write down how the scene is reset and then follow that written procedure instead of their memory. TRI did this with an image overlay: the person resetting the cell matched the objects to a picture of the desired scene. ACT constrained object placement to a 15 cm reference line on the table. Robot Utility Models reused a fixed grid of start positions across every environment.
For one SO-100 on a desk, the cheap version is a printed sheet taped down with the target zone marked, plus a photo of the start scene on your phone. Ten minutes of work, and it removes the largest single source of variance. If the arm itself is not yet repeatable, fix that first with the SO-100 setup guide.
- Mark the object start zone physically. Tape or a printed template, not "about here".
- Return the arm to a defined start pose every time.
--strategy.reset_to_initial_positiondoes this in lerobot. - Photograph the reference scene once and match to the photo, not to memory.
- Fix the lighting. Same lamps, same blinds. Note it if you cannot.
- Do not touch the cameras. If you must, before and after the move are two experiments.
- Set the time limit up front and let attempts fail on the clock, not on your patience.
- Randomise order when comparing policies, and if a second person is free, let them run the arm blind.
SO-100 and SO-101 run Feetech STS3215 servos on a 7.4 V rail. Koch v1.1 uses Dynamixel motors on 5 V and 12 V rails, and LeKiwi mixes a 7.4 V arm with a 12 V base. A 12 V supply on an STS3215 bus kills the servos quietly enough that you will spend the afternoon blaming the policy. Check the arm comparison before swapping a power brick.
Running the evaluation on real hardware
The tooling exists and most people skip it. In lerobot, lerobot-rollout is the single CLI for deploying a trained policy on a real robot, and its episodic strategy is built for scored attempts: the policy drives each episode, then an optional leader arm drives during a timed reset phase. Flags below were read from the lerobot deployment docs on 2026-08-24.
- 1Check the checkpoint offline first
Comparing predicted actions against ground truth from a held-out episode costs nothing and catches checkpoints that will not move.
bashuv run python gr00t/eval/open_loop_eval.py \ --dataset-path /data/so100_cube \ --embodiment-tag NEW_EMBODIMENT \ --model-path /checkpoints/gr00t_n17_cube/checkpoint-20000 \ --traj-ids 0 \ --execution-horizon 16 - 2Do one throwaway run to shake out the cell
Base strategy, no recording. This is where you find a moved camera index or an upside-down wrist view. Nothing here counts.
bashlerobot-rollout \ --strategy.type=base \ --policy.path=${HF_USER}/act_so100_cube \ --robot.type=so100_follower \ --robot.port=/dev/ttyACM0 \ --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}, wrist: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30}}" \ --task="Pick up the red cube and put it in the box" \ --duration=60 - 3Run the scored block with episodic
Numbered episodes, a fixed limit per attempt, a reset phase between them. Pin the revision rather than trusting main; each pushed checkpoint is tagged with its step.
bashlerobot-rollout \ --strategy.type=episodic \ --policy.path=${HF_USER}/act_so100_cube \ --policy.pretrained_revision=010000 \ --robot.type=so100_follower \ --robot.port=/dev/ttyACM0 \ --teleop.type=so100_leader \ --teleop.port=/dev/ttyACM1 \ --strategy.reset_to_initial_position=true \ --dataset.repo_id=${HF_USER}/eval_cube_ckpt10000 \ --dataset.num_episodes=30 \ --dataset.episode_time_s=30 \ --dataset.reset_time_s=15 \ --dataset.single_task="Pick up the red cube and put it in the box" - 4Score each attempt while the reset runs
Live scoring, not retrospective scoring from video. Video is slower and reliably kinder to the policy.
textep outcome note 01 S clean 02 F-grasp closed 1 cm short 03 S 04 X leader arm bumped during reset, rerun 05 F-stall froze above the cube, 12 s left - 5Compute the interval, write the honest sentence
Excluded attempts do not count in n. Report interval, n and reset procedure together; any one alone is not reproducible.
text24 / 30 = 80.0% (95% CI 61.4% to 92.3%) reset: taped 10 cm zone, arm homed, overhead lamp only, 30 s limit
Binary success is a blunt instrument
Pass or fail throws away most of what a rollout tells you. Pi0.5 reports task progress rather than binary success for its home evaluations, and SmolVLA decomposes real-world tasks into subtasks. A policy that reaches the object and fails the grasp is a different engineering problem from one that never leaves its start pose, and averaging them into one zero hides which you have.
| Code | What you saw | Where to look next |
|---|---|---|
| S | Completed inside the time limit | Nothing |
| S-r | Completed after an automatic retry | Track separately, it inflates the headline |
| F-approach | Never got near the object | works in one setup only |
| F-grasp | Reached it, gripper never closed on it | gripper does not close |
| F-stall | Stopped moving with time left | freezes mid-motion |
| F-range | A joint stopped short of where it needed to be | joint stops early |
| F-nothing | Arm did essentially nothing all episode | loss falls, policy does nothing |
| X | Operator error or hardware fault | Excluded, rerun, note why |
Robot Utility Models reports 74.4 percent from the policy alone and 90 percent once a multimodal LLM watched the rollout, judged failure and restarted the attempt: 15.6 points from a wrapper, averaging 1.31 tries with a 10-try timeout. Build the retry, but report both numbers.
Two ways to get to a number you trust
You own the whole loop: arm, cameras, dataset, GPU, serving process, score sheet. Nothing is hidden and nothing is done for you.
pip install lerobot
# record (defaults: 60 s episode, 60 s reset, 50 episodes)
lerobot-record --robot.type=so100_follower --robot.port=/dev/ttyACM0 \
--teleop.type=so100_leader --teleop.port=/dev/ttyACM1 \
--dataset.repo_id=${HF_USER}/so100_cube --dataset.num_episodes=50
# evaluate
lerobot-rollout --strategy.type=episodic --policy.path=${HF_USER}/act_so100_cube \
--dataset.num_episodes=30 --dataset.episode_time_s=30 --dataset.reset_time_s=15- Every variable is visible and yours to fix
- Zero-latency inference, the GPU is on the same desk
- The protocol is yours to change mid-experiment
- Calibration, camera and driver problems are all yours
- A 24 GB card will not fine-tune GR00T N1.7 or Pi0.5
- One arm, one attempt at a time: 80 attempts is an afternoon, a two-policy comparison is days
- Nobody reproduces your number without your reset table
The platform removes the infrastructure around the measurement. The desktop client records LeRobot datasets straight from a teleoperation session, the training form rents a GPU by required VRAM and writes checkpoints to object storage, and /api/inference/pod auto-provisions a pod that serves the policy back to your robot client. Pods carry an idle watchdog and destroy themselves when idle.
AY-Robots does not score your rollouts, compute your confidence interval, or enforce a reset procedure. There is no success-rate dashboard. Tallies, exclusions and intervals stay manual. What the platform buys is that the arm, the dataset pipeline and the GPU stop being the reason you only ran eight attempts.
- Record on your own arm, or drive a real SO-100 with no signup on the live queue.
- Pick from the five trainable policies. Minimum useful dataset: 50 episodes for GR00T N1.7, GR00T N1.5, Pi0.5 and ACT, 30 for SmolVLA.
- Train. A100 or H100 runs are 3 to 6 hours at 1.20 to 2.00 USD per hour, about 4 to 12 USD; RTX 4090 runs are 2 to 5 hours at 0.30 to 0.60 USD per hour, about 1 to 3 USD.
- Serve on a pod, or pull the checkpoint down and serve locally if latency matters.
- Script the block through the CLI or the MCP server so it re-runs identically.
- A cheap run is 1 to 3 USD, so re-evaluating three checkpoints is affordable
- GR00T N1.7 and Pi0.5 without owning an 80 GB card
- Idle watchdog means a forgotten pod is not an open-ended bill
- CLI and MCP make the block scriptable
- No evaluation harness, no scoring, no interval computation
- Remote inference adds internet round trips on top of model latency
- GR00T and Pi0.5 are cloud-only here; SmolVLA and ACT also run locally
- Spot pricing is a range, not a quote
Latency quietly changes the number you measure
A success rate is comparable across setups only if the control loop was the same, and it usually is not. Per-action inference latency across the five trainable policies spans more than an order of magnitude, a direct consequence of how vision-language-action models are built. Those figures are the floor; anything you add comes out of the same budget.
| Policy | Inference per action step | GPU tier | Min. episodes |
|---|---|---|---|
| ACT | 20 ms | RTX 4090 or any 24 GB card | 50 |
| GR00T N1.7 | 152 ms | A100 80 GB or H100 80 GB | 50 |
| GR00T N1.5 | 165 ms | A100 80 GB or H100 80 GB | 50 |
| SmolVLA | 245 ms | RTX 4090 or any 24 GB card | 30 |
| Pi0.5 | 485 ms | A100 80 GB or H100 80 GB | 50 |
Inference has to sit next to the servos for fast tasks. Public-internet round trips on top of a 245 ms or 485 ms model turn a working policy into a hesitant one, and a hesitant policy scores worse for reasons unrelated to training. Remote inference is viable for slow pick and place, not fast reactive motion. Evaluate remotely and deploy locally and the two numbers do not belong in one table.
There is real work on this. Real-Time Chunking generates the next action chunk while the current one is still executing, freezing the actions guaranteed to run and inpainting the rest, which keeps motion continuous despite inference delay. lerobot exposes it as an inference backend.
lerobot-rollout \
--strategy.type=base \
--inference.type=rtc \
--inference.rtc.execution_horizon=10 \
--inference.rtc.max_guidance_weight=10.0 \
--policy.path=${HF_USER}/pi05_policy \
--robot.type=so100_follower \
--robot.port=/dev/ttyACM0 \
--task="Pick up the cube" \
--duration=60 \
--device=cudaMonitoring: read the loop, not just the outcome
Every lerobot control loop reports what it actually achieved, per episode and for the whole run. This is the closest thing to free monitoring you will get, and almost nobody reads it. It landed after the 0.6.1 release, so you need lerobot from main to see it. It gives you effective control frequency against target, how often the loop blew its budget, where the time went, and how much pacing headroom is left.
Cadence summary - whole run, 2 episodes - target 30 Hz
effective cadence: 29.84 Hz policy over 40.2 s measured
cycles over the 33.3 ms work budget: 12/1197 (1.0%)
loop-body steps (share of measured work):
observe mean 3.13 ms ... 31.7% of work
infer mean 5.18 ms ... 52.4% of work
pacing headroom: 7.4 ms slept per tick on averageThe number to watch across a long session is pacing headroom. Near zero means the loop is saturated, and any hiccup, a camera stall, a slow disk write, a thermal throttle, costs you actions. A policy that scored 24 of 30 in the morning and 15 of 30 in the afternoon has usually not forgotten anything; something in the loop got slower. The client guide is a better first stop than a retraining run.
- Log the cadence summary from every scored block beside the tally.
- Treat any camera reconnect during a block as grounds to exclude that attempt. See camera not detected.
- Record evaluation runs as datasets.
--strategy.type=sentryrecords continuously with auto-upload; episodic records per attempt. - Keep the failure code distribution, not just the total. A drift from F-grasp toward F-approach usually means a camera moved.

What honest evaluation actually costs
The objection is time, and it is fair. Thirty attempts at 30 seconds plus 15 seconds of reset is about 22 minutes of arm time, but with scoring, exclusions and the servo that needs re-homing, budget an hour. Eighty attempts is an afternoon. That cost is real and worth naming.
The GPU side is comparatively cheap; an RTX 4090 tier run for SmolVLA or ACT is roughly 1 to 3 USD. The expensive resource is the human next to the arm, which is why so much published work stops at 10 rollouts, and why distributed efforts like RoboArena exist: seven academic institutions pooling more than 600 pairwise double-blind real-robot evaluation episodes.

- A number you can defend, with an interval saying how much to trust it
- Failure codes that point at a specific fix, not a general suspicion
- Comparability across checkpoints, because the protocol did not move
- Grounds to stop optimising when two checkpoints are indistinguishable
- An hour of arm time per 30 attempts, afternoons for real comparisons
- Small improvements are out of reach for a single arm
- Blind scoring needs a second person, which most solo setups lack
- It makes your policy look worse than the demo did, which is the point
The short version
The difference between a demo and a system is not a bigger model. It is a written reset procedure and a number with an interval on it. Once you have those, running a policy stops being a party trick, and the data collection choices that actually move the number become visible instead of guessed at.
Pin the checkpoint. Write the reset down and tape the zone to the table. Choose n from the gap you need to detect, not from your patience. Run lerobot-rollout --strategy.type=episodic. Score live with failure codes and exclude hardware faults explicitly. Compute a Clopper-Pearson interval. Log the cadence summary next to the tally. Report the interval, the n and the reset procedure together.
How many rollouts do I need for a success rate I can quote?▾
For a single number, 30 attempts gives an interval about 31 points wide at an 80 percent success rate, enough to say whether a policy roughly works. For comparing two policies it depends on the gap: 50 versus 80 percent needs about 39 attempts per policy, 70 versus 90 needs 62, 80 versus 90 needs 199, at alpha 0.05 and 80 percent power.
Is it cheating to report a success rate that includes retries?▾
No, as long as you say so. Robot Utility Models went from 74.4 percent single-shot to 90 percent with a verifier that restarted failed attempts, and reported both. Note the retry budget too, since an unbounded retry loop converges to 100 percent and means nothing.
Why did my policy get worse over the afternoon without any change?▾
Usually the servo bus warmed up, the lighting changed, a camera got nudged, or the control loop slowed down. The cadence summary lerobot prints at the end of every run separates the last from the others: if effective cadence dropped and pacing headroom is near zero, you are dropping actions. If cadence held, look at the cameras.
Can I evaluate in simulation instead of on the arm?▾
Partly. Simulation gives hundreds of rollouts for the price of one afternoon, and SIMPLER showed carefully matched simulated evaluations can track real-world behaviour. But for your SO-100 on your desk with your cameras, the disparities you care about are the ones the simulator does not model. Use it to reject bad checkpoints cheaply, then confirm on hardware.
Does AY-Robots track success rates for me?▾
No. It handles teleoperation, dataset recording, cloud training and serving the policy back to your robot, and exposes those operations to a terminal and to AI agents. It does not run your evaluation protocol, keep your tally, or compute your interval. What it removes is the infrastructure friction that makes people stop at eight attempts.
Which model gets me to a reliable policy fastest?▾
The cheapest thing that fits the task. ACT trains from scratch at about 20 ms per action step and has no base model, the fastest loop for repetitive pick and place. SmolVLA fine-tunes on a 24 GB card from 30 episodes. Move to GR00T N1.7 or Pi0.5 when you need broader generalisation and can accept 152 ms or 485 ms per step.
When the number is bad, start with the failure mode
Each failure code in your tally maps to a documented cause. Gripper does not close, policy freezes mid-motion, joint stops early, works in one setup only: the fix pages cover what actually produces each symptom on SO-100 class hardware.
Open the failure mode indexSources
- A Careful Examination of Large Behavior Models for Multitask Dexterous Manipulation
- Large Behavior Models project page, TRI: evaluation protocol and rollout counts
- How Generalizable Is My Behavior Cloning Policy? A Statistical Approach to Trustworthy Performance Evaluation
- Deep Reinforcement Learning at the Edge of the Statistical Precipice
- RoboArena: Distributed Real-World Evaluation of Generalist Robot Policies
- Robot Utility Models: General Policies for Zero-Shot Deployment in New Environments
- Learning Fine-Grained Bimanual Manipulation with Low-Cost Hardware (ALOHA, ACT)
- Diffusion Policy: Visuomotor Policy Learning via Action Diffusion
- Pi0.5: a Vision-Language-Action Model with Open-World Generalization
- SmolVLA: A Vision-Language-Action Model for Affordable and Efficient Robotics
- Real-Time Execution of Action Chunking Flow Policies
- Evaluating Real-World Robot Manipulation Policies in Simulation (SIMPLER)
- lerobot: Policy Deployment (lerobot-rollout), strategies, flags and cadence reporting
- lerobot: recording a dataset, default episode and reset durations
- NVIDIA Isaac-GR00T: open-loop and closed-loop evaluation entry points
Ready for high-quality robotics data?
AY-Robots connects your robots to skilled operators worldwide.
Get Started