The AY-Robots policies comparison page listing GR00T N1.7, GR00T N1.5, Pi0.5, SmolVLA and ACT with parameter counts, GPU tier, inference latency and minimum episode counts
InsertionContact-Rich ManipulationPolicy ComparisonAction ChunkingSO-100Force Control

Insertion and Assembly Tasks on a Low-Cost Robot Arm

AY-Robots ResearchAugust 23, 202624 min read

An SO-100 has no force sensor, and one encoder count is already 0.31 mm at the gripper. The real tolerance budget for insertion, and which of the five policies closes the loop fast enough.

Insertion is not pick-and-place with a smaller target

A pick-and-place policy is allowed to be sloppy. Close the gripper 4 mm off centre on a cube and the cube slides between the fingers, the error washes out, and the episode still counts. Insertion has the opposite property. The moment a peg touches the rim of a hole, misalignment stops being a position error and becomes a force, and an SO-100 answers a force by winding up servo current until the part scrapes, the arm sags, or the servo overheats.

That difference is why contact-rich tasks are the place where a cheerful demo turns into a week of debugging. This page covers three things: the real tolerance budget on a hobby-price arm, why the control mode underneath the arm works against you, and which of the five trainable policies actually closes the loop fast enough to react to contact. Platform numbers come from the policy catalogue. Everything else comes from papers and repositories opened on 24 August 2026, with versions named where they matter.

What you need to know

  • One Feetech STS3215 encoder count is 360/4096 = 0.088 degrees. At a 200 mm lever arm that is already about 0.31 mm at the gripper, the same order of magnitude as the 0.5 to 0.6 mm part clearances NVIDIA's IndustReal calls realistic for industrial assembly.
  • The SO-100 follower in LeRobot puts every servo in position mode with P 16, I 0, D 32 and reads back only Present_Position. Present_Load sits on the bus at register 60 and is never touched. Your recorded dataset contains no force signal at all.
  • The default action chunk is the bigger problem. ACT ships chunk_size 100 with n_action_steps 100, so at the 30 fps LeRobot records by default the arm runs 3.3 seconds of motion after a single look at the scene.
  • Only ACT (20 ms per action step) can re-plan at the 30 Hz rate the data was recorded at. GR00T N1.7 tops out near 6.6 Hz, SmolVLA near 4.1 Hz, Pi0.5 near 2.1 Hz.
  • Every published system with high insertion reliability adds something this stack lacks. HIL-SERL reports 100 percent on RAM insertion over 100 trials, against 27 percent for Diffusion Policy trained on 200 demonstrations and 12 percent for plain behaviour cloning.

The tolerance budget nobody writes down

Before you argue about model architectures, do the stack-up. Insertion succeeds when the total error between the held part and the hole is smaller than the clearance. Every term below adds into that total, and most of them are properties of the hardware rather than of the policy you train on top of it.

Error sourceSize on an SO-100 class armCan more training data fix it?
Encoder quantisation0.088 degrees per count (LeRobot lists 4096 counts per turn for the sts3215), roughly 0.31 mm at a 200 mm lever armNo. This is a hardware floor.
Gearbox backlash and printed-part flexNot published by the vendor. Measurable by hand: hold the base, waggle the gripper, watch the reported joint angle stay put.No. Re-print, shim or accept it.
Calibration and homing drift between sessionsDepends entirely on how repeatable your homing pose isNo. Re-run calibration and keep the file.
Camera to arm registrationThe 2021 off-the-shelf assembly benchmark measured under 0.1 mm with industrial cameras and vendor calibration, and noted research setups are commonly 0.5 mm to 5 mmPartly. Rigid mounts and a wrist camera help more than more episodes.
Grasp pose variationThe same benchmark's part nests allowed about +/-3 mm and +/-5 degrees, and the cell still needed force or 3D vision to insertYes. This is the one term demonstrations genuinely cover.
Part clearanceIndustReal used 0.5 to 0.6 mm and pointed out that many earlier RL papers used 1 mm or moreNo. That is the part. Change the part.
Do the arithmetic once, it saves a week

4096 counts over a full turn is 0.0879 degrees per count, or 1.53e-3 radians. Multiply by the distance from the joint to the point you care about: 200 mm gives 0.31 mm, 300 mm gives 0.46 mm. That is the best case, with a perfect model, perfect cameras and zero backlash. If your target clearance is 0.5 mm you have already spent most of the budget on quantisation alone. Pick a chamfered target, or widen the hole, before you blame the model.

Why position control fights you

The STS3215 is a smart servo, not a joint with a torque interface. In teleoperation and during rollout, LeRobot configures every motor the same way. This is the configure step from the SO follower in lerobot main, checked on 24 August 2026:

python
# src/lerobot/robots/so_follower/so_follower.py  (lerobot main, 24 Aug 2026)
def configure(self) -> None:
    with self.bus.torque_disabled():
        self.bus.configure_motors()
        for motor in self.bus.motors:
            self.bus.write("Operating_Mode", motor, OperatingMode.POSITION.value)
            self.bus.write("P_Coefficient", motor, self.config.position_p_coefficient)  # default 16
            self.bus.write("I_Coefficient", motor, self.config.position_i_coefficient)  # default 0
            self.bus.write("D_Coefficient", motor, self.config.position_d_coefficient)  # default 32

            if motor == "gripper":
                self.bus.write("Max_Torque_Limit", motor, 500)   # 50% of max torque to avoid burnout
                self.bus.write("Protection_Current", motor, 250) # 50% of max current to avoid burnout
                self.bus.write("Overload_Torque", motor, 25)     # 25% torque when overloaded

# and the entire proprioceptive observation:
obs_dict = self.bus.sync_read("Present_Position", num_retry=self.config.num_read_retries)
Position mode, a proportional-derivative gain pair with the integral term disabled, and a state read that returns angles only.

Two things in that snippet decide how insertion behaves. First, Operating_Mode is POSITION for every joint, so the servo's only job is to drive its output shaft to the last Goal_Position it was given. When the peg jams, the position error grows, the proportional term grows with it, and the servo pulls more current into a part that is not going to move. There is no compliance term to give way. Second, the register table in LeRobot does define Present_Load at address 60 and Present_Current at 69, but get_observation never reads them.

The consequence is blunt. A LeRobot dataset recorded from an SO-100 contains joint angles and camera frames. It contains no measurement of contact. A policy trained on it cannot learn a force strategy, because it has never observed a force. Whatever it learns about contact, it learns indirectly from pixels: the wrist camera view of a peg that stopped moving.

The trap that eats a day: a jam looks like success in the recorded data

Leader-follower teleoperation on an SO-100 gives the operator no force feedback. When the follower stalls against the rim of a hole, the operator keeps moving the leader, because the leader moves freely. LeRobot records the leader pose as action and the follower pose as observation.state. So the episode ends up containing commanded positions the arm never reached, sometimes for a second or more. The policy dutifully learns to command exactly those unreachable positions, and at rollout you get a servo pushing into a wall until the overload protection trips. If your rollouts end with a joint that stops short or an arm that twitches then sags, check the action-minus-state gap in the offending episodes before you touch a hyperparameter. See joint stops early and arm twitches then sags.

Do not chase torque with voltage

The obvious reaction to a stalling insertion is to give the servos more power. The SO-100 and SO-101 use 7.4 V STS3215 servos; the SO-ARM100 repository lists a stall torque of 16.5 kg.cm at 6 V for that variant and 30 kg.cm for the separate 12 V version. Feeding 12 V into 7.4 V servos destroys them. If you need more torque, buy the 12 V motors and the matching supply, do not re-label the one you have.

What the contact-rich literature actually does instead

It is worth looking at what the systems with high insertion success rates have in common, because the answer is consistent and it is not "a bigger model". They add a sensing or control channel that the SO-100 does not have.

SystemWhat it addsReported result
Off-the-shelf assembly cell benchmark (2021)Hybrid force/motion control plus 2D and 3D pattern matching, on NIST Assembly Task Board #1 partsUSB 100 percent, RJ45 96, waterproof 98, DSUB 100, over 50 trials each; mean cycle times 28.0 to 33.6 s. Force control widened the tolerance area over pure position control on every peg type.
IndustReal (2023)Sim training with signed-distance-field rewards and sampling-based curricula, deliberately without force/torque sensors83 to 99 percent over 600 real trials on a Franka Panda with a wrist RGB-D camera. Before the algorithmic work, insert policies reached about 12 percent.
SERL (2024)Online RL in the real world with an impedance controller underneathPCB board assembly, cable routing and object relocation learned in 25 to 50 minutes of training per policy
HIL-SERL (2024)Human corrections during RL, with an impedance controller at 1000 Hz taking 10 Hz setpoints from the policyRAM insertion 100 percent over 100 trials. Same task: Diffusion Policy on 200 demos 27 percent, HG-DAgger 29, plain behaviour cloning 12.
ACT on ALOHA (2023)50 Hz bimanual teleoperation, action chunking and temporal ensembling. No force sensing.Slot Battery 96 percent, Slide Ziploc 88 percent, but Thread Velcro fell from 92 percent at the first stage to 20 percent at the end.

The HIL-SERL detail is the one to sit with. Their low-level controller is an impedance controller running at 1000 Hz that accepts 10 Hz setpoints from the policy, with the position error clamped so the spring-damper cannot generate an unbounded force on contact. The neural network is not doing the contact handling. It is nudging the equilibrium point of a spring that handles contact for it, a thousand times per second. Nothing in the SO-100 stack plays that role, which is why behaviour cloning on this hardware has to solve a harder problem than the same algorithm solves on a Franka.

The other useful reference point is the pure geometry. IndustReal's peg set is round and rectangular pegs with maximum dimensions of 8, 12 and 16 mm at 0.5 to 0.6 mm clearance, and the NIST board it draws from includes round pegs at 4, 8, 12 and 16 mm plus USB, RJ45, waterproof and DSUB connectors. The board designs, CAD and STL files are free downloads from NIST, so you can print a real benchmark instead of inventing one, and the public dataset directory is a reasonable place to look for what other people recorded against similar targets.

Which of the five trainable policies handles insertion best

The AY-Robots policies page showing the five trainable policies side by side with parameter counts, GPU tier, inference latency per action step and minimum episode counts
The /policies comparison table. For contact-rich work the column that decides the outcome is inference latency, not parameter count.

The honest answer is that latency decides this, not architecture. LeRobot records at 30 fps by default, which means each recorded action step is 33 ms of real time. A policy that needs longer than 33 ms to produce an action cannot react within one step of the data it was trained on, no matter how good it is. Combine that with the action chunking defaults and you get the table below.

PolicyInference per action stepChunk predictedSteps executed per callOpen-loop window at 30 fpsCeiling if you re-plan every step
ACT20 mschunk_size 100n_action_steps 1003.33 sabout 50 Hz
GR00T N1.7152 msaction_horizon 40 on the base checkpoint--execution-horizon default 160.53 sabout 6.6 Hz
GR00T N1.5165 msnot documented in the N1.7 repositorynot exposed in the training formnot applicableabout 6.1 Hz
SmolVLA245 mschunk_size 50n_action_steps 501.67 sabout 4.1 Hz
Pi0.5485 mschunk_size 50n_action_steps 501.67 sabout 2.1 Hz

Read the fifth column as "how long the arm moves blind". A peg approach and mate on a small arm takes on the order of one to three seconds. With ACT's shipped defaults the entire insertion happens inside one chunk, from a single observation, with no chance to correct. That is not a subtle effect. It is the difference between a policy that nudges its way in and one that runs a memorised trajectory and hopes.

ACT wins on latency, not on cleverness

At 20 ms per action step, ACT is the only one of the five that fits inside a 33 ms control period, so it is the only one you can genuinely run closed loop at the rate the data was recorded. Two flags get you there. Lowering n_action_steps shortens the blind window directly. Turning on temporal ensembling smooths the seams between chunks, but LeRobot ships temporal_ensemble_coeff as None and its config validation forces n_action_steps to 1 when you enable it, because the model has to be queried every step to form the ensemble.

bash
# closer to closed loop: predict a long chunk, commit to a short slice of it
lerobot-train \
  --policy.type=act \
  --dataset.repo_id=$HF_USER/so100_insert_usb \
  --policy.chunk_size=100 \
  --policy.n_action_steps=10 \
  --steps=100000 \
  --batch_size=8 \
  --output_dir=outputs/train/act_insert

# or full per-step re-planning with temporal ensembling (ACT paper used 0.01)
#   --policy.temporal_ensemble_coeff=0.01 --policy.n_action_steps=1
lerobot main defaults for reference: steps 100000, batch_size 8, seed 1000. The platform's ACT trainer sends batch 8 and 100000 max steps as well.

The cost is real: querying the model ten times more often means ten times the compute at rollout, and on a 20 ms model that is still affordable. The ACT paper's own ablation shows why the chunk exists in the first place. Averaged over their simulated settings, success went from 1 percent at chunk size 1 to 44 percent at chunk size 100, then tapered slightly above that. Short chunks fight compounding error; long chunks fight contact. Insertion sits exactly on that trade-off, which is why the default is wrong for it in one direction and 1 is wrong in the other.

GR00T N1.7 exposes the knob by name

GR00T N1.7 is the one model here that names the receding horizon in its CLI. The Isaac-GR00T repository renamed the old --action-horizon flag to --execution-horizon precisely to separate "how many actions the model predicts" from "how many it executes before re-planning". The base nvidia/GR00T-N1.7-3B checkpoint uses action_horizon 40, the documented default execution horizon is 16, and the repository's own SO100 example runs with --execution-horizon 16. N1.7 also moved to a relative end-effector action space and a flow-matching DiT head that the repository documents as dropping from 32 to 16 diffusion layers between N1.6 and N1.7. The platform lists it at 152 ms per action step against 165 ms for N1.5, so the newer model is also the quicker one.

bash
# Isaac-GR00T, examples/SO100/README.md (main, 24 Aug 2026)
uv run python gr00t/eval/open_loop_eval.py \
  --dataset-path examples/SO100/finish_sandwich_lerobot/izuluaga/finish_sandwich/ \
  --embodiment-tag NEW_EMBODIMENT \
  --model-path /tmp/so100_finetune/checkpoint-10000 \
  --traj-ids 0 \
  --execution-horizon 16 \
  --steps 400
Open-loop evaluation against a recorded trajectory. Drop --execution-horizon toward 8 to see how much of the motion depends on re-planning.

Pi0.5 is the slowest, and has the most interesting answer for it

Pi0.5 represents actions with flow matching rather than discrete tokens, and the pi0 paper is explicit about why: flow matching lets the model handle high-frequency action chunks up to 50 Hz and dexterous tasks that the authors say pose a major problem for autoregressive VLAs. Pi0.5 keeps that structure, pre-training with discrete FAST tokens and then attaching the flow-matching action expert during post-training for finer action granularity. The theory is right for contact. The practice on this platform is that each action step costs 485 ms, which is roughly fifteen recorded frames at 30 fps.

Real-Time Chunking is in the version you are running

Physical Intelligence's real-time chunking generates the next chunk while the current one is still executing, freezing the actions that are guaranteed to run and inpainting the rest, and it works on any diffusion or flow policy with no retraining. LeRobot ships it: src/lerobot/policies/rtc/configuration_rtc.py exists in tag v0.5.1 with execution_horizon 10, max_guidance_weight 10.0 and a linear prefix-attention schedule, wired into the Pi0.5 config as rtc_config. Note the version difference: in v0.5.1 the enabled flag defaults to False, while on main it defaults to True. A 485 ms model against a 333 ms execution window is exactly the regime RTC was designed for, so if you are running Pi0.5 on contact work, this is the first thing to switch on.

The AY-Robots head-to-head comparison page for GR00T N1.7 against Pi0.5, showing parameters, GPU tier, dataset format and inference latency in a single table
GR00T N1.7 against Pi0.5 side by side. For insertion the deciding rows are inference latency and the dataset format each one demands.

For completeness: SmolVLA sits in the middle at 245 ms with chunk_size 50 and n_action_steps 50, and it is the cheapest of the four pretrained models to iterate on because it fits a 24 GB card. It is a good choice for testing whether your demonstrations contain a learnable strategy at all, before you spend an A100 run on the same data. The ACT against GR00T N1.7 comparison is the one worth reading if you are deciding between the extremes of that latency range.

Recording insertion demonstrations a policy can learn from

Contact-rich data has failure modes that pick-and-place data does not. The list below is the order that has actually saved time, and none of it needs hardware you do not already have. If you have never recorded an episode before, start with record your first dataset and come back.

  1. 1
    Fixture the target, then randomise the part

    Bolt or tape the receptacle down so its pose is constant, and randomise the starting pose of the part being inserted. This is what ALOHA did (targets randomised along a 15 cm reference line) and what the off-the-shelf benchmark did with nests allowing about +/-3 mm and +/-5 degrees. Randomising both ends at once on a five-joint arm with no force sensing is how you end up on policy only works in one setup.

  2. 2
    Add a wrist camera and point it at the mating face

    The gripper is the only place the policy can see contact from. A wrist view is what lets it distinguish 'touching the rim' from 'in the hole', since no other channel carries that information. Two views is the usual minimum: one overview for approach, one wrist for the mate.

    bash
    lerobot-record \
      --robot.type=so100_follower \
      --robot.port=/dev/tty.usbmodem58760431541 \
      --robot.id=black \
      --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}
      }' \
      --teleop.type=so100_leader \
      --teleop.port=/dev/tty.usbmodem58760431551 \
      --teleop.id=blue \
      --dataset.repo_id=$HF_USER/so100_insert_usb \
      --dataset.num_episodes=60 \
      --dataset.single_task="Insert the USB plug into the socket" \
      --display_data=true
  3. 3
    Slow the mating phase down, not the approach

    LeRobot's defaults are fps 30, episode_time_s 60 and reset_time_s 60. Move quickly to a pre-insert pose, then spend most of the frames on the last two centimetres. Frames spent on the approach teach the model nothing it cannot get from ten other episodes; frames spent on the mate are the only ones that carry the correction behaviour.

  4. 4
    Record recoveries on purpose

    Deliberately miss, back off 5 mm, re-approach at a slightly different angle, then succeed. Without recovery examples in the data, a behaviour-cloned policy has no representation of 'this is not going in' and will keep pressing. This is the cheapest available substitute for the online corrections that HIL-SERL uses, and it is also what keeps you off policy freezes mid-motion.

  5. 5
    Replay before you train, and look for the stall

    Replay an episode on the arm and compare the commanded action against the recorded state. A sustained gap means the follower was jammed while the leader kept moving. Delete those episodes or re-record them. This is the single highest-value check in contact-rich data collection.

    bash
    lerobot-replay \
      --robot.type=so100_follower \
      --robot.port=/dev/tty.usbmodem58760431541 \
      --robot.id=black \
      --dataset.repo_id=$HF_USER/so100_insert_usb \
      --dataset.episode=7
Fine-tuning a VLA for insertion on an SO-100
What this buys you
  • No force/torque sensor, no impedance controller and no calibrated cell. A wrist camera and demonstrations are the entire apparatus, and IndustReal deliberately avoided F/T sensors too, citing cost, noise and fragility.
  • Language conditioning means one checkpoint can cover several targets in the same fixture, instead of one hand-tuned search routine per connector.
  • Iteration is cheap. A run on the A100 or H100 tier is about 4 to 12 USD, and the 24 GB tier used by SmolVLA and ACT is about 1 to 3 USD, so a wrong hypothesis costs less than lunch.
  • ACT infers in 20 ms, which is the only latency on the list that permits per-step re-planning during the mate. It also trains from scratch, so there is no gated base model to request access to.
  • Minimum episode counts are low enough to be practical: 30 for SmolVLA, 50 for ACT, GR00T and Pi0.5.
What it costs you
  • Nothing in the observation says 'jammed'. Recovery has to be demonstrated, and if it is not in the data it will not appear in the policy.
  • The shipped chunk lengths make the mating phase open loop. You have to change them, and changing them costs rollout compute.
  • Stage-wise compounding is severe on contact tasks. ACT's Thread Velcro run went from 92 percent at the first stage to 20 percent at the last.
  • The strongest published insertion results come from RL with human corrections and an impedance controller, not from behaviour cloning. Expect a gap and plan around it.
  • GR00T and Pi0.5 are cloud-only on this platform, so a contact-speed loop over the public internet is not an option for those two.

Two ways to get from demonstrations to a policy that inserts

Everything above is reproducible from open repositories. You need the arm, a leader arm or an on-screen pad, two USB cameras and a GPU you can rent or own. The install and record path is documented in the LeRobot repository; the version numbers below are what main resolved to on 24 August 2026.

bash
# lerobot main was version 0.6.2 on 24 Aug 2026
git clone https://github.com/huggingface/lerobot.git
cd lerobot
pip install -e '.[core_scripts,training]'   # dataset + hardware + viz + training extras

lerobot-find-port                 # identify the follower and leader serial ports
lerobot-setup-motors --help       # write servo ids one motor at a time
lerobot-calibrate --help          # homing offsets and joint ranges

# record, then train, then roll out
lerobot-record  ...               # see the two-camera example above
lerobot-train   --policy.type=act --policy.n_action_steps=10 ...
lerobot-eval    --help

For GR00T you use a second repository. NVIDIA's Isaac-GR00T is the reference implementation, its fine-tune entry point is a tyro CLI, and its VLM backbone nvidia/Cosmos-Reason2-2B is a gated model on Hugging Face that every GR00T checkpoint loads on first use, so you have to request access before anything runs. GR00T's loader also wants a LeRobot v2.0 or v2.1 dataset; hand it a v3.0 dataset and it crashes, which is the single most common first-run failure.

  • You own the GPU scheduling, the checkpoint storage and the dataset conversion.
  • You get every flag, including the ones the hosted form does not expose.
  • GR00T's fine-tune launcher exposes no seed, so those runs are not bit-for-bit reproducible. LeRobot's default seed is 1000.
  • Budget a day for the first end-to-end pass, most of it on serial ports, camera indices and dataset versions rather than on the model.
The AY-Robots training matrix at /train with five policy rows and four robot arm columns, every cell linking to the specific guide for that model and arm combination
The find-your-combination matrix. Each cell is a guide for that exact pairing, for example ACT on SO-100 or GR00T N1.7 on SO-100.

Where this platform does not help

Being useful about contact-rich work means being clear about the parts of it this stack does not solve. None of the following is fixed by choosing a different model or recording more episodes.

  • There is no force feedback anywhere in the loop. The servos expose Present_Load and Present_Current, the robot class does not read them, and none of the five policies has an input for them if it did.
  • There is no compliance to tune. No impedance controller, no admittance controller, no remote centre of compliance at the wrist. Compliance on this arm is whatever the printed parts and the gearbox happen to give you.
  • Remote inference is not viable for the mating phase. The control loop is already 20 to 485 ms per action step depending on the model, and adding public-internet round trips turns a working policy into a hesitant one. It is fine for slow pick-and-place. It is wrong for fast reactive contact.
  • Three of the five models are cloud-only here. GR00T N1.7, GR00T N1.5 and Pi0.5 all need an A100 or H100 80 GB tier; SmolVLA and ACT also run locally on a 24 GB card, which for contact work is an argument in their favour beyond cost.
  • The dataset format is a real constraint. GR00T wants LeRobot v2.0 or v2.1 and crashes on v3.0; Pi0.5, SmolVLA and ACT want v3.0. Converting down is a step, not a checkbox, and it is the reason for dataset rejected as v3.
  • Nothing here gives you a spiral search. The classical fallback when a peg will not seat is a small force-guided spiral, and the benchmark data shows why it works so well on round pegs. Reproducing that behaviour from demonstrations alone is possible but you have to demonstrate it, many times, deliberately.

Five policies, one comparison table

Parameters, GPU tier, inference latency per action step, minimum episodes and dataset format for GR00T N1.7, GR00T N1.5, Pi0.5, SmolVLA and ACT. For contact-rich tasks, latency is the column that decides.

Compare the policies

What success rate is a reasonable target

Calibrate expectations against published numbers rather than against a demo video. An industrial cell with force control, sub-0.1 mm camera calibration and roughly 0.14 mm control accuracy reached 96 to 100 percent on connector insertion. A sim-to-real system on a Franka with no force sensing reached 83 to 99 percent over 600 trials, after specific algorithmic work that lifted naive insert policies from about 12 percent. Behaviour cloning on a bimanual 50 Hz teleoperation rig got 96 percent on slotting a battery into a spring-loaded compartment and 20 percent on threading a velcro tie.

On a 110 to 150 EUR arm with a 0.088 degree encoder step and no force channel, a chamfered target with a millimetre or more of clearance is a task that fine-tuning can plausibly get into the high tens of percent. A sub-half-millimetre press fit is not a data problem, it is a hardware problem, and the correct response is to change the part, add a chamfer, or add compliance at the end effector with a piece of foam or a sprung finger. Design the task down to the arm before you scale the dataset up. If you want the wider background on how these models are built, the VLA overview and the pi-zero flow matching article cover the architecture side, and collecting high-quality VLA training data covers the recording side in more depth.

Can I read servo load and feed it to the policy as an extra state dimension?

You can read it. LeRobot's Feetech register table defines Present_Load at address 60 and Present_Current at 69 for the sts3215, so the value is available over the bus. What you cannot do is feed it to any of the five trainable policies unchanged, because their observation space is camera images, a joint-state vector and a language instruction. People work around this by appending the value to observation.state, which means retraining with a wider state vector and accepting that the pretrained normalisation statistics no longer match. It is a real project, not a flag.

Which policy should I try first for an insertion task?

ACT, for latency reasons. At 20 ms per action step it is the only one of the five that can re-plan inside the 33 ms period of a 30 fps loop, and it needs 50 episodes and a 24 GB card, so a run costs roughly 1 to 3 USD. Train it with n_action_steps well below the default 100 so the mating phase is not open loop. If ACT cannot learn the task at all, that is usually evidence about the demonstrations rather than about the model.

Does a longer action chunk help or hurt insertion?

Both, at different ends. The ACT paper's ablation shows success climbing from 1 percent at chunk size 1 to 44 percent at chunk size 100 averaged over their simulated settings, because long chunks fight compounding error. But a long chunk that is also fully executed means the arm moves blind, and on contact tasks blind is exactly wrong. The workable setting is a long predicted chunk with a short executed slice: keep chunk_size high, drop n_action_steps.

Why is Pi0.5 so slow if flow matching is meant to be good for dexterity?

The architecture argument is about expressiveness, not about wall-clock speed. Flow matching lets the model represent continuous action chunks at up to 50 Hz, which is why the pi0 authors chose it over autoregressive token prediction for dexterous tasks. The 485 ms figure is the cost of running a roughly 3 B parameter model with a PaliGemma backbone through several denoising steps. Real-time chunking exists precisely to hide that latency, and it ships in the LeRobot version this platform pins.

Is remote inference workable for assembly tasks?

For the approach, yes. For the mate, no. The control loop is already 20 to 485 ms per action step before any network hop, and public-internet round trips on top of that produce a policy that hesitates at exactly the moment it should be correcting. If the task tolerates a slow, deliberate insertion with generous clearance, hosted inference is fine. If it needs reactive correction against contact, the model has to sit next to the servos.

What does a realistic insertion benchmark look like if I want to compare fairly?

Use the NIST Assembly Task Boards. There are four of them, they cover peg insertion, gear meshing, connector insertion, nut threading, belt and pulley work and cable routing, and NIST publishes fabrication instructions, CAD and STL files for free so you can build the same artefact other papers used. Board #1 alone gives you round pegs at 4, 8, 12 and 16 mm plus USB, RJ45, waterproof and DSUB connectors, which is a much better spread of difficulty than one hand-made target.

Ready for high-quality robotics data?

AY-Robots connects your robots to skilled operators worldwide.

Get Started