Be Still, My Beating Heart
It's that festival of red and pink and hearts and all that gubbins. Part craft and part coding, this Valentine's project might get you into a geek's heart. Failing that, you've got a nice pulsing light.
Here's what it will look like:
Making the Pibow top
First off, a Unicorn HAT HD was hidden inside a custom pibow. You can customise your own pibow top into a glittery diffuser with the helpful aid of some silicone bathroom sealant and sequins or gems. To make this one, we took a Pibow top and smeared an even layer of silicone sealant over it.
A box of gems was sorted by colour and size, and the gems were pressed into the sealant in a pattern. You need to leave the sealant to set for 24 hours, but after that it is reasonably hard-wearing.
Foolishly, I used white sealant, which works well as a diffuser, but I'd use clear next time to allow a little more light to shine through.
Other ideas - push broken/old components into the sealant, or nuts and bolts for a more rugged version.
Coding the heart
Rather than just having a pulsing light behind the top of the Pibow, I wanted to have an actual heart shape. Handily, Sandy made a heartbeat example for the non-HD Unicorn HAT, so I modified his code to apply to the Unicorn HAT HD, and also simplified the code.
The Unicorn HAT HD is 16 x 16 pixels, so I drew a heart on squared paper that would be translated into a list. To do this, everywhere you see a heart pixel, you type a 1, and everywhere it should be dark/background, type a 0.
heart = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0],
[0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0],
[0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
[0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
[0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
[0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
[0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0],
[0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0],
[0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]
NumPy is a library of useful mathematical functions in Python, and this is what we use to handle our little heart picture.
heart = numpy.array(heart)
Making the heart flash
This is not quite as easy as it should be; making something in RGB colours flash is harder than making something in HSV colours flash.
while True:
for i in 2*(range(1,11)[::-1]+range(1,10)):
The maths to make the flashing pattern is easiest to show in a picture:
To make the ba-BUMP of a heartbeat, you need to dial the brightness up to full and back again, twice. The easiest bit to explain is the times two at the start - two bumps. The value for the brightness is 1 divided by whatever number is next in the list, so it starts off being divided by 10, and goes through to full brightness, and then back to 1/10th when the pattern repeats.
By far the largest chunk of code is changing the HSV into RGB so we can send the information to the Unicorn HAT HD to actually show the heart! Hopefully the comments amongst the code explain this.
A full copy of the code with or without comments is at the bottom of this tutorial.
Now you can display a beating heart, maybe you could change the shape, or colour, or even make it so that the heart beats when you send the Pi a certain message (Tweepy is a good place to start)?
Happy Valentine's Day!
The code
import unicornhathhd as unicorn
import time, colorsys
import numpy
unicorn.brightness(1)
unicorn.rotation(90)
heart = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0],
[0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0],
[0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
[0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
[0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
[0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
[0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0],
[0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0],
[0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]
heart = numpy.array(heart)
while True:
for i in 2*(range(1,11)[::-1]+range(1,10)):
for y in range(16):
for x in range(16):
h = 0.0
s = 1.0
v = heart[x,y] / float(i)
rgb = colorsys.hsv_to_rgb(h, s, v)
r = int(rgb[0]*255.0)
g = int(rgb[1]*255.0)
b = int(rgb[2]*255.0)
unicorn.set_pixel(x, y, r, g, b)
unicorn.show()
time.sleep(0.005)
time.sleep(0.8)
The commented code
import unicornhathhd as unicorn
import time, colorsys
import numpy
unicorn.brightness(1)
# need to rotate the image to have the heart the right way up
unicorn.rotation(90)
heart = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0],
[0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0],
[0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
[0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
[0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
[0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
[0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0],
[0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0],
[0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]
heart = numpy.array(heart)
while True:
# go through the range 1-10 backwards then back up
# the 2* makes a ba-BUMP for the heart
for i in 2*(range(1,11)[::-1]+range(1,10)):
# the x and y ranges are the size of the Unicorn Hat HD - 16 x 16 pixels
for y in range(16):
for x in range(16):
h = 0.0 # red
s = 1.0 # saturation at the top of the red scale
v = heart[x,y] / float(i) # the brightness of the heart depeds where it is in the range
rgb = colorsys.hsv_to_rgb(h, s, v) # convert the hsv back to RGB
r = int(rgb[0]*255.0) # makes a 0-1 range into a 0-255 range and rounds it to a whole number
g = int(rgb[1]*255.0)
b = int(rgb[2]*255.0)
unicorn.set_pixel(x, y, r, g, b) # sets the pixels on the unicorn hat
unicorn.show() # show the pixels
time.sleep(0.005) # tiny gap, sets the frames of the heart animation to 200 a second so it looks smooth
time.sleep(0.8) # waiting time between heartbeats
Search above to find more great tutorials and guides.