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 - http://www.parallax.com/product/555-27401

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’ - http://www.parallax.com/product/28108 - bundles four QTI sensors with cables, mounting hardware, etc.)

3. Magnetic security switch for starting gate (for example, http://www.radioshack.com/product/index.jsp?productId=12706325&utm_source=GooglePLA&utm_medium=pla&utm_term=55050590&gclid=CIi_1saDrr0CFQWRKwodaUcAAA&gclsrc=ds)

- 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 (http://learn.parallax.com/KickStart/555-27401), 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.

Can you attach the plans on how to make the derby track otself.
<p>HI,</p><p>I am having an issue with running pinewood derby timer outside with excess ambient light as well. I have implemented the suggestion regarding the placement of the detector. I need some clarification on the pinewood calibrate sketch. Do I upload and run the calibrate sketch, then when finished re upload the timer sketch? I am using the LED/phototransistor from miscjunk. Definatley had issues running the derby for the 4-H filed day event that was outside at the Paso Robles fair grounds.</p><p>Thanks</p>
<p>Yes, first you run the Calibrate program to determine the best <br>setting for the detection threshold, then you load the Timer program and<br> set the value of the detection threshold variable accordingly. The <br>procedure is described fully with comments in the Arduino code listings.</p><p>The design at <a href="http://www.miscjunk.org">www.miscjunk.org</a><br> is rather different than ours in terms of both hardware and software, <br>so I&rsquo;m not quite sure exactly what setup you&rsquo;ve got. Using the miscjunk<br> components (discrete visible-light LEDs and photodetectors) would <br>require modifying my program (which uses an integrated reflected-IR <br>sensor). </p><p>As for my design, in high ambient IR<br> environments (ex: direct sunlight) a shade for the finish line area is a<br> must. Even with a shade it may be difficult to achieve reliable <br>operation outdoors considering reflected IR from nearby objects, <br>variation from shadows, clouds, changing sun angle, etc. In that case I<br> would try a rather large &amp; low finish line shade that blocks <br>sunlight intrusion from all sides as much as possible.</p><p>If<br> outdoor operation (i.e. high/varying ambient IR) is generally required <br>an option would be to modify the design to utilize a different (i.e. not<br> optical) finish line sensor. </p><p>Good luck!</p><p>SLOMakerSpace</p>
<p>Hi! I really appreciate the tutorial. I bought all the parts and am ready to attach the electronics to my derby track. I am a bit of a novice with Arduino though. Do you happen to have a circuit diagram or a photo of your wired connections to your Arduino? I imagine that you are using a breadboard too, correct? Many thanks!</p>
I used male jumpers for the wiring, they connect directly to the Arduino so no breadboard is required.<br>The wiring connections are as follows&hellip;<br>1. Connect wires from all the QTI sensor &lsquo;W&rsquo; terminals together and then to &lsquo;5V&rsquo; on the Arduino<br>2. Connect wires from all the QTI sensor &lsquo;B&rsquo; terminals together and then to a &lsquo;GND&rsquo; on the Arduino.<br>3. Connect the &lsquo;R&rsquo; wires from the QTI sensors for lanes 1-3 to pins &lsquo;5&rsquo;, &lsquo;6&rsquo; and &lsquo;7&rsquo; respectively on the Arduino.<br>4. Connect one wire (it doesn&rsquo;t matter which) from the starter switch to the second &lsquo;GND&rsquo; on the Arduino.<br>5. Connect the other wire from the starter switch to pin &lsquo;2&rsquo; on the Arduino<br>Note: the pin assignments are determined by the code&hellip;<br>#define STARTER_PIN 2 // starting gate switch on pin 2<br>&hellip;and&hellip;<br>#define QTI_PIN_OFFSET 5 // QTI for lanes 1-3 = pins 5-7<br>&hellip;so you can change them if necessary, just make sure the code and wiring match.<br>Here are a couple of pictures showing the wiring as described above&hellip;<br><br><br>A few notes about implementation for best sensor sensitivity and reliability&hellip;<br>1. The distance between the QTI sensors and bottom of the cars should be minimized i.e. the sensors should be flush with the track surface. Here you can see how they are inset into the top of the track.<br><br>2. Dark colors are more difficult to detect. If participants are painting their cars you might suggest they leave the bottoms unpainted or painted a light color. Or you can use a strip of white tape on the bottom.<br>3. In high ambient-IR conditions (ex: sunlight) use a shade over the finish line to improve the sensors detection margin.<br><br>Let the races begin!<br>
Thanks so much for your prompt feedback! My students and I were able to figure out a similar wiring scheme yesterday, except we <em>are</em> using a breadboard. <em>It was a great reason to finally learn how!</em><br> <br> Thanks for your code comments too, they really explained everything clearly. I've attached a video of our first proto-test run, which was a success. Our big race event is tomorrow and we're so grateful for your tutorial and code, which helped us add an electric timer to this year's school pinewood derby!<br> <br> Many thanks again!

About This Instructable




Bio: 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 ... More »
More by SLOMakerSpace:Euler Vase ParentSaddle Child Carrier Skylight Lifter 
Add instructable to: