A motion stream that behaves this way burns an afternoon: the first capture runs clean, the second start of the pipeline throws, and re-plugging the camera buys exactly one more good run. This page is for engineers integrating depth cameras on Linux stations who read the accelerometer alongside depth — for shake gating, AGV motion checks or robot triggering. You will confirm the cause from the kernel log in about five minutes, apply a one-line udev rule that keeps the port awake, and prove the fix with a start/stop loop before the station ships.
Why does the accelerometer stream fail on the second run and not the first?
The kernel's USB autosuspend parks the whole device about 2 s after your pipeline closes. The camera's motion interface comes back from suspend in a state the SDK refuses to stream. Re-plugging re-enumerates the device, which is why one unplug buys exactly one run.
Closing the last open interface returns the device to idle. The kernel's runtime power manager then counts 2 s of idleness and suspends the USB port, recording a usb_suspend_both line in the log. Depth and color interfaces re-open cleanly on the next start because the kernel's video class driver re-initializes them. The motion interface is different: your SDK drives it directly, and its streaming handshake lives in the camera firmware, which handles a suspend and resume cycle badly. The fingerprint is consistent: first run good, failure at start rather than mid-stream, the device still listed by lsusb, and a re-plug or a full reboot resets the pattern without fixing anything. If your stream freezes during capture instead of refusing to start, that is a different fault with its own isolation procedure.
How do you confirm USB autosuspend is the cause in five minutes?
Read the timestamps of the enumeration line and the suspend line in the kernel log and subtract them. A 2 s gap, followed by a second run that fails while the device stays enumerated, is the autosuspend signature.
Run the pipeline once, let it close cleanly, and watch the log in a second terminal with dmesg -w. The pair of lines that decides it looks like this, with illustrative bus path and timestamps:
[250123.088400] usb 2-2: new SuperSpeed USB device number 12 using xhci_hcd
[250125.288400] usb 2-2: usb_suspend_both: status 0
The arithmetic:
2.2 s is the kernel's default 2 s runtime-suspend delay plus enumeration overhead: the port is parked on idle, not powered down. Then run the three-step live test.
-
cat /sys/bus/usb/devices/2-2/power/control—automeans the port is allowed to suspend, and it is the default. -
echo on | sudo tee /sys/bus/usb/devices/2-2/power/control—onpins the port awake. - Start the pipeline twice. If run two now passes, the cause is confirmed. If it still fails with
onset, go to the other causes below.
What do you change so the kernel never suspends the camera port?
Write a udev rule that matches your camera's vendor and product ID and sets its power policy to on. One line in /etc/udev/rules.d keeps that one device awake through re-plugs, reboots and SDK updates.
- Read the IDs with
lsusb: your camera's line prints a1234:5678-style pair, vendor ID first, product ID second. - Create
/etc/udev/rules.d/91-depth-camera-power.ruleswith the single line below. - Reload and reapply:
sudo udevadm control --reload-rules && sudo udevadm trigger. - Unplug the camera, plug it back, and confirm:
cat /sys/bus/usb/devices/2-2/power/controlmust printon.
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="1234", ATTR{idProduct}=="5678", ATTR{power/control}="on"
The 1234:5678 pair stands in for the four-digit hex values lsusb printed for your camera; a real rule carries your camera's own values. The rule fires on every add event, so it follows the camera rather than the session, with no init script to maintain. If you would rather switch runtime suspend off for every USB device on the station, boot with the kernel parameter usbcore.autosuspend=-1; that is harmless on a mains-powered vision cabinet and wasteful on battery-backed hardware, so the matched rule is the better default.
Why does only the motion stream fail while depth and color recover?
A depth camera enumerates as a composite USB device with several interfaces. The kernel's video class driver binds only the interfaces whose stream formats it recognizes, so the custom motion interface is left to the SDK, and it loses its state across a suspend and resume.
The kernel log shows the split. On enumeration, uvcvideo prints an Unknown video format line for every stream whose format identifier it does not know, and skips that interface; the standard depth and color interfaces it claims normally. The same log often shows the motion module announcing itself as a HID input device too — the desktop may even tag it as a keyboard, which is harmless.
The model behind this is a video device exposing its capabilities through a set of interfaces, each of which the inbox class driver either claims or leaves alone. That division explains the asymmetry after a suspend: the class-driven interfaces are re-initialized by the kernel on the next open, while the SDK holds the raw motion interface itself, and the camera firmware restores that interface's streaming state badly. Hence the exact symptom: the start call fails for the accelerometer, depth still streams, and only a full re-enumeration clears it.
Does building the SDK from source make the failure worse?
The source build does not cause the suspend, but it can make the recovery worse, so keep the board on the vendor's distribution packages for your platform and pin a current release before you debug anything deeper.
Embedded ARM boards need board-specific patches in the camera stack, and the vendor's packages for your distribution carry them. A hand-built stack on an unsupported kernel can open the motion interface in a slightly different way, which is one reason identical code behaves differently on two machines. Second-run motion failures of exactly this shape have cleared after moving to a later release, because the motion access path was reworked between versions. Order of operations matters: fix the power policy first, update the SDK second, and only then retest, or you will not know which change cured it. Keep the stack aligned while you do — camera firmware and the host driver layer move together, and the driver-stack rebuild after a firmware update is its own fix.
When is the second-run failure not autosuspend?
Four causes cover most of the rest, in this order: a stale process holding the device, a hub between camera and host, a link that fell back from SuperSpeed to high speed, and settings leaking between runs — each has a one-command test.
-
A crashed viewer still holds the device.
sudo fuser -v /dev/video*names the process; stop it and rerun. Releasing a camera after a crash follows a fixed pattern, shown in the camera release fix after a crash. - A hub sits between camera and host. Raw and custom streams — the motion interface among them — are the first to refuse through hubs. Plug into a root port: if it then works twice in a row, the hub is the cause, and why raw streams refuse through hubs explains the mechanics.
-
The link fell back to 480 Mbps. The enumeration line must say
new SuperSpeed USB device; if it sayshigh-speed, something downgraded the link from 5 Gbps to 480 Mbps and depth plus motion no longer fits. Replace the cable before suspecting the camera. - State leaks between runs in your own code. If a minimal second process streaming depth only also fails on its second run, the leak is in configuration reuse, not power management — start from a known state each run, as in the leftover-settings fix.
If power/control stays on through all of these and the motion stream still refuses, the evidence points at the SDK or firmware; send the vendor your dmesg excerpt and SDK version.
How do you verify the fix holds before shipping the station?
Run ten start and stop cycles with 60 s of idle between them — thirty times the 2 s delay that caused the fault — and require zero start failures and zero suspend lines in the kernel log.
A plain loop is enough:
# verification loop, pseudocode
for run in 1..10:
start pipeline with depth and accelerometer
stream for 5 s
stop pipeline
idle for 60 s # 30x the 2 s delay that started this
Two checks decide pass or fail. After every stop, the port's power/control file still reads on. And the kernel log for the boot after you added the rule counts zero suspends:
journalctl -k -b | grep -c usb_suspend_both
That command must print 0. Ten starts with a 60 s idle after each prove the policy rather than luck; a single re-plug proves nothing, because re-plugging resets the idle timer. Then bake the rule into the station image so every cabinet gets it, and note it in the station folder next to the trigger wiring. Motion data at typical depth-camera IMU rates of 100–250 Hz earns its keep in exactly that kind of gating logic — triggering depth capture from IMU motion shows the pattern.
If you are still choosing hardware for a station that pairs depth with motion, start from the 3D sensors range, then let the camera step of the configurator build the chain; the 3D topic page collects the rest of the integration fixes, and odd combinations are worth a note to the applications team before you order.
Laser profilers and stereo 3D cameras
170 models · from $699.00Questions
Does USB autosuspend cut power to the camera?
No. The 5 V bus power stays on and the camera keeps running; autosuspend stops bus traffic and asks the device to enter its low-power suspend state. The failure is a resume problem inside the camera firmware, not a power cut, which is why the port never disappears from the bus when the streams break.
Will the udev rule survive a reboot and a package update?
Yes. Files in /etc/udev/rules.d are read at every boot and reapplied whenever the device is plugged in or re-enumerated, so the policy follows the camera, not your login session, and package updates do not touch custom files there. The one-off sysfs echo from the confirmation test is the opposite: it dies with the next re-plug.
Do you need root to apply and keep the fix?
Once. Writing the rule, reloading udev and the first sysfs write need root, but after that the kernel event system applies the policy on every plug event with no privileges involved, and the application streams as a normal user in the usual device access group.
Can you just re-plug the camera between runs instead?
It works, and it is exactly what makes the bug confusing: every re-plug re-enumerates the device and resets the suspend timer, buying one clean run. It does not scale to an unattended station, it costs a full enumeration each time, and it wears out connectors. The udev rule removes the manual step permanently.