Introduction: Arduino Pinewood Derby Timer

About: SLO MakerSpace offers tools, training, and consultation services that enable community members to experiment with and master a wide variety of Maker skills. We are dedicated to the following values: Commun…

Last summer, SLO MakerSpace decided to host a NOVA ‘Making Stuff’ workshop for our local community. One of the workshop activities is a Pinewood Derby.

The good news is those are always great fun. The bad news is we only had a week to prepare! SLOMS resident woodworking expert Rich Farwell accepted the challenge of building the track while I (Tom Cantrell) put together an Arduino-based race timer.

A baseline timer just needs a way to detect the start of the race (starting gate) and each car crossing the finish line. With no time to lose I decided to experiment with parts I had at hand; a generic magnetic security switch for the starting gate and Parallax QTI infrared proximity sensors at the finish line. The QTI sensors work by using an LED to illuminate an area and measuring the reflection from a nearby object using a phototransitor.

I experimented mounting the QTI sensors under a piece of test track. That setup worked on my bench, but then had problems on the actual track at SLOMS where the finish line was located in a brightly lit area under a large skylight. Together, the relatively large sensor-to-car spacing and the high level of ambient IR erased the margin available to set a reliable detection threshold. Rich came to the rescue with track modifications addressing both the signal and the noise; Relocating the QTI sensors on top of the track (i.e. closer to the cars) provides a much stronger proximity signal while a simple overhead ‘shade’ shields the sensors from ‘sunburn’ (i.e. excessive ambient IR).

For now, calibration of the detection threshold is being handled using a dedicated sketch (PinewoodCalibrate). See the comments in that sketch for the details of the procedure. The basic idea is to sample the sensors both with and without cars at the finish line to determine baseline QTI response and ambient IR levels respectively. In the next revision I would like to add automatic calibration with lane-specific THRESHOLD by monitoring the ambient IR between races and tracking the QTI response of finishers.

Step 1: Materials and Construction


- Arduino

- Parallax QTI Sensors -

and 3-pin (servo-type) cables to connect the QTI sensors (one set for each lane)

(note: the Parallax ‘QTI Line Follower Kit for the Boe-Bot’ - - bundles four QTI sensors with cables, mounting hardware, etc.)

3. Magnetic security switch for starting gate (for example,

- Track-length 2-conductor cable to connect magnetic switch at starting gate to Arduino at finish line


1. Best results are obtained by mounting the QTI sensors close to the cars (ex: within ¼”). Watch out for cars with reduced ground clearance as impact with the sensors should be avoided. Make sure the 3-pin cable is connected properly to the QTI before applying power.

2. A shade is very helpful to reduce ambient IR interference. The shade should be dark colored and high enough over, or offset from (i.e. angled light source), the finish line so its own reflection doesn’t interfere.

3. The design of the starting gate mechanism must provide proper spacing and travel for the starter switch so it quickly and fully transitions between open (ex: >1” inch separation) and closed (ex: < ¼” separation) states.

Step 2: The Timer Sketch

Turning attention to the PinewoodTimer sketch, first some key parameters are defined…

#define IR_THRESHOLD 200 // car detect threshold

#define STARTER_PIN // starting gate switch = pin 2

#define QTI_PIN_OFFSET 5 // lanes 0-2 = pins 5-7

#define NUM_LANES 3 // number of lanes

#define TRACK_LENGTH 50 // feet

#define SCALE 25 // 1:25 scale

#define TIMEOUT 6000 // ms for race timeout/restart

The IR_THRESHOLD should be set within the window defined by ambient IR conditions and QTI response as determined with the PinewoodCalibrate sketch. STARTER_PIN specifies the pin used for the starting gate switch (the other side of the switch is connected to ground) while QTI_PIN_OFFSET determines the pin connections for the QTI sensors. Various track configurations and car sizes are supported with NUM_LANES, TRACK_LENGTH and SCALE. Finally, a TIMEOUT ends the race if, for example, a car doesn’t finish or only two cars are racing, etc.

The setup routine just enables the serial terminal and sets the pin mode for the starter gate switch.

void setup() {




The main loop starts by defining the variables used. The start_time is the base for the running et (elapsed time) with the array finish_et[] storing the time for each lane. The race_over variable counts how many cars have crossed the finish line.

After clearing the finish_et[]for each lane, “Ready…” is displayed on the terminal and the sketch waits for the race to start. When the start switch opens the sketch prints “Go” and then enters the main timing loop. Within the loop each lane is checked for the presence of a finisher by comparing its QTI sensor reading with the THRESHOLD. Once a car is detected the elapsed time for that lane is stored. The timing loop runs until the race is over (i.e. NUM_LANEs cars cross the finish line or the TIMEOUT is exceeded).

I include a statement (here commented) to display the time required to check all the lanes, which in turn determines how many lanes the sketch can handle. I observed the loop time for a 3-lane setup to be 9-10 milliseconds, or about 3 milliseconds per lane. If, for example, the time per lane is 3ms and a car takes 30 milliseconds to cross the finish line, the sketch could theoretically support up to ten lanes. However, some margin should be provided to accommodate, for example, a particularly fast (or short) car. To actually test the lane capacity you can increase NUM_LANES and run repeated trials to determine at which point the timer begins to ‘miss’ a fast car crossing the finish line. Note that you can do this testing for any NUM_LANES using just a single car/lane.

void loop() {

long start_time,et = 0,finish_et[NUM_LANES];

int race_over = 0;

int i;

for (i=0;i < NUM_LANES; i++) {

finish_et[i] = 0;



while (digitalRead(STARTER_PIN)==0) {



start_time = millis();

while((race_over < NUM_LANES) && (et < TIMEOUT)) {

et = millis()-start_time;



if (finish_et[i] == 0) {

finish_et[i] = et;





// Serial.println(millis()-(et+start_time));


Once the race is over the finish time for each lane is displayed. Using the TRACK_LENGTH and SCALE I also display the average speed in ‘scaled MPH’ (folks get excited when their car goes 250 MPH :=). After the race results are displayed the sketch waits for the starting gate to close in preparation for the next race. The delay statement insures starting gate switch bounce doesn’t falsely trigger an immediate restart.


for (i=0;i

Serial.print("Lane ");


Serial.print("Time ");


Serial.print("Speed ");

float fps = TRACK_LENGTH/(finish_et[i]/1000.0);

float mph = ((fps * 3600.0) / 5280.0) * SCALE;


Serial.println(" MPH");



while (digitalRead(STARTER_PIN) != 0) {}



All that’s left is the RCTime routine courtesy of Parallax (, which acquires the QTI sensor reading. It works by measuring the discharge time of a capacitor through a variable (depending on the amount of reflected IR) resistor.

long RCTime(int sensorIn){

long duration = 0;

pinMode(sensorIn, OUTPUT); // Make pin OUTPUT

digitalWrite(sensorIn, HIGH); // Pin HIGH (discharge capacitor)

delay(1); // Wait 1ms

pinMode(sensorIn, INPUT); // Make pin INPUT

digitalWrite(sensorIn, LOW); // Turn off internal pullups

while(digitalRead(sensorIn)){ // Wait for pin to go LOW



return duration;


Step 3: Results

The timer performed very well during the Derby. The starter switch worked reliably with 50’ of low-cost unshielded wire (4-conductor phone wire, two conductors per switch side). At the finish line, of perhaps 100 finishers only two weren’t detected. In one case, a racer used scrap hard disk platters(!) for wheels, so ground clearance (i.e. distance from the QTI to the car body) was excessive. In the other, the car had extra weight secured using black electrical tape completely covering the bottom centerline (darker colors reflect less IR), a strip of white tape solved that problem.

Car and Motorcycle Contest

Participated in the
Car and Motorcycle Contest