Friday Fun: Radio Controlled micro:bit Pumpkin 🎃

It's nearly Halloween!

The night when creatures of pure evil roam the land, seeking their next victim!
alt No brains were harmed...or found during the creation of this photo

So...

How can we scare them away?

alt There are lots of evil spirits in this picture, can you find them all?

Well we need to build a micro:bit powered radio controlled neopixel pumpkin!

What will you need?

All of the code for this project can be found on my Github repo.

Hardware

Building the GPIO expansion

The micro:bit has a gold edge at the bottom of the board, and this is the GPIO (General Purpose Input Output) but you can see that some of these connections are broken out using holes, to which we can connect crocodile clips.

For this project we will need to insert the machine screws into pins 0, 3V and GND, then slide the washer on to each screw. Finally, lightly screw the nut to make sure that nothing goes missing.

alt

Soldering the neopixel ring

Our neopixel ring has lots of places where we can solder, but in particular we need to solder our single core wires to pins IN, PWR/VCC and GND. In the image below the wiring is as follows.

Yellow = IN
Red = VCC/PWR
Blue = GND

alt

Once soldered an optional step is to apply hot glue to the connections to provide a little more strength to the joint.

Crimping the ring terminals

Strip the end of each of the 3 wires so that about 2cm of bare wire is showing. Insert the wire into the ring terminals plastic sleeve so that you can see the base metal end, then using a crimping tool apply even pressure so that the plastic is squashed around the wire. This will form a strong mechanical connection and enable the micro:bit to talk to our neopixel ring. An optional step, but you can also add a little solder to the ring terminal to ensure the wire is well connected.

alt For the red wire I went a little too far, so I used my snips to trim the bare wire

Attach the ring terminals to the micro:bit

Remember those screws we inserted into the micro:bit? Well now we need to attach our neopixel ring terminals to the micro:bit GPIO.

The connections are made as follows.

alt

In reality they look like this.
alt

Be careful not to over tighten the machine screws as they are countersunk and can apply too much pressure on the micro:bit, causing it to crack!

Insert the micro:bit into a plastic pumpkin

My pumpkin was from Asda, and inside the mouth is a white plastic shroud that covers an RGB LED. Flipping the pumpkin over I found a battery holder that also enabled access to the underside of the LED. Using gentle persuasion I removed the LED and battery holder and saved them for another project.

alt

Using hot glue I stuck the neopixel ring to a piece of cardboard just a little bigger than the hole. Then I stuck the plastic shroud over the neopixel ring to diffuse the light.

alt This was taken before I trimmed the board down to size.

Now insert the neopixel/carboard rig into the pumpkin and use hot glue to seal it in!

Software

For the project I use Mu to write the code, but you can also use the online Python editor, and the blocks editor.

Pumpkin Code 🎃

alt We shall start with the software for our pumpkin. We import four libraries, the radio functionality so that we can receive messages, then the microbit library, then the sleep function and finally we import functionality for our neopixels.

import radio  
from microbit import *  
from microbit import sleep  
import neopixel  

Next we create an object that will store the pin used to connect and control our neopixel ring. We attached it to Pin 0 and there are 7 pixels in the ring, so our config is as follows.

np = neopixel.NeoPixel(pin0, 7)  

Now lets turn the radio on so that our punpkin is ready to receive messages from the controller.

radio.on()  

So now we create a loop that will constantly loop...forever! This is called while True (Scratch/Blocks call this Forever) and inside the loop our first task is to check that we are receiving incoming messages and to store them in a variable called incoming.

while True:  
    incoming = radio.receive()

So we have a message!!!

To check that the message contains a keyword, which in this case will be face up, shake, left, right, up, down

we need to use a conditional statement test if...else if...else to check the value stored in our incoming variable against hard coded values. Let's take a look at the first as an example. If the incoming message contained face up then that is printed to the Python shell for debug (we don't see this unless we are connected to the micro:bit from our computer and using the REPL) then a for loop is used to change the colour of all 7 pixels in our neopixel ring. In this case each pixel is coloured 255,0,0 which is an RGB (Red, Green, Blue) colour value for Red on at full brightness, and Green, Blue to be off. Then in order to see the colour change we tell the neopixels to show the changenp.show() We then break out of the for loop and tell the code to wait for 0.05 seconds.

    if incoming == "face up":
        print("face up")
        for i in range(7):
            np[i] = (255,0,0)
            np.show()
        sleep(50)  

We then repeat the process for each gesture using elif which is how Python identifies an else if condition to test.

Here are all the elifs

    elif incoming == "shake":
        print("shake")
        for i in range(7):
            np[i] = (255,69,0)
            np.show()
        sleep(50)  
    elif incoming == "left":
        print("left")
        for i in range(7):
            np[i] = (0,255,0)
            np.show()
        sleep(50)  
    elif incoming == "right":
        print("right")
        for i in range(7):
            np[i] = (255,0,255)
            np.show()
        sleep(50)  
    elif incoming == "up":
        print("up")
        for i in range(7):
            np[i] = (0,191,255)
            np.show()
        sleep(50)  
    elif incoming == "down":
        print("down")
        for i in range(7):
            np[i] = (124,252,0)
            np.show()
        sleep(50) 

But what if the message received is not one that we expect?

If the gesture sent from the controller is not one that we wish to recognise then we use an else condition. If all of the previous if..elif conditions are proven to be False then else must be True. In this case we simply turn off the neopixels.

    else:
        for i in range(7):
            np[i] = (0,0,0)
            np.show()
        sleep(50) 

That's all of the code for our Pumpkin micro:bit. Flash it on to the micro:bit and wait for the micro:bit to reset. Give it about 30 seconds and then unplug the pumpkin micro:bit from your computer and then attach it to a USB powerbank. The unit will power up and will await commands from our controller...which we shall code now!

Controller micro:bit Code

Our micro:bit controller uses gestures (moving the board around and holding it a certain way) to create the input for our pumpkin. The gesture is sent over the radio to the pumpkin which reacts accordingly.

Our first three lines of Python import the microbit library and the sleep function, used to pace our code then import the radio function used to transmit/receive messages.

from microbit import *  
from microbit import sleep  
import radio  

Then we turn the micro:bit's built in radio on, so that we can transmit.

radio.on()  

Then we create a while True loop that will constantly run the code within. In this case it constantly checks the way the micro:bit is being held / used and stores it in a variable called gesture.

while True:  
    gesture = accelerometer.current_gesture()

The gesture is then checked against a series of conditions using an if...else if conditional test. If a gesture matches, then a radio message is sent to our pumpkin.

    if gesture == "face up":
        radio.send("face up")
    elif gesture == "shake":
        radio.send("shake")
    elif gesture == "left":
        radio.send("left")
    elif gesture == "right":
        radio.send("right")
    elif gesture == "up":
        radio.send("up")
    elif gesture == "down":
        radio.send("down")

Lastly we have a 0.05 seconds pause in the loop to give the micro:bit time to detect the gesture and send the message. I tried this without a sleep and the received messages on the pumpkin were often blank (NoneType errors).

    sleep(50)

Flash this code on to your micro:bit and then let it reset. Give it about 30 seconds and then unplug your micro:bit from your computer and plug in the USB powerbank to your micro:bit.

Complete Code Listing

Pumpkin

import radio  
from microbit import *  
from microbit import sleep  
import neopixel

np = neopixel.NeoPixel(pin0, 7)

# The radio won't work unless it's switched on.
radio.on()

# Event loop.
while True:  
    incoming = radio.receive()
    if incoming == "face up":
        print("face up")
        for i in range(7):
            np[i] = (255,0,0)
            np.show()
        sleep(50)     
    elif incoming == "shake":
        print("shake")
        for i in range(7):
            np[i] = (255,69,0)
            np.show()
        sleep(50)  
    elif incoming == "left":
        print("left")
        for i in range(7):
            np[i] = (0,255,0)
            np.show()
        sleep(50)  
    elif incoming == "right":
        print("right")
        for i in range(7):
            np[i] = (255,0,255)
            np.show()
        sleep(50)  
    elif incoming == "up":
        print("up")
        for i in range(7):
            np[i] = (0,191,255)
            np.show()
        sleep(50)  
    elif incoming == "down":
        print("down")
        for i in range(7):
            np[i] = (124,252,0)
            np.show()
        sleep(50) 
    else:
        for i in range(7):
            np[i] = (0,0,0)
            np.show()
        sleep(50) 

    #if incoming == 'flash':
    #    print("Hello")

Controller

from microbit import *  
from microbit import sleep  
import radio  
# The radio won't work unless it's switched on.
radio.on()  
while True:  
    gesture = accelerometer.current_gesture()
    if gesture == "face up":
        radio.send("face up")
    elif gesture == "shake":
        radio.send("shake")
    elif gesture == "left":
        radio.send("left")
    elif gesture == "right":
        radio.send("right")
    elif gesture == "up":
        radio.send("up")
    elif gesture == "down":
        radio.send("down")
    sleep(50)

Testing the code!

This is fun part! Wave your hands in the air and you will see the pumpkin react, changing colour as it receives data from your controller micro:bit.

You did it! You saved the world from boring darkness!

via GIPHY