-
Notifications
You must be signed in to change notification settings - Fork 4
Making A Trigger Generator
← Previous topic: Triggers | Next topic: Testing Your Trigger Generator →
A good external trigger generator for image collection would have several important properties.
- Stable. Same pulse rate day in, day out.
- Low power.
- Programmable. If you want to change from 2 fps to something else...
- Cheap.
- Small.
A crystal-controlled microprocessor can have all of these. For example, an Arduino Nano. While the official Nano is rather expensive, Chinese versions of the device can be found online (Amazon) for less than $5 each. They may require a bit of soldering to install the pins so the device can be socketed, but you can always solder to the holes if you want to hardwire the connections.
The code to create a simple, fixed 2fps pulse generator is very simple. The 1/2 second interval is provided by the two instances of the constant "500000" -- 500,000 microseconds. It is left to the reader as an exercise to determine how you would create a four fps trigger source.
unsigned long now;
void setup() {
// put your setup code here, to run once:
pinMode( 4, OUTPUT );
pinMode( 5, OUTPUT );
pinMode( 6, OUTPUT );
pinMode( 13, OUTPUT );
digitalWrite( 4, HIGH );
digitalWrite( 5, HIGH );
digitalWrite( 6, HIGH );
digitalWrite( 13, LOW );
now = micros();
}
void loop() {
// put your main code here, to run repeatedly:
digitalWrite( 4, HIGH );
digitalWrite( 5, HIGH );
digitalWrite( 6, HIGH );
digitalWrite( 13, LOW );
while( (micros() - now) < 500000 ) { };
now += 500000;
digitalWrite( 13, HIGH );
digitalWrite( 4, LOW );
digitalWrite( 5, LOW );
digitalWrite( 6, LOW );
}
The "setup" function configures the I/O pins to be output for D4, D5, and D6 and sets all three to "high". The "loop" function repeatedly sets the same pins high, waits for 500,000 microseconds, turns the output pins low. It immediately returns to the top of the loop and sets the outputs back to high. This creates a short (20ms or so) low pulse on the output pins. Pin 13 is the red LED on the Nano, which is pulsed "on" when the low trigger pulse is output.
Three outputs are pulsed so that you can distribute the load across multiple outputs. I.e., camera 1 goes to D4, camera 2 to D5, etc. This circuit will drive more than two cameras per pin.
The Chinese version of the Nano is certainly the cheaper one, and the difference is, in large part, the use of a different USB to serial interface circuit. The Chinese Nano has a CH340, which is not found automatically by Windows Update (at least not for my version of Windows.) You can download the driver from here.
The wiring to the Nano is very simple. Here's a diagram.
Well, I said it would be an interesting modification to change the trigger code to allow changing the trigger via serial (USB) input, and it is. Here's my version. It is a lot longer than the first one, but you can send the desired microsecond period out the COM port at 9600 baud followed by a newline and change the timing.
I've found that using a period of 500185 microseconds puts the timing almost dead on 2Hz. Your Arduino may be different.
// global variables
unsigned long now;
unsigned long interval;
unsigned long snap;
String inputString = "";
boolean stringComplete = false;
unsigned long temp;
int ports[] = {4,5,6,7,8,9,10,11,12,0};
int ii;
// initializations
void setup() {
// open a 9600 baud serial link through USB
Serial.begin( 9600 );
while ( !Serial ) {
;
}
Serial.println("Hello, starting trigger loops...");
// reserve 100 characters in my input string
inputString.reserve(100);
// set all digital pins to output
for( ii=0; ports[ii]>0; ii++ ) {
pinMode( ports[ii], OUTPUT );
digitalWrite( ports[ii], HIGH );
}
// plus the on-board LED
pinMode( 13, OUTPUT );
// turn off LED
digitalWrite( 13, LOW );
// when is now?
now = micros();
// and default interval of 500,000 microseconds
interval = 500259;
}
void loop() {
// if we haven't reached out interval yet, nothing
if ( (micros() - now) < interval ) {
;
}
// otherwise, send pulse
else {
// set next pulse time
now += interval;
// light the LED
digitalWrite( 13, HIGH );
// and send out our active low pulse
for( ii=0; ports[ii]>0; ii++ )
digitalWrite( ports[ii], LOW );
// a temporary timer to set pulse length
snap = micros();
// wait 100 micros for trigger pulse
while ( (micros() - snap) < 100 ) {
;
}
// and go back HIGH
for( ii=0; ports[ii]>0; ii++ )
digitalWrite( ports[ii], HIGH );
// wait 5 ms for the LED flash
while ( (micros() - snap) < 5000 ) {
;
}
// and turn it back off
digitalWrite( 13, LOW );
}
// every loop, look for serial input
while ( Serial.available() ) {
// if there, read one char
char inChar = (char)Serial.read();
// add to input string
inputString += inChar;
// look for newline to end input
if ( inChar == '\n' ) {
stringComplete = true;
}
}
// if we got a newline ...
if ( stringComplete ) {
// convert to integer and say string is not complete
temp = inputString.toInt();
stringComplete = false;
// if we got anything but 0 for our conversion ...
if ( temp ) {
// report the change in case Poppa is listening
Serial.print("Changing interval from ");
Serial.print( interval );
Serial.print(" to ");
Serial.print( temp );
Serial.println(" microseconds");
// change the interval and clear the temp
interval = temp;
temp = 0;
}
// invalid input if 0
else {
Serial.print("Error: invalid interval: ");
Serial.print( inputString );
}
// clear the input for the next time
inputString = "";
}
}
[[ ← Previous topic: Triggers | Triggers ]] | [[Next topic: Testing Your Trigger Generator → | Testing-Your-Trigger-Generator ]]
CIRN
Wiki Home
CIRN Website
CIRN Research and Workshops
CIRN Monthly Webinars Existing Monitoring Stations
Sampling Goals
Pixel Resolution
Fixed Mounting Platforms
Temporary Towers
FOV and Lenses
Installation Design
Cookbook
Data Processing
Understanding Image Geometries
Photogrammetry
Intrinsic Calibration
GCPs
Extrinsic Calibration
File Naming
Directory Naming
Time Conventions
Common Variable Names
Parallel Processing Issues
Etc
GitHub Help
GitHub Cheat Sheet
CIRN repository help
GitHub Best Practices and GuidelinesGitHub Repository Structure
GitHub Workflow Overview
Using Teams & Roles
Issues
Testing & Review
Code Requirements
General Guidance
Admin
Software Development Life Cycle