You have the pulse. The Arduino pin toggles on the scope exactly as coded, the trigger setting reads On, and the camera still ignores every edge. In most cases the fault is not the pulse: it is an open current loop or a missing resistor on the camera's opto-isolated input. This guide takes you from an Arduino output to a hardware trigger on an area scan camera GPIO block: which of the two input types to drive, the series resistor for either logic level, and the line-status test that proves the pulse lands before you touch a single acquisition setting.
Two inputs, one decision
An industrial camera's GPIO connector usually carries two kinds of trigger input.
The opto-isolated input is a current loop that crosses a light barrier: your signal drives an LED inside the camera, a phototransistor on the far side flips the digital line, and the camera's electronics never share a node with your Arduino. The non-isolated input is a plain logic line with an internal pull-up; it asserts when you short it to camera ground.
The decision: drive the opto-isolated input from an Arduino. It costs one extra wire (a ground return) and one series resistor, and in exchange the bench supply, the PC's USB ground and the camera supply stay decoupled, so no ground loop rides on the trigger cable. Use the non-isolated line only when camera and driver already share a ground and you want the simplest contact closure, because a bare switch then works with no electronics.
GenICam names the inputs Line0, Line1, Line2 and so on. The GPIO table in your camera's installation guide tells you which pin is the opto input, which pin is its dedicated return, and which is camera power ground. The return is a separate pin from power ground, and confusing the two is the most common silent failure in this wiring, so keep that table open while you work.
| Opto-isolated input | Non-isolated input | |
|---|---|---|
| Wires from the Arduino | Two: output through the resistor, plus ground return | One, plus a ground bond to camera ground |
| How it asserts | 3.8 mA through the input LED (1 kΩ series) | Short the line to camera ground |
| Extra parts | One series resistor | None |
| Arduino drive style | Push-pull pulse to the logic rail | Sink low, release to high-impedance |
| Choose when | Separate supplies, USB ground loops, noise, bench rigs | Shared ground and the simplest one-contact assert |
Any global-shutter camera with a GPIO block suits this rig; the model below is a 2.5 MP GigE camera with a C-mount:
- Sensor format
- 1/1.7"
- Lens mount
- C-mount
- Interface
- GigE
- Resolution
- Up to 3 MP
Size the series resistor
The opto input is an LED, so the resistor has one job: set its current. Installation guides anchor the value at 1 kΩ in series with a full-rail drive, and the same figure covers the opto and the non-isolated lines. The arithmetic behind the anchor: an optocoupler LED drops roughly 1.2 V at these currents (the usual forward voltage), and the resistor takes the rest of the supply.
Worked example, using the numbers from the table above:
- 5 V output, guide value 1 kΩ: I_loop = (5.0 V - 1.2 V) / 1000 Ω = 3.8 mA, and the resistor dissipates P_R = (0.0038 A)² × 1000 Ω = 14.4 mW, so a 0.125 W part stays cold.
- 3.3 V board (most small dev boards run 3.3 V logic): R = (3.3 V - 1.2 V) / 3.8 mA = 553 Ω, so fit the nearest standard value, 560 Ω, and I_loop = 2.1 V / 560 Ω = 3.75 mA — the same current as the 5 V case.
- 560 Ω from a full-rail pin also triggers: I_loop = 3.8 V / 560 Ω = 6.8 mA. That is a normal optocoupler drive level (2-20 mA typical) and well under the 20 mA per pin the board's microcontroller is rated for, but 1 kΩ holds the guide's anchor current, so keep it as the default at that rail.
The same three-line calculation governs any Arduino-driven LED string; a series-resistor wiring guide for addressable LEDs works the identical numbers for LED strips.
Wire the opto-isolated loop
Break the camera's I/O connector out to bare wires first; breakout looms live with the camera power and I/O cables. The one below is an M8 8-pin male-to-open-end cable, 7 m long, drag-chain rated:
- Type
- Power and I/O cables
- Length
- 6-8 m
Then wire the loop:
- Identify three pins in the GPIO table: the opto-isolated input, its dedicated opto return, and camera power ground.
- Fit the resistor between the Arduino output pin and the opto input pin: 1 kΩ at the 5 V rail, 560 Ω at 3.3 V.
- Run a wire from Arduino GND to the opto return pin. The full loop is output pin → resistor → camera input pin → opto return → Arduino ground. A bond between the two power supplies elsewhere on the bench does not close this loop; the return wire does. Missing it is exactly why line status stays dead while the pulse looks perfect on a scope.
- Leave camera power ground and Arduino ground unconnected otherwise. Isolation is the point: the trigger needs only its two conductors.
- Keep the pulse short and the train slow: 12 µs high, with a low gap longer than one frame period.
- Press the button and read line status before configuring anything (next section).
The sketch that fires it:
const int trigPin = 4; // any digital output pin
const int pulseUs = 12; // pulse width in microseconds
void setup() {
pinMode(trigPin, OUTPUT);
digitalWrite(trigPin, LOW); // idle: no current through the input LED
}
void loop() {
digitalWrite(trigPin, HIGH); // full rail -> resistor -> camera opto input
delayMicroseconds(pulseUs);
digitalWrite(trigPin, LOW);
delay(100); // about 10 pulses/s; stay below the frame rate
}
One decision hides in the pulse: if the camera's exposure mode is set to trigger width, your 12 µs pulse becomes the exposure, which is far too short for a usable image. Set a timed exposure explicitly or lengthen the pulse on purpose; the pulse-width exposure guide explains how that mode decides.
Prove the pulse before configuring anything
The camera reports input state live. Select the wired line with LineSelector and read LineStatus while you press the button: it should flip false → true → false on every press, and the viewer's event log prints an entry per edge. Two minutes of this beats an hour inside trigger menus.
Work the failures in order:
- LineStatus stays false with the button held: the loop is open. The usual culprit is the return wire landing on camera power ground instead of the opto return.
- LineStatus toggles but no frames: the wiring is proven; move to the trigger settings.
- You want the check repeatable: read the line state over the SDK while you drive it; the GPIO read guide turns the wiring check into a script.
Trigger configuration that grabs frames
With the loop proven, close it in GenICam. Set TriggerSelector to FrameStart, TriggerMode to On, TriggerSource to the wired opto line, then start acquisition: the camera waits, and each pulse yields exactly one frame.
Three settings cause most no-frame cases:
- TriggerMode left Off, or left On for a different TriggerSelector.
- TriggerSource pointing at a line you did not wire.
- The camera refusing the source value outright. An enumeration rejects a symbolic name it does not know, so check the valid names before writing an integer — the GenICam enumeration guide covers that failure.
Read the value back after writing it; if the camera reports a different source than the one you set, the trigger readback guide shows how to catch the mismatch. When the source is on, the loop is closed and the camera still times out, the line-configuration checklist walks the remaining GenICam line settings.
The non-isolated shortcut
Many cameras also expose a non-isolated line that asserts on a short to camera ground. It is the fastest way to prove a camera's trigger side: touch the line to camera power ground a few times while watching line status, and frames should grab with no electronics at all.
To drive it from the Arduino, keep the push-pull output out of the circuit. Configure the pin as an output driving LOW to assert and switch it to high-impedance input to release; the Arduino then only sinks the camera's pull-up current and never forces the line high. A plain switch or an open-collector stage behaves identically with no code.
The shortcut's price is the ground: camera ground and Arduino ground become one electrical node again, so USB and bench-supply loops are back in play. If the line chatters or frames double, that shared reference is the first suspect, and the trigger common-reference guide covers the diagnosis.
Mistakes that keep LineStatus dead
The same handful of faults explains nearly every silent trigger. Check them in this order:
- Return wire on camera power ground instead of the opto return. With power off, measure continuity from Arduino GND to the return pin.
- Resistor omitted or shunted by a solder bridge. With power off, measure about 1 kΩ through the series path.
- TriggerMode On but acquisition never started: cameras only sample trigger lines while acquiring, so the camera waits for nothing until you press play.
- TriggerSource set to a different line than the one your return wire reaches. Read the value back and compare.
- Trigger-width exposure with a 12 µs pulse: frames come out black and the camera looks unresponsive. Switch to timed exposure.
- Pulses faster than the frame period: the camera is mid-frame and drops triggers. Slow the loop before blaming the wiring.
When an Arduino is the wrong clock
An Arduino is the right clock for bench tests, single-camera rigs and slow sequences. Move the timing upstream when frames must lock to motion: an encoder or a PLC output in the trigger path holds every frame at the same part position, which no free-running loop can. To fire several cameras from one board, fan the same pulse out with one resistor per camera — each input draws only its 3.8 mA — as the multi-camera fan-out guide details. When the goal is only a pulse train to exercise a trigger input, a frame grabber can generate one internally, as the frame grabber pulse-train guide shows.
Parts and next steps
The decisions, one line each:
- 5 V Arduino: opto input, 1 kΩ series resistor, ground return wired — the default.
- 3.3 V board: the same loop with 560 Ω.
- Shared-ground bench, one contact wanted: non-isolated line asserted low.
- Machine-timed production: encoder or PLC pulse instead of the Arduino.
To build the rig, filter the camera finder by interface and resolution, pick a breakout loom from the accessories finder, or step through the camera configurator, which checks lens coverage as you go. In-stock items ship within one business day, and the contact page reaches the applications team if your camera's GPIO table disagrees with the loop above. The rest of the trigger guides sit on the systems topic page.
Questions
Can I trigger the opto-isolated input without a series resistor?
No. The resistor sets the current through the input LED. Straight from the pin, current is limited only by the driver's output stage, up to tens of milliamps, which stresses both the LED and the chip. The guide's 1 kΩ at full rail dissipates about 14 mW and holds the loop near 3.8 mA, so the part costs nothing and removes the failure mode.
How fast can an Arduino pulse camera triggers?
The pulse costs 12 µs; the frame period does not. A camera needs exposure plus readout per frame, often tens of milliseconds, so pulses arriving faster than the camera can finish a frame get dropped or queued. Start near 10 pulses per second, confirm every pulse yields one frame, then raise the rate until frames slip; that ceiling is the rig's real limit.
Can one Arduino output trigger several cameras at once?
Yes, within the pin's current budget. Each camera's opto input draws about 3.8 mA through its own series resistor, so three cameras put roughly 11 mA on one pin, below the 20 mA an Arduino-class output is rated to source. Give every camera its own resistor and tie each opto return to the Arduino ground; the loop arithmetic stays per-camera.
A bare-wire short triggers the camera but the Arduino pulse does not — what now?
The camera side is then proven, so the fault sits between the pin and the loop. Measure the pin with a meter: it should idle near 0 V and jump to the rail when the code fires. If the pin moves, check that the resistor feeds the input pin and that the return wire lands on the opto ground rather than camera power ground; the two wrong-pin mistakes look identical from the GUI.

