A camera that works on its own disappears as soon as a second one is plugged in, or it appears in the list and delivers black frames, or it was camera 1 yesterday and camera 0 today.
With two or more USB cameras the usual cause is bandwidth rather than a broken camera: several cameras streaming uncompressed video on one USB controller ask for more than the controller can carry, and the one that loses the race never starts. Move a camera to a port on a different controller or onto a powered hub, and identify cameras by their label rather than their index, because index numbers change between reboots. A camera that is listed but black is almost always held open by another process.
Three failures, one complaint
| What you see | Cause | First move |
|---|---|---|
| Works alone, vanishes when a second camera is plugged in | USB bandwidth on one shared controller | Move one camera to a different controller or a powered hub |
| Listed, but every frame is black | Another process holds the camera | Close whatever opened it, only one process gets a camera |
| Was camera 1 yesterday, camera 0 today | Enumeration order is not stable | Select by label, never by number |
| Works for a few minutes, then drops out | Power on a passive hub, or a marginal cable | Powered hub, shorter cable, direct port |
| Never appears on any machine or port | The camera or its cable | Test it in any other application first |
| Appears, but only at a low resolution | The controller granted what was left | Free up bandwidth, then reconnect |
ay-robots devices
# SERIAL PORTS
# /dev/ttyACM0 SO-100 (6 servos responding)
# CAMERAS
# 0 USB 2.0 Camera 1920x1080
# 1 HD Webcam 1280x720Bandwidth is the usual answer
A USB camera that streams uncompressed frames reserves bandwidth on its controller for as long as it is open, whether or not anything is looking at the frames. The reservation is made up front, and if the controller cannot satisfy it, the camera does not start. That is the mechanism behind the most common report on this page: two cameras that each work perfectly on their own and refuse to work together.
The trap is that USB sockets are not independent. Several physical ports on a machine usually hang off one controller and share its budget, and which ports share is not something you can tell by looking at the case. Two ports right next to each other may be one controller; a port on the opposite side of the laptop is often a different one. This is why "I moved it to another port and nothing changed" is such a common second sentence.
The levers, roughly in order of how well they work: put the second camera on a genuinely different controller, add a powered hub so the hub arbitrates and supplies its own power, lower the resolution of whichever camera matters least, and prefer a camera that can deliver a compressed stream, since compressed video needs a fraction of the budget that raw frames do. Two cameras at moderate resolution is an ordinary setup that works on ordinary hardware. The difficulty scales with pixels per second, not with the number of devices.
# Linux: which controller does each port hang off
lsusb -t
# Linux: what the kernel calls each camera, and its capabilities
v4l2-ctl --list-devices
# The platform view of the same hardware
ay-robots devicesCamera indexes are not identities
The number in front of a camera is the order in which the operating system happened to enumerate it. Reboot the machine, plug the arm in before the camera instead of after, or wake from sleep with a hub attached, and the numbers can rearrange. Nothing warns you, because from the system’s point of view nothing went wrong.
The consequence for recording is expensive and delayed. If your wrist camera was 1 on Monday and 0 on Wednesday, and both sessions went into the same dataset by index, then half your episodes have the wrist view in the scene column and the other half do not. Nothing crashes. Training runs. The policy is asked to make sense of two contradictory views of the world and does poorly, and the cause is three weeks upstream by the time you look for it.
Label the cameras once and use the labels everywhere. The recording command takes camera names, and those names are what end up in the dataset column names, so a consistent label is what makes a dataset portable across sessions and machines.
ay-robots record --task "pick up the red cube and place it in the bowl" \
--dataset cube_pick \
--episodes 10 \
--cameras wrist,topSet the label when you first add a camera and keep it for the life of the project. Index numbers are fine for a quick look at what is plugged in and wrong for anything you intend to keep.
Only one process gets the camera
In practice a camera is exclusive: the first process to open it holds it, and everything after that is refused or handed nothing. The refusal is rarely reported as clearly as it should be, so the second consumer typically shows the camera in its list and then produces black frames, which reads as a broken camera.
The usual holders are a video call application minimized in the background, a browser tab that was granted camera permission and never released it, a preview window you opened yourself and forgot, and an earlier instance of the client that did not exit cleanly. Two backends running at once do it to each other as well, so it is worth confirming there is only one.
# Is a backend already running on this machine
ay-robots status
# After closing the other consumers, rescan
ay-robots devicesWork through it in this order
- 1Scan and note what is actually listed
A camera that is missing from the list and a camera that is listed but black are different problems. Do not skip this distinction, it halves the search.
bashay-robots devices - 2Unplug every camera but the failing one
If it works alone, the camera is fine and you have a bandwidth or contention problem. If it fails alone on a known-good port, the camera or its cable is the suspect.
- 3Close everything else that could hold a camera
Video calls, browser tabs with camera permission, any preview window, any second copy of the client. Then rescan before changing anything physical.
- 4Move the camera to a port on the other side of the machine
You are trying to land on a different controller. On Linux, lsusb -t tells you whether you succeeded instead of leaving you to guess.
- 5Put it on a powered hub
A powered hub supplies its own current and often resolves both the bandwidth contention and the slow dropouts that come from a laptop port supplying two cameras and an arm adapter.
- 6Shorten the cable, remove extensions
Long unpowered extensions are a leading cause of "worked for five minutes then stopped". Test with the shortest cable you own before concluding anything about the camera.
- 7Reduce the pixel rate
Lower the resolution of the camera that contributes least, or use one that delivers a compressed stream. This is the lever that makes an over-subscribed controller viable without buying anything.
- 8Fix the labels, then record one throwaway episode
Confirm that the labels you expect appear in the recording before you commit a session to it. One test episode is cheap; discovering a swapped camera after fifty is not.
bashay-robots record --task "camera check" --episodes 1 --cameras wrist,top
Adding a powered hub puts another brick on your desk, and desks with several bricks are where the expensive mistake happens. Feetech STS3215 servos run at 7.4 V and 12 V destroys them in seconds. Label the hub supply and the arm supply so that a tired hand at the back of the desk cannot confuse them.
What a dropout does to an episode
The client timestamps each stream and keeps them aligned, so a camera that stops delivering does not silently smear frames across the gap. What you get instead is an episode with missing coverage during the interesting part, which is worth exactly nothing as training data even though it costs the same disk space. Review episodes before you keep them, and throw away anything recorded during a session where a camera was dropping. The reasoning behind the review habit is on /learn/record-your-first-dataset, and the composition of a usable dataset is on /so-100/data-collection.
Frequently asked questions
How many cameras can I use at once?▾
Two is the common setup and it works on ordinary hardware. Beyond two you are managing bandwidth on purpose: separate controllers, compressed streams, and resolutions chosen deliberately rather than left at whatever the camera offers.
The camera works in a video call but not here. Why?▾
Two reasons, and both can apply. Call applications typically request a lower resolution or a compressed format, which fits where a raw stream does not. And if the call application is still running, it is holding the camera, so nothing else can open it.
Does the camera index end up in my dataset?▾
No, the label does. That is exactly why the label is worth setting once and keeping: it is stable across reboots and across machines, while the index is neither.
Can I move a camera to a better position halfway through a dataset?▾
Not without splitting the dataset. A policy learns the mapping from pixels to actions, so moving the camera invalidates everything recorded before the move in the same way that nudging a tripod does.
Do I need a wrist camera at all?▾
You can record with one scene camera and get a working pipeline. A wrist view earns its place at the moment of the grasp, when the gripper occludes the object from any camera that is not on the wrist.
My camera is fine but the arm disappeared when I added the second camera.▾
Then the serial adapter and the cameras are sharing a controller and the cameras took the budget. Move the arm adapter to a port on a different controller, or move the cameras onto a powered hub and leave the adapter directly on the machine.
A symptom in one part of the chain is regularly produced by the part before it. These pages cover the neighboring areas.