System designTroubleshooting

How to mix USB and GigE cameras in one ROS launch

Why one ROS launch crashes USB depth cameras and a GigE camera together, and the port pinning, dedicated NIC and bandwidth budget that keep all three running.

LumaSpec Vision10 min read Share on LinkedIn

On this page 8 sections
  1. 01Why do the cameras work alone but crash in one launch file?
  2. 02How much bandwidth does each camera really consume?
  3. 03Which USB port does each depth camera belong on?
  4. 04Where should the GigE camera's network interface sit?
  5. 05What startup order stops the driver nodes racing?
  6. 06How do you verify the combined launch is healthy?
  7. 07When is one machine no longer enough for three cameras?
  8. 08Questions

The fix is a three-part budget: pin each USB depth camera to its own USB 3.0 root-hub port with an explicit usb_port path, put the GigE camera on a dedicated network interface, and stagger the driver node starts by two to three seconds. Budget first, because the numbers decide the layout: gigabit Ethernet carries about 118 MB/s of payload and one USB 3.0 controller about 400 MB/s of real streaming throughput. Two USB depth cameras and one GigE camera each run cleanly from their own launch file, then the combined launch kills them within seconds of startup — the driver nodes are competing for the same USB controller, the same network interface and the same startup instant. This page gives you the bandwidth arithmetic to run first, then the fixes in the order that matters. The worked examples use a 720p depth triple at 30 fps and a 20 MP GigE stream at 15 fps, so you can substitute your own resolution and frame rate.

Why do the cameras work alone but crash in one launch file?

Alone, each driver reserves the bus bandwidth it needs when its stream opens; combined, every node opens at the same instant against one USB controller and one network interface, the late streams find no budget left, and their drivers exit and can pull the whole launch down.

The symptom pattern is specific: the USB depth topics publish a few frames, then stall, while the GigE camera answers ping at first and later disappears from the driver's device list. USB video is isochronous — the host controller reserves bus time when a stream is configured, and a controller whose periodic budget is already committed refuses the next stream instead of degrading everyone. The refused driver exits or releases its device, and the depth data stops.

The network side fails the same way with fewer warnings. A gigabit link carries about 118 MB/s of payload, so one uncompressed stream sized for the wrong link consumes the entire interface, and the camera drops off at the first burst. Startup adds a race: several nodes probing devices in the same second can bind to the wrong one, which is why you pin the physical port path rather than trust device names — the same discipline that stops identical USB cameras swapping device names.

How much bandwidth does each camera really consume?

Run the arithmetic before touching the launch file: gigabit Ethernet delivers about 118 MB/s of payload, one USB 3.0 controller about 400 MB/s of real streaming throughput, and two uncompressed cameras are all it takes to exceed either limit.

bytes per frame = width × height × bytes per pixel MB per second = bytes per frame × frame rate ÷ 1,000,000

One USB 3.0 controller moves 5 Gbit/s on the wire, which 8b/10b encoding cuts to 4 Gbit/s of payload — 500 MB/s raw and roughly 400 MB/s of real throughput once packet overhead is paid. Two 152 MB/s streams fit with about a quarter of the budget to spare, but only while both cameras sit directly on USB 3.0 ports. Behind any USB 2.0 hop a camera is capped at 480 Mbit/s, about 40 MB/s of payload, and its 152 MB/s stream cannot open at all — the same bandwidth check that rejects depth cameras parked on USB 2.0 ports.

The GigE camera fails higher up the stack. A 20 MP mono camera at 8 bit emits 5472 × 3648 × 1 B = 19,961,856 B ≈ 20 MB per frame, and 20 MB × 15 fps ≈ 299 MB/s. That is 2.5 times the 118 MB/s link, so gigabit tops out at 118 ÷ 19.96 ≈ 5.9 fps for this stream uncompressed. The choices are three: drop the frame rate to about 5.9 fps, shrink the image with ROI or binning, or move the camera to a 2.5G or 10G interface.

If you are specifying the station rather than debugging it, this arithmetic decides the camera class before anything else. The MV-CS200-10GC is a 20 MP Color GigE area scan camera, the class of part this budget arithmetic is for.

Area scan camerasHikrobot MV-CS200-10GC 20 MP Area Scan Camera, GigE, IMX183, Color, BasicMV-CS200-10GC
Sensor format
1"
Lens mount
C-mount
Interface
GigE
Resolution
16-25 MP
$739.00View partBuild a system with it

Which USB port does each depth camera belong on?

Give each USB camera its own USB 3.0 root-hub port on the motherboard and bind the driver to that physical position with an explicit usb_port argument, because the kernel port path — like the 2-1.1 and 2-1.2.1 pair in a failing launch — is the only address that survives reboots.

A Linux USB path reads bus first, then the hub-port chain: 2-1.1 is bus 2, root port 1, and port 1 of whatever hangs from there. Print the tree with lsusb -t, match each camera's vendor and product ID to a slot, and write that path into the include. Then hold the placement rules:

  • One camera per motherboard USB 3.0 root-hub port at full rate.
  • If the board exposes a second USB controller, split the cameras across controllers — each contributes its own ≈400 MB/s.
  • If a hub is unavoidable, use a powered USB 3.0 hub; frame-rate sag on shared hubs is its own failure mode.
  • Never put a USB 2.0 extension anywhere in the chain.

A depth camera that disconnects when its infrared stream starts points at the USB power budget rather than bandwidth, and no port pinning rescues an underpowered hub.

A projected structured-light 3D camera such as the MV-DPS200P-02 obeys the same port rules as any depth camera on the bus.

3D sensorsHikrobot MV-DPS200P-02 Projected structured-light 3D cameraMV-DPS200P-02
Type
Stereo / structured light
$8,829.00 · quotedView and quote

Where should the GigE camera's network interface sit?

Put the GigE camera on a dedicated network interface of its own, because a gigabit port carries only about 118 MB/s, one uncompressed stream can consume all of it, and a shared NIC turns a working camera into one that disappears mid-run.

Dedicate the port in hardware: an onboard second NIC or an inexpensive PCIe gigabit card, addressed on a private subnet that no other adapter uses — two adapters on one subnet confuse discovery and can hang the vision stack.

Set the MTU to 9000 bytes on the NIC and the camera. Packet size does not buy bandwidth, it buys CPU: a saturated link moves 118,000,000 ÷ 1,500 ≈ 78,700 packets per second at the default frame size and 118,000,000 ÷ 9,000 ≈ 13,100 at 9000 bytes, roughly a six-fold cut in interrupt load.

If a second GigE camera must share that NIC later, split the budget explicitly and add inter-packet delay in the driver, the way a host survives two GigE cameras on one NIC port budget, instead of hoping. Read the negotiated speed with ethtool on the first run too: a link that falls to 100 Mbit/s carries a tenth of the budget, and the driver usually reports it as a packet-size error when the link falls below gigabit.

What startup order stops the driver nodes racing?

Start the GigE driver first and bring up each USB driver a few seconds apart, because enumeration, bandwidth reservation and camera-side streaming setup are one-time operations that collide when several nodes request them in the same instant.

Any delay mechanism works: a wrapper that sleeps before spawning each node group, or starting the groups one at a time from a shell with sleep between them. Two to three seconds per node is enough in practice, GigE first so the network camera claims its link while the USB drivers still have the controller to themselves.

Audit the copied arguments while you are in the file. In the launch behind this question, both depth includes passed device_num 2; if that argument counts devices your driver should open, set it to the cameras actually bound to that node's ports rather than a value inherited from another include.

Reconnect behaviour matters as much as startup: a driver that times out with other USB devices on one shared controller can drag its camera down, which is why the stagger belongs ahead of every node, not only the first.

How do you verify the combined launch is healthy?

Prove the buses one at a time before proving them together: each depth topic holding its 30 fps for ten minutes, the network link at 1000 Mbit/s with clean error counters, then the full launch for half an hour with at least one CPU core still idle.

Measure instead of watching the visualizer. rostopic hz on each image topic prints the true publish rate, and a topic that sags within a minute of adding the third camera names the short bus. ethtool gives negotiated speed and error counters, and the kernel log is the honest witness on USB: any disconnect line during the soak means port placement or power, not the driver. When the camera answers ping but the driver still times out, suspect the stream path — ICMP is not the control port.

The prevention list that falls out of every fix above:

  1. Budget every stream with the formula before writing the launch file.
  2. Pin each USB camera to a named USB 3.0 root-hub port with usb_port.
  3. Give each GigE camera a dedicated NIC on a private subnet, MTU 9000.
  4. Stagger driver starts by two to three seconds, GigE first.
  5. Soak the combined launch at full rate for ten minutes before calling it fixed.

More bus-budget debugging lives on the systems topic page.

When is one machine no longer enough for three cameras?

Split the hardware when the arithmetic says so: once your USB streams pass roughly 400 MB/s on one controller or the GigE stream needs more than a single 118 MB/s link, move a camera to its own controller, a faster link or a second host.

Three cases decide it:

  • Two 720p-class USB depth cameras plus a low-resolution GigE camera: one machine with the three fixes above — the 304 MB/s USB figure and a modest Ethernet stream both fit their buses.
  • A 20 MP GigE stream at 15 fps, ≈299 MB/s: it never fits a 118 MB/s link, so move the camera to 2.5G or 10G or accept ≈5.9 fps.
  • Three or more full-rate USB depth cameras: add a PCIe USB controller card so a second controller contributes its own ≈400 MB/s, or move cameras to a second host.

Building rather than repairing? Pick the cameras from the area scan cameras and 3D sensors pages, or start at the camera finder.

Build the whole station

The configurator matches a camera, lens, light, light controller and cables to each other, step by step, and lists only parts that fit what you already picked.

Start with the camera

If the arithmetic says second host and you want a sanity check on the split before ordering, send the stream table through the contact page and we will run the numbers with you.

Questions

What does a usb_port value such as 2-1.1 mean?

It is the Linux kernel's physical address of a USB port: the first number is the bus, then the hub-port chain, so 2-1.1 means bus 2, port 1, downstream port 1. Because the path follows hardware positions rather than enumeration order, it is the stable way to bind one driver node to one camera. Print the tree with lsusb -t and match each camera's IDs to its slot before writing the launch.

Can two depth cameras share one powered USB 3.0 hub?

Only when the streams are small enough. A hub's upstream link carries about the same 400 MB/s as a controller port, so two 720p-class cameras at roughly 152 MB/s each just fit, while two 1080p triples at about 342 MB/s each never do. Give full-rate cameras separate root ports and reserve hubs for reduced streams, lower frame rates or narrow ROIs.

Do I need jumbo frames for a single GigE camera?

Not to fit the link — packet size does not change payload capacity. A 9000-byte MTU cuts the packet rate roughly six-fold, from about 78,700 to about 13,100 packets per second on a saturated gigabit link, which lowers CPU and interrupt load. At low frame rates nothing measurable changes; on a full-rate stream it is the first setting to raise.

Why does my GigE camera answer ping but the driver still times out?

A ping proves the link and IP stack, not the data stream: the driver opens separate control and streaming connections that an ICMP reply says nothing about. The usual culprits are a link that negotiated 100 Mbit/s, a camera addressed off the NIC's subnet, or a second adapter sharing the camera's subnet. Check negotiated speed and adapter addressing before suspecting the camera.