Arduino-based Chronometer for Electric Car Racing Tracks

Introduction: Arduino-based Chronometer for Electric Car Racing Tracks

In this project I am using a custom-built infra-red proximity sensor connected to an Arduino board to time the laps on an electric car racing circuit. The sensor detects the car when it passes in front of it and measures the time elapsed since the previous detection. I have programmed it so that it also records and displays the best time.

Step 1: What You Need

1) An Arduino board. I use the UNO R3.

2) An infra-red proximity sensor. I have built this myself using two IR LEDs recycled from old remote controls. One works as emitter and the other works as detector. I have not used commercial proximity sensors, but I presume those would work as well.

3) OPTIONAL - A LCD display. I use a 1602 serial LCD module. Any other Arduino-compatible should do. If you do not have one, you can print the time on the serial console of a PC connected to the Arduino.

4) OPTIONAL - A loudspeaker. You will need this if you want to hear a beep every time the car passes the finish line. Not strictly necessary, but useful. I use a small loudspeaker recycled from an old broken toy.

5) OPTIONAL - A battery pack. You do not need it if you operate the Arduino connected to USB.

Step 2: Wiring It Up

The IR sensor is made of two identical IR LEDs. One is connected (red wire) to 5v through a 330 ohms resistor and casts IR light. In my setup it is connected to digital output pin 12. On the picture you can see the LED shining because digital cameras are sensitive to IR light. With bare eye you would not see it. The detector led is connected straight to the analog input pin A0 (yellow wire). The ground (black wire) is common to the two LEDs and is connected to a ground pin on the Arduino.

The two LEDs are wrapped together with heat shrink wrap and are mounted in a parallel position. The emitter casts IR light. When an obstacle (in our case the car) is in front of the sensor, it reflects the IR rays. The reflected light hits the detector LED, which, as a consequence, produces a small current. The current is fed to an analog input on the Arduino board and, due to the internal resistance of the board, produces a voltage that can be measured. The closer the obstacle, the higher the intensity of the reflected light and the higher the voltage value read.

The loudspeaker (optional) is connected to one digital PWM pin (number 3 in this case) and to the ground.

The LCD display (optional) is connected to 5v, ground and to the SDA and SCL pins. In the Arduino UNO Rev. 3 these are two dedicated pins placed next to the AREF pin. In earlier versions analog pins A4 and A5 must be used instead. To drive the LCD screen I use the new LiquidCrystal library of fmalpartida, which replaces the stock Arduino LiquidCrystal library.

Step 3: The Arduino Sketch

Here is the sketch I use to run the chronometer.

// Load libraries for LCD display and create and lcd object
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// Initialise variables
int sensorPin = A0;
int ledPin = 12;
int sensorValue = 0;
int beepPin = 3;
unsigned int start = 0;
unsigned int lap = 0;
unsigned int tempo = 0;
unsigned int bestLap = 1000000; // High value so that the first lap is always a best lap
char last[16];
char best[16];

void setup()
// Initialise the LCD display
lcd.setCursor(0, 0);

// Initialise serial communication at 9600 bps

// Power up the IR sensor
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);

void loop()
sensorValue = analogRead(sensorPin);
if (sensorValue > 130) // An object is detected
tempo = millis(); // Record the current time
tone(3, 440, 50); // Play a beep
lap = tempo - start; // Calculate the lap time
start = tempo; // Reset the clock

// Check if this is the best lap
if (lap < bestLap)
bestLap = lap;

// Calculate the seconds and milliseconds for nicer printout of lap time
unsigned int sec = lap / 1000;
unsigned int msec = lap - sec*1000;

// Print out the lap time on the serial port
sprintf(last, "Last: %02u\"%03u", sec, msec);

// Print out the lap time on the LCD display
lcd.setCursor(0, 0); // Set the cursor on the first diplay line

// Calculate the seconds and milliseconds for nicer printout of best lap time
unsigned int bestSec = bestLap / 1000;
unsigned int bestMsec = bestLap - bestSec*1000;

// Print out the best lap time on the serial port
sprintf(best, "Best: %02u\"%03u", bestSec, bestMsec);

// Print out the best lap time on the LCD display
lcd.setCursor(0, 1); // Set the cursor on the second display line

delay(500); // Needed to avoid that the car triggers multiple detections

Be the First to Share


    • Mason Jar Speed Challenge

      Mason Jar Speed Challenge
    • Bikes Challenge

      Bikes Challenge
    • Remix Contest

      Remix Contest

    3 Discussions


    3 years ago

    Why does it not count past 1:05.55?


    4 years ago

    How far does the LED IR light reach? If you had a pinewood derby track, could it cover multiple lanes?


    4 years ago


    i am workind on something similar, he differences are:

    - i have a line follower sensor on digital pin 2

    - i have a black and white stripe with 20 mm between 2 white stripes

    - i need the output on the serial monitor, and not on the lcd.

    i have put up a sketch, but i have some issues with the time.

    i need to:

    - start the counting every time the pin 2 changes (the sensor has moved) and count the millis until next pin 2 changes, and have the speed. at the end, if the pin 2 does not changes for 1 sec, the program stop's

    can someone help me?

    i have this sketch until now:

    // Constante:

    const int buttonPin = 2; // pinul digital pentru senzorul de linie

    // Variabile:

    int buttonPushCounter = 0; // counter numar impulsuri (1 sau 0)

    int buttonState = 0; // starea actuala a senzorului de linie (1 sau zero)

    int lastButtonState = 0; // starea anterioara a senzorului de linie (1 sau zero)

    long time = 0;

    void setup() {

    // inititalizeaza intrarea pentru senzorul de linie:

    pinMode(buttonPin, INPUT);

    // initializeaza comunicatia seriala:



    Serial.println("Program test");



    void loop() {

    // citeste intrarea senzorului de linie:

    buttonState = digitalRead(buttonPin);

    time = 0;

    // compara starea butonului actuala cu cea anterioara

    if (buttonState != lastButtonState) {

    // if the state has changed, increment the counter

    if (buttonState == HIGH) {

    // if the current state is HIGH then the button

    // wend from off to on:




    Serial.print("Deplasare [mm]: ");


    Serial.print("Timp [s]: ");

    time = millis();

    //prints time since program started


    Serial.print("Viteza [mm/s]: ");



    // Delay a little bit to avoid bouncing



    // save the current state as the last state,

    //for next time through the loop

    lastButtonState = buttonState;

    time = 0;