
A second camera on an SO-100 costs USB bandwidth, vision tokens, inference latency and a full re-record. Published ablations on when it pays for itself and when it does not.
A second camera on an SO-100 is a cheap decision at the hardware shop and an expensive one everywhere else. What you actually spend is USB isochronous bandwidth on the recording machine, extra vision tokens in every forward pass, milliseconds of inference latency on every control step, and a full re-record of your LeRobot dataset, because you cannot retrofit a view into episodes captured without it.
Below is each bill, priced from upstream code and published ablations. Short version: on a tabletop pick-and-place with one fixed third-person view, a wrist camera is usually the highest-return change available. Where the existing views already cover the workspace it can make things worse, and there is a 2026 SO-101 result where it did.
What a second camera costs, in one screen
- •Bandwidth. A USB 2.0 bus has about 384 Mbit/s for all isochronous streams, and one camera endpoint can reserve up to 196 Mbit/s of it. Two uncompressed 640x480 streams need 295 Mbit/s of real payload, but cameras reserve on a declared worst case that is often far above what they send, and then the second stream refuses to start.
- •Compute. GR00T N1 spends 64 image tokens per frame; a second camera makes it 128. ACT appends a whole ResNet-18 feature map per camera, about 300 tokens at 480x640.
- •Latency. In the OpenVLA-OFT study, adding a wrist image and proprioceptive state to an identical recipe moved A100 latency from 0.0729 s to 0.1120 s per query and throughput from 109.7 Hz to 71.4 Hz.
- •Payoff. robomimic measured relative drops of 9 percent on Square and 43 percent on Transport when the wrist image was removed; its study page rounds this to 10 to 45 percent. On a real Franka Can task, 43.3 percent success without the wrist view against 73.3 percent with it.
- •Money. Almost nothing. An A100-tier run costs about 4 to 12 USD and a 24 GB-tier run about 1 to 3 USD. A second view does not move those bands; re-recording is the expensive part.
- •Not automatic. On a mobile SO-101 whose body-fixed cameras already covered the workspace, a wrist camera dropped ACT from 90 to 86 percent and SmolVLA from 79 to 12 percent over 100 trials.
Bill one: USB bandwidth, and the error that pretends to be a disk problem
A UVC webcam does not negotiate a bitrate. It asks the host for an isochronous endpoint with a fixed payload per microframe, and the host either grants the whole reservation up front or refuses the stream. Two separate ceilings apply, and conflating them is why the arithmetic often looks like it should work. USB 2.0 high speed signals at 480 Mbit/s in 125 microsecond microframes, and the specification caps periodic transfers at 80 percent of each microframe, leaving about 384 Mbit/s for every camera on the bus to share. Separately, one high-bandwidth isochronous endpoint tops out at three 1024-byte transactions per microframe, about 196 Mbit/s, and that is the most a single camera can ever reserve.
The 384 Mbit/s figure is per bus, not per port. A hub adds no bandwidth; it multiplexes devices onto the same upstream reservation. So the number that decides whether your second camera opens is what each stream reserves, not what it sends, and for uncompressed formats the payload at least is exact arithmetic.
| Stream at 30 fps | Bytes per frame | Actual payload | Two of them on one USB 2.0 bus? |
|---|---|---|---|
| 640x480 YUYV, 16 bits per pixel | 614,400 | 147.5 Mbit/s | Only if both reserve honestly. 295 Mbit/s of payload fits under 384, two worst-case reservations do not |
| 1280x720 YUYV | 1,843,200 | 442.4 Mbit/s | No. One stream alone is past the 196 Mbit/s an endpoint can reserve |
| 1920x1080 YUYV | 4,147,200 | 995.3 Mbit/s | No. Past the raw 480 Mbit/s signalling rate. USB 3.0 territory |
| 640x480 MJPEG | varies with scene | far lower in real bytes | Usually yes, but the reservation is still the trap |
One camera works. Open the second and VIDIOC_STREAMON returns ENOSPC, printed as No space left on device, with uvcvideo: Failed to submit URB 0 (-28) in the kernel log. Your disk is fine. In microframe terms the 80 percent budget is 6000 bytes per 125 microseconds; a 640x480 YUYV stream genuinely needs about 2304 of them, so two would fit at 4608. But the driver sizes the reservation from the camera's declared dwMaxPayloadTransferSize, and many cameras declare a value at or near the 3072-byte endpoint ceiling regardless of format, so the pair does not fit. The Good Penguin traced a 320x240 MJPEG stream that reserved 3060 bytes per microframe, 195 Mbit/s, for a payload that could not exceed about 46 Mbit/s even uncompressed. Fixes, cheapest first: move the second camera to a different USB root controller, drop the resolution or frame rate, or reload the driver with the bandwidth quirk. UVC_QUIRK_FIX_BANDWIDTH is 0x00000080 in uvcvideo.h, so the parameter is quirks=128. Note what that quirk does not cover: the kernel only recomputes the bandwidth for uncompressed formats, so it cannot rescue an MJPEG stream, and switching to MJPEG cuts the bytes actually sent without necessarily cutting the reservation. The Good Penguin's failing example was MJPEG.
- 1Ask what the host already sees
LeRobot ships auto-discovery. The identifiers it prints are not stable across reboots.
bashlerobot-find-cameras opencv # use 'realsense' instead of 'opencv' for Intel RealSense devices - 2Find which controller each camera hangs off
Separate root controllers get separate isochronous budgets. Two cameras behind one hub share one.
bashlsusb -t # look for Driver=uvcvideo, and whether both sit under the same Bus - 3Check which formats the camera really offers
No MJPEG in the list means an uncompressed stream, and the arithmetic above applies.
bashv4l2-ctl --list-formats-ext -d /dev/video0 - 4Stream both at the resolution you intend to record
The test that matters. Two minutes here, or an evening of episodes with a camera that drops out.
bashv4l2-ctl -d /dev/video0 --set-fmt-video=width=640,height=480,pixelformat=MJPG \ --stream-mmap --stream-count=300 & v4l2-ctl -d /dev/video2 --set-fmt-video=width=640,height=480,pixelformat=MJPG \ --stream-mmap --stream-count=300 - 5If it still fails, reload uvcvideo with the quirk
Uncompressed formats only. Close everything holding a camera or the module will not unload.
bashsudo modprobe -r uvcvideo sudo modprobe uvcvideo quirks=128 # UVC_QUIRK_FIX_BANDWIDTH = 0x80

Bill two: what each policy does with the second view
There is no single answer: the five trainable policies ingest images in four different ways. The table below is read out of upstream source in August 2026.
| Policy | How images enter the model | What the second camera adds | Read from |
|---|---|---|---|
| ACT | One shared ResNet-18 backbone; each camera's layer4 feature map is flattened onto the encoder sequence | About 300 tokens at 480x640, since a stride-32 backbone yields a 15x20 grid. Two cameras is 600 | lerobot modeling_act.py |
| SmolVLA | Each image feature is resized with padding to 512x512 and pushed through the frozen SigLIP encoder of SmolVLM2-500M-Video-Instruct | A full vision-encoder pass per step; the paper caps visual tokens at 64 per frame | lerobot configuration_smolvla.py |
| GR00T N1.5 and N1.7 | Frames go through a pretrained SigLIP-2 vision transformer and the image tokens of all frames are concatenated into one sequence; the GR00T N1 paper puts this at 224x224 plus pixel shuffle, 64 image token embeddings per frame | Another frame's worth of tokens per step, 64 more at the configuration the N1 paper describes. The Isaac-GR00T SO-100 example already declares two video keys | GR00T N1 paper, Isaac-GR00T examples/SO100 |
| Pi0.5 | Fixed 224x224 slots: one third-person view and two wrist views; missing slots are zero-filled and masked | Nothing structural, it fills an existing slot. A third external view has no slot without editing the transform | openpi libero_policy.py |
# NVIDIA/Isaac-GR00T, examples/SO100/so100_config.py (main branch, 24 Aug 2026)
so100_config = {
# Video: current frame only; keys must match "video" entries in meta/modality.json
"video": ModalityConfig(
delta_indices=[0],
modality_keys=["front", "wrist"], # front third-person view + wrist egocentric
),
"state": ModalityConfig(
delta_indices=[0],
modality_keys=["single_arm", "gripper"],
),
...
}// NVIDIA/Isaac-GR00T, examples/SO100/modality.json
"video": {
"front": { "original_key": "observation.images.front" },
"wrist": { "original_key": "observation.images.wrist" }
}Hugging Face's guidance on what makes a good dataset is to name streams by location rather than by device: images.top, images.front, images.left, images.right, with an orientation suffix for wrist cameras such as images.wrist.left. Avoid images.laptop or images.phone. Two more things to settle before recording: GR00T's loader wants LeRobot v2.0 or v2.1 and a v3.0 dataset must be converted down first, which is the failure behind dataset rejected as v3; and the same keys must be passed at rollout, or the policy gets an observation layout it never saw. Format details are in the dataset docs.
Bill three: latency, paid on every control step
The cleanest published measurement of what an extra view costs at inference time is the OpenVLA-OFT study by Kim, Finn and Liang: throughput and latency for 7-dimensional actions on an NVIDIA A100, averaged over 100 queries, holding the recipe fixed and changing only the inputs.
| Configuration | Throughput | Latency per query | LIBERO-Long success |
|---|---|---|---|
| OpenVLA, one third-person image | 4.2 Hz | 0.2396 s | 53.7 percent |
| plus parallel decoding and action chunking | 108.8 Hz | 0.0735 s | 86.5 percent |
| plus continuous actions with L1 regression | 109.7 Hz | 0.0729 s | 90.7 percent |
| plus wrist image and proprioceptive state | 71.4 Hz | 0.1120 s | 94.5 percent |
The last row is the price tag: latency up about 54 percent, throughput down a third, LIBERO-Long success up 3.8 points. Note what is bundled there. That row adds the wrist image and the proprioceptive state together, so the delta is an upper bound on what the camera alone costs, not a camera-only measurement. Per-step figures here span an order of magnitude, from 20 ms for ACT through 152 ms for GR00T N1.7 and 245 ms for SmolVLA to 485 ms for Pi0.5. Half again on 20 ms is invisible. Half again on 485 ms is a different robot.
This is also where action chunking earns its keep. ACT predicts 100 steps per forward pass by default, Pi0 uses a horizon of 50, GR00T N1 uses 16. A long chunk amortises the second camera's encoder cost over many actuator commands.

A view costs tens of milliseconds. Moving inference off the machine wired to the servos costs a public-internet round trip on every step, the larger number by a wide margin. AY-Robots provisions a cloud GPU pod for serving, which works for slow pick-and-place, not for fast reactive motion. See policy freezes mid-motion.
Bill four: time and money, smaller than people expect
This bill surprises people in the good direction. A second camera changes the token count, but not the GPU tier, and the tier is what money is attached to.
| GPU tier | Policies | Typical run | Price per hour | Cost per run |
|---|---|---|---|---|
| A100 80 GB or H100 80 GB | GR00T N1.7, GR00T N1.5, Pi0.5 | 3 to 6 hours | 1.20 to 2.00 USD | about 4 to 12 USD |
| RTX 4090 or any 24 GB card | SmolVLA, ACT | 2 to 5 hours | 0.30 to 0.60 USD | about 1 to 3 USD |
The real cost is recording, paid in arm time. LeRobot's episode defaults are 50 episodes, 60 seconds of recording and 60 of reset: 100 minutes at the leader arm and 90,000 frames per camera. A second camera adds none of that, provided it was mounted before you started. If it was not, you pay those 100 minutes again. That asymmetry is the whole argument for settling the layout first.

What the second view buys, according to people who measured
The literature agrees on one thing and splits on another. Agreed: a wrist view helps most where a third-person view is weakest, in the last few centimetres before contact. Split: whether it helps once your existing views already cover that region.
| Study | What was compared | Result |
|---|---|---|
| robomimic, Mandlekar et al., 2021 | Image agents with and without wrist observations, simulated manipulation | Relative drops of 9 percent on Square and 43 percent on Transport with the wrist image removed; the study page rounds the range to 10 to 45 percent |
| robomimic, real robot | The Can task on real hardware (Franka, BC-RNN, 30 rollouts), with and without the wrist view | 43.3 percent success without it, 73.3 percent with it |
| OpenVLA-OFT, Kim, Finn and Liang, 2025 | Same recipe and same dataset on LIBERO: third-person view and language, against third-person plus wrist image plus proprioceptive state | Average over four suites 95.3 to 97.1 percent; on LIBERO-Long alone, 90.7 to 94.5 percent |
| Hsu et al., ICLR 2022 | Hand-centric against third-person perspective on Meta-World tasks and real arms | Hand-centric improves training efficiency and out-of-distribution generalization; where it is insufficient, third-person is needed but harms generalization |
| SEVO, 2026 | Mobile SO-101, two body-fixed cameras already covering the workspace, wrist added as a third view, 100 trials per condition | ACT fell from 90 to 86 percent, SmolVLA from 79 to 12 percent |
The SEVO authors offer two mechanisms as hypotheses, and say direct verification is left to future work. As the gripper closes in, the wrist view fills with the object surface and carries almost nothing about the gripper-to-object relationship. And on a moving base it sees rapid visual flow, from which ACT learned continuous oscillation and SmolVLA learned to grasp and release in open air. Note the setup before generalising: a mobile platform with active red illumination and two body-fixed cameras already covering the workspace. A static SO-100 with one front camera is not that. The lesson is narrower than 'wrist cameras are bad': a second view pays only when it shows what the first cannot.
- Close-range evidence of where the gripper sits relative to the object, which is what a front view loses to occlusion.
- robomimic measured relative drops of 9 percent on Square and 43 percent on Transport when the wrist image was removed.
- Hsu et al. found hand-centric views improve out-of-distribution generalization, not only success.
- The Isaac-GR00T SO-100 example and the Pi0 input layout already assume a wrist view.
- It is the one view that survives moving the robot to a different table.
- Every episode recorded without it is unusable for the new configuration. No retrofit exists.
- It doubles the isochronous reservation on the recording host.
- It adds a vision-encoder pass per step. In the OFT measurements a wrist image plus proprioception cost about 54 percent more latency.
- Mounted close to the gripper its field of view is narrow, easily swamped by the object at contact.
- Two cameras is two more chances for a device index to shift and silently swap the views.
Where to put the second camera
Placement decides most of the payoff. The points below come from the Hugging Face dataset guidance and the LeRobot imitation-learning tutorial, and every one of them is something people get wrong on a first imitation learning run.
- Two views is the recommended default. More is more tokens, more bandwidth, more ways to disagree.
- Record at 480x640 or better, around 30 fps. Below that the wrist view stops resolving what it is for.
- Keep both cameras mechanically fixed. One nudged between sessions trains a policy that only works in one setup.
- Keep the leader arm out of frame. The policy will happily learn to watch the human instead of the scene.
- The only moving things in frame should be the follower arm and the objects it moves.
- The LeRobot rule of thumb: you should be able to do the task yourself by only looking at the camera images. If you cannot, neither can the policy.
Recording a two-camera dataset that will train
The manual path end to end, against upstream LeRobot 0.6.2. Substitute your own ports and device paths. The platform walkthrough is at record your first dataset.
- 1Teleoperate with both streams visible first
Ten minutes here saves discovering after 50 episodes that the wrist camera is upside down.
bashlerobot-teleoperate \ --robot.type=so100_follower \ --robot.port=/dev/ttyACM0 \ --robot.id=my_follower_arm \ --robot.cameras="{ front: {type: opencv, index_or_path: /dev/video0, width: 640, height: 480, fps: 30}, wrist: {type: opencv, index_or_path: /dev/video2, width: 640, height: 480, fps: 30} }" \ --teleop.type=so100_leader \ --teleop.port=/dev/ttyACM1 \ --teleop.id=my_leader_arm \ --display_data=true - 2Record the episodes
The camera keys here become the dataset feature names. num_episodes defaults to 50, episode_time_s and reset_time_s to 60 s each.
bashlerobot-record \ --robot.type=so100_follower \ --robot.port=/dev/ttyACM0 \ --robot.id=my_follower_arm \ --robot.cameras="{ front: {type: opencv, index_or_path: /dev/video0, width: 640, height: 480, fps: 30}, wrist: {type: opencv, index_or_path: /dev/video2, width: 640, height: 480, fps: 30} }" \ --teleop.type=so100_leader \ --teleop.port=/dev/ttyACM1 \ --teleop.id=my_leader_arm \ --dataset.repo_id=${HF_USER}/so100_twocam \ --dataset.num_episodes=50 \ --dataset.single_task="Pick up the cube and drop it in the bin" \ --dataset.streaming_encoding=true \ --dataset.encoder_threads=2 \ --display_data=true - 3Check that both streams landed
Encoder settings land in meta/info.json from the first episode. You want two video features with matching fps and resolution.
bashpython - <<'PY' import json, os, pathlib repo = f"{os.environ['HF_USER']}/so100_twocam" root = pathlib.Path.home() / ".cache/huggingface/lerobot" / repo info = json.loads((root / "meta/info.json").read_text()) for key, feat in info["features"].items(): if feat["dtype"] == "video": i = feat["info"] print(key, feat["shape"], i["video.codec"], i["video.fps"], "crf", i["video.crf"]) PY - 4Train
ACT adapts to the camera count stored in the dataset, so there is no camera flag. That convenience is the trap: a broken second stream trains quietly and badly.
bashlerobot-train \ --dataset.repo_id=${HF_USER}/so100_twocam \ --policy.type=act \ --output_dir=outputs/train/act_so100_twocam \ --job_name=act_so100_twocam \ --policy.device=cuda \ --policy.repo_id=${HF_USER}/act_so100_twocam - 5Roll out with the same camera keys
front and wrist must be spelled exactly as at recording time. The most common way a two-camera setup fails on demo day.
bashlerobot-rollout \ --strategy.type=base \ --policy.path=${HF_USER}/act_so100_twocam \ --robot.type=so100_follower \ --robot.port=/dev/ttyACM0 \ --robot.cameras="{ front: {type: opencv, index_or_path: /dev/video0, width: 640, height: 480, fps: 30}, wrist: {type: opencv, index_or_path: /dev/video2, width: 640, height: 480, fps: 30} }" \ --task="Pick up the cube and drop it in the bin" \ --duration=60
The LeRobot camera docs warn that device identifiers "may change after rebooting your computer or re-plugging the camera, depending on your operating system". With one camera that is harmless. With two, front and wrist can quietly trade places between sessions and nothing errors: half your episodes have the views swapped, training converges to a low loss, and the arm does something confident and wrong. On Linux, pin devices by their stable path under /dev/v4l/by-id/ instead of /dev/videoN, and open the dataset in the visualiser before paying for a run. If you are past that point, loss falls but the policy does nothing and camera not detected are the pages to read.

Two routes to the same two-camera policy
You own the whole chain: USB topology, drivers, encoding, GPU rental, serving. Budget the first evening for bandwidth and device naming.
- Confirm both cameras stream together with
v4l2-ctlbefore touching the arm. - Record with
lerobot-recordand explicit camera keys. Video defaults to libsvtav1 at crf 30, keyframe every 2 frames, tunable via--dataset.rgb_encoder.*. - For GR00T, convert to v2.1 and write a modality.json with both video keys before fine-tuning.
- Rent a GPU sized to the model: 80 GB for GR00T N1.7 and Pi0.5, 24 GB for SmolVLA and ACT.
- Serve the checkpoint on the machine wired to the servos if the task needs reaction time.
Full control of encoder settings, the option of three or four views if the bus can carry them, and no platform dependency. Keep the LeRobot pages for cameras and video encoding parameters open.
The desktop client records LeRobot-format datasets straight from a teleoperation session, every camera stream and joint state included. The training form then picks model, dataset and hyperparameters, and the backend rents a GPU by required VRAM.
- Install the desktop client and record with both cameras attached. Datasets can also come from a Hugging Face repo id or your own machine.
- Pick a combination from the training matrix: ACT on SO-100, say, or GR00T N1.7 on SO-100. Each guide carries the defaults actually sent.
- Run the fine-tune: about 4 to 12 USD on the A100 tier, 1 to 3 USD on the 24 GB tier.
- Serve it. The inference endpoint auto-provisions a cloud GPU pod, and pods carry an idle watchdog that destroys them.
- The same operations exist in the CLI and the MCP server.
It does not fix USB bandwidth on your machine. If two cameras will not stream together locally, the recording does not happen. It cannot make remote inference fast either: a cloud pod adds internet round trips on top of a control step already costing 20 to 485 ms. And it cannot add a view to a dataset recorded without one.
A decision rule that survives contact
Put the camera where the current view is blind. If the front camera loses the gripper behind the object at the moment of the grasp, a wrist view is worth the bandwidth and the latency. If the existing views already show the contact clearly, the second camera buys tokens and little else.
Unsure? Record two views and train both ways. A fine-tuning run on the 24 GB tier costs 1 to 3 USD, so training ACT once with both views and once with the front view alone is cheaper than a considered opinion. You can drop a camera from a dataset; you cannot add one, and the dataset, not the checkpoint, is the expensive artefact.
- Episode design: collecting high-quality VLA training data.
- Hardware: the SO-100 complete guide.
- The model class: vision-language-action models, plus the glossary entry.
- The two cheap options: ACT against SmolVLA, and the arena, 85 models and 332 benchmark results.
- No arm yet: drive a real one, or browse the dataset directory.
Record both views in the right format the first time
The AY-Robots desktop client records LeRobot-format datasets straight from a teleoperation session: every camera stream, the joint states and the episode boundaries, in the shape the trainers expect.
Get the desktop clientDo I need two cameras to train a policy on an SO-100?▾
No. One fixed third-person view is enough to train ACT or SmolVLA on a simple pick-and-place. Two views is the recommended default in the Hugging Face dataset guidance, and the Isaac-GR00T SO-100 example declares two video keys. Start with one if bandwidth forces it, but decide before recording.
Wrist camera or a second external view?▾
Wrist, in most cases. Close-range gripper-to-object information is what a third-person view is worst at: robomimic measured 43.3 percent success without the wrist view against 73.3 percent with it on a real Can task (Franka, BC-RNN, 30 rollouts), and Hsu et al. found it also improves out-of-distribution generalization. A second external view mostly buys redundancy against occlusion.
How much slower is inference with two cameras?▾
In the OpenVLA-OFT measurements on an A100, averaged over 100 queries, adding a wrist image and proprioceptive state to the same recipe moved latency from 0.0729 s to 0.1120 s per query, about 54 percent. Those two inputs are bundled in that row, so treat it as an upper bound on the camera alone. What it means depends on your budget: per-step figures here run from 20 ms for ACT to 485 ms for Pi0.5.
My second camera will not start and I get 'No space left on device'. What is wrong?▾
USB isochronous bandwidth, not disk. A USB 2.0 bus has about 384 Mbit/s for all isochronous streams and a single camera endpoint can reserve up to 196 Mbit/s of it, and cameras reserve on a declared worst case that is often far above what they actually send. Move the second camera to a different USB root controller, drop the resolution or frame rate, or reload the driver with modprobe uvcvideo quirks=128, which sets UVC_QUIRK_FIX_BANDWIDTH. That quirk only recomputes bandwidth for uncompressed formats, so it will not help an MJPEG stream, and switching to MJPEG lowers the bytes sent without necessarily lowering the reservation: the case The Good Penguin documented was a 320x240 MJPEG stream reserving 195 Mbit/s.
Does a second camera make training more expensive?▾
Not enough to change the tier. It adds tokens per step, but the A100 tier still lands in the 4 to 12 USD band and the 24 GB tier in the 1 to 3 USD band. The expensive consequence is re-recording: at LeRobot defaults, 100 minutes of arm time and 90,000 frames per camera.
Can a second camera make the policy worse?▾
Yes, and it has been measured. A 2026 study on a mobile SO-101 whose two body-fixed cameras already covered the workspace added a wrist camera as a third view: ACT fell from 90 to 86 percent and SmolVLA from 79 to 12 percent, over 100 trials per condition. The mechanisms given were the wrist view filling with the object surface at close range, and visual flow from the moving base. On a static arm with one front camera this is far less likely, but it is real.
Sources
- What Matters in Learning from Offline Human Demonstrations for Robot Manipulation (robomimic), Mandlekar et al., 2021
- robomimic: study takeaways, including the wrist camera observation finding
- Fine-Tuning Vision-Language-Action Models: Optimizing Speed and Success (OpenVLA-OFT), Kim, Finn, Liang, 2025
- Vision-Based Manipulators Need to Also See from Their Hands, Hsu et al., ICLR 2022
- SEVO: Semantic-Enhanced Virtual Observation for Robust VLA Manipulation, Fang, Zhuang and Miao, 2026
- GR00T N1: An Open Foundation Model for Generalist Humanoid Robots, NVIDIA, 2025
- SmolVLA: A Vision-Language-Action Model for Affordable and Efficient Robotics, 2025
- LeRobot documentation: Cameras
- LeRobot documentation: Imitation Learning on Real-World Robots
- LeRobot documentation: Video encoding parameters
- Hugging Face blog: LeRobot Community Datasets, The ImageNet of Robotics, When and How (the good-dataset checklist)
- NVIDIA Isaac-GR00T: SO-100 example modality config with front and wrist video keys
- Physical Intelligence openpi: image slot layout for Pi0 models
- The Good Penguin: running multiple UVC cameras on Linux, and the isochronous bandwidth ceiling
- Linux kernel: uvcvideo.h, the UVC quirk bit definitions including UVC_QUIRK_FIX_BANDWIDTH
Sources
- What Matters in Learning from Offline Human Demonstrations for Robot Manipulation (robomimic), Mandlekar et al., 2021
- robomimic: study takeaways, including the wrist camera observation finding
- Fine-Tuning Vision-Language-Action Models: Optimizing Speed and Success (OpenVLA-OFT), Kim, Finn, Liang, 2025
- Vision-Based Manipulators Need to Also See from Their Hands, Hsu et al., ICLR 2022
- SEVO: Semantic-Enhanced Virtual Observation for Robust VLA Manipulation, Fang, Zhuang and Miao, 2026
- GR00T N1: An Open Foundation Model for Generalist Humanoid Robots, NVIDIA, 2025
- SmolVLA: A Vision-Language-Action Model for Affordable and Efficient Robotics, 2025
- LeRobot documentation: Cameras
- LeRobot documentation: Imitation Learning on Real-World Robots
- LeRobot documentation: Video encoding parameters
- Hugging Face blog: LeRobot Community Datasets, The ImageNet of Robotics, When and How (the good-dataset checklist)
- NVIDIA Isaac-GR00T: SO-100 example modality config with front and wrist video keys
- Physical Intelligence openpi: image slot layout for Pi0 models
- The Good Penguin: running multiple UVC cameras on Linux, and the isochronous bandwidth ceiling
- Linux kernel: uvcvideo.h, the UVC quirk bit definitions including UVC_QUIRK_FIX_BANDWIDTH
Ready for high-quality robotics data?
AY-Robots connects your robots to skilled operators worldwide.
Get Started