TARDIS Pinewood Derby Car With Light and Sound!

photo 3

This January my daughter decided that she wanted to join in her brother’s cub pack’s Pinewood derby with a replica of Doctor Who’s TARDIS on wheels.

tardis-in-space-tardis-6289810-1280-768

Her design was pretty straightforward – balsa wood trim, poster paint, paper cutouts for the windows and sign, and her construction was quickly nearing completion. Then came the ask – “Dad, could you help me make a blue light on top flash? Also, it should sound like the TARDIS landing – can we do that? How about only when someone touches it?”.

photo 2

Playing a wav file, blinking a LED and setting timeouts so it wouldn’t run continually led to the idea of using a Teensy 3.0 that had been generously donated to Nova Labs by PJRC. It is Arduino compatible, has decent libraries and has a ton more flash than a Nano. The space limitation was dictated by how large (small) a hole we could hack in the underside of the Pinewood car, so small factor boards were necessary – and the aptly named Teensy fit the bill.

photo 1

The hardware was cake – we used an orphaned micro speaker from a broken monitor (liberated by said daughter during a Take Apart Day at NovaLabs), a jiggle-switch motion sensor from an offshore arduino vendor, and a blue LED. Power came from a gutted $1 Harbor Freight LED flashlight (3*AAA carrier) and we were all done but the code A tiny SPDT switch was salvaged from a broken toy.

photo 4

Hardware

Jiggler board took 3.3v from the teensy, gnd and returned a line to an analog input that went momentarily high when the car was moved. If I were doing it again, I’d just use a jiggler switch and dispense with the board and circuitry (opamp integrator for debouncing, needed +/gnd, two wire would have been easier).

Speaker was capacitively coupled to a PWM digital output with a .1uF cap, the idea being that varying the pulse width duty cycle from 0 to 255 at a high rate (>>>8 kHz) would drive AC to the speaker via the cap.

Power was supplied to the Teensy per it’s pinout Vin (4.5V).

Software

The only tough part was to find a utility to turn an MP3/wav I downloaded of the Tardis landing into an array of values that my arduino code would step through. Thanks to the internet, I found that https://github.com/olleolleolle/wav2c has exactly what I was looking for – input is a wav file, output is a C def file to link in that provides a representation of the wav as an array of 8 bit unsigned values samples at 8 kHz (thanks to Ino Schlaucher).

Perfect – run the program pointed at your sound from the command line and a “foobar.h” file is output for inclusion into your arduino program.

The Arduino “IDE” is an inscrutable bodge, so I had to mess around with paths before giving up and putting files where I thought it would look (instead of pointing the IDE to where I wanted them to be). Your mileage will vary. Be prepared to fight it over where your files go.

The program was really simple as well, two timers are used – one to blink the blue LED on top, the other one used to grab a new sample out of the sampled array every 125uS, set the designated PWM channel appropriately and repeat until the entire sampled array has been played. A global keeps track of # plays, and it stops and waits for a new “jiggle input” before repeating again (twice actually).

WARNING: SOURCE CODE

#include <avr/pgmspace.h> // needed to support defining sounddata as FLASH based
#include <sounddata.h> // this is the noise/sound to play

const int ledPin = 13; // Teensy3 has LED on 13

void TardisLightisr(void);

volatile int TardisLightStatus = 0;

IntervalTimer TardisLight;
const int speakerPin = 3; // Teensy3 has Speaker on 3
void TardisSpeakerisr(void); // we’re going to call this function at 8kHz
IntervalTimer TardisSpeaker; // interval timer construct to call TardisSpeakerisr
const int jigglerPin = 14; // I wired the jiggle switch to pin 14
int jiggle=0; // jiggle state
volatile uint32_t sample = 0; // needed 32 bit unsigned, had issues w larger (8 seconds) samples rolling over the 16 bit counter – duh
volatile uint16_t PlaybackCount = 0; // keep track of the number of plays per ISR playback loops
byte lastSample;
byte ontime;

void setup(){
pinMode(ledPin, OUTPUT); // duh, LED is an output
pinMode(speakerPin, OUTPUT); // the PWM speaker output is an output
pinMode(jigglerPin, INPUT); // listen for motion on the jigglerswitch input
analogWriteFrequency(speakerPin, 400000); // Teensy 3.0 lets you do 400kHz comfortably, no aliasing or high freq artifacts
analogWrite(speakerPin, 0); // pull down the speaker to 0 to reduce current consumption
}

void loop(){
jiggle = analogRead(jigglerPin);
while (jiggle > 128){
jiggle = analogRead(jigglerPin);
}

TardisLight.begin(TardisLightisr, 600000); //sets the ISR rate inmicroseconds for the TardisLight – 1.2Hz rate
TardisSpeaker.begin(TardisSpeakerisr, 125); //sets the ISR rate in microseconds for the TardisSpeaker – 8kHz rate

while(PlaybackCount < 2){} //play the tardis landing loop twice
PlaybackCount=0; //reset the play count
TardisSpeaker.end(); //turn off the ISR
TardisLight.end(); //turn off the ISR}
analogWrite(speakerPin, 0); //turn off speaker output
digitalWrite(ledPin, LOW); // turn off LED just in case
}

void TardisLightisr(void){ // this is the very simple ISR routine called to make the TardisLED blink
TardisLightStatus=1-TardisLightStatus; //invert the status of the LED & write it digitalWrite(ledPin, TardisLightStatus);
}

void TardisSpeakerisr(void){
if (sample < sounddata_length) {
lastSample = pgm_read_byte(&sounddata_data[sample]); // read the sample index into lastSample from the datastructure hard-coded into sounddata.h
analogWrite(speakerPin, lastSample); //set the PWM to the just-read sample, this will average out because of the speaker’s inertia to a position
sample = sample +1; // increment sample
}

else {
PlaybackCount++; // guess we’re done playing the sample, inc the count and
pause a second
delay(1000);
sample=1; // reset sample to 1}
}

Included sounddata.h, created by wav2c.exe (you will make your own file from a wav):

/* sounddata.h */
// sounddata sound made by wav2c
// (wav2c modified to use unsigned samples)

const int sounddata_length=69990;
const unsigned char sounddata_data[] PROGMEM = {,48,48,0,100,97,116,97,61,17,1,0,112,123,135,141,144,143,132,119,106,103,111,120

,129,115,97,92,93,94,103,124,139,142,141,140,140,138,138,133,128,128,122,114,10

6,107,122,126,139,144,140,152,155,150,137,118,115,114,117,125,127,127,128,124,1

15,120,122,128,140,135,130,121

/* SNIP — 65000 values removed for brevity */

128,126,126,128,127,127,128,129,128,127,128,127,126,127,131,131,128,128,127,12

8,126,125,127,129,129,128,130,133,131,130,130,127,0,};

One thought on “TARDIS Pinewood Derby Car With Light and Sound!

Comments are closed.