Task 1. Dataset Exploration & Quality Audit

For this task I used three different datasets: lerobot/aloha_sim_insertion_human and lerobot/aloha_static_coffee for teleoperation and n3puiol/epic_kitchens_100_lerobot for egocentric.

Why two datasets for teleoperation?

I wanted to compare and see the tradeoffs between two different methods of data collection from the same robot platform. (Simulation v. Real)

QUALITY AUDIT: TELEOP raw joint positions estimate encoder quantum Savitzky-Golay fit smooth derivatives threshold above noise floor sets the floor for every derivative downstream DROP impossible velocity, frozen reading, spikes KEEP & LABEL effort saturation, joint-limit contact
FRAMES FLAGGED, BY RULE simulation real robot position spike 519 867 above velocity spec 151 0 frozen reading 0 63 jerk spike 25 52

Simulation does not respect the hardware's physics bounds, so it produces motion the real arm cannot do. The real robot has the opposite problem, like a sensor repeating a stale reading.

NOTE: MOST SIM DEFECTS ARE FALSE ALARMS 519 what sim scored (no noise floor) 76 what is really there (real robot's noise floor) spikes flagged in sim 85% were noise
Simulation scored a worse defect rate than the real robot, which makes no sense. The spike test ignores anything smaller than one encoder step. Simulation has no encoder, so nothing gets ignored and it flags tiny numerical wobble as real spikes.

What does sim lack? Encoder quantization, sensor freezes, state-action latency, real actuator limits, torque saturation behavior.

What I would filter

  1. Hardware velocity limit (sim only): there are 151 frames that peak 5.22 vs 3.0 rad/s which is impossible with the given hardware. Clip them before any sim2real transfer.
  2. Gripper scale mismatch: the gripper's tracking error is 29.3x the arm's in sim and 3.7x on real hardware, because the two channels live on different scales. Normalise the gripper separately so it does not dominate the loss.
  3. Frozen readings: there are quite a few bit identical channels that assume our arm is stale when it is not. We should interpolate so models don't misunderstand.
  4. State/action lag: 46/3/1 episodes sit at a lag of 0/1/2 frames, so realign actions with the correct state timestamps.
  5. Effort outliers: 1,359 frames sit at the 99.9th percentile. Label them as contact rather than delete, and drop only what is physically unreasonable.

Egocentric

For egocentric I used two sources: the two wrist cameras on lerobot/aloha_static_coffee and the head cam from n3puiol/epic_kitchens_100_lerobot.

Why two sources for egocentric?

Same reason as teleop. A wrist cam moves because the robot commanded it, so I already know the motion. A human head cam moves because a person turned their head, so I have to guess the motion from pixels. Those are two different problems and I wanted both.

HOW MUCH SHARPNESS EACH CAMERA LOSES WHEN IT MOVES no loss strong loss left wrist right wrist human head overhead static low static sim overhead
Blur correlates with the action on a wrist camera, not on a fixed one. So an absolute sharpness threshold is really a fast-motion detector: it deletes every reach and retract, biasing the data toward a still robot.
FRAME PIPELINE decode video sharpness, exposure, entropy estimate ego-motion fit sharpness per camera tag the residual, keep the frame can fail silently on violent head motion and return nonsense, so it needs a sanity bound
The question becomes relative: is this frame blurrier than its own speed predicts?
Sharpness against camera motion, fitted per camera stream
The fits behind the chart above.

What quality issues are specific to egocentric?

  1. Blur is caused by the action: sharpness falls with camera speed at a slope of −0.48 on a wrist cam versus −0.09 on a fixed one. The blurriest frames are the reach and the retract, which are the frames a policy most needs.
  2. The motion estimate can fail silently: 18 frames came back with a shift of 2507 px on a 224 px image. It does not error, it just returns nonsense, so it needs a sanity bound before anything trusts it.
  3. Auto-exposure hunting: 41 exposure shifts on the head cam and 0.68% of frames over 5% blown out. A fixed camera in a fixed room never does this.
  4. Clips are too short: median 23 frames at 12 fps, which is shorter than a single ACT chunk, so the episode cannot supply one training sample.
  5. Decoder stalls: 9, 6 and 3 duplicate runs across the three real streams. A repeated frame reads as a still camera and quietly poisons the motion estimate.
  6. Occlusion is normal, not a defect: a wrist cam is supposed to be full of gripper and object during a grasp. The real defect is a blocked lens.
  7. Letterbox padding: 41% of every sim frame is black bars, which made all 25,000 frames read as underexposed until I cropped to the active region.

How would your filtering criteria differ from the joint-state data?

  1. Threshold the residual, not the value: on joints a big number is a fault, on video a big blur is usually just speed. An absolute sharpness cut deletes every reach and retract and leaves a dataset of a robot standing still.
  2. Calibrate per camera, not once: one model covers all 14 joints, but sharpness floors run from 0.62 to 16.13 across cameras, so a shared threshold condemns one stream and excuses another.
  3. Tag and keep instead of repair or drop: a corrupted joint value poisons the label a policy regresses onto, so it has to go. A blurry frame is still a truthful observation with a correct action beside it.
  4. Trust the input less: encoder velocity is always valid, camera motion is an estimate that can be wrong. The joint pipeline never has to sanity check its own measurement.
  5. Budget for it: joint audit is about 0.005 s per episode, frame scoring is about 2 ms per frame, so vision runs once and gets cached to parquet instead of rerun per experiment.
Flagged frames against the sharpest frames from the same EPIC-KITCHENS clips
Flagged against sharpest, same clips.
Blur anomalies flagged on the wrist camera streams

Task 2. Labeling & Annotation Design

Schema lives in configs/label_schema.yaml. I label at three levels because three different consumers need three different things.

LABEL STACK human writes it derived automatically EPISODE what happened 3 written instructions, outcome, failure mode, operator and rig id scene config quality score and flags, straight from the Task 1 audit SEGMENT when each phase happened align vs place, recover spans. the ambiguous 20% grasp and release from gripper aperture, contact onset from the tracking-error step, approach and retract from the path the deterministic 80% FRAME kept thin contact, phase id filled down from segments, quality. At 50 Hz frames are 20 ms apart, so dense human labels mean paying someone to label the same image 20 times.

Which boundaries can I derive instead of annotate?

Most of them, which is the whole budget argument. These are pre-annotations, not finished labels. They land in the tool already drawn so an annotator confirms or drags a boundary instead of creating one.

What tool?

Label Studio, because it syncs a time-series channel with video in one view, so the annotator watches the gripper trace move with the footage instead of guessing. CVAT for pure video work, where track mode and ground-truth QA pay off. Pre-annotations always loaded, so annotators correct rather than create.

How do I measure inter-annotator agreement for motion labels?

Kappa is the wrong primary metric here. Cohen's and Fleiss' assume a fixed set of items every annotator classifies. Free temporal segmentation has no such set, since two people emit different numbers of segments at different boundaries. You can force it by discretising into frames and I do report that, but frame-wise kappa is dominated by the long easy spans and says almost nothing about boundary placement, which is the part that actually disagrees.

TWO SEPARATE QUESTIONS, TWO METRICS Did they agree on WHAT? Krippendorff alpha, nominal, frame-wise phase. Reported per category, never pooled. Did they agree on WHEN? Krippendorff alpha, interval, on the timestamps, so 3 frames off scores better than 30 frames off. Are boundaries drifting? Segmental F1 at 10, 25 and 50 percent overlap, plus an edit score for over-segmentation. Gates Ship the guidelines at alpha 0.75 or better. Re-audit anything under 0.67.
High F1 at 10% overlap with low F1 at 50% means the guideline is vague, not that the annotator is bad. Double-annotate a fixed 10% of the corpus continuously, not once at onboarding.

What do I label for egocentric?

Existing schemas, not invented ones, so labels stay comparable with public corpora and a pretrained detector can bootstrap them.

  1. Object interactions: the 100DOH per-hand format of box, side, contact state and contacted-object box. A pretrained detector proposes, a human corrects.
  2. Dense contact masks: EgoHOS for left hand, right hand, first and second order objects. Also from a pretrained model.
  3. Hand-eye phases: the Ego4D four keyframes, pre, contact, point-of-no-return, post. PNR is the frame after which the outcome is already decided, which is exactly what a success predictor should key on.
  4. Failure moments as instants, not spans: a timestamp plus a 0.5 s window. Failures are near instantaneous, and forcing annotators to invent a start and an end destroys agreement.
  5. Gaze proxy: no eye tracker, so either a fixed centre prior, reasonable on a wrist cam rigidly aimed at the end-effector, or the projected end-effector position from forward kinematics. The second is a task-relevance map, not gaze, and I name it that way.

Auto-label first or the budget never closes. HD-EPIC measured 263 annotations per minute of video. Detector bootstrapping, CVAT track mode and VLM hindsight relabelling at 2.2x throughput make that survivable. Auto-labels are training data, never evaluation data.

How do I align egocentric labels with the joint-state labels?

WHERE THE TWO STREAMS DISAGREE, THAT IS THE LABEL video sees contact video sees nothing gripper closed gripper open agree merge into one contact event within 3 frames, 60 ms at 50 Hz empty grasp closed on nothing bumped the object touched it without grasping nothing happening The joint timestamp wins when they agree: lower latency, no exposure ambiguity.
Empty grasp and bumped-the-object are failure labels neither stream produces on its own. That is the strongest argument for keeping both modalities in one labelling pipeline.

Curation has to protect this. Task 3 never deletes interior frames, so a label timestamp stays valid after curation, and every emitted segment records its source episode and frame range.

Task 3. Curation Pipeline

In: LeRobot v2/v3 or ALOHA HDF5. Out: a LeRobot v3 dataset plus a manifest with the config, the fitted thresholds and a per-episode decision log, so every drop is traceable.

CURATION PIPELINE CALIBRATE fit thresholds SCORE joint + video SELECT reject episodes PLAN trim/repair/split SMOOTH zero-phase WRITE verify or raise Episode rejects happen at SELECT, before any re-encoding, so nothing expensive runs on data that gets thrown away. Smoothing is zero-phase and offline only. It feeds QC and derivative estimates, never the observations a policy trains or runs on.

What gets rejected as a whole episode?

What gets dropped frame by frame, and what does not?

Dropped: impossible velocity, frozen readings, position spikes, jerk spikes, timestamp gaps. Kept: velocity outliers, joint-limit contact, effort saturation, tracking spikes. That second group is events, not defects, and dropping it leaves a dataset of free-space motion. Treating velocity outliers as defects cut 25 to 42 frames from 12 of 50 sim episodes, all of them the rapid initial reach.

The trap that breaks everything downstream

The obvious implementation is keep = ~bad then reindex. That quietly breaks any policy consuming contiguous windows, which is all of them: ACT, Diffusion Policy, LeRobot's delta_timestamps.

DELETE VS SPLIT DELETE AND RENUMBER bad a window here spans a 20 ms jump. Nothing errors. The policy learns the arm teleports. SPLIT INTO SEGMENTS segment A segment B Two real episodes. Fixed timestep preserved exactly.
Delete frame 300 of a 500-frame episode and every frame after it pairs with the wrong state, because the video still has 500 frames. Interior frames are never silently deleted.

So what happens to a bad run instead?

Joint defects and video defects are not treated the same

This is the core design decision. A joint defect breaks the dynamics, since the frames either side are no longer consecutive states, so the episode splits. A video defect ruins one observation while the dynamics stay intact, so the frames stay and get marked in an observation.quality channel. Training then picks drop, down-weight or keep. That choice differs between a VLA and a world model, so curation should not make it irreversibly.

WHAT THAT DECISION IS WORTH OR the two masks 79.9% kept 18 usable segments out of 7 episodes Treat them separately 97.7% kept 64 segments out of 49 episodes
Same data, same detectors. The only difference is refusing to let a blurry frame delete a perfectly good state transition.

Verified, not assumed

verify_alignment runs on every written segment and raises rather than warns. Seven checks pass on both corpora: loads with stock LeRobotDataset, timestamps uniform within every episode to about 1e-06 s, zero padded steps in 100-step ACT chunks, video frames equal to state rows across all four cameras, no NaN or Inf, quality channel present, every episode clearing the chunk size. Zero padding is the one that matters: it proves no interior frame was silently deleted.

EPIC-KITCHENS is audited but deliberately not curated. Median clip is 23 frames at 12 fps, under both the minimum segment length and an ACT chunk, so nearly every clip would be dropped whole. Pre-segmented human video belongs in a latent-action or world-model path, not an action-chunked BC path.

Task 4. Policy Evaluation

What do I actually measure?

How many rollouts do I need?

HOW WIDE THE ANSWER IS, BY ROLLOUT COUNT 20 rollouts 37 points wide 50 rollouts 25 points 200 rollouts 13 points At 20 rollouts, 18 successes and 15 successes are the same measurement.
A ±10% interval at roughly 70% success needs 81 rollouts. A ±5% interval needs 323. Detecting a real move from 70% to 80% at 80% power needs 294 per arm.

Unaffordable on hardware, so three things buy it back:

Success criteria

Written before running, mechanically checkable, time limited. Peg insertion: axis within 5 mm and 5 degrees, held at least 1 s, inside 30 s. Plus three training seeds minimum, the checkpoint fixed in advance since picking the best by eval success and reporting it is a leak, and the scorer blinded to which policy produced the rollout.

It works in sim and fails on the real robot. What now?

Cheapest first. The first two need no robot time and resolve most cases.

  1. Feed real frames offline and compare predictions against sim frames at matched state. Points to a perception gap.
  2. Replay a demo's actions open loop on both sim and hardware and compare realised state. Points to dynamics, which is fixed with system identification, not more data.
  3. Inject the measured 30 to 100 ms latency into the sim loop. If sim success falls to match reality, that was the answer.
  4. Per-step distance to the nearest training state in a learned embedding. Covariate shift looks like tracking fine for about 50 steps, then diverging.
  5. Check commanded against realised joint positions and camera extrinsics. Calibration is boring and it is the cause more often than anything above.

One candidate is findable from the data alone, before booking robot time: 151 sim frames exceed the ViperX velocity limit at a peak of 5.22 against 3.0 rad/s, versus zero on real hardware. A policy trained on that is being taught to command motion the arm cannot execute.

What does the egocentric stream change?

The wrist camera is the only stream recording what the policy could see at each decision, which is what makes failure attribution possible at all.

  1. Empty grasp: joints show the gripper closing and the arm lifting. The wrist cam shows jaws closing on air.
  2. Slip after grasp: often no joint signature at all. The object simply leaves frame mid-transport.
  3. Wrong target: a clean confident trajectory in joint space, gripper over the wrong object on camera.
  4. Visual-servo lock-up: the arm holds still, and the frame turns out to be saturated or smeared with no usable features.
  5. Near miss: scored as a success, but the alignment margin is visibly about 1 mm and the next trial fails.

The last one matters most. Success rate scores a 1 mm margin and a 10 mm margin identically, so a policy can degrade with no movement in the headline number. Alignment margin at the point-of-no-return frame is a graded signal with lower variance than a binary outcome, so it should detect the same change in fewer rollouts.

Bonus: I built the success detector, and it does not work

A frozen ImageNet ResNet-18 on wrist frames feeding a logistic probe, trained in seconds on CPU with no manual labels. The supervision is weak, not absent: episode position supplies the pseudo-labels, with the last 10% of an episode as 1, the first 25% as 0, and the middle excluded from training and scored at test.

AUROC 0.9995, AND STILL NOT A COMPLETION DETECTOR episode start episode end where a real detector fires where mine fires: 0.53 about 11 s early, then stays fired for the rest of the episode
The probe learned arm pose, which recurs mid-episode on a multi-stage task, not task completion. Shuffled-label controls sit at chance, so this is not split leakage. It is the real failure mode, and it took an explicit metric to see.

Three guards caught it, and all three were needed:

So it ships as a pre-filter, not an oracle: score every rollout, human reviews the uncertain band plus a random audit sample, track agreement. Validating it properly needs human-labelled failed rollouts, which by construction do not exist in a demonstration dataset.

Task 5. Model Adaptation

The brief says pick one, VLA or world model. I did both, because they want opposite things from the same pipeline, and that conflict constrains how Task 3 has to be built.

THE TWO CONSUMERS DISAGREE A VLA wants clean, successful, canonically framed demos. Failures and view diversity are noise to it. A world model wants coverage. Failures, contacts, recoveries. Those are where its dynamics are uncertain. vs So the pipeline tags, it does not delete. Hard-deleting what the VLA dislikes destroys the world model's best data.

Option A: the VLA

The curated output is already LeRobot v3, so π0 is the lower-friction target; OpenVLA needs a conversion hop into RLDS. Stock pi0_aloha_sim is the closest starting config for an ALOHA-topology arm. On the OpenVLA side, LoRA at rank 32 tunes 1.4% of parameters and is reported to match full fine-tuning, and OpenVLA-OFT's chunked action head reports 26x throughput and 3x lower latency.

What is most likely to silently break the training run?

Action normalisation. π0 rescales q01 to q99, OpenVLA bins that same range into 256 tokens. Both are wrong for absolute joint angles: clipping the outliers means the model can never emit certain joint positions at all.

How does egocentric video get preprocessed?

What breaks when a third-person pretrained model meets a wrist camera?

Viewpoint is one of the two most damaging perturbation axes for a VLA. LIBERO-Plus reports performance falling from 95% to under 30% under modest perturbations, viewpoint doing the most damage. A wrist camera is not a modest perturbation, it is a different imaging geometry.

  1. Spatial reasoning collapses: the camera frame is the end-effector frame, so "move left" is ambiguous without knowing wrist rotation. The pretrained prior is not merely absent, it is actively wrong.
  2. Scale and field of view mismatch: pretraining sees a whole workspace, the wrist sees a few centimetres, so "the red block" fills the entire frame.
  3. Constant self-occlusion: the jaws occupy a fixed region of every single frame and no third-person prior covers a large static occluder.
  4. Blur becomes a shortcut feature: sharpness tracks camera speed at −0.48 on the wrist versus −0.09 on a static view, so blur is predictive of the action. A model is free to lean on it instead of scene content, which then breaks when frame rate or exposure changes.
  5. No global context and no absolute frame: it cannot see whether the target is still on the table, and image coordinates stop mapping to world coordinates.

What I would do: keep both views as separate image tokens, feed history rather than a single frame since one frame is ambiguous about ego-motion, warm up the wrist encoder separately, match the coordinate convention, then ablate wrist-only against both.

Option B: the world model

Supervision is self-supervised, since the next frame is the label. No success labels and no reward engineering, which is exactly why a world model benefits from the data a VLA wants filtered out.

Post-train, do not pretrain. Fifty episodes cannot train a video world model from scratch. Fine-tune a pretrained model like Cosmos on OpenArm episodes, generate rollouts, recover pseudo-actions with an inverse dynamics or latent action model, then train the policy on the result. Ctrl-World reports +44.7% success from that loop.

For unlabelled human video with no actions, the LAPA route applies: learn latent actions between consecutive frames, pretrain to predict them, then fine-tune the mapping onto real 14-DoF actions. That is the consumer for a corpus like EPIC-KITCHENS, which I audit but cannot curate into BC episodes.

Are robot ego and human ego interchangeable inputs?

No. Robot wrist motion has a median of 0.61 px and a 95th percentile near 2.3 px; human head motion sits at 1.72 and 12.84 px. Sharpness tracks motion at −0.48 on the wrist against −0.15 on the head. And the human corpus has no actions at all.

It supplies scene diversity the lab cannot, but its ego-motion statistics are a different distribution, so action conditioning learned there should not be expected to transfer directly. That is the argument for latent actions over direct action regression.

How do I verify the model learned something useful?

Not by reporting FVD and stopping. A model can generate beautiful coherent video and hold no usable dynamics.

FOUR TIERS, WEAKEST TO STRONGEST 1. PSNR, SSIM, FVD on held-out continuations. Necessary, not sufficient. A regression check, nothing more. 2. Physical plausibility. Does a released object fall? Visual realism and physical understanding are largely uncorrelated. 3. Linear probes on the frozen latent for object pose, contact and task phase. High accuracy means the representation contains the state. 4. Downstream control. Rank candidate policies inside the model and check the ranking holds in reality. The only test that settles it.
For any surrogate evaluator report both MMRV and Pearson r. A high r with a bad MMRV means the trend is right but adjacent policies are reordered, which is exactly the comparison you wanted it for.

What this means for the pipeline