Three GigE cameras, one 1 GbE switch: two stream cleanly, and the third pushes the link past what it can carry. The fix is not a bigger switch — it is to stop streaming what nobody is reading. Connect a camera when a node subscribes to its image topic and disconnect it when the last subscriber leaves, and the idle camera contributes zero bytes to the link. You will set one driver parameter, prove the stream is down with netstat and tcpdump, and budget the link with three numbers. The guide is for anyone running several GigE area scan cameras through one switch or one network interface.
Why a third camera breaks a link that two shared
A 1 Gbit/s link moves 125 MB/s at the wire: 1,000 Mbit/s ÷ 8 bits per byte. GigE Vision wraps every image fragment in a UDP/IP datagram inside an Ethernet frame, and headers plus inter-packet gaps cost roughly 5-8% of that gross rate. Plan on about 118 MB/s of usable image payload per 1 GbE link, counting only cameras that are connected at the same moment. The constraint is simultaneous demand, not an average.
When the sum goes over, the switch drops packets and the symptoms arrive together: blank or torn frames, retransmissions and buffer overflow errors in the driver. GigE Vision stream packet loss: diagnose blank frames treats the symptom side; if your logs show buffer faults, this GigE camera buffer overflow walkthrough covers the same failure from the capture side. How much frame rate one camera may claim from a link is its own sum: GigE Vision for a high speed camera: how much frame rate fits works it through.
Most cameras that hit this ceiling are 5 MP class running near full rate; a 2.5 MP sensor halves the per-camera load. The MV-CU020-90GC is a 2.5 MP color GigE camera with a 1/1.7" sensor, C-mount and global shutter.
- Sensor format
- 1/1.7"
- Lens mount
- C-mount
- Interface
- GigE
- Resolution
- Up to 3 MP
What subscriber-gating changes
Subscriber-gating moves connect and disconnect out of your application code and into the driver. The driver watches the subscriber count on the image topic: the first subscriber starts the camera, the last unsubscribe stops it. The node, the topic and the publisher stay advertised throughout, so a viewer that comes back receives frames without a launch restart. The camera keeps its IP address and its control channel; only the UDP image stream closes.
Two consequences matter. First, the idle camera costs nothing: no packets on the link, and the driver process falls to essentially zero CPU, which is the fastest signal that the stream is really down. Second, every subscribe cycle runs the SDK's start and stop paths, and those are the heaviest paths a camera driver has. If a driver has ever hung on shutdown for you, the same fragility is in play — camera crash when stopping acquisition: isolate the cause walks that failure down. Gating is also not the same as pausing frames inside a live session: pause and resume camera acquisition in a vision system covers stopping acquisition while the camera stays connected, which suits one camera with a duty cycle rather than a saturated shared link.
Turn the setting on
The parameter is driver-side and defaults to False, so nothing changes until you set it. One ROS 2 camera driver implements the pattern as connect_while_subscribed; set it in the launch file, not in the parameter yaml.
parameters = {
'connect_while_subscribed': True,
}
- Check the build. Set the parameter and judge behavior, not launch output: if the camera still streams with zero subscribers, your build predates the feature. Update the driver first — an outdated clone behaves exactly like a correct one from the launch file.
-
Set the flag where it lives. Pass
connect_while_subscribed: Truein the parameters block of the camera node's launch entry, as above. The yaml needs no edit. - Restart the launch and subscribe from a viewer; frames should arrive as before.
- Drop the subscriber. Close the viewer, then run the checks in the next section before you trust the setting.
- Soak it. Run a couple of weeks of open-and-close cycles before the rig goes into service. Start and stop is the code path that breaks first.
Prove the stream actually stopped
Publisher count will not help you — it stays at 1 by design. Work down this list instead; the whole check takes two minutes.
-
ros2 topic info /camera/image_raw— you wantSubscription count: 0.Publisher count: 1is the healthy resting state. -
ros2 node infoon the driver and on anything that ever opened the topic. A forgotten recorder or viewer keeps the camera connected. - Watch the driver process's CPU. It should fall to near zero with no subscribers, because frames stop at the SDK boundary.
- Run
netstat -apon the host: a UDP listener appears when the camera connects and disappears when it disconnects. A missing listener is the direct proof that the stream is closed. - Run
tcpdump -i eth0 host 192.168.1.50(your interface and camera IP) while the camera streams, then after the last unsubscribe: packets while connected, silence after.
If subscriber-gating is on and CPU stays high with zero subscribers, the connection did not close. That is the build problem from step 1, not a network problem.
Worked example: three 5 MP cameras on one 1 GbE switch
Inputs, with where each comes from:
- Cameras: three 5 MP GigE models in
mono8, so 1 byte per pixel — the camera class behind the "two run, three do not" case. - Frame rate: 10 fps each, set in software, because that is all an operator display needs.
- Link: one 1 GbE switch — 125 MB/s gross, about 118 MB/s usable payload.
The rule in words: a connected GigE camera sends at its set frame rate continuously, so the sum of simultaneously connected streams must stay below the usable link rate, with headroom for bursts.
Result: two cameras fit with roughly 15% headroom, which is why that pair ran clean. The third adds 50 MB/s to a link with about 18 MB/s left, so the switch drops roughly a fifth of the demand — and you see blank frames, not a subtle loss.
Decision: never connect the third camera while two are streaming. Cycle which pair is live through subscriptions and let gating hold the idle camera at 0 MB/s. Design to a working limit of about 100 MB/s of simultaneous stream on a 1 GbE link (≈85% of usable) and treat 118 MB/s as the hard ceiling. To run all three continuously instead, each camera drops to about 7 fps: 5,000,000 × 7 × 1 ÷ 1,000,000 = 35 MB/s, and 3 × 35 = 105 MB/s, about 89% of usable.
Common mistakes
-
The flag is set but nothing changes. Your driver build predates the feature; an outdated clone is indistinguishable from a correct one at the launch file. Update, restart, then judge by CPU and
netstat, not by logs. -
Trusting the publisher count.
Publisher count: 1is the resting state, not proof of streaming.Subscription count: 0, near-zero CPU and a missing UDP listener are the signals that matter. -
A forgotten subscriber. One recorder, diagnostic node or open viewer holds the camera open.
ros2 node infoon every node in the system finds it. - Putting the flag in the yaml. It belongs in the launch file's parameter block; the yaml needs no change.
-
Reaching for a software trigger instead. Setting
trigger_modeto"Software"changes when frames are captured, not whether the camera is connected, and it hands you the pacing job that gating does automatically.
When gating is the wrong fix
Gating fits displays and occasional checks, not continuous inspection: a line that needs every frame cannot have one camera disconnected. For those cases change the numbers instead. Cut frame rate or crop the ROI until the sum fits the 118 MB/s budget, enable jumbo frames to shave overhead, or stop sharing one interface. A controller with 5+ LAN ports gives every GigE camera its own NIC, and PoE camera ports carry data and power over one cable. For switch sizing and per-port budgeting across a whole cell, see GigE camera network planning: switch ports and bandwidth.
The vision controllers below take that path: choose by LAN port count first, then by CPU for the image processing you run alongside the streams.
- LAN ports
- 5+ LAN ports
- USB 3 ports
- 3-4 USB 3 ports
- LAN ports
- 5+ LAN ports
- USB 3 ports
- 3-4 USB 3 ports
- LAN ports
- 3-4 LAN ports
- USB 3 ports
- 2 USB 3 ports
The decision, per case
- Two display cameras on one 1 GbE link: run them straight. You sit near 85% utilization with nothing to configure.
-
Three or more cameras used one or two at a time: enable
connect_while_subscribed, cycle subscriptions from your viewers, and keep the two-minute verification in your commissioning checklist. - All cameras needed at once, continuously: shrink frame rate or ROI until the sum fits about 100 MB/s, or give each camera its own port on a multi-LAN controller. Jumbo frames recover a few percent more.
- The link still saturates after all that: move one camera off the shared link. The camera finder filters by interface, so a USB3 or 10GigE model ends the contention without touching the network design.
If you are sizing the rig from scratch, work out the network budget before the camera list and step through the camera configurator. More multi-camera networking work lives on the systems topic page, and layout questions reach the team through the contact page.
Questions
Does the camera stay reachable on the network after it disconnects?
Yes. Subscribe-gating closes the image stream, not the device: the camera keeps its IP address and its control channel, so discovery still finds it and the next subscriber reconnects it in place. What disappears is the UDP image stream and its listener on the host, which is what frees roughly 50 MB/s in the worked example. Gating therefore behaves as a bandwidth control, not an on/off switch for the camera.
How many bytes per pixel does a GigE camera stream use?
The pixel format sets it exactly: mono8 and other 8-bit raw formats are 1 byte per pixel, YUV422 is 2, RGB8 is 3, and packed 10- or 12-bit mono formats land near 1.25-1.5. Multiply pixels by frame rate by that factor to get megabytes per second. A 5 MP camera at 24 fps in RGB8 needs about 360 MB/s, which is why color or high-bit-depth streams rarely share a single 1 GbE link.
Why does the publisher count stay at 1 after I unsubscribe?
The publisher belongs to the driver process, not to the camera connection. The driver keeps the node, topic and publisher advertised so a late subscriber finds them instantly; what closes is the connection to the camera itself. Judge the state by Subscription count: 0, by the driver process falling to near-zero CPU, and by the UDP listener vanishing from netstat -ap. Publisher count reads 1 whether the camera is streaming or idle.
Is reconnecting on every subscribe hard on the driver?
It exercises the SDK's start and stop paths every cycle, and those carry the most thread handling in any camera driver, so soak-test before you trust it: run normal operation with viewers opening and closing for a couple of weeks and watch for hangs. If your workload toggles cameras dozens of times per minute, prefer a dedicated NIC per camera over cycling connections, and keep gating for occasional display switching.
Can all three cameras run continuously if I lower the frame rate?
Yes, if each stream shrinks enough. Divide the usable link rate by the camera count: 118 MB/s ÷ 3 gives about 39 MB/s per camera, and a 5 MP mono8 camera reaches that at about 7 fps — 3 × 35 = 105 MB/s, roughly 89% of the link. Watch motion blur below about 8-10 fps on moving parts; if that hurts, gating or a second NIC beats slowing every camera down.
Does this pattern only apply to ROS 2?
The parameter name is driver-specific, but the pattern is not: connect on demand, disconnect when idle, and keep the sum of simultaneous streams inside the link budget. Any middleware that knows its subscriber count can do it, and recorders and debug viewers are usually the subscribers people forget. The verification tools are middleware-agnostic too: netstat, tcpdump and CPU use tell the truth about any GigE camera.



