Arduino Race Track Timer

Hello everyone. My church is doing a Grand Prix(basically a pinewood derby), and want me to make a timer. So far I have built the timer system, which uses one photoresistor at the start, and four at the bottom. I also have lasers shining at the sensors, so that it's very easy to tell when they're tripped. The whole thing is ready except for the code, which is giving me some difficulties. I want each cars time to get recorded from when the first sensor is tripped. This has proved a challenge, and I have not figured out a solution yet. I've got it to show the winners' time, but nothing else. Here's the code. Thanks in advance for anyone who helps me!!!! :slight_smile:

/* For track setup, first connect all sensors in the right order. Next, test the value of the photoresistor output. Now change all the <=? to about 50-100 lower than their normal values.
You also need to change the delay on the start timer depending on how fast most of the cars are. After each run you have to reset the arduino.*/
const int sensorPin1 = A2;

const int sensorPin2 = A3;

const int sensorPin3 = A4;

const int sensorPin4 = A5;

const int sensorPin = A0;

const int TIMEOUT = 5000; // milliseconds

#define THRESHOLD 100

unsigned long start, finished, elapsed;

void setup() {

Serial.begin(9600);
Serial.print("Ready...");
pinMode(sensorPin1, INPUT);
pinMode(sensorPin2, INPUT);
pinMode(sensorPin3, INPUT);
pinMode(sensorPin4, INPUT);

}

void displayResult()
{
float h,m,s,ms;
unsigned long over;
elapsed=finished-start;
h=int(elapsed/3600000);
over=elapsed%3600000;
m=int(over/60000);
over=over%60000;
s=int(over/1000);
ms=over%1000;
Serial.print("Time: ");
Serial.print(s,0);
Serial.print("s ");
Serial.print(ms,0);
Serial.print("ms");
Serial.println();
}

void displaystatus5()
{
start=millis();
Serial.println();
Serial.println("...Started...");
Serial.println();
}

void loop() {
int status1 = analogRead(sensorPin1);
int status2 = analogRead(sensorPin2);
int status3 = analogRead(sensorPin3);
int status4 = analogRead(sensorPin4);
int status5 = analogRead(sensorPin);

if (status5 <=THRESHOLD) {
displaystatus5();
}
else if (status1 <=THRESHOLD) {

Serial.println("Lane #1");
finished=millis();
displayResult();
delay(TIMEOUT);
}

else if (status2 <=THRESHOLD) {
Serial.println("Lane #2");
finished=millis();
displayResult();
delay(TIMEOUT);
}

else if (status3 <=THRESHOLD) {
Serial.println("Lane #3");
finished=millis();
displayResult();
delay(TIMEOUT);

}

else if (status4 <=THRESHOLD) {
Serial.println("Lane #4");
finished=millis();
displayResult();
delay(TIMEOUT);
}
}

Race_Track_Place_Stopwatch.ino (1.98 KB)

Thanks in advance for anyone who helps me

Why don't you tell us what the problem is? Suppose that you had 5 friends helping you. The first one hits the release button, and writes down when that happens. The other 4 watch a lane each, and writes down the time when the car passes the finish line, in his/her lane.

Could you then tell how long each car took to complete the course? Could you then determine which one finished 1st? 2nd?

const int sensorPin1 = A2;

const int sensorPin2 = A3;

const int sensorPin3 = A4;

const int sensorPin4 = A5;

const int sensorPin = A0;

Arrays are good. Useless blank lines are not. Useless names like sensorPinN are not.

One of the pins is not a finish line pin. The names should reflect that.

pinMode(sensorPin1, INPUT);
pinMode(sensorPin2, INPUT);
pinMode(sensorPin3, INPUT);
pinMode(sensorPin4, INPUT);

So, 4 of the 5 input pins are INPUT pins. Hmmm...

Your completed code will have NO delay()s in it.

My problem is that I need all of the cars' times and place showing up, and I only know how to get the first one. This is after a week of searching without good results. I've seen so many examples on the internet, but am not able to change a seven segment display output to serial monitor. Also, the names aren't very important for me, I just need the code to work :slight_smile:

There is no need to use analogRead() which is slow. With suitable resistors for the voltage dividers the LDRs can be reliably detected with digitalRead(). It also makes the code much simpler.

I suspect something like this is all you need

if (raceStarted == false) {
    if (digitalRead(startLDRpin) == LOW) {
        startMillis = millis();
        raceStarted = true;
        numCarsFinished = 0;
    }
}

if (raceStarted == true and raceEnded == false) {
    for (byte n = 0; n < numCars; n++) {
        if (digitalRead(laneLDR[n]) == LOW) {
            carFinishMillis[n] = millis();
            numCarsFinished ++;
            if (numCarsFinished == numCars) {
                raceEnded = true;
            }
        }
    }
}

if (raceEnded == true) {
    // code to print the results
}

...R

Thelevite:
Also, I don't have five friends helping me, and an arduino is more accurate.

That's a silly response.

The purpose of the example was to get you to think about how to approach the problem.

...R

I'm sorry, I'm totally new at writing code. Could this code that you sent work for all four tracks? The race is tomorrow evening, and this is kind of my last resort. Also, thanks for responding so quickly! :slight_smile:

Could this code that you sent work for all four tracks?

Yes. The point is that you need an array of times that each car crossed the finish line, and you populate the array as each car finishes.

Robin2's code is not complete, and it assumes that you will define global variables correctly and write the rest of it correctly.

Thelevite:
I'm sorry, I'm totally new at writing code. Could this code that you sent work for all four tracks?

Yes, that was my intention - but it is not a complete program. You need to fill in all the other bits.

The race is tomorrow evening, and this is kind of my last resort. Also, thanks for responding so quickly! :slight_smile:

If you really are new to programming then I reckon you have left it too late. I'm not sure that I could get it all tested and working that quickly.

...R

I have a backup program that will just show first place with time time, but it would be much more useful to have all of the results. I also changed the names off the integers to make more sense, and took out some of the useless spaces.

/* For track setup, first connect all sensors in the right order. Next, test the value of the photoresistor output. Now change all the <=? to about 50-100 lower than their normal values.
You also need to change the delay on the start timer depending on how fast most of the cars are. After each run you have to reset the arduino.*/
#define THRESHOLD 100
const int finishPin1 = A2;
const int finishPin2 = A3;
const int finishPin3 = A4;
const int finishPin4 = A5;
const int startPin = A0;
const int TIMEOUT = 5000; // milliseconds
unsigned long start, finished, elapsed;

void setup() {
Serial.begin(9600);
Serial.print("Ready...");
pinMode(finishPin1, INPUT);
pinMode(finishPin2, INPUT);
pinMode(finishPin3, INPUT);
pinMode(finishPin4, INPUT);
pinMode(startPin, INPUT);
}

void displayResult()
{
float h,m,s,ms;
unsigned long over;
elapsed=finished-start;
h=int(elapsed/3600000);
over=elapsed%3600000;
m=int(over/60000);
over=over%60000;
s=int(over/1000);
ms=over%1000;
Serial.print("Time: ");
Serial.print(s,0);
Serial.print("s ");
Serial.print(ms,0);
Serial.print("ms");
Serial.println();
}

void loop() {
int status1 = analogRead(finishPin1);
int status2 = analogRead(finishPin2);
int status3 = analogRead(finishPin3);
int status4 = analogRead(finishPin4);
int status5 = analogRead(startPin);

if (status5 <=THRESHOLD) {
start=millis();
Serial.println();
Serial.println("...Started...");
Serial.println();
}
else if (status1 <=THRESHOLD) {

Serial.println("Lane #1");
finished=millis();
displayResult();
delay(TIMEOUT);
}

else if (status2 <=THRESHOLD) {
Serial.println("Lane #2");
finished=millis();
displayResult();
delay(TIMEOUT);
}

else if (status3 <=THRESHOLD) {
Serial.println("Lane #3");
finished=millis();
displayResult();
delay(TIMEOUT);

}

else if (status4 <=THRESHOLD) {
Serial.println("Lane #4");
finished=millis();
displayResult();
delay(TIMEOUT);
}
}

To make it easy for people to help you please modify your post and use the code button </>
codeButton.png

so your code looks like this and is easy to copy to a text editor. See How to use the Forum

Your code is too long for me to study quickly without copying to my text editor. The text editor shows line numbers, identifies matching brackets and allows me to search for things like all instances of a particular variable or function.

Also please use the AutoFormat tool to indent your code for easier reading.

...R

I have a backup program that will just show first place with time time

It would be nearly trivial to add 3 more finishedN variables, and set the appropriate one at the appropriate time.

Then, you could add some code to repeat what displayResult() does, for each of the 4 finish times.

Using arrays for the finish pin numbers and finish times means that you could use for loops instead of copy/paste. But, copy/paste will probably be faster for you than learning about arrays and for loops.

Still, learning about arrays and for loops is still a thing.

/* For track setup, first connect all sensors in the right order. Next, test the value of the photoresistor output. Now change all the <=? to about 50-100 lower than their normal values.
You also need to change the delay on the start timer depending on how fast most of the cars are. After each run you have to reset the arduino.*/
#define THRESHOLD 100
const int finishPin1 = A2;
const int finishPin2 = A3;
const int finishPin3 = A4;
const int finishPin4 = A5;
const int startPin = A0;
const int TIMEOUT = 5000; // milliseconds
unsigned long start, finished, elapsed;

void setup() {
Serial.begin(9600);
Serial.print("Ready...");
pinMode(finishPin1, INPUT);
pinMode(finishPin2, INPUT);
pinMode(finishPin3, INPUT);
pinMode(finishPin4, INPUT);
pinMode(startPin, INPUT);
}

void displayResult()
{
  float h,m,s,ms;
  unsigned long over;
  elapsed=finished-start;
  h=int(elapsed/3600000);
  over=elapsed%3600000;
  m=int(over/60000);
  over=over%60000;
  s=int(over/1000);
  ms=over%1000;
  Serial.print("Time: ");
  Serial.print(s,0);
  Serial.print("s ");
  Serial.print(ms,0);
  Serial.print("ms");
  Serial.println();
}


void loop() {
int status1 = analogRead(finishPin1);
int status2 = analogRead(finishPin2);
int status3 = analogRead(finishPin3);
int status4 = analogRead(finishPin4);
int status5 = analogRead(startPin);

if (status5 <=THRESHOLD) {
  start=millis();
  Serial.println();
  Serial.println("...Started...");
  Serial.println();
}  
     else if (status1 <=THRESHOLD) {

   Serial.println("Lane #1");
   finished=millis();
   displayResult();
   delay(TIMEOUT);
      }



   else if (status2 <=THRESHOLD) {
    Serial.println("Lane #2");
    finished=millis();
   displayResult();
   delay(TIMEOUT);
   }

      else if (status3 <=THRESHOLD) {
   Serial.println("Lane #3");
   finished=millis();
   displayResult();
   delay(TIMEOUT);

}

   else if (status4 <=THRESHOLD) {
   Serial.println("Lane #4");
   finished=millis();
   displayResult();
   delay(TIMEOUT);
  }
 }

Here is the code in a nicer format

And here is the code in an even nicer format (auto Formatted in the IDE)

/* For track setup, first connect all sensors in the right order. Next, test the value of the photoresistor output. Now change all the <=? to about 50-100 lower than their normal values.
You also need to change the delay on the start timer depending on how fast most of the cars are. After each run you have to reset the arduino.*/
#define THRESHOLD 100
const int finishPin1 = A2;
const int finishPin2 = A3;
const int finishPin3 = A4;
const int finishPin4 = A5;
const int startPin = A0;
const int TIMEOUT = 5000; // milliseconds
unsigned long start, finished, elapsed;

void setup()
{
  Serial.begin(9600);
  Serial.print("Ready...");
  pinMode(finishPin1, INPUT);
  pinMode(finishPin2, INPUT);
  pinMode(finishPin3, INPUT);
  pinMode(finishPin4, INPUT);
  pinMode(startPin, INPUT);
}

void displayResult()
{
  float h, m, s, ms;
  unsigned long over;
  elapsed = finished - start;
  h = int(elapsed / 3600000);
  over = elapsed % 3600000;
  m = int(over / 60000);
  over = over % 60000;
  s = int(over / 1000);
  ms = over % 1000;
  Serial.print("Time: ");
  Serial.print(s, 0);
  Serial.print("s ");
  Serial.print(ms, 0);
  Serial.print("ms");
  Serial.println();
}

void loop()
{
  int status1 = analogRead(finishPin1);
  int status2 = analogRead(finishPin2);
  int status3 = analogRead(finishPin3);
  int status4 = analogRead(finishPin4);
  int status5 = analogRead(startPin);
  if (status5 <= THRESHOLD)
  {
    start = millis();
    Serial.println();
    Serial.println("...Started...");
    Serial.println();
  }
  else if (status1 <= THRESHOLD)
  {
    Serial.println("Lane #1");
    finished = millis();
    displayResult();
    delay(TIMEOUT);
  }
  else if (status2 <= THRESHOLD)
  {
    Serial.println("Lane #2");
    finished = millis();
    displayResult();
    delay(TIMEOUT);
  }
  else if (status3 <= THRESHOLD)
  {
    Serial.println("Lane #3");
    finished = millis();
    displayResult();
    delay(TIMEOUT);
  }
  else if (status4 <= THRESHOLD)
  {
    Serial.println("Lane #4");
    finished = millis();
    displayResult();
    delay(TIMEOUT);
  }
}
  float h,m,s,ms;
  unsigned long over;
  elapsed=finished-start;
  h=int(elapsed/3600000);
  over=elapsed%3600000;
  m=int(over/60000);

What kind of pinewood-style derby could take 1.23 hours, 458.7 minutes, 33046.6 seconds, and 18277 milliseconds to complete? h is probably not necessary. m, s, and ms should be integral types. Probably byte, for m and s, since there aren't more than 60 of each in the next higher unit of measure.

I prefer to see spaces before and after operators. The code is more readable, in my opinion.

if (raceStarted == false) {
if (digitalRead(startLDRpin) == LOW) {
startMillis = millis();
raceStarted = true;
numCarsFinished = 0;
}
}

if (raceStarted == true and raceEnded == false) {
for (byte n = 0; n < numCars; n++) {
if (digitalRead(laneLDR[n]) == LOW) {
carFinishMillis[n] = millis();
numCarsFinished ++;
if (numCarsFinished == numCars) {
raceEnded = true;
}
}
}
}

if (raceEnded == true) {
// code to print the results

This code is great, but I'm not able to add all the variables. Also, it only shows hours and minutes because it might be needed for something else as well. Other than that, no reason :slight_smile:

Thelevite:
This code is great, but I'm not able to add all the variables.

Why not?

Also, it only shows hours and minutes because it might be needed for something else as well.

My code does NOT show hours and minutes. It just uses milliseconds. It's up to you to convert the millisec value to whatever you want.

If you are in a hurry don't worry about "something else as well"

...R

I wasn't talking about yours being the one that showed hours and minutes, I was talking about mine. Also, I'm pretty new to writing code and can't write all the variables. :frowning:

I could use mine, but the problem is I don't know how to make the if commands independent from each other. I need a way of keeping an if command from repeating even if the sensors are tripped multiple times. Is this possible? (Also, I could just use a whole code :slight_smile: )

I need a way of keeping an if command from repeating even if the sensors are tripped multiple times. Is this possible?

It is perfectly possible but you are running out of time.

if (thisIsTrue && previouslyTested == false)
  {
    //do stuff here
    previouslyTested = true;  //stop the test succeeding next time
  }

You will need a new boolean variable named previouslyTested initially set to false

Like this?

if (status1 <=200 && previouslyTested == false)
  {
    //do stuff here
    previouslyTested = true;  //stop the test succeeding next time
  }

Also, what would be the code for the boolean variable? And last question; Could I make it so that once the start sensor is tripped once the loop starts? It would be better because then there would be no way of the finish sensors getting tripped first. Thanks a lot for the help!!!