System designHow-to

Abort a capture waiting for a trigger without missing edges

Abort a capture waiting for a hardware trigger: arm once, poll the retrieve with a timeout, and stop in under a second without missing trigger edges.

LumaSpec Vision12 min read Share on LinkedIn

On this page 10 sections
  1. 01Why a blocking capture cannot be interrupted
  2. 02The pattern: arm once, poll with a timeout
  3. 03What you need
  4. 04Steps: arm, poll, abort, verify
  5. 05Worked example: 500 ms timeout for a 12 MP USB3 camera and a 1 s stop button
  6. 06Multi-stream 3D sets: one wait for the whole capture
  7. 07When edges still go missing after a long idle
  8. 08Checks before you rely on it
  9. 09When polling is not enough
  10. 10Questions

A capture call that waits for a hardware trigger with no timeout parks your thread inside the SDK until an edge arrives. When the line jams, the shift ends, or the operator hits stop, the call never returns and the software looks dead. The fix is not a smarter timeout on that one call. Split the wait: arm the camera once, poll the retrieve call with a bounded timeout, and check an abort flag between polls. The camera keeps latching trigger edges the entire time, so nothing is lost, and your loop leaves within one timeout period. What follows: the trigger settings, the timeout arithmetic, the multi-stream variant for 3D heads, and the idle test that proves edges are not lost.

Why a blocking capture cannot be interrupted

An acquisition call with no timeout waits for an edge that may never come. While it waits, the thread cannot read a stop flag, answer the GUI, or close the camera cleanly. On Windows, a thread that owns a window and stops pumping messages for about 5 seconds is reported as not responding, so a five-minute idle spell looks like a crash to everyone watching.

Killing the thread from outside is not better. The SDK's buffers and acquisition engine are left in an undefined state that only a restart clears, and the next camera open can fail or hang for its own reasons. So keep the rule strict: never let the only path to a clean stop run through a call you cannot interrupt. Keep the wait short, repeat it, and own the loop yourself.

The pattern: arm once, poll with a timeout

Set the trigger exactly as for a normal triggered capture: TriggerMode On, TriggerSource pointed at the input line your sensor wires to, TriggerActivation FallingEdge or RisingEdge to match the electrical edge, ExposureMode Timed. Then start acquisition once. In GenICam terms that is AcquisitionStart; SDKs that hide GenICam expose it as the trigger or start command.

From there, the loop owns only retrieval. Each pass calls retrieve with a bounded timeout and gets one of two answers: a frame, or a timeout that means no edge yet. A timeout is not an error and disarms nothing. The camera latches the next edge into its buffer stream whether your loop is inside the retrieve call, between passes, or busy handing off the previous frame. When the abort flag is set, exit, stop acquisition, and close.

The timeout is a sizing decision with a floor and a ceiling:

t_frame = 1 / frame_rate T_poll > t_exposure + t_frame (keep 2x to 5x headroom) T_poll <= t_stop_deadline (and under ~5 s, the GUI not-responding zone)

The floor is set by the camera, the ceiling by your stop requirement. How long a triggered frame takes to become ready — exposure plus readout — is laid out in maximum frame rate on a hardware trigger: exposure plus readout time, and measuring frame trigger wait time and polling resolution shows how to time your own loop's passes.

What you need

A camera with a hardware trigger input, and an SDK whose grab or retrieve call accepts a timeout; GenICam-based stacks expose both. Add a pulse source for testing — a PLC output or a bench pulse generator — and an abort flag that the UI or the PLC handler sets. The area scan cameras category is the place to pick hardware, or the camera finder filters by interface, shutter and resolution directly.

For a first build, a compact global-shutter GigE model such as the MV-CU020-90GC keeps the pipeline short while you get the loop right. The loop you write here moves unchanged to bigger sensors and faster interfaces later.

Area scan camerasHikrobot MV-CU020-90GC 2.5 MP Area Scan Camera, GigE, GMAX4002, ColorMV-CU020-90GC
Sensor format
1/1.7"
Lens mount
C-mount
Interface
GigE
Resolution
Up to 3 MP
$309.00View partBuild a system with it

Steps: arm, poll, abort, verify

  1. Set the trigger once, before anything loops: TriggerMode On, TriggerSource to your input line, TriggerActivation FallingEdge, ExposureMode Timed. Match the activation edge to what the sensor actually sends; most PLC and proximity outputs sink to ground when active, which is a falling edge at the camera input. If one output drives several cameras, the wiring and sag budget is covered in trigger multiple cameras from one opto-isolated output without sag.
  2. Choose the poll timeout before arming and keep it in a single variable so tests can change it. Start from 500 ms and size it properly in the worked example below.
  3. Arm once. Run AcquisitionStart, or your SDK's trigger or start command, exactly one time, outside the loop. Nothing between edges should run it again.
  4. Loop on retrieve with the timeout. Each pass returns either a frame or a timeout. Treat the timeout as the normal no-part-yet outcome, not a fault.
  5. Check the abort flag every pass, including straight after a timeout return. If it is set, break out, run AcquisitionStop, and let the close path finish. Expect zero or one frame still in flight and discard it.
  6. On a delivered frame, hand it to a queue and return to polling at once. Keep work between retrieves to a few milliseconds; if processing is heavier than the trigger interval, a queue with at least two slots absorbs the overlap at part rates of a few parts per second.
  7. Verify by counting. Fire a known number of edges and require delivered frames to equal edges fired, with nothing delivered after the stop. A wait that returns twice per frame, or swallows one, shows up in that count; the failure patterns behind it are described in frame didn't arrive within timeout: one wait call per frame.
// Illustrative names - keep your SDK's own function and constant names.
int timeout_ms = 500;         // poll period and abort-latency bound
bool abort_requested = false; // set by the stop button or the PLC handler

set_feature("TriggerMode", "On");
set_feature("TriggerSource", "Line0");           // the input line wired to your sensor
set_feature("TriggerActivation", "FallingEdge"); // match the electrical edge
set_feature("ExposureMode", "Timed");
acquire_start();                                  // arm ONCE - outside the loop

while (!abort_requested) {
    status = retrieve_frame(timeout_ms);          // returns after at most timeout_ms
    if (status == FRAME_DELIVERED) {
        hand_off(frame);                          // queue it; keep this loop light
    }
    // TIMEOUT: no edge yet. The camera is still armed. Poll again.
}

acquire_stop();                                   // disarm before closing

Worked example: 500 ms timeout for a 12 MP USB3 camera and a 1 s stop button

Inputs for the case:

  • Stop deadline: 1,000 ms — the machine should be safe to approach within a second of the stop button. Example requirement; set yours from your own risk assessment.
  • Camera rating: 12 MP over USB3, 30 fps at 4000 × 3000, from the catalog sheet of the camera in the card below.
  • Triggered exposure: 5 ms — an example setting for a part that is stopped or moving slowly under the camera.
  • Frame format for the arithmetic: mono 8-bit, so a frame is 4000 × 3000 = 12 MB. An example format; your pixel format sets the size.
  • Margin policy: 2x on the delivery estimate.

Rule: the poll timeout must clear the worst case from trigger edge to a retrievable frame, and must not exceed the stop deadline.

Arithmetic:

  • Frame period at the full-resolution rating: 1 / 30 fps = 0.0333 s, about 33 ms.
  • Worst case from edge to delivery: exposure plus one frame period, 5 ms + 33 ms = 38 ms. The transfer is already inside the 30 fps rating.
  • Floor with the 2x margin: 2 × 38 ms = 76 ms, so keep the timeout at 100 ms or more in practice.
  • Ceiling: the 1,000 ms stop deadline, and for a GUI well under the ~5,000 ms not-responding threshold.
  • Chosen value: 500 ms. That is 500 / 38 ≈ 13x the worst-case delivery, and half the deadline.

Result: the loop notices a stop within 500 ms plus about a millisecond of loop overhead, 250 ms on average — inside the 1,000 ms deadline with room to spare. The camera stays armed through 20 minutes or 20 hours of idle, because arming ran once and does not decay.

Decision: set the retrieve timeout to 500 ms for this camera and deadline. If your deadline tightens to 200 ms, set 200 ms — still 5x the 38 ms floor. Below about 100 ms the poll starts expiring during ordinary deliveries; move to a callback at that point instead of shrinking further.

The LS-CMR-0166 carries exactly this rating: 12 MP over USB3 at 30 fps and 4000 × 3000.

Area scan cameras12 MP USB3 area scan camera, IMX226, 1/1.7" rolling shutter, 30 fps, 4000 × 3000 resolution (LS-CMR-0166)LS-CMR-0166
Sensor format
1/1.7"
Interface
USB3
Resolution
12 MP
Shutter
Rolling
$560.00View partBuild a system with it

Multi-stream 3D sets: one wait for the whole capture

Stereo heads that also return a color or texture image, and profiler set-ups with an intensity stream, complete a capture only when every stream delivers. Two bugs eat captures here.

First, serial waits stack. A loop that retrieves stream A with a 5 s timeout and then stream B with its own 5 s timeout can spend 10 s inside one logical capture — twice the stop latency you designed for. Give the whole set a single timeout budget, sized for the slowest stream.

Second, partial completion. Code that checks only one camera's delivered flag never consumes the image that arrived from the other stream, so the capture never completes and the trigger looks missed. Loop until every stream reports delivered, then consume the set as one unit — the same discipline as the multi image capture per trigger: get an image set from one shot pattern for burst sets.

The arm-once discipline holds on 3D hardware too. A laser profiler such as the MIS-DP3850-01P takes a per-scan trigger from an encoder or part sensor; arm the acquisition once when the line starts, poll between scans, and stop cleanly at the end of the run.

3D sensorsHikrobot MIS-DP3850-01P 3D laser profile sensorMIS-DP3850-01P
Type
Laser profiler
$12,379.00 · quotedView and quote

When edges still go missing after a long idle

The polling pattern itself does not lose edges; a camera that stays armed latches them all day. When the first trigger after a long idle — 20 minutes is a common report — comes up empty, work down this list:

  1. Arm or retrieve re-executed per pass. A command re-run inside the loop overwrites its previous result, and a completed frame is dropped unread. Arm once, outside the loop.
  2. Cameras that must capture as one, opened as separate devices. A stereo head with a texture camera has to be opened together so both sides arm in the same instant; opened separately, one side waits for a trigger the other never shares.
  3. Settings written while armed. Trigger, exposure or ROI changes on a live acquisition can drop the armed state; stop acquisition first. The clean sequence is covered in apply camera settings while streaming without stalling capture.

Then prove the fix: arm, leave the rig idle for 30 minutes, fire one edge, and require a delivered frame within one poll period. One-shot styles that re-arm per shot miss frames in exactly this situation; software trigger image timeout: why one-shot capture misses frames walks through that failure and its fix.

Checks before you rely on it

Run these once the loop is in, and again after any SDK update:

  • 100 edges at the real trigger rate, counted: delivered frames equal edges fired, none after the stop. Proves arming survives repeated edges.
  • One edge after 30 minutes idle, delivered within one poll period. Proves arming does not decay over time.
  • Stop pressed mid-wait: the loop exits within one timeout plus overhead and the GUI stays live. Proves the abort path.
  • Pulses stopped for a minute, then resumed: timeouts stay clean, no error burst, and the next edge delivers. Proves the timeout is a normal outcome, not a fault state.
  • One settings write per session, none between edges. Proves nothing rewrites the trigger while armed.

For test edges, a PLC output or a bench pulse generator is all you need; if you prototype in LabVIEW, triggering fixed-width pulses from falling edges shows the DAQ set-up in a few lines.

When polling is not enough

Two cases outgrow the loop. If triggers arrive faster than the poll cycle can drain them — trigger interval shorter than processing time — buffers overflow and frames drop no matter how clean the abort is. Register a frame-available callback or use an event wait with a cancel handle instead, keeping the same arm-once discipline. If the stop must act in single-digit milliseconds, a callback wins over any poll period. Hardware headroom helps too: the MV-CH120-11UC is a 12 MP global-shutter USB3 camera listed as a high-speed version.

Area scan camerasHikrobot MV-CH120-11UC 12 MP Area Scan Camera, USB3, IMX304, High-speed version, ColorMV-CH120-11UC
Sensor format
1.1"
Lens mount
C-mount
Interface
USB3
Resolution
12 MP
$2,339.00 · quotedView and quoteBuild a system with it

One boundary stays: this pattern aborts the wait, not an exposure already running. Stopping acquisition mid-exposure loses the frame in flight by design; if that frame matters, let it land, then stop.

Ready to spec the hardware side? The build a vision system configurator steps through camera, lens and light in order, the systems topic page collects the capture-timing guides around this one, and the applications team is on the contact page if a loop still misbehaves — send the trigger settings and the timeout counter log from the tip above.

Questions

Does a retrieve timeout disarm the camera?

No. The timeout only bounds how long the retrieve call waits to hand you a frame. Arming comes from the acquisition-start command and stays active until you stop acquisition or rewrite trigger settings. If a frame lands during a timeout window, the next retrieve returns it, provided the buffer queue still has a free slot — which is why two or more queue slots are worth setting on a triggered line.

What retrieve timeout should I start with?

500 ms is a sound default for a GUI application: it reacts to a stop in half a second and sits far above the delivery time of even a 30 fps full-resolution frame. Tighten toward 100-200 ms only when the stop deadline demands it, and never below twice the exposure-plus-frame-period estimate for your camera. Log every expiry so the counter tells you whether timeouts are idle time or lost deliveries.

Why is the first trigger after a long idle missed?

Look at the loop before the camera. An arm or retrieve command re-executed on every pass can overwrite a finished result, and two cameras that must capture as one but were opened separately never arm together. Fix the code first, then rerun the idle proof from the checklist: one idle spell, one edge, one delivered frame.

How do I abort a stereo or profiler capture that returns several streams?

Give the whole capture one timeout budget sized for the slowest stream, and loop until every stream reports a delivered image before you consume the set. Two serial waits of 5 s each put 10 s between stop checks, which is past the point where a GUI reads as frozen. Check each stream's delivered flag individually; a set consumed early is a set half-missing.

Can I kill the waiting thread from another thread instead?

Avoid it as routine practice. A thread killed inside an SDK wait leaves buffers, locks and the acquisition engine in an undefined state; most stacks only recover on process restart, and the next open can fail or hang. The arm-once pattern gives the same abort from inside the waiting thread. Reserve forced teardown for fault recovery, and re-open and re-arm before trusting the camera again.

Do I need a global shutter camera for hardware triggering?

Only when the part moves during the exposure. A global shutter samples every row at the same instant, so a fast part stays undistorted; a rolling shutter scans row by row and shears fast motion even though the trigger edge itself was captured on time. For stationary or slow parts either shutter type works, and the arm-once abort pattern is identical on both.