System designHow-to

Synchronize serial data with triggered image capture at 60 fps

Synchronize serial data with image capture at 60 fps: trigger on the hardware line, read the port in a thread, and pair each frame with the nearest reading.

LumaSpec Vision11 min read Share on LinkedIn

On this page 10 sections
  1. 01The decision: trigger on the wire, pair on one clock
  2. 02The timing budget at 60 fps
  3. 03What you need
  4. 04The build, step by step
  5. 05Worked example: 24-byte readings at 115200 baud against 60 fps
  6. 06Verify the pairing before shipping
  7. 07When nearest-time pairing is not tight enough
  8. 08Mistakes that corrupt the pairs
  9. 09Checklist before you order
  10. 10Questions

You have a serial device doing two jobs at once: it strobes the camera once per inspection, and it sends a reading over RS232 that the PC must store beside that exact frame. The goal is one synchronized pair per trigger, 60 times a second, with the alignment provable. The setup that ruins this is polling the port and software-triggering the camera from the same loop, because OS scheduling adds 1 to 15 ms of jitter — nearly a full 16.7 ms frame period at 60 fps. The pattern that holds has three parts on one clock: a wire that triggers the camera, a thread that reads the serial stream, and a rule that pairs by timestamp. This guide wires it, configures it, and shows the arithmetic.

The decision: trigger on the wire, pair on one clock

Do not software-trigger this camera. Wire the device's trigger output to the camera's trigger input — through the grabber's I/O on a Camera Link system, straight to the camera's I/O connector on GigE, USB3 or CoaXPress. The strobe then starts every exposure with sub-microsecond jitter on the wire, and the PC is never in the trigger path. The readings stay asynchronous on purpose: a dedicated reader thread timestamps each complete message as it lands, the acquisition thread timestamps each frame as it arrives, and both stamps come from one monotonic PC clock.

Constant delays cancel in that arrangement. A frame that takes 5 ms to reach the PC is 5 ms late every single time, so nearest-time matching still picks the reading from its own trigger. Only variation hurts you, and the table shows where it comes from.

Approach Pairing accuracy at 60 fps What breaks it
Software trigger plus port polling, one loop 1-15 ms, drifting OS scheduler; one blocking read stalls capture
Hardware trigger plus nearest-time pairing Bounded at ±8.3 ms Dropped serial bytes, wrong baud
Hardware trigger plus device-latched reading Under 1 ms The device must send the reading at strobe time

Start with the middle row. Move to the third only when the reading must describe the part at the exposure instant to better than a millisecond.

The timing budget at 60 fps

frame period = 1 / frame rate byte time (8N1) = 10 bits / baud pairing window = frame period / 2

At 60 fps the frame period is 1/60 = 16.7 ms. Consecutive frames sit 16.7 ms apart, so a reading belongs to at most one frame and sits at most half that gap, 8.3 ms, from its center. That 8.3 ms is the pairing window; every choice below either protects it or spends it.

Serial speed decides whether a reading can arrive per frame at all. 8N1 framing puts 10 bits on the wire per byte: 1 start, 8 data, 1 stop. At 115200 baud a byte takes 10/115200 = 86.8 µs; at 9600 baud it takes 1.04 ms, so a 24-byte message needs 25 ms — longer than the frame period.

Two terms you cannot design away: the serial thread's arrival stamp is good to about 2 ms on a loaded PC, and frame transfer adds a steady 1-5 ms offset plus a millisecond or two of wobble. Budget ±10 ms end to end and prove it with the verification run at the end of this guide.

What you need

  • A camera with a hardware trigger input; global shutter if the part moves. Filter for both in the area scan cameras listing or the camera finder.
  • A grabber or NIC whose trigger I/O you can reach. On Camera Link the I/O sits on the grabber; on GigE, USB3 and CoaXPress it also sits on the camera body.
  • A shielded I/O cable from the device to that connector, plus the camera's data cable — see I/O cables and the accessories finder.
  • A serial port on the PC: a native COM port, or a USB-serial adapter whose receive latency timer you can set to 1 ms.

For the Camera Link route, the strobe lands on the grabber's I/O connector and the grabber drives the camera over the link. The MV-GC1102IOL is a Camera Link frame grabber.

Frame grabbersHikrobot MV-GC1102IOL Frame GrabberMV-GC1102IOL
Interface
Camera Link
$2,189.00View partBuild a system with it

On GigE, trigger the camera directly. The MV-CU020-90GC is a 2.5 MP GigE camera with a global shutter and a C-mount.

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

If the rack consolidates several cameras, a multi-port card keeps trigger routing in one place. The MV-GE1104 is a 4-port GigE frame grabber and the LS-CBL-0199 is a 3 m high-flex GigE camera cable with screw locks.

For the trigger wire itself, use a shielded cable with the right connector on the instrument end. The LS-CBL-0224 is a frame grabber I/O cable, DB9F to open leads, 7 m.

CablesFrame Grabber I/O Cable, DB9F to Open, 7 m (LS-CBL-0224)LS-CBL-0224
Type
Frame grabber I/O cables
Length
6-8 m
$79.00View partBuild a system with it

The build, step by step

  1. Wire the strobe. Connect the device's trigger output to the camera or grabber trigger input and tie the grounds at one point. Match levels before you power up: TTL inputs take 3.3 or 5 V, opto-isolated inputs take 5-24 V, and a 24 V PLC output into a TTL pin destroys the input. Keep the line opto-isolated whenever it shares a ground with 24 V loads.

  2. Arm the camera for continuous hardware trigger. In GenICam terms: TriggerSelector = FrameStart, TriggerSource = the wired line, TriggerActivation = RisingEdge, ExposureMode = Timed, AcquisitionMode = Continuous. Set exposure to 2 ms so exposure plus readout fits the 16.7 ms period with headroom. If the camera ignores the line, the GenICam trigger line settings walkthrough names the switches; if it fires once and stops, why a hardware trigger stops after one frame points at the acquisition mode. Sample code for arming and grabbing is in hardware-triggered acquisition in Python.

  3. Read the serial stream in its own thread. Open the port at 115200 baud, 8N1, no flow control. The thread blocks on read, collects bytes until a message is complete — terminator plus checksum — stamps the instant the last byte lands, and pushes (reading, t) onto a queue. If the port yields nothing or torn messages, the RS232 data capture failures walkthrough covers the cable, ground and driver checks.

  1. Grab frames with one wait per frame. The acquisition loop calls the grab API once per frame and takes the PC timestamp on return; handle timeouts per frame, never globally, as one wait call per frame shows. When the camera supports chunk data, enable ChunkModeActive and the Timestamp chunk so each image carries camera-side time too — camera buffer timestamp latency explains which clock each stamp reflects.

  2. Pair by nearest time. For each frame at time t_f, find the reading whose time t_r minimizes the absolute difference. Accept the pair when that difference is at most 8.3 ms at 60 fps; otherwise store the frame with a no-reading mark. Never fill a gap by reusing the previous reading.

  3. Log from a third thread. The writer pulls finished pairs off a queue and writes image plus reading to disk, so a slow disk stalls nothing upstream. Plan capacity for it before the first production run — image-save lag and disk-write bottlenecks covers the sizing.

Worked example: 24-byte readings at 115200 baud against 60 fps

Inputs: the device strobes the camera at 60 fps and sends one reading per trigger; each message is 24 bytes (4 header + 16 payload + 2 checksum + CR LF); the port runs 8N1 at 115200 baud; the serial thread's arrival stamps are good to 2 ms on a loaded PC.

Rules in words: frame period comes from the frame rate, wire time per message from bytes and baud, and the pairing window is half the frame period.

  • Frame period = 1/60 = 16.7 ms.
  • Byte time = 10/115200 = 86.8 µs, so message time = 24 x 86.8 µs = 2.08 ms.
  • Line occupancy = 2.08/16.7 = 12.5 percent.
  • Pairing window = 16.7/2 = 8.3 ms; with 2 ms of stamping error, accept skew up to ±10 ms.
  • Minimum baud for one reading per frame = 24 bytes x 10 bits x 60 fps = 14,400 bits per second. At 19,200 baud occupancy is 75 percent — no headroom. At 57,600 baud the message takes 4.2 ms and occupancy is 25 percent.

Decision: run 115200 baud. Occupancy stays near 12.5 percent, a status burst or a doubled message still fits inside the frame period, and pairs hold inside ±10 ms. At 9600 baud the same message needs 24 x 1.04 ms = 25 ms, which exceeds the 16.7 ms frame period, so the port physically cannot deliver one reading per frame — raise the baud or accept a reading every other frame.

Verify the pairing before shipping

Have the device put an incrementing counter in each reading, run 1,000 triggers, and log both timestamps for every pair. Pass criteria: 1,000 frames captured, at least 999 paired, every accepted pair inside ±10 ms, and skew spread evenly across the window with no drift. A tail beyond the window points to dropped bytes — check the checksum rejects and the baud. Frame count below trigger count means the camera cannot keep up with the strobe; frame rate limits with external trigger pulses explains where that ceiling sits.

When nearest-time pairing is not tight enough

±10 ms is fine when the reading changes slowly between frames: temperature, weight, a slow position. It is wrong when the reading must describe the part at the exposure instant to better than a millisecond — a fast position read this way is a frame old. Three fixes, in rising cost. First, make the device send the reading immediately after the strobe edge and pair by trigger count instead of time. Second, have the device stamp its own readings and sync clocks once per run. Third, calibrate the constant offset with a one-time flash test and use the camera's chunk timestamps, watching for camera timestamp clock rollover on long runs.

One more limit no software fixes: if the device sends readings at its own slow rate — once a second, say — pairing accuracy is that rate, not the frame period. Fix the device, not the matcher.

Mistakes that corrupt the pairs

Pair by time instead; matching asynchronous streams by timestamp is the same discipline as matching vision output to frames by timestamp. Then clear the rest of the list:

  • Wall-clock time for stamps: the time of day can jump on an NTP correction mid-run. Use the monotonic clock everywhere.
  • A blocking serial read inside the acquisition loop: one slow message stalls capture, and the recovery costs minutes.
  • Software triggering because it looks simpler: it moves 1-15 ms of scheduler jitter straight into the pairing.
  • Dropping the acceptance bound: a reading 20 ms from its frame is matched across a frame boundary, which is a wrong pair by definition.

Checklist before you order

  • Camera: hardware trigger input on your interface, global shutter if parts move.
  • Grabber or NIC: trigger I/O broken out to a connector you can wire, from frame grabbers matched to the camera interface.
  • I/O cable: correct connector each end, shielded, long enough for the I/O cables run from device to rack.
  • Serial path: native COM port, or an adapter whose latency timer sets to 1 ms.
  • Bandwidth: baud at least bytes x 10 bits x fps x 4 — 115200 baud for 24-byte readings at 60 fps.
  • Software: monotonic clock, one wait per frame, acceptance bound of half the frame period.
  • Test: 1,000-trigger counter run, pass at 999 or more pairs inside ±10 ms.

Once the camera and interface are fixed, the system configurator walks the camera, cable and I/O steps, and expert support with every order covers the trigger wiring questions before you cut a cable.

Questions

Can I software-trigger the camera and still pair readings at 60 fps?

You can capture that way, but the pairing budget fails. A software trigger travels through your SDK, the network stack and the OS scheduler, adding 1 to 15 ms of jitter on a general-purpose OS; the whole pairing window at 60 fps is 8.3 ms. Keep software triggers for still-capture workstations and use the hardware line whenever pairs must line up frame after frame.

What baud rate do I need for one reading per frame at 60 fps?

Compute it: baud must be at least message bytes times 10 bits times frames per second. A 24-byte reading at 60 fps needs 24 x 10 x 60 = 14,400 bits per second, so 19,200 baud passes at 75 percent line occupancy, which leaves no headroom. 57,600 baud gives 4.2 ms per message and 25 percent occupancy; 115,200 baud gives 2.1 ms. Pick 115,200 so status bursts and retries still fit.

What happens to the pairs when a frame drops?

Nothing, if you pair by time. Nearest-time matching compares timestamps, so a missing frame leaves a hole and every later frame still finds the reading closest to it. Pairing by sequence number is what corrupts data: one dropped frame shifts every later pair by one, silently. That is why the drop counter and the pairing bound both belong in the verification run.

Should I timestamp the serial reading when it arrives or when I parse it?

Timestamp on arrival, at the instant the last byte of a complete message lands, then parse afterwards. Parsing time varies with CPU load and message length, so a parse-time stamp smears your timeline by milliseconds. Keep a small ring buffer of raw bytes with their arrival stamps and parse in the same thread or a slower one; only the arrival stamps feed the pairing rule.

How do I know the frame and the reading describe the same part?

Log both timestamps for every pair during the verification run. A healthy system shows skews spread evenly inside plus or minus 8.3 ms at 60 fps, with no drift. A constant offset is harmless for pairing; slow drift means one clock or the trigger rate is off; and steps larger than the frame period mean you are matching readings across frame boundaries.

Do I need a frame grabber to do this with a GigE camera?

No. A GigE camera takes the trigger on its own I/O connector and a plain PoE NIC carries the frames. A grabber still earns its slot in multi-camera racks: it breaks trigger and I/O lines out in one place, keeps power on the PoE ports, and gives every camera the same wire discipline. A single camera on a short run needs none of that.