Firing an LED from a GPIO pin and grabbing a frame from a streaming camera looks like a delay you can tune by hand. It never converges. The frame you retrieve was exposed line by line at some earlier instant, delivery latency moves by milliseconds between grabs, and the lit rows land wherever the drifting phase puts them — so images show two LEDs, none, or the wrong one. This guide gives the numbers behind that behavior, a worked timeline for the fix, and the parts that make it hold: a global shutter camera on a hardware trigger, and a strobe controller that fires the light inside the exposure window. You will be able to decide whether your tolerance allows a plain streaming grab or demands the triggered chain.
Why the grabbed frame is never the frame you triggered
A streaming pipeline has no trigger input. The sensor exposes and reads continuously, the image processor runs behind it on its own clock, the driver hands you the next completed buffer, and your grab call returns whenever the scheduler lets it. Between the GPIO edge you write and the exposure of any particular row sit at least four delays you cannot observe from your code: operating-system scheduling of the write, the readout phase inside the current frame, image-processor latency, and the buffer queue.
A still-capture entry point does not change this. It picks one frame out of the same internal stream, so reading the buffer twice or waiting longer before retrieve changes which exposure you get. On one embedded 640 × 480 setup, grab latency alone wandered up to 15 ms at constant settings. A delay tuned against that drifts the moment resolution, frame rate or CPU load changes.
If your symptom is a black frame rather than the wrong LED, that failure has its own fix, covered in Strobe light on but camera image is black: fix the timing. And settings you write per frame take effect a frame late — Set exposure every frame: latency and the one-frame delay shows that arithmetic.
Rolling shutter line time: the arithmetic that breaks software sync
With a rolling shutter, the rows of one frame are exposed one after another, each offset from its neighbor by the row period. There is no instant at which the whole frame was exposed, so 'when was this frame captured' has a spread, not an answer.
Worked example: a 640 × 480 stream at 30 fps. The frame period is 1 / 30 Hz = 33.3 ms, so each row starts about 33.3 ms / 480 ≈ 69 µs after the one above it. A 1 ms LED pulse covers 1 ms / 69 µs ≈ 14 rows — a lit band, not an instant. Where the band sits is set by the pulse's phase inside the frame cycle, which you do not control: if grab latency moves 5 ms, the band jumps 5 ms / 69 µs ≈ 72 rows. Two channels pulsed 200 µs apart appear 200 µs / 69 µs ≈ 3 rows apart, so both fit inside one frame even though they never overlapped in time. That is the two-LEDs-in-one-image effect, and no delay value fixes it, because the phase drifts.
The chain that does synchronize
Move the timing into hardware and give every row the same exposure instant. Three requirements:
- A global shutter camera with a hardware trigger input. All rows integrate simultaneously, so the frame has a single exposure instant, and the trigger edge starts it after a fixed camera delay.
- A strobe controller firing the light. The same edge — or the camera's flash output, asserted during exposure — drives a light controller that holds the LED on for a set window. Current, rise time and sequencing belong there, not on a GPIO pin; LED lighting controller benefits: why your vision light needs one explains the division of labor.
- One exposure per trigger, light inside it. Strobe width matches the exposure, and the frame is fetched only after exposure plus readout, when it is complete.
Your original GPIO line now goes to the camera trigger input and the controller trigger input: one edge, microseconds of skew. Match it to the electrical standard the inputs expect — Wire a GPIO output to a camera trigger input: TTL levels and pull-ups covers the levels — and keep the trigger leads short and away from the light's power wiring.
The triggered timeline, with numbers
Second worked example, the fixed chain. Trigger edge at t = 0 µs, arriving at camera and controller within about a microsecond of each other. Give the camera a 5 µs example trigger delay and set exposure to 100 µs: pixels integrate from t = 5 µs to t = 105 µs. The controller asserts the strobe on the same edge and holds it for 120 µs, covering exposure plus the LED's rise time of a few microseconds; measure that rise as in LED strobe optical rise time: measure usable light once the pulse width gets close to the exposure.
At t = 105 µs the exposure closes with the light fully on for all of it, and every row of the global shutter saw the same 100 µs window. Readout then consumes the rest of the frame period: for a 3 MP-class sensor at 30 fps that is 33.3 ms − 0.1 ms ≈ 33.2 ms, so the frame is complete about 33.4 ms after the edge — the same arithmetic as Maximum frame rate on a hardware trigger: exposure plus readout time. Fetch after that and each image shows exactly the light state during the window, with jitter set by the trigger path — a few microseconds — instead of by an operating system. Against a sub-millisecond target that is three orders of magnitude of margin.
Choose the camera: global shutter and trigger input
Any global shutter model with a hardware trigger input in the area scan cameras category does this job; the interface changes transfer time, not synchronization. Pick mono over color unless the part's color carries information — mono puts more signal in every strobed frame. Pick resolution by the measurement and frame rate by the cycle budget: a 2.5 MP GigE camera suits high frame rates, a 12 MP USB3 camera suits defect detail that needs the pixels. The MV-CU020-90GC is the 2.5 MP GigE global shutter option, and the MV-CH120-11UC is the 12 MP USB3 global shutter option in its high-speed version.
| Specification | MV-CU020-90GC | MV-CH120-11UC |
|---|---|---|
| Sensor model | GMAX4002 | Sony® IMX304 |
| Pixel size | 4 μm × 4 μm | 3.45 μm × 3.45 μm |
| Sensor size | 1/1.7" | 1.1" |
| Resolution | 2048 × 1200 | 4096 × 3000 |
| Max. frame rate | 49 fps @ 2048 × 1200 Bayer GB 8 | 30.3 fps @ 4096 × 3000 Bayer RG 8 |
| Dynamic range | 66.9 dB | 72.2 dB |
| SNR | 40.8 dB | 40.2 dB |
| Gain | 0 dB to 11.1 dB | 0 dB to 24 dB |
| Exposure time | 4 μs to 10 sec | UltraShort exposure mode: 1 μs to 14 μs; Standard exposure mode: 15 μs to 10 sec |
| Pixel format | Bayer GB 8/10/10Packed/12/12Packed | Mono 8/10/12; Bayer RG 8/10/10Packed/12/12Packed; YUV422Packed, YUV422_YUYV_Packed; RGB 8, BGR 8 |
| Reverse image | Supports horizontal and vertical reverse image output | Supports horizontal and vertical reverse image output |
| Data interface | Gigabit Ethernet (1000 Mbit/s), compatible with Fast Ethernet (100 Mbit/s) | USB 3.0, compatible with USB 2.0 |
| Price | $309.00 | $2,339.00 · quoted |
All 2 share: Sensor type CMOS, global shutter; Exposure mode Off/Once/Continuous exposure mode; Binning Supports 1 × 1, 2 × 2, 4 × 4; Decimation Supports 1 × 1, 2 × 2, 4 × 4; Lens mount C-mount; Weight Approx. 100 g (0.2 lb.); Certification CE, RoHS, KC; Mono/color Color. Values as printed in each product's data sheet; open a part for its drawing and full specifications.
Browse more global shutter models in the camera finder or jump into the camera step of the configurator.
Choose the controller: channels, power and strobe
Size by channel count and total power: one channel per light, with headroom above the summed load. A four-light rig lands on a 4-channel, 200 W digital box with a strobe feature — the LS-CTL-0070 is exactly that shape. Smaller counts of hungrier LED banks fit the LS-CTL-0264, a 2-channel high-power constant-voltage 24 V unit rated 400 W with a network option. Constant-current lights need a constant-current output instead; the light controller finder filters on channels, strobe and output type.
- Output
- Constant voltage 24 V
- Channels
- 4 channels
- Control
- Digital
- Feature
- Strobe
- Channels
- 2 channels
- Control
- Digital
- Feature
- High power
- Output
- Constant voltage 24 V
Bench checks before you trust the timing
Run these once on the bench and once at production rate; zero mismatches over a few thousand cycles is the pass mark.
- Diffuser test. Point the camera at the light through a diffuser, fire 500 triggered frames, and compute the mean pixel value of each. A matched strobe-to-exposure pair keeps every mean within a few percent; an outlier means the light strayed outside the window.
- Alternation test. Light channel A on one trigger, channel B on the next, for several hundred cycles. Every frame must show exactly one channel. A frame showing both means triggers arrive closer than one frame period — space them out, or take both frames from one edge as in Multi image capture per trigger: get an image set from one shot.
- Dark test. Disable the strobe and read the mean that remains. That is your ambient floor, the level the strobed frames must stand above.
- Scope test. When the timing budget is tight, a photodiode across the light against the trigger edge shows the true optical window including rise time — the measurement in LED strobe rise time: why microseconds of light delay blur your image.
- Fetch timing. Pull each frame only after exposure plus readout. The pattern in Hardware trigger grab loop in Python: acquire and save each frame is the shape to copy.
When a rolling shutter camera is still the right choice
Decide by tolerance. If the question is 'is the indicator lit' or 'is the part present' and one frame of slop is acceptable — 33 ms at 30 fps — keep the streaming pipeline and skip the hardware. The moment the answer must name which pulse a frame saw, to better than a millisecond, streaming cannot deliver it at any tuned setting.
Existing rolling shutter hardware has one more option: some such sensors can reset every row simultaneously and still read out line by line, and a flash timed to that reset lights all rows identically. The flash must span the whole readout — tens of milliseconds — so it suits static parts; the set-up is in Rolling shutter global reset with flash for moving objects.
The decision, case by case
- One frame per pulse with sub-millisecond association — the multi-LED rig, µs-scale metrology flashes: global shutter camera, strobe controller, one hardware edge, exposure and strobe width set as in the timeline (100 µs and 120 µs in the example). The only path of the three that meets the target.
- Presence and state checks with a frame of slop: keep the stream and budget one frame period, 33 ms at 30 fps.
- Rolling shutter hardware you cannot change: global reset with a flash spanning readout, and accept the tens-of-milliseconds window.
Build the chain by matching camera and controller at the configurator's controller step, or send the timing sketch through the contact page and we will size it with you. The rest of the strobe-timing material sits on the lighting topic page.
Questions
Can software delays ever hold a sub-millisecond offset on a rolling shutter camera?
No. The phase between your GPIO edge and the sensor's row clock is unobservable from the grab API and drifts with resolution, frame rate and CPU load, while delivery latency alone has been measured wandering by up to 15 ms. At 30 fps the row phase spans a 33 ms window, so a tuned delay matches only by luck. Use a hardware trigger, or accept a tolerance of at least one frame period.
How long should the strobe pulse be relative to the exposure?
Start from pulse width = exposure, then add the LED's rise time: for a 100 µs exposure with a 5 µs rise, 110-120 µs works. Begin the pulse at or just before exposure start. Light outside the exposure costs a little duty cycle; light missing the start of exposure leaves rows dark, and that is the failure to design out.
Does the camera interface affect strobe synchronization?
No. Exposure timing is fixed by the trigger input on the camera and the strobe output on the controller, both hardware paths. GigE, USB3 and CoaXPress only carry the finished frame to the host; they change transfer and readout time, so your fetch moment moves, but the exposure window itself stays where the trigger edge placed it.
How do I capture one frame per LED when there are four lights?
Put each light on its own controller channel, then either fire four separate triggers at least one frame period apart, or use a camera mode that delivers several frames from a single trigger while the controller steps through channels. At a 100 µs exposure and 30 fps, four frames take about 133 ms, which fits most staging and indexing applications.
What is global reset, and when does it beat swapping to a global shutter?
Global reset is a rolling shutter sensor mode that resets every row at once and then reads out line by line. A flash timed to the reset illuminates all rows identically, so it can rescue existing rolling shutter hardware. The light must stay on through the entire readout — tens of milliseconds — so it suits static parts and modest cycle rates rather than fast sequences.

