Pinewood Derby Ducted Fan Car.

For the 'No Rules' race for our local Cub Scout pack, I made a ducted fan car to win everything! It was not trivial, but this page should help you get over some of the issues I came across. I'm sure people with a model aircraft or electrical background will be face palming at my ignorance, but as a coder, these were the problems I found and addressed.

Hardware

Ducted fan - I went for overkill and bought this one - "Dr. Mad Thrust 50mm 10 Blade Alloy EDF 3300kv". The 50 mm is the diameter of the blades, EDF stands for "Electric Ducted Fan", and 3300kv is the number of RPM per volt with no load. It takes a 4S battery - which is 3.7V per 'S' of the battery - so 14.8V. In theory it should run on a 3s battery (11.1V), but I had no luck with this. It took a max of 27A. These seem to be constructed in South Korea - so allow a couple of months for shipping.

Modern ducted fans require an ESC (Electric Speed Controller) to operate; it is not just a matter of attaching power to the fan to make it work. These are controlled by a PWM signal. Typically, the PWM (Pulse Width Modulation) signal comes from a remote contoller but in my case came from an Arduino.

A standard LiPo (Lithium Polymer) battery - or rather 4 cells. I went for 450 mAh as longevity is not an issue for the 3 seconds per Pinewood Derby race. Read up on the C rating of a LiPo battery, but I don't think this is an issue for this use case. This is the battery I used.

Arduinos. I got a free Uno from CES, and this worked great! However, it was too big for the car, so I bought some Arduino Nanos. Unfortunately, they were the counterfeit ones with the CH340G USB interface that required custom drivers that I could not get to work. Arduino Micros are much more expensive (about $20) but work out of the box. I also got an Arduino starter kit that came with a bunch of connectors and a micro breadboard. The breadboard fits nicely inside a cutout Pinewood Derby block and supplies a very practical set of cables to interface with an Arduino micro.

Micro limit switch - also known as a roller lever switch. This has a light spring that has one connection when some pressure is applied, and another when there is no pressure applied. Something like this. The biggest issues are finding ones that aren't industrial sizes or come in industrial numbers.

Velcro tape. This was used to secure the ESC, battery, and fan. Any would do.

Crimp connectors - 'Straight Wire Butt Connector Electrical Crimp Terminal Connectors'. I found these to be reliable but not malleable at all meaning stuffing the cables in the car was more difficult than it should have been.

Power connectors and form convertors. The battery came with an XT30 connection, and I ended up connecting this via JST adapters.

Pinewood Derby car. All the standard speed tips apply; polished axles, trimmed wheels etc. The fan will provide extra thrust, but could be crippled by a sloppily prepared car.

Setting Up

Try and isolate each step; it's not going to work first time, so bite it off in small chunks. The two ways to debug Arduino code are to use the LED to show a state (e.g. switch pressed), and the serial monitor to read basic debug text. The serial monitor on the Micro requires you to wait for a connetion, so remember to take this wait out when running in the wild. The Arduino IDE leaves a lot to be desired, but works fine for the small amount of code that was needed.

The limit switch is the easiest, but still confused me. I was expecting to hook up two of the connectors to a pin and ground, and the pin would read high when there was a connection. However, it requires a pullup circuit. Luckily, the Arduino has this built in, so setting the input mode to INPUT_PULLUP and it works as expected. The pins on the switch are labeled C (common - to ground on Arduino), NC (normally closed - to pin 7 on Arduino), and NO (normally open - not connected).

I connected the three ESC wires on the output side to the three wires on the fan using crimp connectors. I went red -> red, black -> black, and white -> yellow. Soldering would be a better solution, but my soldering skills are limited. If the connections are wrong, the fan may go backwards (?). This should be able to be fixed by sending different signals from the Arduino (?)

I connected the battery to the ESC by crimp connecting a female JST connector, plugging this into JST to XT30 convertor, and plugging the battery's XT30 connector into that. It was very handy to be able to detach the battery for debugging purposes, so I'd recommend something pluggable. This concoction of connectors wasn't bendable, so putting them in the car was a little awkward. I'm not sure why I didn't buy a female XT30 connector and use that here, and that would have helped fitting everything in the car.

Controlling the fan with the Arduino was by far the most challenging part, but I almost certainly have a short inside the fan that didn't help. Use the servo library that comes with the Micro dev kit; I tried using direct control with microsecond delays, but that didn't work at all. The Pulse Width Modulation (PWM) frequency could be changed on the ESC - I used the lowest settable frequency of 8kHz. The Arduino's documentaion states that it can't represent 8kHz exactly, which may account for some of the anomalies. Also, there was no way to set this frequency in the servo library - it just seemed to work by magic. The first step is to arm the ESC - this requires sending a magic number to the ESC - which for mine was 0. This makes it beep and flash LEDs. Then you can send power levels between 1 and 255 to the ESC to change the thrust of the fan. I used test code to send each thrust level to the ESC to see the effect. It seemed that 55 was minimum power, 66 was the maximum reliable, and 72 sometimes. If the ESC failed to arm, disconnecting the battery was the only reliable way to reset it that I found (the plug on the battery was a boon here). The ESC came with a 3 pin connector - orange, red, and brown. The Arduino gets its power from the USB port when developing, or the middle red cable of the ESC to the 5V connection when the USB cable is not plugged in. Don't ever use both at the same time. The other two go to a PWM enabled pin on the Arduino and ground.

I used a table router to rout the Pinewood Derby block to a U shape wide enough to fit the micro breadboard. I then routed out a channel wide and deep enough for the limit switch at the front and wide enough for the ESC at the back. The limit switch was super glued in and the connecting wires run down the channel (underneath the breadboard). The breadboard came with a back sticker which was used to attach it. This had the added advantage of keeping the limit switch in place). I then used velcro tape on the bottom of the rear, the battery, and the ESC to put everything in place, but removable. Make sure you use the table router carefully, going one way e.g. left to right will work as expected. Going the other will fling the block across the room with part of a severed finger.

Arduino Code

        
    #include <Servo.h>
            
    Servo servo;
            
    int ledPin = 13;
    int inPin = 7;
    int servoPin = 9;

    int msdelay = 20;
    int starttime = 0;
    int pinValue = 0;
    int counter = 0;
            
    // The mode we're in
    // 0 - waiting for limit switch to be depressed
    // 1 - waiting for limit switch to be depressed for a while
    // 2 - waiting for the limit switch to be released
    // 3 - run the servo for a set amount of time
    int mode = 0;
            
    void setup()
    {
        // Allow us to set the LED on when requested
        pinMode( ledPin, OUTPUT );
        // The limit switch pin input state
        pinMode( inPin, INPUT_PULLUP );
            
        // The PWM enabled pin to send signals to the ESC
        servo.attach( servoPin );
        // Arm the ESC
        servo.write( 0 );
        // Wait for it to be armed
        delay( 500 );
            
        // Turn the LED off
        digitalWrite( ledPin, 0 );
            
        // Disabled serial comms for Nano
        //Serial.begin( 9600 );
        //while( !Serial )
        //{
        //  delay( 20 );
        //}
        //Serial.println( "Mode 0" );
    }
            
    void loop()
    {
        switch( mode )
        {
        case 0:
            pinValue = digitalRead( inPin );
            if( pinValue == 0 )
            {
                mode = 1;
                counter = 0;
                //Serial.println( "Mode 1 " );
            }
            break;

        case 1:
            pinValue = digitalRead( inPin );
            if( pinValue == 0 )
            {
                // Switch held down long enough to be real
                counter++;
                if( counter >= 50 )
                {
                    //Serial.println( "Mode 2 - waiting" );
                    // Swith the LED on to show we're ready to rumble
                    digitalWrite( ledPin, 1 );
                    mode = 2;
                }
            }
            else
            {
                mode = 0;
                counter = 0;
                //Serial.println( "Mode 0 - rechecking" );
            }
            break;

        case 2:
            pinValue = digitalRead( inPin );
            if( pinValue == 1 )
            {
                //Serial.println( "Mode 3 - Go!" );
                starttime = millis();
                mode = 3;
                servo.write( 64 );
                counter = 0;
                digitalWrite( ledPin, 0 );
            }
            break;

        case 3:
            servo.write( 64 );
            counter++;
            if( counter >= 125 )
            {
                servo.write( 0 );
                mode = 0;
                //Serial.println( "Mode 0 - reset" );
                //Serial.println( millis() - starttime );
            }
            break;
        }

        delay( msdelay );
    }
        
    

Next Steps

The car looks like a block of wood with a fan on top - it should look more like a jet engine car! The cable management was poor; this could be fixed with some soldering and better connectors.