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
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
// Initialise the LCD display
// Initialise serial communication at 9600 bps
// Power up the IR sensor
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