Why is my USB camera not detected, or dropping out mid-recording?

Three separate camera problems get reported with the same sentence. This page splits them apart, explains why two cameras that each work alone can be impossible together, and covers the labeling habit that quietly puts your wrist camera in the scene column.

Connection · Last updated 2026-08-09

Symptom

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 the wrist view shows up in the wrong column in some episodes.

Short answer

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 make sure each camera actually carries the label you pass to record, because a label that matches no camera is filled from scan order instead, and scan order moves. A camera that is listed but black is almost always held open by another process.

Three failures, one complaint

What you seeCauseFirst move
Works alone, vanishes when a second camera is plugged inUSB bandwidth on one shared controllerMove one camera to a different controller or a powered hub
Listed, but every frame is blackAnother process holds the cameraClose whatever opened it, only one process gets a camera
The wrist view shows up in the wrong column in some episodesThe label matched no camera id or name, so it was assigned by scan orderRename the camera to the label you pass to record, then record one test episode
Works for a few minutes, then drops outPower on a passive hub, or a marginal cablePowered hub, shorter cable, direct port
Never appears on any machine or portThe camera or its cableTest it in any other application first
Appears, but only at a low resolutionThe controller granted what was leftFree up bandwidth, then reconnect
bash
ay-robots devices

# SERIAL PORTS
#   robot_1   unknown
# CAMERAS
#   camera_1  USB 2.0 Camera
#   camera_2  UGREEN Camera 2K (gripper)
The first column is the id the platform keeps for this camera, stored against its hardware id, so it survives a reboot. What can move is which physical camera sits behind a label you pass to record.
On macOS the built-in camera is left out on purpose

The FaceTime camera and any iPhone or iPad paired through Continuity are deliberately not listed and never opened, so that no camera on your Mac can switch itself on without you noticing. If a Mac user goes looking for the built-in webcam in this list and does not find it, nothing is broken. If you need it for a test, start the backend process with AYR_ALLOW_BUILTIN_CAMERAS=1 and it appears after the external cameras, never in front of them.

Bandwidth 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.

bash
# 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 devices
lsusb -t is the fastest way to find out whether two ports are really independent.

Labels only bind if a camera carries the label

When you pass --cameras wrist,top, each name is looked up against the cameras the platform knows about: it matches if the name appears inside a camera’s id or inside its reported name, compared in lower case. A name that matches nothing is not an error. The recorder falls back to taking the next camera that is still free, in scan order, and carries on.

That fallback is where the quiet column swap comes from. Scan order follows device paths, and device paths move after a replug, after a reboot, or after waking with a hub attached. So as long as no camera is actually called wrist, the words wrist and top are only two column names in your dataset, filled in whatever order the scan produced that day. Nothing warns you, because from the system’s point of view nothing went wrong.

The consequence for recording is expensive and delayed. If the scan order flipped between Monday and Wednesday and both sessions went into the same dataset, 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.

The fix is to rename the camera to the label you intend to use. Renaming changes the id the platform keeps for that device, which is stored against its hardware id and therefore survives reboots, so afterward the device list shows wrist next to the camera model and the label binds to that specific camera instead of to a position in a queue. There is no CLI command for renaming, and there is no rename in the desktop client either: it is done on the Hardware page for your robot in the dashboard, in the device list at the top, where every camera and every arm carries a small edit control next to its id. The camera dropdown in the client’s settings is a different list, built from what the operating system hands the client’s own webview, so the entries you pick there are not the ids a label is matched against. Then record one throwaway episode and look at the column names before you commit a session to them.

bash
ay-robots record --task "pick up the red cube and place it in the bowl" \
  --dataset cube_pick \
  --episodes 10 \
  --cameras wrist,top
The labels wrist and top are what appear in the dataset. Whether they point at the cameras you meant depends on those cameras being named wrist and top.
Rename the cameras once, then stop thinking about order

Give each camera the name you intend to record with the first time you add it, and keep that name for the life of the project. A device list is fine for a quick look at what is plugged in. It is the rename that makes the label in your recording command mean one specific piece of hardware.

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. A policy that is still running counts too, since the inference loop opens a camera and only gives it back when the loop is stopped. Rule all of that out before you touch the hardware.

bash
# What the local backend is doing: hardware, simulation or demo, and
# whether it is idle, teleoperating or running a model. A backend that
# is running a model has a camera open.
ay-robots status

# After closing the other consumers, rescan
ay-robots devices
Neither line proves a backend was already up. Any ay-robots command starts one when nothing is answering, so an answer is not evidence of a second instance.

Work through it in this order

  1. 1
    Scan 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.

    bash
    ay-robots devices
  2. 2
    Unplug 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.

  3. 3
    Close 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.

  4. 4
    Move 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.

  5. 5
    Put 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.

  6. 6
    Shorten 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.

  7. 7
    Reduce 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.

  8. 8
    Rename the cameras, then record one throwaway episode

    Give each camera the name you pass to record, then confirm that the right view landed in the right column before you commit a session to it. One test episode is cheap; discovering a swapped camera after fifty is not.

    bash
    ay-robots record --task "camera check" --episodes 1 --cameras wrist,top
A hub power supply is not a servo power supply

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 recorder does not leave a hole. It holds the newest complete camera snapshot and writes that same snapshot again whenever a fresh one is not ready, so a camera that stops delivering produces a run of byte-identical repeat frames, not a gap. The episode therefore looks intact: the check that runs when an episode is saved counts one JPEG per camera against the number of rows in the parquet file, and repeated frames satisfy that count exactly. A camera that falls out of the capture entirely does fail that count, and then the save is refused and the artifacts are moved to a quarantine folder rather than written into the dataset, so the case you have to catch yourself is the quiet one. The recorder does report it: dropped_camera_frames comes back with every saved episode and counts frames written with no image at all, the recording status carries a separate stale_camera_frames count for every tick where a snapshot had to be reused, and the web cockpit raises a warning while you are still recording once camera frames start going missing or arriving incomplete. Treat any of those as a reason to discard the session, because a policy trained on frozen frames learns that the scene holds still while the arm keeps moving. 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 id end up in my dataset?

No, the label you pass to record does, as the column name. That is why the two should be the same word: rename the camera to wrist on the Hardware page for your robot in the dashboard, and the column called wrist holds that camera. The rename does not travel, though. It is written into the device config of the machine whose backend answered, so a second machine starts with an empty mapping, hands the same camera an automatic camera_1 or camera_2 id, and falls back to scan order for your label until you open the Hardware page for that machine’s robot and rename there as well.

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.

Was this page helpful?

Often the real cause is elsewhere

A symptom in one part of the chain is regularly produced by the part before it. These pages cover the neighboring areas.