Your USB camera shows up in lsusb, the SDK lists its serial number, and the moment your code opens it without sudo the call fails with permission denied. That is a missing udev rule, not a broken driver. This guide is for anyone putting a USB depth camera, stereo camera or industrial area scan camera on a Linux vision PC — on a bench, on a robot, or in a multi-camera rig — who needs the device to open for a normal account, at boot, and from a service. You will confirm the cause, read the vendor and product ID, write or install the rule the camera's own package ships, reload udev without a reboot and prove the fix with a non-sudo open. The whole job is one short file and a handful of commands.
Why does a USB camera only open with sudo?
Libusb-based SDKs need write access to the camera's device node, and on a default install that node belongs to root, so root succeeds and your login account fails until a udev rule grants ordinary users or a group read and write.
libusb documents the requirement itself: opening a USB device needs write permission on its node, and every frame you read afterwards flows through that same handle. Linux exposes each USB device as a node under /dev/bus/usb/, named for its bus and address: Bus 001, Device 004 becomes /dev/bus/usb/001/004, both numbers padded to three digits. Run ls -l on that path and you will see root ownership with no write bit for your account — the exact asymmetry that makes sudo work and your shell fail.
A GigE camera has no device node at all; if a network camera is unreachable, the fault lives in subnets and links, not in udev — see 3D camera not pingable on a Linux controller: fix subnet and link.
Is it a permissions fault or a driver fault?
Open the device twice, once with sudo and once without: if the root run enumerates the camera and your user run stops with permission denied on the same node, permissions are the fault; if both fail, the problem is detection or the driver instead.
Three checks take a minute each. lsusb must list the camera — if the line is missing, follow USB camera in lsusb but not detected by the vision SDK on Linux first, because no rule can fix a device the kernel has not enumerated. dmesg right after a replug should announce the new USB device with its bus and device numbers. ls -l /dev/bus/usb/001/004 should show root ownership and no write bit for others.
When even the sudo run cannot find the camera, the SDK's access path is the suspect: work through camera SDK cannot find device: isolate Linux access errors before touching udev.
Where do the vendor and product ID come from?
Run lsusb with the camera plugged in and read the ID field: the hex pair is vendor:product, you paste those two strings into the rule, and udevadm info confirms which attributes the tree really carries.
$ lsusb
Bus 001 Device 004: ID 1234:5678 Depth Camera
1234:5678 is an illustrative pair — your line carries your camera's own values, and those are what the rule must match. The bus and device numbers give the node: Bus 001, Device 004 is /dev/bus/usb/001/004. Confirm the attributes udev will see:
$ udevadm info -q path -n /dev/bus/usb/001/004
$ udevadm info -a -n /dev/bus/usb/001/004 | grep -E 'idVendor|idProduct'
ATTRS{idVendor}=="1234"
ATTRS{idProduct}=="5678"
Two details matter. The values are strings: write 1234, never 0x1234. With two identical cameras on one bus, read ATTRS{serial} from the same output, or unplug all but one and watch dmesg to tell them apart. The USB ID decides more than permissions: a depth camera sitting in firmware update mode announces its state through a changed product ID, as covered in depth camera stuck in firmware update mode: read the USB ID first.
How do you write and apply the rule?
Write one line into a file in /etc/udev/rules.d/, reload udev, replug, and the camera opens for your account; the whole procedure is six steps and no reboot.
- Create the file with sudo: /etc/udev/rules.d/99-usb-camera.rules. The name must end in .rules — udev reads nothing else — and the 99- prefix runs your rule after the distribution's own.
- Paste the rule, with the IDs from your own lsusb output in place of the illustrative pair:
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1234", ATTRS{idProduct}=="5678", MODE:="0666"
- Read the three keys: SUBSYSTEMS=="usb" walks up the device's parent chain to the USB device itself; ATTRS{idVendor} and ATTRS{idProduct} match that parent against the strings from lsusb; MODE:="0666" grants read and write to owner, group and others — a 6 is 4 for read plus 2 for write — and the := fixes the value so later rules cannot override it.
- Reload: sudo udevadm control --reload.
- Replug the camera, or replay the plug event without touching the hardware by running sudo udevadm trigger with the usb subsystem as its match.
- Check the node: ls -l /dev/bus/usb/001/004 should now read rw-rw-rw-.
On a machine with several logins, grant a group instead: MODE:="0660" plus GROUP:="plugdev" (the Debian and Ubuntu group), then sudo usermod -aG plugdev yourname and log out and back in — group membership is read at login, not live. Distributions outside the Debian family name their own groups; the mechanism is identical.
Does the camera package already ship the rule?
Most depth-camera SDK packages ship their udev rule inside the package but do not install it: list the package contents with dpkg -L and grep for udev, then run the vendor's documented registration script or copy that shipped file into /etc/udev/rules.d/.
$ dpkg -L your-sdk-package | grep -i udev
/opt/your-sdk-package/udev/99-your-camera-libusb.rules
A result shaped like the second line means the rule exists but sits in the package's own directory — a layout some vendors choose so you can install or remove the rule deliberately. Installing it is one copy, then the usual reload and replug:
$ sudo cp /opt/your-sdk-package/udev/99-your-camera-libusb.rules /etc/udev/rules.d/
$ sudo udevadm control --reload
If dpkg -L returns no udev hit, the package omits the rule and the file from the previous section is the fix. Either way, everything you install comes from the package you already have or from the vendor's documented script — the same discipline as any Linux camera file, where a reinstall beats copying undocumented files around, as set out in camera driver file corrupted: reinstall, don't copy files.
How do you prove the camera opens without sudo?
Read the node's mode, then open the camera from your normal account with the SDK's own sample: the node should show rw for everyone or for your group, and the open must succeed with no sudo anywhere in the command.
ls -l on the node is the first half of the proof. A two-line pyusb check is the second, with 0x1234 and 0x5678 as the illustrative IDs from above:
import usb.core
cam = usb.core.find(idVendor=0x1234, idProduct=0x5678)
print("found:", cam is not None)
cam.set_configuration() # needs write access: errno 13 before the rule
print("open ok")
Before the rule, set_configuration raises USBError with errno 13 — access denied, the kernel refusing the write. After the rule and a replug, the same script prints open ok from your normal account.
One branch to know: a camera that presents a standard video class also creates /dev/video0 nodes, which stock Debian and Ubuntu rules hand to the video group. If your SDK reads V4L2 rather than libusb, join the video group instead, and check which class the camera presents — the camera in lsusb but no video device: check the USB class walkthrough shows how the class decides which node appears.
Why is the rule still not applying?
Work down this list in order: file not in /etc/udev/rules.d/ or missing the .rules suffix, an idVendor or idProduct that differs from your own lsusb line, and rules not reloaded — these three cover most failures, and the rarer ones follow.
- The rule was edited under /lib/udev/rules.d or /run/udev: keep local rules in /etc/udev/rules.d, because the other directories belong to the distribution and to runtime, and package updates overwrite them.
- The key names do not match udevadm info -a: match ATTRS{idVendor}, not ATTRS{vendor}, and copy attribute names and values exactly as printed.
- The values carry a prefix: rules compare strings, so 0x1234 never matches 1234.
- The reload happened but the replug did not: --reload re-reads files, and only a replug or a trigger re-runs rules on a device that is already plugged in.
- The group was joined but the shell is older: membership applies from the next login, and a systemd service counts as its own account — put that account in the group too.
- The denial names renderD128 or card1 instead of the camera: that is the GPU render node when a depth pipeline aligns on the GPU, a separate fault with its own fix in libEGL renderD128 permission denied: why depth alignment hits the CPU.
- Your distribution has no plugdev group: Fedora and RHEL families do not ship it, so use MODE 0666 or a group of your own.
How do two identical cameras keep stable names?
Give each physical camera a stable name by matching its serial number in the same rule and adding a SYMLINK, so /dev/depth_left and /dev/depth_right survive replugs and boots; matching IDs alone cannot tell two identical units apart.
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1234", ATTRS{idProduct}=="5678", ATTRS{serial}=="WW00A1", SYMLINK+="depth_left", MODE:="0660", GROUP:="plugdev"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1234", ATTRS{idProduct}=="5678", ATTRS{serial}=="WW00B2", SYMLINK+="depth_right", MODE:="0660", GROUP:="plugdev"
WW00A1 and WW00B2 are illustrative serials — read yours from the udevadm info -a output. If both units report the same serial, pin each camera to a physical socket instead by matching the parent port chain, the KERNELS entries in that same output, which never changes for a given connector. Hand /dev/depth_left to the SDK wherever it accepts a device path, or match the serial in your own code; the approach in Linux camera device selection: find the RGB stream pairs well with stable names when one camera offers several streams.
Which USB3 cameras pair well with a Linux controller?
Any USB3 vision or depth camera works over the same rule, and the interface decides the bandwidth: USB 3.0 moves up to 5 Gbps against GigE's 1 Gbps, so a streaming depth camera belongs on a USB 3 port and a large rig may belong on GigE instead.
When you are speccing the camera rather than fixing one, the camera finder filters USB3 and GigE models side by side, the area scan cameras page lists the industrial C-mount lines, and the 3D sensors page the laser profilers and stereo cameras. Every order comes with free expert support, so a permissions question like this one travels with the hardware. More depth-camera fixes sit on the 3D topic page.
Laser profilers and stereo 3D cameras
170 models · from $699.00The 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.
If you want a second opinion on the camera, lens and lighting before you order, the contact page reaches the applications team.
Questions
Is MODE 0666 on a camera device node a security risk?
It lets every local account read and write that one camera, which is what most vendor rules ship for a single-purpose vision PC, and nothing is exposed over the network. On a machine with untrusted logins, create a dedicated group, set GROUP to it with MODE 0660, and put only the vision accounts in it. A re-login is needed before the change reaches a shell.
Do you need to reboot after adding a udev rule?
No. udevadm control --reload re-reads the rule files, and a replug or a trigger recreates the node with the new mode immediately. If the fix survives a replug but fails after a reboot, the file itself is at fault: wrong directory, a name without the .rules suffix, or permissions that stop udev reading it.
Does the same rule cover a camera that appears as /dev/ttyACM0?
Yes. Devices that present a serial port carry the same vendor and product attributes on their USB parent, so the identical ATTRS match works; add a KERNEL match on ttyACM or ttyUSB to restrict the rule to the port itself. Run dmesg right after a replug to see which node the kernel assigned, then apply the same reload, replug and open test.
Why must the vendor and product IDs come from your own lsusb output?
The vendor ID belongs to the maker and the product ID is set per model and sometimes per firmware state, so two cameras that look identical can report different pairs. A rule copied from another post then never fires, with no error to explain why. Read the ID field on the machine the camera runs on; a camera sitting in firmware update mode enumerates with a different product ID too.
Can a quick chmod replace the rule?
You can run chmod 666 on the node as a one-minute test, and it proves the diagnosis because the SDK opens straight away. The change does not survive: udev regenerates the node at every replug and boot from its own database, so the rule file is the persistent version of the same edit. Keep chmod for diagnosis, the rule for the fix.