// Timers for Race
int raceStartTime = 0;
int raceElapsedTime = 0;
int raceFinishTime = 0;
// Timers for Light Countdown
int countdown = 0;
int countdownDelay = 7; // stores amount of time between blocking sensor 2 and starting the countdown
int countdownStart = 0;
int now = 0; // used to determine the time the loop starts. This is overwritten with a new time each time the loop runs
All variables that hold millis() (or micros()) values should be declared 'unsigned long', not 'int'. If you ever switched to micros() for more precise timing you would only be able to time 32 milliseconds with an 'int'. An 'unsigned long' would work up to 71 minutes.
The code looks pretty good. It compiles without errors or warnings so that is good.
The code would be easier to follow if you use meaningful names for your three 'Laser' pins. It appears that one is at the staging line, one at the fault line, and one at the finish line. The numbers don't make clear which is which.
You set but never use the values in "myLEDs" so you can get rid of the array and the two lines where it is used. You never use the myLasers array at all so you can get rid of it.
It is good practice to use an initial capital letter on the names of global variables. That makes it easier to keep track of which variables are global and which are local.
if (value > laserInterruptSensitivity)
Since the '>' operator returns a bool, this can be simplified to:
return value > laserInterruptSensitivity;
If timing is critical, there is no need to read the three 'Laser' value at the start of loop(). You can change the 'isSensorBlocked()' function to take a pin number and read the analog input only when the value is needed. That will speed up loop() a bit.
You were accidentally checking the Starting Line laser for a fault when you should be checking the Staging Line laser.
I'm a little confused about 'countdown' vs ' countdownStart' and the countdownInProgress() function. It seems to have something to do with a very short delay (7 milliseconds) between the car reaching the staging line and the start of the display?
Here is your sketch with the above issues fixed and suggestions applied.
// Pin values for Lights
const byte LEDWhite1 = 2;
const byte LEDWhite2 = 4;
const byte LEDYellow1 = 6;
const byte LEDYellow2 = 8;
const byte LEDYellow3 = 10;
const byte LEDGreen = 11;
const byte LEDRed = 12;
// Pin values for Lasers
const byte StagingLinePin = A0;
const byte StartingLinePin = A1;
const byte FinishLinePin = A3;
// Delay between the countdoown lights
const unsigned InitialDelay = 7; // between Start Line and first Yellow
const unsigned YellowDelay = 500; // between each Yellow and Green
const int LaserInterruptSensitivity = 10; // sensitivity value to determine if sensor is blocked
// State Flags
bool RaceHasStarted = false; // Set 'true' when Green light is turned on
bool RaceHasFinished = false; // Set 'true' when Finish Line is crossed
// Timers for Race
unsigned long RaceStartTime = 0; // Set to micros() when Green light is turned on
unsigned long RaceFinishTime = 0; // Set to micros() when Finish Line is crossed
// Timer for Light Countdown
// Note: Doubles as a state flag: if != 0, countdown is in progress
unsigned long CountdownStart = 0; // Set to millis() when Start Line is crossed
// Checks if sensor on analog input 'pin' is blocked
bool isSensorBlocked(byte pin)
return analogRead(pin) > LaserInterruptSensitivity;
// Turns on Light on pin 'lightPin'
void turnOnLight(byte lightPin)
digitalWrite (lightPin, HIGH);
// Turns off Light on pin 'lightPin'
void turnOffLight(byte lightPin)
digitalWrite (lightPin, LOW);
// turn on Red LED, turn off all others
// turn on Red LED
// turn off all other LEDs
pinMode(LEDWhite1, OUTPUT); // Pre-stage: Car is on Staging Line
pinMode(LEDWhite2, OUTPUT); // Staged: Car has reached Start Line
pinMode(LEDYellow1, OUTPUT); // Turns on 'InitialDelay' milliseconds after White2
pinMode(LEDYellow2, OUTPUT); // Turns on 'YellowDelay' milliseconds after Yellow1
pinMode(LEDYellow3, OUTPUT); // Turns on 'YellowDelay' milliseconds after Yellow2
pinMode(LEDGreen, OUTPUT); // Start: Turns on 'YellowDelay' milliseconds after Yellow3
pinMode(LEDRed, OUTPUT); // Fault: Leaving Staging Line between White2 and Green
// Get current time
unsigned long now = millis();
Everything below this line is AFTER race finished
// do nothing?
Everything below this line is for AFTER race starts
else if (RaceHasStarted)
// The race has not finished but it has started to the
// race is in progress. Waiting for car to cross the finish line
// race has just finished
RaceFinishTime = micros(); // Time of Finish
RaceHasFinished = true;
Serial.print("Finishing time (sec): ");
Serial.println((RaceFinishTime - RaceStartTime) / 1000000.0, 6);
// race is still in progress
Serial.print("Elapsed time (sec): ");
Serial.println((micros() - RaceStartTime) / 1000000.0, 6);
Everything below this line is BEFORE the RACE starts
else if (CountdownStart != 0) // The contdown to the start is in progress
// The race has not started or finished but the countdown to start
// is in progress so we light up the lights in sequence
unsigned long elapsedCountdown = now - CountdownStart;
// The car has left the Staging Line before the countdown ended!
// DO NOT CONTINUE COUNTDOWN!
CountdownStart = 0;
if (elapsedCountdown >= (InitialDelay))
if (elapsedCountdown >= (InitialDelay + YellowDelay))
if (elapsedCountdown >= (InitialDelay + YellowDelay + YellowDelay))
if (elapsedCountdown >= (InitialDelay + YellowDelay + YellowDelay + YellowDelay))
RaceHasStarted = true;
RaceStartTime = micros(); // Measure race in microseconds
CountdownStart = 0; // Countdown is done
Everything below this line is Pre-Stage or Stage
// The race is not finished or running and the countdown isn't in
// progress so we are waiting for pre-staging and staging.
// White led 1 is ON when Staging Line sensor is blocked
// if Starting Line sensor is blocked turn on white led 2 and start countdown
CountdownStart = millis(); // Start the countdown to GREEN