You wired the pulse generator to the camera's trigger input and scoped a clean edge at the pin. Frames still arrive whenever they feel like it. On a USB camera that speaks the UVC protocol, that is the expected state of the world: the trigger input is a firmware feature that stays dormant until the host sets three standard controls through the V4L2 stack.
This article is for engineers running UVC cameras on Linux who need pulses to produce frames — one pulse, one frame — and a strobe output that shows edges. You will set the control sequence with v4l2-ctl, learn the exposure-time units that trip most people, and prove the lock with a ten-pulse test. You will also revive a flat open-drain strobe with a 4.7–10 kΩ pull-up to 3.3 V, and decide when the inspection has outgrown UVC trigger and needs industrial trigger I/O.
Why does a UVC camera free-run even with pulses wired to its trigger pin?
A UVC camera ignores a trigger input until the host arms it through three standard controls — auto_exposure, exposure_time_absolute and exposure_dynamic_framerate. Clean 3.3 V pulses on the pin do nothing, and frames keep arriving at the free-run rate regardless.
The UVC standard defines exposure, gain and streaming controls, not trigger modes. A module that supports triggering implements it behind those standard controls, and until they are set the sensor free-runs at its default rate. The signature is unmistakable: frames arrive with the pulse generator switched off. Frame deltas drift around the free-run rate — say 32–60 ms around a nominal 30 fps — instead of repeating the trigger period, which is 33.3 ms for a 30 Hz train. Drifting deltas mean free-run; a locked camera repeats the period exactly, pulse in, frame out.
Before blaming software, scope the pulse at the camera's input pin for level and edge. Confirm the generator's ground reference wire reaches the camera — a trigger floating on an unshared ground reads nothing useful. The wiring-and-timing checks in external camera selection control: fix wiring and timing apply unchanged. Your installed kernel's own control list, read with v4l2-ctl -l, is the authoritative inventory of what the driver exposes.
Which v4l2-ctl settings arm the external trigger input?
Set three controls, in this order: auto_exposure=1 for manual exposure mode, exposure_time_absolute to a fixed value in 100 µs units, then exposure_dynamic_framerate=1 — on these modules that flag arms the trigger path, and one pulse then produces one frame.
Apply them with v4l2-ctl, ideally before the stream starts:
v4l2-ctl -d /dev/video0 -c auto_exposure=1
v4l2-ctl -d /dev/video0 -c exposure_time_absolute=100
v4l2-ctl -d /dev/video0 -c exposure_dynamic_framerate=1
The order matters. Auto exposure ignores a fixed exposure value, so manual mode goes first; the arm flag goes last so nothing resets it. exposure_time_absolute=100 means 10 ms in the control's own units — the arithmetic is in the next section. Read the accepted range back with v4l2-ctl -l: the control reports its own minimum, maximum and step, and your value must sit inside. If a set will not stick while the stream is running, stop the stream, apply the controls, then start streaming again.
If all three read back correctly and frames still arrive with the generator off, set exposure_dynamic_framerate to 0 and re-test before suspecting hardware: firmware reuses this flag in different ways, and the opposite position is the second thing to rule out. Also watch for firmware that derives exposure from the pulse width instead of the absolute control — if your frames get brighter with wider pulses and ignore exposure_time_absolute, read why trigger pulse width sets your camera exposure time, and put the initialization order right with set manual exposure before streaming: initialization order.
What units does exposure_time_absolute use, and how do you pick the value?
exposure_time_absolute counts in steps of 100 µs (0.0001 s), as the V4L2 specification defines, so writing 500 sets a 50 ms exposure — not 500 ms — and caps the free-run frame rate at 1000 / 50 = 20 fps.
That unit is the single most common mis-set on this control. A reader who assumed milliseconds gets an exposure ten times shorter than intended. One who assumed microseconds gets ten times longer. The camera applies whatever it is given.
Worked example. A belt moves parts at 0.5 m/s (500 mm/s) and the inspection tolerates 50 µm of motion blur. The exposure must satisfy blur = v × t, so t ≤ 50 µm ÷ 500 mm/s = 0.1 ms = 100 µs. Set exposure_time_absolute=1 if the control's reported minimum allows it: 100 µs of exposure, 50 µm of blur.
At a 30 Hz trigger the period is 33.3 ms, so the exposure occupies 0.3% of the interval — comfortable. A good working rule is exposure at or under 10% of the trigger period. At 30 Hz that permits up to 3.3 ms, or exposure_time_absolute=33, which would blur a 0.5 m/s part by 3.3 ms × 500 mm/s = 1.65 mm — the blur budget usually binds first. The same logic that caps maximum auto exposure time to stop motion blur applies here, just set by hand.
How do you prove one pulse now produces exactly one frame?
Prove the lock electrically and numerically: request exactly ten frames with v4l2-ctl --stream-mmap --stream-count=10 while firing exactly ten pulses. If capture ends on the tenth pulse and nothing arrives with the generator off, the trigger is armed.
Run that count test at three pulse rates — 1, 10 and 30 Hz — and expect exactly ten frames from ten pulses each time, then a longer run of 100 pulses with zero drops. Stamp arrival times in your capture loop from the V4L2 buffer timestamps your driver fills in. A locked camera repeats the trigger period in those deltas, 33.3 ms at 30 Hz and 100.0 ms at 10 Hz. Deltas that drift between 32 and 60 ms around 30 fps mean the camera is still free-running, whatever the readback claimed.
Two more failure patterns are worth knowing. Pulses faster than the sensor's readout at your format queue or drop frames, so keep the trigger rate below the maximum frame rate the camera reports for that format. And if your program's own capture call and the camera's exposure land at different points in the cycle, trigger call versus exposure time: understand capture timing separates the two clocks. For two cameras sharing one event, hardware sync: trigger both USB cameras together covers the shared-pulse wiring.
Why is the strobe output flat, and what pull-up fixes it?
A strobe that stays flat while the camera triggers correctly is almost always an open-drain output that never drives high. Add a 4.7–10 kΩ pull-up from the strobe pin to 3.3 V and re-scope.
An open-drain pin contains only the pull-down transistor: it can clamp the line to ground but has no transistor to the supply. An undriven, unpulled line sits wherever leakage leaves it, and a scope shows a flat trace. The pull-up gives the line a defined high level. With the numbers:
Both values are fine at frame rates: a 1.0 µs rise is 0.003% of a 33.3 ms trigger period, and 0.7 mA of sink current is trivial for any logic output. Choose 4.7 kΩ for faster edges into longer cable, 10 kΩ for the lightest load. Scope at the receiving end, not just at the camera, and check the high level against the receiver's logic threshold — a 3.3 V pull-up feeds a 3.3 V logic input directly. Arm the trigger first and judge the strobe second: on these modules the strobe means something per triggered frame, so a strobe test during free-run proves nothing.
A flat trace that survives a correct pull-up points to a strobe that needs its own enable or a firmware option, which is a question for the supplier's documentation rather than the scope.
Why do the control names in the supplier guide not match your v4l2-ctl output?
The supplier guide and your camera describe the same three controls under older names: exposure_auto maps to auto_exposure, exposure_absolute to exposure_time_absolute and exposure_auto_priority to exposure_dynamic_framerate — the kernel renamed the printed control names across versions.
The IDs are identical, so both spellings address the same hardware setting. But a script that writes exposure_auto on a newer kernel fails with an unknown-control error that looks exactly like missing trigger support. Use this mapping:
| Older name | Newer name | Value to set |
|---|---|---|
| exposure_auto | auto_exposure | 1 (manual mode) |
| exposure_absolute | exposure_time_absolute | exposure in 100 µs units |
| exposure_auto_priority | exposure_dynamic_framerate | 1 = frame rate may vary with exposure |
Treat v4l2-ctl -l on the unit in front of you as the only inventory that matters: it shows what your kernel and driver actually expose, including each control's range. Run uvcdynctrl --clist once if you want to check for vendor extension controls; on trigger modules that need none, the three standard controls are the whole toolset. When controls read back wrongly or a set silently does nothing, the V4L2 exposure and gain settings ignored by a sensor driver walkthrough isolates which layer is dropping them.
When is a UVC trigger the wrong tool for the inspection?
Move to an industrial camera with real trigger I/O when the inspection needs guaranteed pulse-to-exposure timing, exposures shorter than a few hundred microseconds at high trigger rates, or several cameras locked to one event — UVC specifies no trigger latency, no strobe timing reference and no buffering guarantees.
A triggered UVC module gives you frame-per-pulse correlation, which is enough for presence checks and sorting. It does not give you a number you can put in a timing budget: how long from pulse edge to start of integration is firmware behavior, the strobe's relation to the exposure is unspecified, and USB adds host arrival jitter. Industrial cameras close those gaps with dedicated trigger inputs on their I/O connector, trigger delay and prescaler registers, strobe outputs referenced to the exposure, and PTP-scheduled capture on GigE. The whole ladder from free-run to scheduled capture is in industrial camera trigger modes compared: free run to PTP scheduled. A global shutter sensor also matters once parts move between pulses.
Example of the class: the MV-CU020-90GC is a 2.5 MP GigE area scan camera with a 1/1.7" global shutter sensor, C-mount, colour.
- Sensor format
- 1/1.7"
- Lens mount
- C-mount
- Interface
- GigE
- Resolution
- Up to 3 MP
Trigger and strobe signals land on the camera's I/O connector. The LS-CBL-0211 is a 5 m cable breaking out the 12-pin I/O and power connector.
Browse the area scan cameras category, filter by interface and shutter in the camera finder, or find camera cables and I/O leads under camera cables.
What do you check, in order, when the trigger still fails?
Work down this order and you will find the fault in under an hour: scope the pulse, confirm the ground wire, apply the three controls before streaming, read them back, pass the ten-pulse test, then revive the strobe with a pull-up.
- Scope the trigger input at the camera pin. Level, edge speed and width. Software cannot arm a pulse the pin cannot read, and a generator set for 5 V logic into a 3.3 V input needs a check against the module's I/O specification.
- Confirm the ground reference wire between generator and camera. A trigger referenced to a floating ground sees noise or nothing; this single wire explains a large share of dead trigger inputs.
- Apply the three controls before streaming, then read back with v4l2-ctl -l. Auto exposure overrides any fixed exposure value, so manual mode must take first; the readback proves the sets stuck.
- Run the ten-pulse test. --stream-count=10 with ten pulses; capture must end on the tenth. If one microcontroller output drives several inputs, buffer the split — fan out one TTL pulse to multiple cameras safely shows the resistor logic.
- Dead-man test. Generator off, stream running, zero frames. Any frame here is free-run, whatever the readback said.
- Timestamp run over 100 pulses. Deltas must repeat the trigger period; the spread around it is the arrival jitter you must budget into the timing.
- Strobe pull-up, 4.7–10 kΩ to 3.3 V, scoped at the receiver. Open-drain outputs read flat without it, and the receiver's threshold is the level the high state has to meet.
- Persist the sequence in your launch script. UVC controls are runtime settings and are not stored in the camera: a reboot or replug silently reverts auto exposure and free-run.
If the ten-pulse test keeps failing on a module that has passed every electrical check, spend the remaining hours on hardware with a specified trigger instead. Start at the camera configurator or ask us — we match trigger I/O, cabling and optics to the line before you order, with free expert support on every order. More trigger and timing guides sit on the systems topic page.
Questions
Does every UVC camera support an external trigger?
No. Trigger support is a firmware feature: the UVC standard defines exposure and streaming controls, not trigger modes. Check first that the module physically has trigger and strobe pins, then apply the three-control sequence. If the pins exist and both positions of the arm flag have been tried without stopping the free-run, the module's firmware almost certainly does not implement triggering at all, and no driver setting will create it.
How much delay is there between the pulse and the frame reaching my code?
USB never gives you a number in the UVC standard: the sensor starts integrating on the pulse, but the frame then crosses isochronous transfers and host buffers before your code sees it. Measure it on your own rig: drive an LED from the same pulse that triggers the camera, and the LED's position in the frame shows the real delay at your exposure and format. Budget that figure into the timing; for a guaranteed pulse-to-exposure specification, hardware trigger I/O is the path.
Can these trigger controls be set from OpenCV instead of the command line?
Usually yes: OpenCV's Linux backend hands settings down to V4L2, so the same three controls exist as capture properties. Property names and value scaling have changed between versions, though, and a set that fails often fails silently. The robust pattern is to apply the three controls once with v4l2-ctl before the stream opens and treat the camera as plain UVC inside your program — the settings then hold for every capture you open afterwards.
How do you trigger two UVC cameras on the same event?
Feed both trigger inputs from one pulse generator through a buffered split rather than daisy-chaining, so each input sees the same electrical edge, and keep each branch short. Arrival at the host still jitters independently because USB delivers each camera's stream on its own schedule. When two frames must correspond to sub-millisecond motion, that is the point where cameras with hardware trigger inputs, or PTP-scheduled capture on GigE, take over from UVC.

