3D visionTroubleshooting

No video device for a 3D camera on Linux: fix the driver build

A 3D camera that answers on I2C but shows no video device on Linux has a driver that never built: install matching kernel headers, rebuild, modprobe.

LumaSpec Vision9 min read Share on LinkedIn

On this page 9 sections
  1. 01The symptom, decoded
  2. 02Four causes, most likely first
  3. 03Why the headers must match, character for character
  4. 04The fix: headers, clean rebuild, module load
  5. 05Worked example: from dangling link to first point cloud
  6. 06After the node returns: three checks
  7. 07Keep the driver across kernel updates
  8. 08When to stop rebuilding and change the hardware
  9. 09Questions

You connected a ToF or depth camera to a Linux board, the point-cloud script cannot open the camera, and ls /dev/v* lists only the board's own service nodes. Most of these cases share one root cause: the camera answers on I2C at address 0x30, but the kernel driver that would create /dev/video0 never compiled, because the kernel headers matching the running kernel are absent. This guide decodes the symptom, ranks the causes with a test for each, walks the header install and driver rebuild that restore the video node, and shows how to keep the driver alive across kernel updates.

The symptom, decoded

Three findings define this failure on a Debian-family board image:

  • The Python bindings fail to import with a ModuleNotFoundError on the vendor package name.
  • ls /dev/v* shows board service nodes such as /dev/vchiq and /dev/vcio, and no video device.
  • sudo i2cdetect -y 1 shows a device at address 0x30.

Read them together. I2C is the sensor's control bus, wired point to point, so an answer at 0x30 proves power, connector and wiring. A video capture node exists only after a kernel driver probes the sensor and registers it with the V4L2 layer; an empty lsmod result and an empty dmesg filter mean no driver ever tried. The import error is downstream noise: the vendor install script copies the Python bindings after the driver, and the driver step died first.

Four causes, most likely first

Rank Cause Test that confirms it Fix
1 Driver never built: matching kernel headers absent ls -l /lib/modules/$(uname -r)/build is a dangling link Install the matching headers, rebuild
2 Driver built but not loaded, or built for another kernel release lsmod stays empty after a reported success Load the module, or rebuild against the running release
3 Camera not on the bus sudo i2cdetect -y 1 shows nothing near 0x30 Reseat the connector, confirm the bus is enabled
4 Node exists but is hidden from your session A root shell sees /dev/video0, your user or container cannot Fix node permissions, pass the node into the container

Rank 1 is the subject of this guide, and the I2C-plus-empty-lsmod signature points straight at it. Rank 2 follows a system upgrade: the kernel image moves to a new release string and the module built for the old one stays on disk. Rank 3 is a wiring or bus-enable problem, not a software one. Rank 4 lands after the driver works, and it fools people because the camera was broken minutes earlier.

One branch deserves a note. A USB class camera uses the in-tree uvcvideo driver, so its failure is a module that never loaded rather than a build that never ran; the Uvcvideo module not loaded: check for a built-in driver guide covers that branch. The same class of camera can also stall on kernels trimmed for industrial hardware, as in fixing a UVC camera that is not recognized on an industrial Linux kernel.

Why the headers must match, character for character

An out-of-tree camera driver compiles against the running kernel's build tree: headers, generated Makefiles, the kernel configuration and the module symbol table, all keyed to one release string. The vendor Makefile's -C /lib/modules/$(uname -r)/build line points make at that tree. When the package is missing, the build dies on its first line:

make -C /lib/modules/5.15.84-v7l+/build M=$PWD modules
make[1]: *** /lib/modules/5.15.84-v7l+/build: No such file or directory. Stop.

The release string is the whole key. A tree for 5.15.84-v8l+ does not serve a kernel running 5.15.84-v7l+, because the directory name and the module's compatibility data both carry the full string, so a near miss is a miss. An install script that does not abort on errors then prints its success banner anyway, which is how the gap hides until the first capture.

Industrial PCs hit the same wall when the kernel is custom, and building the correct set of kernel headers on an industrial PC is its own procedure. Add-on hardware fails identically, as in a USB interface driver that stops building when headers miss the kernel.

The fix: headers, clean rebuild, module load

  1. Read the running release: uname -r. On the failing board it returns 5.15.84-v7l+.
  2. Test the build tree: ls -l /lib/modules/$(uname -r)/build. A dangling or missing link names the exact gap.
  3. Install the headers package that carries your release string. On this board's image the package is raspberrypi-kernel-headers, installed with apt after an update; the tree must land at /lib/modules/5.15.84-v7l+/build.
  4. Re-run the step 2 test. The link must resolve to a real directory before you compile anything.
  5. In the driver source directory run make clean, then make. The build must leave a .ko file; find . -name '*.ko' shows it, and its base name is the module name.
  6. Run sudo make install, then sudo modprobe followed by that module name.
  7. Confirm the result: ls /dev/video* lists /dev/video0, and the tail of dmesg shows the sensor probing.

The exact strings from one recovered setup, in order:

  • uname -r returns 5.15.84-v7l+.
  • ls -l /lib/modules/5.15.84-v7l+/build points at a target that does not exist.
  • The vendor build stops with /lib/modules/5.15.84-v7l+/build: No such file or directory.
  • After the headers install, the directory exists, make completes, the .ko appears, and modprobe returns silently.
  • ls /dev/video* now lists /dev/video0.
  • sudo i2cdetect -y 1 still shows 0x30, unchanged, because the hardware was never the fault.

The same error returns after an upgrade. The board now runs 5.15.84-v8l+ while the installed tree is 5.15.84-v7l+; the two strings differ by one character and by nothing else that matters to make, and the build link for the new release dangles exactly as before. Install the headers for the release now running, then rebuild.

Once frames flow, check the data rate, not just the node. A sensor delivering 320 x 240 depth at 30 fps produces 320 x 240 = 76,800 points per frame, and 76,800 x 30 = 2,304,000 points per second. A script that opens the node but returns a trickle of points has a healthy driver and a downstream problem.

One safety note belongs here: the moment the module loads, the camera projects infrared light for every frame. Treat it as an active light source, keep it out of your eyes, and never view it through magnifying instruments.

After the node returns: three checks

Permissions come first. A node your user cannot open is a group and udev matter, not a driver one, and the Linux camera device permissions checks walk the settings for the video and media nodes. Containers come second: a Docker container inherits no devices, so pass the V4L2 node and its media companions explicitly, as passing V4L2 media nodes into Docker demonstrates. Data flow comes third: a node with no depth frames means you find where frames stop on Linux, and frames with holes in the cloud mean you fix the depth holes in a 3D point cloud.

If the sensor probes but the video node still never appears with the module loaded, the port mapping is next, and sensor probes but no video node: fix the devicetree chain covers that layer.

Keep the driver across kernel updates

Every kernel image upgrade changes the release string, and an out-of-tree module built for the old string stays behind while the kernel refuses it at load. Register the driver source with DKMS so each new kernel triggers a rebuild at install time, or rebuild by hand right after every upgrade. A driver that loaded on Monday and is refused after Tuesday's upgrade was built for Monday's kernel; nothing about the camera changed.

If your camera needs a kernel patch rather than a standalone module, fixing or avoiding a depth camera kernel patch failure covers that harder path.

When to stop rebuilding and change the hardware

If the station must survive field kernel updates with no rebuild window, move the driver burden off the board. 3D cameras that stream over Ethernet enumerate as network devices: nothing compiles against your kernel release, and the capture path runs in the vendor SDK and the NIC settings instead. The 3D sensors range covers both worlds, and the camera finder filters by type.

For depth sensing at short range, the MV-DT01WMU is a ToF sensing camera.

3D sensorsHikrobot MV-DT01WMU ToF sensing cameraMV-DT01WMU
Type
Depth / ToF camera
Price on requestView and quote

For structured light rather than time of flight, the MV-DPS200P-02 is a projected structured-light 3D camera and the MV-DLS300P-04 is a laser galvanometer stereo camera:

3D sensorsHikrobot MV-DPS200P-02 Projected structured-light 3D cameraMV-DPS200P-02
Type
Stereo / structured light
$8,829.00 · quotedView and quote
3D sensorsHikrobot MV-DLS300P-04 Laser galvanometer stereo cameraMV-DLS300P-04
Type
Stereo / structured light
$16,579.00 · quotedView and quote

A network camera deserves a proper lead rather than the nearest patch cable: the LS-CBL-0199 is a 3 m GigE camera cable, high-flex for drag chains, with screw locks, and the cables range carries other lengths and connector styles.

Cables3 m GigE camera cable, high-flex (drag chain), screw locks (LS-CBL-0199)LS-CBL-0199$54.00View partBuild a system with it

Whichever camera you keep, mount it rigidly at its rated working distance; the 3D camera working distance and positioning guide sets the numbers and the camera stands range holds the position.

Cameras3D sensors

Laser profilers and stereo 3D cameras

170 models · from $699.00

Next step: build the whole station in the system configurator, read further on the 3D topic page, or send the kernel release string and camera model through the contact page and we will match the parts.

Questions

Why does the camera answer on i2cdetect but /dev/video0 is missing?

I2C is the sensor's control bus, wired straight to the chip; an answer at 0x30 proves power and wiring. A video node appears only after a kernel capture driver probes the sensor and registers it with V4L2. So enumeration without a node means the hardware is healthy and the driver side is absent: build and load the module, and the node follows.

Which kernel headers package does my board need?

The one whose release string matches `uname -r` exactly, board suffix included. On the Debian-based board image in this failure that package is raspberrypi-kernel-headers, and its tree must land at /lib/modules/5.15.84-v7l+/build for a 5.15.84-v7l+ kernel. Test with `ls -l /lib/modules/$(uname -r)/build`: a dangling link means the headers on disk do not match the kernel running now.

The module builds but will not load, so what changed?

The build tree and the running kernel now differ in release string, which happens after an upgrade between compile and load. The kernel refuses modules built against another release, so modprobe rejects it. Run `make clean` and `make` again against /lib/modules/$(uname -r)/build, reinstall, and load once more; registering the driver with DKMS makes that rebuild automatic at every kernel install.

How do I keep the driver working after every kernel update?

Register the driver source with DKMS so each new kernel image triggers a rebuild when it installs. Without DKMS, rebuild by hand immediately after any upgrade, using the build-link test as the habit that catches a mismatch before a shift does. Pinning the kernel on a dedicated imaging station works too: an image that never changes cannot strand a module.

Do network 3D cameras avoid the kernel driver problem?

Largely. Cameras that stream point clouds over Ethernet enumerate as network devices, so nothing compiles against your board's kernel release; the capture path runs in the vendor SDK and the NIC configuration instead. You trade a build problem for a network one: set the interface, allow jumbo frames where the camera calls for them, and use a shielded machine-vision data cable with screw locks.

Is the infrared output of a ToF camera an eye hazard while testing?

Treat it as an active light source. Once the module loads, the camera projects infrared light for every frame, and infrared triggers no blink reflex. Do not view the light source through magnifying instruments, and confirm operation from the point cloud rather than by looking into the lens. Obey the laser class on the camera's label for exposure limits.