The arm starts, then stops partway through the task

Three unrelated faults produce the same picture: the arm moves, then stops. They need different fixes, so the first job is telling them apart.

Deployment · Last updated 2026-08-09

Symptom

The policy starts confidently, gets partway into the task, and then the arm stops moving. Sometimes it holds position, sometimes it sags.

Short answer

This is three different faults wearing the same appearance: a servo that cut torque under overload, an inference loop that cannot keep up with the arm, or a policy that reached a state its demonstrations never contained. Stop the policy, then check whether the joint still holds against a gentle push. Limp means hardware, holding means software.

Three faults, one appearance

From two meters away, a servo that has protected itself, a control loop running at two decisions per second and a policy that has run out of relevant experience are indistinguishable. All three show an arm that was doing something and now is not, and they live in different parts of the stack, so guessing costs you an evening. The differential below takes five minutes.

Stop the policy before you put a hand on the arm

The tests here involve touching the arm. Run ay-robots stop first, so the loop is not about to resume mid-test, and keep the power switch within reach. A policy that has been idle for ten seconds can still issue a large motion the moment the observation changes, and your hand in frame is exactly the observation change that triggers it.

TestServo cut torqueLoop too slowOut of distribution
After stopping, does the joint resist a gentle push?No, it moves freelyYes, it was holdingYes, it was holding
How did the motion end?Abruptly, usually right after the arm pushed against somethingIt never fully stopped: short moves with pauses between themSmoothly, then it holds the last pose
Does it happen at the same point in the task?Wherever the load peaks, often the same joint every timeSpread across the whole run, not one momentThe same moment, and it moves when you change the scene
Does a power cycle and re-home restore it?Yes, until the load repeatsNo effectNo effect
Does changing the model or camera count change it?NoYes, directlyOnly if the new model generalizes further

Cause one: a servo cut its own torque

Feetech STS3215 servos protect themselves against overload. When current stays high for too long, the servo stops driving and the joint goes slack. On the arm this reads as a stall, because motion ends instantly and the arm then sags under gravity instead of holding. It is nearly always mechanical in origin: the gripper closed on something rigid, the arm pressed into the table, a joint reached the end of its travel and kept commanding, or a cable snagged.

Power is the other half of it. A supply that cannot deliver the current the arm draws when several joints load at once will sag, and a sagging rail brings the protection on sooner. If the freeze correlates with the moments where the policy loads two or three joints together, look at the supply before you look at the policy.

STS3215 servos are 7.4 V parts

SO-100, SO-101 and LeKiwi arms all use them. A 12 V supply destroys them in seconds, and the damage is not recoverable. Read the label on your own supply before you swap anything while chasing a power-related stall. Koch v1.1 uses Dynamixel servos with different rails, so check that arm against its own documentation rather than this number.

bash
# Stop the loop first
ay-robots stop

# All six actuators still answering on the bus?
ay-robots devices
#   /dev/cu.usbmodem58FA0821911   SO-100  (6 servos responding)

# Bring it back to a known pose and listen for anything binding
ay-robots home

If devices reports fewer servos than the arm has, you have a bus or wiring fault rather than a policy problem, and no amount of retraining will touch it. If all six answer and the arm homes cleanly, move on to the next cause.

Cause two: the inference loop cannot keep up

Each action step costs one model evaluation, and the models here differ by more than an order of magnitude in what that costs. These are the measured per-step times in the cloud pool, with the rate that follows from them.

ModelPer action stepAction steps per secondRuns locally
ACTabout 20 msabout 50Yes
GR00T N1.7about 152 msabout 6No, cloud only
GR00T N1.5about 165 msabout 6No, cloud only
SmolVLAabout 245 msabout 4Yes
Pi0.5about 485 msabout 2No, cloud only

At two decisions per second the arm moves, waits, moves, waits. Described afterwards it becomes "it froze", but what actually happened is a series of short pauses rather than one stop. The catalog is explicit that Pi0.5 latency is visible as hesitation on fast motions, and this is what that looks like when the task also requires the arm to track something. ACT at roughly 20 ms is the other end: the motion looks continuous because the loop closes faster than you can see.

Two things sit on top of the model time. Running with --mode cloud adds a network round trip to every step, which is added latency per decision rather than a constant offset, so it multiplies the effect on a slow model. And camera capture shares the same loop: resolution and stream count show up in the timing before the model does. Switching from cloud to local on ACT or SmolVLA, the two models the catalog marks as locally runnable, is the largest single change available here.

The test that settles it: watch whether the pauses are rhythmic. A slow loop produces evenly spaced hesitation across the whole run. A latched servo and an out-of-distribution stop both happen once, at a specific moment.

Cause three: the policy has nothing to say

The third case is the arm holding position with torque on, commands still flowing, and the commanded pose barely changing. The policy is producing output. It just is not producing motion, because the observation it is looking at is outside anything in your recordings and the mapping it learned has no useful answer there.

The situations that do this are ordinary. The object slipped into a pose you never demonstrated, your hand entered the frame, or the gripper closed on nothing and the policy is now in a state where every training example had an object between the fingers. The state is legal, the arm is fine, and the policy has never seen it.

To confirm: reset the scene exactly as you reset it while recording, and run again. If the task completes, the fault was the situation and not the checkpoint. Then record targeted episodes of the situation that stopped it, which is a far better use of an hour than another training run on the same data. The reset discipline is written out at /learn/run-your-first-policy.

How much of this a model absorbs depends on what it brought with it. ACT is trained from scratch on your episodes, so its world ends where your demonstrations end, which /policies/act states plainly. GR00T N1.7 arrives pretrained on a large multi-robot corpus and generalizes to object positions your demonstrations never showed, so it stops less often for this reason. That is the practical trade in /compare/act-vs-groot-n1-7: about 20 ms per step and no generalization, against about 152 ms and a good deal of it.

Run the differential in order

  1. 1
    Stop the policy

    Everything after this involves touching the arm or changing the scene, and neither is safe while the loop is live.

    bash
    ay-robots stop
  2. 2
    Push the stopped joint gently

    Limp means the servo cut torque and you are looking at cause one. Resistance means torque was on the whole time, which rules hardware out and leaves the two software causes.

  3. 3
    Confirm the bus and re-home

    Six actuators answering and a clean home run tells you the mechanics are healthy right now, whatever happened during the attempt.

    bash
    ay-robots devices && ay-robots home
  4. 4
    Watch the rhythm on the next attempt

    Evenly spaced pauses across the run point at loop latency. One stop at one moment points at the observation.

  5. 5
    Reset the scene precisely and repeat

    If a clean reset completes the task, you have an out-of-distribution problem and the fix is targeted recording, not retraining on what you already have.

Frequently asked questions

The arm stops at exactly the same point every time. Is that hardware or the policy?

Both can do that, and the push test separates them. A joint that reaches the same high-load pose every attempt will latch at the same moment, and a policy that meets the same unfamiliar observation every attempt will stall at the same moment. Limp joint means hardware, holding joint means the policy.

Does a faster model fix a policy that stops because it is confused?

No. Latency and generalization are different axes. Switching to a faster model removes the hesitation caused by a slow loop and does nothing for a state the policy has never seen. Only new demonstrations of that state fix that.

Can I raise the latency budget by lowering the camera resolution?

You can shorten the capture side of the loop that way, but you also change what the policy sees, and it was trained on the resolution in your dataset. Changing the observation to speed up the loop trades one failure for another. Running the model locally is the cleaner lever.

Should the arm hold position when the policy has nothing useful to do?

Yes, holding is normal and is what a servo under torque does when the commanded pose stops changing. A sagging arm is the abnormal one, because it means the joint is no longer being driven at all.

It only freezes in cloud mode. Is that the network?

Very likely. Cloud mode puts a round trip in every step, and on a model that already needs a few hundred milliseconds per decision, that is enough to turn hesitation into visible stopping. ACT and SmolVLA both run locally, which removes the round trip entirely.