Hello,
First of all, I'm new to Arduino and the forum so apologies if I do something wrong in this post!
I am currently working on a project that is essentially a ballistic chronograph for measuring the speed of a projectile by recording the time between when IR break beam sensors are obstructed. However, unlike a traditional chronograph I have 8 sensor pairs that are tripped in order so that I can observe some non linear behavior. This code is also used to control the switching of a solenoid valve through a relay, but so far I have had zero problems with this part of the code.
At the start of this project I knew very little about electronics/soldering and decided to use what looked simple: Adafruit 3mm IR break beam sensor receiver pairs:
I have been testing these sensors for awhile and have managed to get them working at low speeds (breaking one with a pen, dropping objects past them). Recently I have been trying to test them with much higher speed projectiles (300 ft/s >) and they never seem to trigger / record timestamps at these speeds. I have been doing some research on the forums and looking at other people's chronograph projects and feel like I'm in a little over my head. Right now I am unsure if this is a hardware or code problem and could use a little help/advice before I go chasing my tail around.
Here are all the specs for what I have built:
control board: ELEGOO Mega ATmega2560
Sensor spacing: 8 break beam pairs spaced out evenly 9 inches apart over a six foot span.
Space between sensor/transmitter: .5 inches apart, it is also worth noting that the sensors are almost entirely obscured from ambient light.
Projectile data: projectile is .5 inches long and estimated to be moving around 300-400 ft/s (just some napkin math, the sensors were supposed to tell me what the actual velocity was)
Here is the first version of the control code that I tried:
//single shot control code
//this code fires the gas gun, and clocks all of the IR break sensors, then prints times to the monitor
//THIS CODE WILL NOT WORK IF MULTIPLE TANKS ARE BEING FIRED
//Global variables
// initialize signal pins to the relay board
int Relay1 = 2;
//int Relay2 = 3;
//int Relay3 = 4;
//int Relay4 = 5;
//initialize trigger button
int Trigger = 10;
//a series of counter variables are needed to clock when sensors are broken
unsigned long startTime;
unsigned long endTime1;
unsigned long endTime2;
unsigned long endTime3;
unsigned long endTime4;
unsigned long endTime5;
unsigned long endTime6;
unsigned long endTime7;
//a series of variables are needed to calculate the duration of time between the start time and the time at which a sensor is broken
unsigned long Duration1;
unsigned long Duration2;
unsigned long Duration3;
unsigned long Duration4;
unsigned long Duration5;
unsigned long Duration6;
unsigned long Duration7;
//define all our sensor pinouts, these connect to the IR breakbeams
#define sensorpin1 24
#define sensorpin2 22
#define sensorpin3 23
#define sensorpin4 25
#define sensorpin5 26
#define sensorpin6 27
#define sensorpin7 28
//create a variable to read the state of the trigger, value will change
int triggerpress = 0;
// these variables are for reading if IR breakbeams are broken or not
int sensorstate1 = 0, lastState1=0;
int sensorstate2 = 0, lastState2=0;
int sensorstate3 = 0, lastState3=0;
int sensorstate4 = 0, lastState4=0;
int sensorstate5 = 0, lastState5=0;
int sensorstate6 = 0, lastState6=0;
int sensorstate7 = 0, lastState7=0;
//a variable to track if the timmer is running is needed as well, this will prevent the timer starting if a sensor is accidentlay obstructed
byte timerRunning;
void setup() {
// put your setup code here, to run once:
//initialize sensor pins as inputs
pinMode(sensorpin1, INPUT);
pinMode(sensorpin2, INPUT);
pinMode(sensorpin3, INPUT);
pinMode(sensorpin4, INPUT);
pinMode(sensorpin5, INPUT);
pinMode(sensorpin6, INPUT);
pinMode(sensorpin7, INPUT);
//pins should be initilized in the HIGH state
digitalWrite(sensorpin1, HIGH);
digitalWrite(sensorpin2, HIGH);
digitalWrite(sensorpin3, HIGH);
digitalWrite(sensorpin4, HIGH);
digitalWrite(sensorpin5, HIGH);
digitalWrite(sensorpin6, HIGH);
digitalWrite(sensorpin7, HIGH);
// setup relay pins as outputs
pinMode(Relay1,OUTPUT);
//set trigger pin as input
pinMode(Trigger,INPUT);
//we need to pull our relay pin high to start, when pin is pulled low the relay will trigger
digitalWrite(Relay1,HIGH);
//Considering our button is only a two wire button, we want to set our pin to HIGH so when button is pressed voltage will flow to ground
digitalWrite(Trigger,HIGH);
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
//first we need to read the state of the pushbutton value
triggerpress = digitalRead(Trigger);
//we also need to read all the sensors to see if any are broken with digitalread
sensorstate1 = digitalRead(sensorpin1);
sensorstate2 = digitalRead(sensorpin2);
sensorstate3 = digitalRead(sensorpin3);
sensorstate4 = digitalRead(sensorpin4);
sensorstate5 = digitalRead(sensorpin5);
sensorstate6 = digitalRead(sensorpin6);
sensorstate7 = digitalRead(sensorpin7);
//first loop controls the firing of the tank and the starting of the timer
if (timerRunning == 0 && triggerpress == LOW) {
startTime = micros();
digitalWrite(Relay1,LOW);
timerRunning = 1;
}
//these next loops will control the clocking of each IR breaksensor
if (timerRunning == 1 && sensorstate1 == LOW){
endTime1 = micros();
}
if (timerRunning == 1 && sensorstate2 == LOW){
endTime2 = micros();
}
if (timerRunning == 1 && sensorstate3 == LOW){
endTime3 = micros();
}
if (timerRunning == 1 && sensorstate4 == LOW){
endTime4 = micros();
}
if (timerRunning == 1 && sensorstate5 == LOW){
endTime5 = micros();
}
if (timerRunning == 1 && sensorstate6 == LOW){
endTime6 = micros();
}
if (timerRunning == 1 && sensorstate7 == LOW){
endTime7 = micros();
digitalWrite(Relay1,HIGH);
}
//Finnaly our durations must be calculated and displayed to the serial monitor
if(timerRunning == 1 && endTime7 > 0){
timerRunning = 0;
Duration1 = endTime1 - startTime;
Duration2 = endTime2 - startTime;
Duration3 = endTime3 - startTime;
Duration4 = endTime4 - startTime;
Duration5 = endTime5 - startTime;
Duration6 = endTime6 - startTime;
Duration7 = endTime7 - startTime;
Serial.print("Sensor 1 trip in microseconds:");
Serial.println(Duration1);
Serial.print("Sensor 2 trip in microseconds:");
Serial.println(Duration2);
Serial.print("Sensor 3 trip in microseconds:");
Serial.println(Duration3);
Serial.print("Sensor 4 trip in microseconds:");
Serial.println(Duration4);
Serial.print("Sensor 5 trip in microseconds:");
Serial.println(Duration5);
Serial.print("Sensor 6 trip in microseconds:");
Serial.println(Duration6);
Serial.print("Sensor 7 trip in microseconds:");
Serial.println(Duration7);
}
}
When I run this code I can open the valve and fire the system, but nothing prints to the monitor and the relay switch never gets turned off. I tried a second version of the code that is similar, but made a bit more simple to see if the code was taking too long to run:
//single shot control code
//this code fires the gas gun, and clocks all of the IR break sensors, then prints times to the monitor
//THIS CODE WILL NOT WORK IF MULTIPLE TANKS ARE BEING FIRED
//Global variables
// initialize signal pins to the relay board
int Relay1 = 2;
//int Relay2 = 3;
//int Relay3 = 4;
//int Relay4 = 5;
//initialize trigger button
int Trigger = 10;
//a series of counter variables are needed to clock when sensors are broken
unsigned long startTime;
unsigned long endTime1;
unsigned long endTime2;
unsigned long endTime3;
unsigned long endTime4;
unsigned long endTime5;
unsigned long endTime6;
unsigned long endTime7;
//a series of variables are needed to calculate the duration of time between the start time and the time at which a sensor is broken
//define all our sensor pinouts, these connect to the IR breakbeams
#define sensorpin1 24
#define sensorpin2 22
#define sensorpin3 23
#define sensorpin4 25
#define sensorpin5 26
#define sensorpin6 27
#define sensorpin7 28
//create a variable to read the state of the trigger, value will change
int triggerpress = 0;
//a variable to track if the timer is running is needed as well, this will prevent the timer starting if a sensor is accidently obstructed
byte timerRunning;
void setup() {
// put your setup code here, to run once:
//initialize sensor pins as inputs
pinMode(sensorpin1, INPUT);
pinMode(sensorpin2, INPUT);
pinMode(sensorpin3, INPUT);
pinMode(sensorpin4, INPUT);
pinMode(sensorpin5, INPUT);
pinMode(sensorpin6, INPUT);
pinMode(sensorpin7, INPUT);
//pins should be initilized in the HIGH state
digitalWrite(sensorpin1, HIGH);
digitalWrite(sensorpin2, HIGH);
digitalWrite(sensorpin3, HIGH);
digitalWrite(sensorpin4, HIGH);
digitalWrite(sensorpin5, HIGH);
digitalWrite(sensorpin6, HIGH);
digitalWrite(sensorpin7, HIGH);
// setup relay pins as outputs
pinMode(Relay1,OUTPUT);
//set trigger pin as input
pinMode(Trigger,INPUT);
//we need to pull our relay pin high to start, when pin is pulled low the relay will trigger
digitalWrite(Relay1,HIGH);
//Considering our button is only a two wire button, we want to set our pin to HIGH so when button is pressed voltage will flow to ground
digitalWrite(Trigger,HIGH);
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
//first we need to read the state of the pushbutton value
triggerpress = digitalRead(Trigger);
//first loop controls the firing of the tank and the starting of the timer
if (timerRunning == 0 && triggerpress == LOW) {
startTime = micros();
digitalWrite(Relay1,LOW);
timerRunning = 1;
}
//these next loops will control the clocking of each IR breaksensor
while(timerRunning == 1){
// if ( digitalRead(sensorpin1) == LOW){
// endTime1 = micros();
// }
//
// if ( digitalRead(sensorpin2) == LOW){
// endTime2 = micros();
// }
//
// if ( digitalRead(sensorpin3) == LOW){
// endTime3 = micros();
// }
//
// if (digitalRead(sensorpin4) == LOW){
// endTime4 = micros();
// }
//
// if (digitalRead(sensorpin5) == LOW){
// endTime5 = micros();
// }
//
// if (digitalRead(sensorpin6) == LOW){
// endTime6 = micros();
// }
if (digitalRead(sensorpin7) == LOW){
endTime7 = micros();
timerRunning = 0;
digitalWrite(Relay1,HIGH);
}
}
//Finnaly our durations must be calculated and displayed to the serial monitor
if(timerRunning == 0 && endTime7 > 0){
Serial.print("Shot Start:");
Serial.println(startTime);
// Serial.print("Sensor 1 trip in microseconds:");
// Serial.println(endTime1);
//
// Serial.print("Sensor 2 trip in microseconds:");
// Serial.println(endTime2);
//
// Serial.print("Sensor 3 trip in microseconds:");
// Serial.println(endTime3);
//
// Serial.print("Sensor 4 trip in microseconds:");
// Serial.println(endTime4);
//
// Serial.print("Sensor 5 trip in microseconds:");
// Serial.println(endTime5);
//
// Serial.print("Sensor 6 trip in microseconds:");
// Serial.println(endTime6);
Serial.print("Sensor 7 trip in microseconds:");
Serial.println(endTime7);
//clear all time storage variables
startTime = 0;
endTime1 = 0;
endTime2 = 0;
endTime3 = 0;
endTime4 = 0;
endTime5 = 0;
endTime6 = 0;
endTime7 = 0;
}
}
*I commented out the other sensors here just to see if trying to read all eight sensors was too slow, but this didn't fix the problem.
Both codes produce the same results: If I trip sensor 7 with a slow moving object, the relay is switched off and micros() is printed to the serial monitor. I can then shoot a projectile through and nothing is displayed and the relay is never switched off. This seems to me like the event is happening too fast for the sensors to catch.
I am wondering if this is a hardware limitation or just bad coding on my part? The sensors I am using list a response time of >2ms but the data sheet is very sparse so I'm not really sure what kind of sensor is actually being used. When looking at other peoples projects I have seen the OPL550 IR photo transistors used which have a pullup time listed in nanoseconds.
So are there some tricks I can do to make my code run faster(interrupts, direct port manipulation)? Or do I need to tear up my wiring harness and replace my IR receivers with something faster? Any help is appreciated and apologies again if there is not enough info here! I am happy to elaborate further as needed