Project · Imitation Learning · Robot Manipulation

AIC Connector Insertion Private repo — code cannot be shared

Team entry to Intrinsic's AI for Industry Challenge: teaching a simulated UR5e to plug fiber-optic connectors into a networking task board with a fine-tuned vision-language-action model.

Built with Abhijit Makhal and Amrit Saini. The repo is private, so this page documents the system, the experiments, and the results.

ROS 2 · LeRobot · SmolVLA · Gazebo · Python · C++

01 / Overview

Overview

The challenge is dexterous cable insertion: a UR5e arm in Gazebo picks up SFP and SC fiber-optic connectors and seats them in ports on a task board. It is a peg-in-hole problem that demands sub-centimeter precision under randomized start poses, impedance settings, and force disturbances.

The organizers run a fixed C++ evaluation stack, and participants submit a single Python policy that answers one ROS 2 action. Scoring rewards proximity, smoothness, and above all insertion depth, and punishes collisions.

We took a learned approach: collect demonstrations from a ground-truth oracle policy, convert them into a LeRobot dataset, and fine-tune SmolVLA, a small vision-language-action model, to imitate them. Over a documented experiment campaign the policy went from the provided ACT baseline's 38.2 to 110.3, close to three times the baseline.

The task at the ceiling: a full SFP insertion on a randomized board (93 of about 100)
02 / System

System

System architecture: the organizers' C++ evaluation stack (aic_engine, aic_controller, aic_adapter, Gazebo) exchanges camera, wrench, and joint-state observations and 6-DOF twist commands with the team's Python participant model over the /insert_cable ROS 2 action
Two components, one action interface

Everything meets at one boundary. The evaluation side owns the physics: an engine that orchestrates and scores trials, an impedance controller, and a sensor-fusion adapter around a Gazebo simulation of the arm and task board.

Our side is a ROS 2 lifecycle node that dynamically loads a Policy and answers the /insert_cable action. It consumes camera images, wrench readings, and joint states, and streams back 6-DOF Cartesian twist commands.

The stack runs on ROS 2 Kilted over the Zenoh RMW, and the submission executes inside a resource-limited container with a 30-second model-discovery budget. Heavy imports can silently kill a run.

Everything the policy sees: left / center / right wrist cameras, consumed at 288 by 256 pixels. The policy gets no third-person view and no object poses
03 / Data Pipeline

Data & Training Pipeline

Four-stage imitation learning loop: generate randomized trial configs, roll out the CheatCode oracle in Gazebo to produce rosbags and scores, filter and convert successes into a LeRobot dataset, fine-tune and evaluate SmolVLA, then iterate
The imitation-learning loop

Demonstrations come from CheatCode, an oracle policy that reads ground-truth transforms the real submission never sees.

Stage one generates randomized trial configs covering start-pose jitter, impedance randomization, injected force disturbances, and scene clutter, so the dataset covers the perturbations evaluation will throw at us. Stage two rolls the oracle through Gazebo, recording rosbags and scores.

Stage three filters for successful episodes and converts them into a LeRobot dataset, finite-differencing the oracle's pose commands into the same 6-DOF twist action space the policy will emit. Stage four fine-tunes SmolVLA, sends it back through evaluation, and the loop repeats.

“Randomized” covers a lot, so here is the full inventory. Each form of variation is an independent, seeded block in the config generator, switchable per collection run:

  • Board & rail placement — task-board pose shifted plus or minus 1 to 2 centimeters; the target rail slid and yawed plus or minus 0.03 to 0.12 radians along its channel.
  • Scene clutter — each of the board's 13 rail slots probabilistically populated with distractor cards, ports, and fixtures, so the target always shares the view with other objects.
  • Grasp jitter — the plug's pose in the gripper perturbed plus or minus 2 millimeters and plus or minus 0.04 radians, matching the documented evaluation envelope.
  • Start pose — per-joint Gaussian offsets on the arm's home configuration (sigma of 5 degrees, clipped at plus or minus 10 degrees).
  • Correlated action noise — DART-style temporally correlated noise on the oracle's commands during the approach phase (sigma of 2 millimeters and 0.005 radians, with a 0.5 second time constant), disabled near contact so demonstrations stay clean where precision matters. The expert's recoveries become training data.
  • Force disturbances — one to three random shoves of about 5 newtons applied to the wrist mid-approach through the physics engine.
  • Impedance randomization — controller stiffness scaled by 0.7 to 1.3 times and damping by 0.8 to 1.2 times per trial, so recovery behavior is learned under a range of contact dynamics.
  • Language — every episode carries a minimal task-only prompt matched to its scene. Scene-rich prompts measurably hurt precision, and the evaluator prompts minimally anyway.
Nine training episodes at once, showing the randomization the dataset actually contains: varying targets, board pose, clutter, grasp jitter
Stage two in action: the oracle collecting a demonstration on a randomized, cluttered board

Key Insight

The SC connector trial scored near zero for every policy, and the reason turned out to be the simulator itself: the SC plug's keying tabs collide with interior port geometry 3 millimeters wide, so full insertion is physically impossible. Even the ground-truth oracle caps out around 40 points, and a single “full insertion” filter threshold was discarding 100% of SC demonstrations.

Switching to per-archetype thresholds, 35 for SC and 75 for SFP, let partial-insertion SC demos into the dataset, and partial demos teach the policy to engage instead of hover. The change lifted the SC trial by 56% without hurting SFP.

The decisive experiment: the same oracle seats SFP fully (top) while SC aligns to 0.6 millimeters and stops at the port wall (bottom)
04 / Workflow

Engineering Workflow

Fourteen dataset→train→eval loops in eleven days came from a deliberate working method: pair-engineering with an AI coding agent (Claude Code). The agent operated the experimental apparatus, covering simulator bring-up, batch collection runs, training launches, and checkpoint evaluations, and monitored the logs in real time.

I set the hypotheses, reviewed the same evidence (scoring files, force traces, evaluation videos), and made the calls. Every change got run, watched, and measured before it was written down.

One standing rule made the pairing work: any procedure worth doing twice was promoted into a deterministic, seeded, one-command tool. That covered config generation, the evaluation harness, checkpoint scans, and the recording rig behind the videos on this page.

Determinism also let the agent iterate at a cadence humans don't sustain. Starting, interrogating, and tearing down the simulator dozens of times an hour surfaced the startup races and stale-state quirks that slow manual cycles hide.

Those included zombie transport nodes surviving between runs, silently cached policy files, and a randomization block that turned out to be a silent no-op. Each diagnosis landed back in the tooling as a permanent guard.

Collection and training batches were resumable and ran unattended overnight, with the agent analyzing results as they arrived. Mornings began with a completed analysis and a decision about the next experiment, which kept roughly one full experimental loop per day sustainable on a single consumer GPU.

05 / Results

Results

Bar chart: total score rises from 38.2 for the ACT baseline through 69.8 and 95.3 for SmolVLA v3.1 and v4 to 110.3 for v6, against a dashed CheatCode oracle ceiling of 244.3
Each version is a dataset or training change, scanned across checkpoints

The final dataset was 203 episodes (53,611 frames): SFP demonstrations, a slice targeting the hardest port, and 20 partial-insertion SC demos admitted by the per-archetype filter. Every model was scanned across training checkpoints before judging; the best run peaked at 50k steps and measurably overtrained by 60k.

The negative results were kept on the books too. Default image augmentation regressed every checkpoint (too aggressive for a sub-centimeter task), and three attempts at hand-coded descent overrides all scored worse than the pure learned policy: the remaining gap is lateral precision, not descent timing.

Along the way, compressed-camera republishing cut per-trial bags from 7.4 gigabytes to 0.75 gigabytes, and a host/container launch fix took SC data collection from zero usable episodes to 18 in one sweep.

The best model's complete three-trial evaluation, re-run fresh eight weeks later: 110.8 vs the original 110.3. The result reproduces
06 / Team

Team

Tyler Johnson
Lead — trial randomization framework, C++ engine fixes, evaluation orchestration, and the fine-tuning experiment campaign from baseline to the 110.3 best
Abhijit Makhal
The four-stage data-collection pipeline (config generation, rollout orchestration, LeRobot conversion) and the host↔container integration debugging
Amrit Saini
SmolVLA and Pi0 inference policies and the model training workflow the fine-tuning campaign was built on