Your application runs on an industrial controller whose OS image the vendor maintains, and the camera on your bench is USB and UVC. The question is not image quality; it is whether that image can talk to the camera at all. This guide gives you a three-step check to run on the controller, a worked bandwidth example that sizes a 12 MP stream on USB 3.0 against Gigabit Ethernet, and the decision for each possible outcome. When the check fails, you will know which camera class to order instead of fighting an image you cannot change.
What a controller must provide for a UVC camera
USB Video Class (UVC) is a standard that removes the vendor driver from the equation: any compliant camera enumerates with the operating system's built-in class driver. On Linux that driver is the uvcvideo kernel module. It claims the camera, creates the V4L2 device node /dev/video0, and your capture code reads frames from that node. Support on an industrial controller therefore means one specific thing: the vendor's OS image already contains the module. It is a property of the image, not of the camera.
Four things have to line up:
- The uvcvideo driver exists in the image's kernel, compiled in or as a loadable module.
- It loads at boot, so a plugged-in camera produces a /dev/video node with no action from you.
- The user your application runs as can open the node, which on most images means membership in the video group — see the Linux camera device permission checks.
- User-space capture software reads V4L2: your own code through OpenCV or GStreamer, or the runtime's image-acquisition functions.
Keep UVC and USB3 Vision apart. A USB3 Vision camera speaks a machine-vision protocol, delivers no /dev/video node, and needs the maker's GenTL producer library in user space. UVC is the generic class whose driver already sits in the kernel. On hardware you reimage yourself — a Linux PC or your own embedded board — both routes are routine, and the driver-free UVC path on an embedded board and the UVC-compliant camera setup that skips the driver rebuild cover them step by step. On a vendor-maintained controller, neither route is yours to take.
Many controllers also run their applications in containers. The kernel driver still belongs to the host: you pass the existing /dev/video node into the container, as the Docker V4L2 media-node setup describes. A container cannot create a driver the host image lacks.
Run the three-step check on the controller
Step 1 — ask the image whether the driver exists. Run modinfo uvcvideo. A filename and version in the output mean the module ships in the image. An error saying the module was not found means the image's kernel configuration left the USB Video Class driver out. If the camera is already plugged in, lsusb lists it either way; enumeration is not support.
Step 2 — plug in and look for the node. List the video devices with ls /dev/video*. A node appearing means the driver claimed the camera. A camera that shows in lsusb with no /dev/video node is the textbook missing-driver symptom, and the lsusb-but-no-video-device diagnosis walks through the causes in order.
Step 3 — read a frame and measure it. Capture with the V4L2 utilities on the image or your own framework, at the camera's native resolution, and record two numbers: the frames per second actually delivered, and the CPU load while decoding. A driver that loads but cannot sustain the frame rate is a bandwidth or CPU problem, not a support problem.
The result sorts every controller into one of three rows. Driver present and node appears: the UVC path works, and the bandwidth numbers in the worked example below decide the camera. Driver missing and the image is vendor-locked: go straight to the GigE path. Driver missing and you own the image: rebuilding it with the class driver enabled is routine, and the embedded-board guides above cover the settings.
What “no official support” costs in production
A camera that enumerates without a class driver produces no device node, so nothing on the controller can read it. The deeper cost is time. Suppose you get a module built and loaded on today's image release: the controller vendor does not regression-test UVC, so the next image update can drop it, and you discover that on the shop floor rather than at a bench.
On a locked, verified runtime, loading your own kernel module is not a legitimate route in any case. A module must be built against the image's exact kernel version and configuration, and the verification is designed to refuse out-of-tree modules. The working routes are a UVC-enabled image variant from the controller vendor, a separate device that is built for vision, or an Ethernet camera that needs no kernel module. Where an unrecognized UVC camera on an industrial IoT controller turns out to be a kernel-configuration gap, a walkthrough of that kernel-configuration fix shows what the vendor side of the request looks like, and matching fix for a CIP industrial Linux kernel covers the downstream-kernel case.
Worked example: a 12 MP stream on USB 3.0 versus on GigE
The bandwidth arithmetic is what turns the support question into an order. The catalog sells the same 12 MP sensor twice, once behind each interface, and the two data sheets bracket the decision your controller faces. On the USB 3.0 side sits LS-CMR-0166, a 12 MP camera on a 1/1.7" rolling-shutter IMX226 sensor, streaming 4000 × 3000 pixels at 30 fps.
- Sensor format
- 1/1.7"
- Interface
- USB3
- Resolution
- 12 MP
- Shutter
- Rolling
The inputs, and where each comes from: 4000 × 3000 pixels per frame and 30 fps from the USB 3.0 data sheet; 9 fps for the GigE variant from its data sheet; 8-bit mono at 1 byte per pixel as the working assumption, stated because a UVC camera sending MJPEG compresses the stream by roughly 5-10×; and the link budgets from the interface standards — USB 3.0 signals at 5 Gbit/s, whose 8b/10b coding leaves 500 MB/s of raw payload and, after protocol overhead, about 400 MB/s of practical sustained throughput, against Gigabit Ethernet at 1 Gbit/s ÷ 8 = 125 MB/s theoretical and roughly 115 MB/s in practice.
The arithmetic, written out:
- Bytes per frame: 4000 × 3000 = 12,000,000 pixels × 1 byte = 12 MB.
- USB 3.0 side: 12 MB × 30 fps = 360 MB/s of sustained payload. That is 90% of the ~400 MB/s practical budget, which is why the rated rate wants a short, certified USB 3.0 cable.
- GigE side: 12 MB × 9 fps = 108 MB/s, below both the 125 MB/s theoretical budget and the ~115 MB/s practical ceiling.
- Cross-check from the ceiling: 125 MB/s ÷ 12 MB ≈ 10.4 fps, and 115 MB/s ÷ 12 MB ≈ 9.6 fps. The GigE variant's 9 fps rating sits just under the practical ceiling, which is exactly where a data-sheet rate should sit.
The result: 360 MB/s on USB 3.0 against 108 MB/s on GigE for the same sensor. The decision follows a threshold: once sustained payload passes about 115 MB/s, one Gbit link cannot carry the stream — lower the frame rate (budget ÷ bytes per frame) or change the link class. At 12 MP in 8-bit mono, that reads as about 9 fps maximum on GigE, and 30 fps only over USB 3.0 or 10GigE. UVC changes the USB side of this, not the Ethernet side: an MJPEG stream at 5-10× compression lands near 36-72 MB/s, comfortably inside USB 3.0.
The GigE variant in the catalog is LS-CMR-0053, the same 12 MP IMX226 sensor rated at 9 fps.
- Sensor format
- 1/1.7"
- Lens mount
- C-mount
- Interface
- GigE
- Resolution
- 12 MP
Why the GigE path is the safer default on a locked runtime
A GigE Vision camera is an Ethernet device. The controller's existing network stack carries the packets, no camera-vendor kernel module is involved, and an image update does not silently remove the camera path. What you check instead is software: the maker's GenICam/GenTL library must exist for the controller's OS and processor architecture. Both are application-layer questions, and the GenICam-over-Ethernet connection guide and the GigE Vision driver-support check on an RT controller show how they are answered in practice.
Size the camera to the budget from the worked example, and a small sensor keeps you far under it. MV-CU020-90GC is a 2.5 MP color GigE camera with a global shutter and a C-mount. In 8-bit mono each frame is about 2.5 MB (2.5 million pixels × 1 byte), so the ~115 MB/s practical budget of one Gbit link carries about 46 frames per second of that payload; the port is never the constraint.
- Sensor format
- 1/1.7"
- Lens mount
- C-mount
- Interface
- GigE
- Resolution
- Up to 3 MP
Wiring improves as well. Copper Gigabit Ethernet runs to 100 m under IEEE 802.3, against roughly 3 m for a passive USB 3.0 cable, so the controller can sit in the cabinet while the camera sits on the machine — pick the run from the camera data cables. With a PoE port the same cable powers the camera, which the PoE support check covers; the MV-GE2002P dual-port PoE NIC adds two such ports to a controller that has none.
- Interface
- GigE
- Ports
- 2 ports
When the application outgrows 1 Gbit/s, the same logic moves up one class: 10GigE network cards and frame grabbers take multi-camera rates off the CPU, the GigE Vision high-performance NIC driver measurements show what a tuned port adds, and the accessories finder lists the cards. For the camera side, filter the area scan cameras by interface and resolution in the camera finder.
The decision for each case
| What the check shows | What it means | What you order or do |
|---|---|---|
| uvcvideo present, /dev/video node appears, delivered fps meets target | Supported UVC path | Run the UVC camera; switch to its MJPEG format above ~80% of the link budget; record the image version your validation ran on |
| uvcvideo missing, image locked, vendor offers a UVC-enabled image variant | Supported after an image change | Order that image variant and re-run the three-step check on receipt |
| uvcvideo missing, image locked, no image variant offered | USB path unsupported | Build on a GigE Vision camera: confirm the GenTL library for the controller's OS and CPU, size the frame rate to the ~115 MB/s budget, add a PoE NIC for one-cable wiring |
| You own the OS image | UVC is driver-free | Enable the class driver in your build and follow the embedded-board UVC guides; containers just receive the /dev/video node |
For the controller that raises this question in the first place — a vendor-maintained runtime with no USB camera statement — the realistic row is the third one, and taking it is the right call. It keeps the image stock and the updates safe, and it moves your dependency from a kernel module you cannot ship to a user-space library you can test. The price is one added software check and, if you want PoE, one network card.
Before you order: five checks
-
Image and driver. Record the controller's image version and the
modinfo uvcvideoresult. Together they identify exactly what ships and make the vendor conversation concrete. - UVC declaration. Confirm the camera data sheet states USB Video Class compliance and lists its MJPEG and YUV formats. Non-UVC USB devices need a maker library that may not exist for your controller's OS or CPU.
- Bandwidth. Run the payload formula with your resolution, pixel depth and frame rate, then compare with about 400 MB/s on USB 3.0 and about 115 MB/s on GigE. Above 80% of budget, change the format or the interface before it drops frames in production.
- Decode load. Measure CPU load at the delivered frame rate in step 3 of the check. Fanless low-power cores are where MJPEG decode hurts; a desktop-class CPU shrugs it off.
- Library and cables. For the GigE path, the maker's GenTL producer must list the controller's OS and processor architecture; for either path, check cable reach — about 3 m for passive USB 3.0, up to 100 m for copper Ethernet.
If the check lands on the GigE row, the camera configurator filters by interface, resolution and shutter, and the systems topic page collects the controller-side guides. Tell us the image version and the camera model through the contact page and we will settle the support question before you order.
Questions
Will a USB 2.0 port help if the controller has no USB 3.0?
The same uvcvideo driver serves both, so port speed never fixes a missing driver. Bandwidth is the second limit: USB 2.0 moves 480 Mbit/s, about 40 MB/s of payload, so a 4000 × 3000 8-bit frame of 12 MB streams at roughly 3 fps uncompressed (40 ÷ 12 ≈ 3.3). Above that, the camera's MJPEG mode carries motion acceptably for code reading and monitoring.
Is every USB camera a UVC camera?
No. UVC is a class the camera must declare; those cameras work with the operating system's built-in driver. Everything else, including USB3 Vision cameras, needs a maker's user-space library, and that library must exist for the controller's OS and processor architecture. Read the data sheet for a UVC compliance statement and the supported MJPEG and YUV formats before you plan the port.
Can you add the uvcvideo driver to a locked controller image?
Not legitimately. A kernel module must be built against the image's exact kernel version and configuration, and a verified runtime is designed to refuse out-of-tree modules — while the next image update removes anything added by hand. Ask the controller vendor for an image with the USB Video Class driver enabled, run the camera on a separate vision controller, or use a GigE Vision camera.
How many UVC cameras can one USB 3.0 host carry?
Count payload, not ports. A 1920 × 1080 uncompressed stream at 30 fps in 2-bytes-per-pixel YUV 4:2:2 is 1920 × 1080 × 2 × 30 ≈ 124 MB/s. Against a practical USB 3.0 budget near 400 MB/s, three such cameras fill the controller; beyond that, switch them to MJPEG and confirm the CPU decodes each stream within the frame period.
Do GigE Vision cameras on a controller need a frame grabber?
Usually not. A spare Gbit Ethernet port carries one camera at moderate rates; the camera is just another network device. A dedicated NIC earns its slot for three reasons: PoE to power the camera over the data cable, separation from the plant network, and lower CPU load at high or multi-camera rates. Frame grabbers and 10GigE cards enter when the link budget itself becomes the limit.



