Arduino laser lap timer(not working)

Hi everybody. Please give me a helping hand. There is a project with laser, photoresistor and buttons with arduino uno to measure the lap times in a car race. It starts the timer when laser light cannot reach on the photoresistor and stops when object pass from the light second time. I (finally)successfully made the circuit and download the code to the arduino uno.

Everything seems like working but timer starts when it shouldn't do or not starts even interrupting the light. Where is the problem please? Here is my code and the schematic.(I used lcd-i2c instead of that one in the schematic and modified the code according to the lcd that i used)

Thanks a lot.

#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>

//Define variables 

#define I2C_ADDR          0x3F        //Define I2C Address where the PCF8574A is
#define BACKLIGHT_PIN      3
#define En_pin             2
#define Rw_pin             1
#define Rs_pin             0
#define D4_pin             4
#define D5_pin             5
#define D6_pin             6
#define D7_pin             7

//Initialise the LCD


/*

VERSION 0.3 

-Added Green LED For Best Round

*/


// PIN CONFIGURATION
LiquidCrystal_I2C      lcd(I2C_ADDR, En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);
int laserPin = 13;
int buttonPin1 = 11;
int buttonPin2 = 8;
int speakerPin = 9;
int ledPin1 = 12; // red 
int ledPin2 = 10; // GREEN



/*

 States // The central state the timer is in
 
 0 = pause;
 1 = countdown;
 2 = running;
 
*/


int state = 0;
boolean displayLastRound = true;
boolean running = false;

int lightLevel = 0;
long lastHit = 0; //time of the last hit in the barrier (absolut)
boolean lock; // locks the light barrier while a car is passing. The look is removed as soon the car left the lightbeam and the roundTreshold time has passed

long lastRound = 0; // time of the lastround (absolut)
long bestRound = 0; // time of the bestround (relative)
int roundNr = 0;


int laserTreshold = 10;
int roundTreshold = 300; // minimum time that has to pass before a new round is counted

// Absolut time for pressing buttons
long lastPress1 = 0;
long lastPress2 = 0;


// LED Timer

long timeLEDGreen = 0;

void setup() {
  pinMode(laserPin, OUTPUT);
  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);
  pinMode(speakerPin, OUTPUT);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
    lcd.setBacklight(HIGH);

  lcd.setCursor(0, 0);
  lcd.print("Arduino");
  lcd.setCursor(0, 1);
  lcd.print("Laser Lap Timer  ");
  
  delay(2000);
  
  lcd.setCursor(0, 0);
  lcd.print("HERO          ");
  lcd.setCursor(0, 1);
  lcd.print("ROBOTICS             ");


  //Serial.begin(9600);
  delay(1500);

}

void loop() {

  if(!digitalRead(buttonPin1)){

    button1Pressed();

  };

  if(!digitalRead(buttonPin2)){

    button2Pressed();

  };



  switch (state){
  case 0: 
    statePaused(); 
    break;
  case 1: 
    stateCountdown(); 
    break;
  case 2: 
    stateRunning(); 
    break;
  }
}

void didFinishRound(){
  if(roundNr > 0)lastRound = millis()-lastHit;
  

  if (bestRound == 0){
    bestRound = lastRound;
  }
  if (lastRound < bestRound){
    bestRound = lastRound;
    timeLEDGreen = millis()+1000;
  }
  lastHit = millis();
  lock = true;  
  ++roundNr;
  displayLastRound = true;  

}

void statePaused(){
  digitalWrite(ledPin1, LOW);
  digitalWrite(ledPin2, LOW);
  digitalWrite(laserPin,LOW);
  lcd.setCursor(0, 0);
  lcd.print("Press right   ");
  lcd.setCursor(0, 1);
  lcd.print("button to start");

}

void stateRunning(){

  //switch laser on

  digitalWrite(laserPin,HIGH);


  //mesasure light

  lightLevel = analogRead(0);
  lightLevel = map(lightLevel, 0, 900, 0, 255);
  lightLevel = constrain(lightLevel, 0, 255);

  //Serial.println(lightLevel);
  // react to light

  if(lightLevel < laserTreshold){
    //digitalWrite(ledPin,LOW);
    lock = false;
  }
  else{
    // digitalWrite(ledPin,HIGH);
    if (millis()-lastHit > roundTreshold && lock == false){
      didFinishRound();
    }
  }

  // We have'nt finished the first round
  if(roundNr == 0){

    lcd.setCursor(0,0);
    lcd.print("Standby...      ");
    lcd.setCursor(0,1);
    lcd.print("                ");    

  }
  // Display the time and best / last round
  else{
    displaySecondLine();
    displayFirstLine();

  }
  
  // turn off all LED
  
  digitalWrite(ledPin1, LOW);
  digitalWrite(ledPin2, LOW);

  if (timeLEDGreen > millis()){
 
  }
  
  else{

  }
  
  



}

void stateCountdown(){

  lcd.clear();

  lcd.setCursor(0, 0);
  lcd.print("Ready             ");
  digitalWrite(ledPin1, HIGH);

  playNote('c',300);

  delay(1000);

  lcd.setCursor(0, 0);
  lcd.print("Set             ");
  digitalWrite(ledPin2, HIGH);

  playNote('c',300);

  delay(1000);

  lcd.setCursor(0, 0);
  lcd.print("Go             ");
  digitalWrite(laserPin,HIGH);

  playNote('g',600);

  state = 2;

}



void displayFirstLine(){

  lcd.setCursor(0, 0);


  lcd.print("Rd");
  lcd.print(" ");
  lcd.print(roundNr);
  lcd.print(" ");
  lcd.print(millis()-lastHit);
  lcd.print("ms");

  lcd.print("                       ");



}

void displaySecondLine(){

  lcd.setCursor(0, 1);

  if(displayLastRound){



    lcd.print("Last ");
    lcd.print(lastRound);
    lcd.print("ms");
    lcd.print("                       ");


  }



  else{
    lcd.print("Best ");
    lcd.print(bestRound);
    lcd.print("ms");
    lcd.print("                       ");

  }



}

void button1Pressed(){
  if(millis()-lastPress1 > 800){
    lastPress1 = millis();
    displayLastRound = !displayLastRound;
  }

}

void button2Pressed(){
  if(millis()-lastPress2 > 800){
    lastPress2 = millis();
    if (state == 0){
      state = 1;
    }
    if (state == 2){
      digitalWrite(laserPin,LOW);
      roundNr = 0;
      bestRound = 0;
      lastRound = 0;
      state = 0;
    }    

  }
}

void playTone(int tone, int duration) {
  for (long i = 0; i < duration * 1000L; i += tone * 2) {
    digitalWrite(speakerPin, HIGH);
    delayMicroseconds(tone);
    digitalWrite(speakerPin, LOW);
    delayMicroseconds(tone);
  }
}
void playNote(char note, int duration) {
  char names[] = { 
    'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C'   };
  int tones[] = { 
    1915, 1700, 1519, 1432, 1275, 1136, 1014, 956   };

  // play the tone corresponding to the note name
  for (int i = 0; i < 8; i++) {
    if (names[i] == note) {
      playTone(tones[i], duration);
    }
  }
}

You seem to have various delay()s in your program and some FORs that will block your program and make it unresponsive. Have a look at how millis() is used to manage timing without blocking in Several things at a time.

Have you written a short test/learning program that does nothing but register the state of the LDR in response to the laser?

...R

thanks for helping but I couldnt get the problem as I m a beginner and I got the code from a guy who did this project and made it works. I dont know why mine doesnt work.

hero04:
I got the code from a guy who did this project and made it works.

Then he's the guy to help you.

The alternative is to start learning Arduino programming yourself. There are lots of simple programs with the Arduino IDE and dozens or hundreds of web tutorials.

...R

Robin2:
The alternative is to start learning Arduino programming yourself. There are lots of simple programs with the Arduino IDE and dozens or hundreds of web tutorials.

...R

you are totally right but I need this project to use in a rc car racing competition between my students. Due to time limit I need it in 2 days. Tried to contact that person but no response yet as the project is a few years old. Anyway thanks for your time.

hero04:
Everything seems like working but timer starts when it shouldn't do or not starts even interrupting the light.

This points to possible ambient light problems, and/or misaligned laser beams.

The delays in the code don't seem to be a major issue as it's in the tone playing which is supposedly before the start of the race. While those tones are playing indeed the laser will be ignored.

An actual circuit diagram would be nice, too.

The block diagram mentions three LEDs, connected to pin 0, 1, and 10. Your code mentions two LEDs, connected to pins 10 and 12.

There's a laser that's apparently powered by pin 13 - with a resistor of just 10Ω. How much current does this laser take?

hero04:
Tried to contact that person but no response yet as the project is a few years old. Anyway thanks for your time.

Where did you find the original?

wvmarle:
Where did you find the original?

on youtube: Arduino Laser Lap Timer 0.2 - YouTube

and yes i have modified because of my lcd is using the pins from 0 to 7, so i was in need of pins for buttons etc. I removed third led also from the actual code. I have tried to switching lights off but no luck.

should I connect the laser without any resistor?

should I connect the laser without any resistor?

NO. Arduino output pins can safely supply 20mA of current. How much current does the laser require? A transistor controlled by the Arduino to switch the laser is the safe way to supply more than 20mA.

groundFungus:
NO. Arduino output pins can safely supply 20mA of current. How much current does the laser require? A transistor controlled by the Arduino to switch the laser is the safe way to supply more than 20mA.

I see. So no problem with the code as I understood from the comments. I dont know how many mA requires the laser as I just took out from a cheap laser pointer. But it was powered with 3 button cells that I dont remember their power current.

[quote author=hero04 link=msg=3526910 date=1513526174]
I see. So no problem with the code as I understood from the comments.

I wouldn't say it that strongly, but for me after reading your description of the problem (false and missed readings) and quickly reading (not analysing!) the code my suspicion is with the hardware.

Really best course of action is to write a very simple script that just checks the laser sensor, and prints the details.

What actual readings do you get from your analog input, with and without the laser light shining on it? What is the actual resistance of the LDR with and without light?

I dont know how many mA requires the laser as I just took out from a cheap laser pointer. But it was powered with 3 button cells that I dont remember their power current.

Then grab your multimeter and measure the current, you really should know this. Maybe 10Ω is too much, maybe it's too little - that depends on how that laser pointer is supposed to be powered. If there is no big reason to switch it off during operation, why don't you just use the laserpointer as is - battery powered and all - and mount it in a way it nicely shines on your LDR. Those things tend to work quite long on their batteries. You can always use the original on/off button to switch it off when no race takes place.

wvmarle:
Really best course of action is to write a very simple script that just checks the laser sensor, and prints the details.

What actual readings do you get from your analog input, with and without the laser light shining on it? What is the actual resistance of the LDR with and without light?

thanks for helping again. i did simple ldr reading and in a room enlighten with white florescent I got these results:
872
872
873
874
875
877
878
880
881
883
885
886
888
889

even I covered the ldr with my finger the results were around 400-500. And the current for laser was 0.001a .

If you followed the block diagram above (LDR wired between GND and pin, 10k resistor between pin and Vcc), there’s something very wrong.
When lit, the reading should be much lower than when not lit, as the LDR resistance drops with more light so pulling down the pin. These values should be reversed: 800+ for when the LDR is dark (in the shadow of the car - which I suppose passes close by), maybe 200-600 for ambient light, and well below that for bright illumination.

Then I looked at this part of your code:

int laserTreshold = 10;



//mesasure light

  lightLevel = analogRead(0);
  lightLevel = map(lightLevel, 0, 900, 0, 255);
  lightLevel = constrain(lightLevel, 0, 255);

  // react to light

  if(lightLevel < laserTreshold){
    lock = false;
  }
  else{
    if (millis()-lastHit > roundTreshold && lock == false){
      didFinishRound();
    }
  }

The light level is measured, then mapped, then constrained (that constrain() isn’t doing anything as map() brings it in that range already).

It waits for the lightLevel to drop below 10 (or a raw reading of about 40 - so really brightly lit which is consistent with a laser shining directly on it and the LDR wired as per block diagram), then starts counting the time until it sees another such event.

So for you to fix this: first make sure your LDR is wired as per block diagram, then measure the analog readings for dark (place a car in front of it - normal ambient light), without car/laser, and with laser shining on it. You should get three rather distinct values for this, with the laser being the lowest by far.

Otherwise, if you wire your LDR with pull-down resistor, you have to amend the values in the map(). You may also have to amend laserTreshold (it’s confusingly misspelled, and there are more spelling errors in the comments) to have it react to the proper light levels.

The explanation for the wrong light levels in this case could be loose wiring on the LDR. If that is not connected properly, the reading will drop to zero the moment contact is broken (and the way you appear to have wired it all). Make sure those wires are soldered properly.

wvmarle:
If you followed the block diagram above (LDR wired between GND and pin, 10k resistor between pin and Vcc), there’s something very wrong.
When lit, the reading should be much lower than when not lit, as the LDR resistance drops with more light so pulling down the pin. These values should be reversed: 800+ for when the LDR is dark (in the shadow of the car - which I suppose passes close by), maybe 200-600 for ambient light, and well below that for bright illumination.

Then I looked at this part of your code:

int laserTreshold = 10;

//mesasure light

lightLevel = analogRead(0);
  lightLevel = map(lightLevel, 0, 900, 0, 255);
  lightLevel = constrain(lightLevel, 0, 255);

// react to light

if(lightLevel < laserTreshold){
    lock = false;
  }
  else{
    if (millis()-lastHit > roundTreshold && lock == false){
      didFinishRound();
    }
  }





The light level is measured, then mapped, then constrained (that constrain() isn't doing anything as map() brings it in that range already).

It waits for the lightLevel to drop below 10 (or a raw reading of about 40 - so really brightly lit which is consistent with a laser shining directly on it and the LDR wired as per block diagram), then starts counting the time until it sees another such event.

So for you to fix this: first make sure your LDR is wired as per block diagram, then measure the analog readings for dark (place a car in front of it - normal ambient light), without car/laser, and with laser shining on it. You should get three rather distinct values for this, with the laser being the lowest by far.

Otherwise, if you wire your LDR with pull-down resistor, you have to amend the values in the map(). You may also have to amend laserTreshold (it's confusingly misspelled, and there are more spelling errors in the comments) to have it react to the proper light levels.

The explanation for the wrong light levels in this case could be loose wiring on the LDR. If that is not connected properly, the reading will drop to zero the moment contact is broken (and the way you appear to have wired it all). Make sure those wires are soldered properly.

Thanks a lot. After your advice I tried to make it without using laser. And did some searches about ldr and added some codes from other projects made with ldr.

FYI I added this part of code instead of laser threshold creep and works very well:

boolean dark = false;
const int DAWN = 600;
const int DUSK = 580;
//Serial.println(lightLevel);
  // react to light

{
  if(analogRead(0) < DUSK){
    //digitalWrite(ledPin,LOW);
    lock = false;

Do name your variables something sensible, as dawn and dusk has no relation to your project.

Indeed it should work without the laser but a laser will help big time as it makes it much less sensitive to ambient light, as the laser overshines most ambient light conditions bar direct sunlight. It gives you have a much larger difference in LDR readings between car present and no car present.

wvmarle:
Do name your variables something sensible, as dawn and dusk has no relation to your project.

Indeed it should work without the laser but a laser will help big time as it makes it much less sensitive to ambient light, as the laser overshines most ambient light conditions bar direct sunlight. It gives you have a much larger difference in LDR readings between car present and no car present.

You are right about using laser will give more accurate results but couldnt get the problem of original project and tomorrow I need this timer. If I can find a way to make it work with laser will use it for sure. It's an outdoor place but has roof so the place will not be bright, I guess it will work for the job.

Thanks again

finally made it! Guess what, the problem was the laser! I changed it before last time but even two different lasers didnt make the project work well. But last laser that I found in a drawer worked very well!

Thanks a bunch @wvmarle you pushed me to on the project and it helped me a lot!

Really! What was wrong with it? That's the last I would think of.
Anyway good to hear it works now.