laser speed detector/calculator

Hi guys im new here to the forum, ive been making small arduino based projects for about 1 year now and im having some issues with a project im working on.

the project is to calculate the speed of rc vehicles in mph, i have 2 photo diodes at a set distance apart with lasers as the "trip" sensors to detect the time it takes the vehicle to travel the set distance

the problem is the timer "starts and stops" in only one direction ie. Left to right
also when both sensors are covered at the same time the timer "freaks out" so to speak and spits out random numbers

my goal is when the "first" sensor gets triggered it starts the timer then gets disabled and arduino waits for the "second" sensor to get tripped to stop the timer , then spits out the current time and speed also compare the "current run" with the "fastest run" and then resets both sensors.

It needs to be able to start and stop the timer in both directions (left -right, right-left) but i cant figure it out and have searched all over the web for something similar the closest thing found was a chronograph but they only operate in one direction.

thank you guys so much ahead of time for any help received

Your in luck, I never delete my sketches, so you can learn from this one.

#define FPS_to_MPH 0.68182 // scale factor
#define DISTANCE 35.5625 // distance between the two sensors or gates in feet.
#define swap(type, A, B) {type T = A; A = B; B = T;}

float Speed = 0, MPH = 0, tmp = 0;
boolean GotFirstSensor= false, GotSecondSensor = false;
unsigned long SensorOne_timer = 0, SensorTwo_timer = 0;

void setup() 
{
  Serial.begin(115200);
  attachInterrupt(0, SensorOneState, RISING);
  attachInterrupt(1, SensorTwoState, RISING);
}

void loop() 
{
  // This is using normal buttons to detect car passing through one gate to another,
  // this can be changed to use US sensors to replace the buttons. That part you will  
  // need to write yourself.

  if(GotFirstSensor & GotSecondSensor) //both must be true for this condition to be true
  {
    Speed = GetSpeed(SensorOne_timer, SensorTwo_timer, DISTANCE); // send the times and the distance into the function.
    Serial.print("MPH: ");
    Serial.println(Speed);
    ClearStates();
  } 
}

void SensorOneState()
{
  SensorOne_timer = millis(); //record the time the car reaches the first gate
  GotFirstSensor = true;
}

void SensorTwoState()
{
  SensorTwo_timer = millis(); //record the time the car reaches the second gate
  GotSecondSensor = true;
}

void ClearStates()
{
  GotFirstSensor= false;
  GotSecondSensor = false;
}

float GetSpeed(unsigned long T1, unsigned long T2, float distance)
{
  MPH = distance * (FPS_to_MPH); // "(FPS_to_MPH)" -> conversion factor, feet per second to miles per hour
  if(T1 > T2) // This flips the times if the object went through the gate the other way.
    swap(unsigned long, T1, T2);
    
  tmp = (T2 - T1)/1000.00; // since the time we are using is in milliseconds, we need to convert milliseconds to seconds
  Serial.print("Time (seconds): ");
  Serial.println(tmp);
  return (MPH / tmp); //return the speed of the car in MPH
}

I'm thinking you need to adopt a "state" approach with a flag. Off the top of my head:

Have a flag (just a boolean variable) called say Timing, initialised false. Let's call the beams leftBeam and rightBeam.

So, if leftBeam has been tripped, and Timing is false, start the clock (ie save millis()), set Timing true.

My thinking there is that we know car is going left to right, so the other beam stops the timer:

So then, if rightBeam has been tripped and Timing is true, stop the clock (ie save millis(), calc speed), set Timing false.

On the other hand:

if rightBeam has been tripped, and Timing is false, we are going right to left, start the clock (ie save millis()), set Timing true.
Then when leftBeam has been tripped and Timing is true, stop the clock (ie save millis(), calc speed), set Timing false.

I'm not guaranteeing I thought that through, so check my logic, but something along those lines should do the trick.

Oh, and on the error state of both beams covered, I guess you could just have a line:

if leftBeam is high and rightBeam is high, report error code, flash lights or something.

I was thinking i would need to use a state something like
state = sensor1_tripped
state = sensor2_tripped
state = sensor1_clear && sensor2_clear

I would also prefer not to use interrupts because i dont know an awful lot about them and i dont need the code to do anything at all while it waits for the first sensor to be tripped then time it till the second sensor gets tripped

Ok so i got the states to work they way i want havent worked on both directions yet but everything else is good

The system doesnt restart till both sensors are clear but i have a timing issue if i time with micros() after about 70,000 microseconds it overflows but i dont think millis() will be accurate enough

any clue on this??

Also what "function" do i use to have arduino choose between 2 different sets of instructions in the void loop() section depending on the intup of whatever sensor

sorry for all of the questions this is my first time writing a script like this

but i have a timing issue if i time with micros() after about 70,000 microseconds it overflows

Use the correct data type for the return value of the function.
Post code.
Use code tags.

ebolton92:
Also what "function" do i use to have arduino choose between 2 different sets of instructions in the void loop() section depending on the intup of whatever sensor

You can do that all using if or if - else. the syntax to look for two things being true at once is the "&&", so you could have something like:

if (rightBeam == HIGH && Timing == true)
   {
       //do stuff
   }

Also be alert to using the "==" not just "=" when doing a comparison. This one catches a lot of people a lot of the time...

Ok so i got it to clock the time going right to left and left to right, Serial.print shows when the first beam is broken when the second one is broken, tells the calculated time and the best time so far.

The code looks really weird and doesnt make sense to me i had to play with a few things to get it to work.

can i upload it for someone to go over it and tell me if its correct or what i can do to simplify it ???

ebolton92:
can i upload it for someone to go over it and tell me if its correct or what i can do to simplify it ???

Of course you can, but first you might want to read up a bit on state machines, which is what this is.

Here are some links, in no particular order. One and Two are by members here.

Nick Gammon
Grumpy Mike
Robert C Martin

Alright here is the code

// speed trap

int sensor1 = 4;
int sensor2 = 5;
unsigned int startTime;
unsigned int stopTime;
unsigned int calculatedTime;
unsigned int bestTime = 1000000;
const int sensor1_tripped = 1;
const int sensor2_tripped = 2;
const int sensors_clear = 3;
unsigned int state = sensors_clear;
unsigned int Direction;

 

void setup()
{
  pinMode(sensor1,INPUT);
  pinMode(sensor2,INPUT);
  digitalWrite(sensor1,HIGH);
  digitalWrite(sensor2,HIGH);

  Serial.begin(9600);
  Serial.println("READY");
}

void loop(){
   if(state == sensors_clear){ 
    Direction=0 == (digitalRead(sensor1) == HIGH && digitalRead(sensor2) == LOW);
    
   }
   if(state == sensors_clear){ 
     Direction=1 == (digitalRead(sensor2) == HIGH && digitalRead(sensor1) == LOW);
   }
     
  switch (Direction){
    
   case 0:
     
    if(state == sensors_clear){ 
      if(digitalRead(sensor1) == HIGH){
    startTime=millis();
    
    Serial.println("SENSOR 1 TRIPPED");
    
    state = sensor1_tripped;
      }
    }
   else if(state == sensor1_tripped){
   if(digitalRead(sensor2) == HIGH){

    stopTime = millis();
    
    calculatedTime = stopTime - startTime;
    
    if(calculatedTime < bestTime){
    bestTime = calculatedTime;
    }
    
    Serial.println("SENSOR 2 TRIPPED");
    Serial.println("CALCULATED TIME :");
    Serial.print(calculatedTime);
    Serial.println(" MS");
    Serial.println("BEST TIME :");
    Serial.print(bestTime);
    Serial.println(" MS");
    
    state = sensor2_tripped;
      
   }
  }
 
  else if(state = sensor2_tripped){
   if(digitalRead(sensor1) == LOW && digitalRead(sensor2) == LOW){
     
     
     Serial.println("SENSORS CLEAR");
     Serial.println(" ");
     
     state = sensors_clear;
   }
  }
  


 break;
  

 
 case 1:
   
   if(state == sensors_clear){
     if(digitalRead(sensor2) == HIGH){
    startTime=millis();
    
    Serial.println("SENSOR 2 TRIPPED");
    
    state = sensor2_tripped;
   }
   }
 
   else if(state == sensor2_tripped){
   if(digitalRead(sensor1) == HIGH){

    stopTime = millis();
    
    calculatedTime = stopTime - startTime;
    
    if(calculatedTime < bestTime){
    bestTime = calculatedTime;
    }
    
    Serial.println("SENSOR 1 TRIPPED");
    Serial.println("CALCULATED TIME :");
    Serial.print(calculatedTime);
    Serial.println(" MS");
    Serial.println("BEST TIME :");
    Serial.print(bestTime);
    Serial.println(" MS");
    
    state = sensor1_tripped;
      
   }
  }
 
  else if(state = sensor1_tripped){
   if(digitalRead(sensor2) == LOW && digitalRead(sensor1) == LOW){
     
     
     Serial.println("SENSORS CLEAR");
     Serial.println(" ");
     
     state = sensors_clear;
   }
 }
 
 break;

  }
  }
unsigned int bestTime = 1000000;

Nope.

How would you reccomend i give bestTime a value to compare calculatedTime against that will be greater than calculatedTime nomatter what, just to give me a value to start comparing calculateTime with???

That was the only way i knew for sure bestTime would be higher than calculatedTime until my real calculated time were put into bestTime

How would you reccomend i give bestTime a value to compare calculatedTime against that will be greater than calculatedTime nomatter what, just to give me a value to start comparing calculateTime with???

For a start, (and assuming this isn't a Due, because the question isn't in the Due section) I'd chose a value that would fit in the variable.

What do you mean a value that fits the variable? Do you mean since it is in millis() the number i put would be an overflow value???

unsigned int bestTime = 1000000;

"unsigned int" 16 bits
log2 1000000 = 19.93
19.93 into 16 does not go.

edit: Brain-fart corrected

AWOL:

unsigned int bestTime = 1000000;

"unsigned long" 16 bits

?

I apologize for mt stupidity but most of the projects i have done where just led arrays and using PWM signals to operate relays on rc airplanes for various uses

Ok so i have change "unsigned int" to "unsigned long"

but is asigning bestTime a random number that is guaranteed to be greater than calculatedTime really an acceptable way to go about starting the bestTime value?

If you want a big number in there, then the simplest way is to put the biggest you can in it, and avoid any ambiguity.

unsigned int bestTime = ~0UL;