Scientific Computing
& Physics Experiments

using the RaspberryPi & SenseHAT



Light-up Rainbow Hearts

Use your Raspberry Pi and SenseHAT to display flashing, colorful hearts




Things You Need

A Raspberry Pi
A SenseHAT, connected to your Pi's GPIO pins
A monitor connected to your Pi with an HDMI cable
Keyboard & mouse attached to your Pi
A power adapter


Getting Set Up

This tutorial assumes you've correctly attached the SenseHAT to your Raspberry Pi's GPIO pins. If the LEDs show a rainbow when you power on the Pi, you're all set. The tutorial also assumes that you can see your Desktop (if you're using a monitor) or Bash (if you're using SSH).


Resources

Here are links to useful resources for this project. You might want to open each one in a new tab, so you can refer to them later as you're working through this tutorial.


Let's Start Coding!

Open your Terminal. If you're using your RaspberryPi from a Desktop, click the icon in the top menu bar that looks like a black box. If you're accessing your RaspberryPi via SSH, you are already in the Terminal. From your Terminal, navigate to the Desktop by typing the following command. (Remember that the dollar sign ($) is part of your Terminal; you do not need to type this in.)

$ cd ~/Desktop

Let's make a new directory to hold the Rainbow Hearts project, and then navigate into it:

$ mkdir pi_rainbow_hearts
$ cd pi_rainbow_hearts

To double check that we're in the right place, we can run the pwd command, which will print to our screen the file path we're currently in:

$ pwd
/home/pi/Desktop/pi-rainbow-hearts

Now that we're in the directory for the Rainbow Hearts project, we need to create a Python file to put our code in.

$ touch hearts.py

We can verify that our new file was actually created by running the ls command (that's lowercase L, by the way). You should see a filed called hearts.py print to your Terminal.

$ ls
hearts.py

Let's open this file with the Raspberry Pi's built-in Python 3 IDLE. Click on the RaspberryPi logo in the upper left corner, then click on the "Programming" tab that appears, then click on the "Python 3 IDLE" choice that appears. Note that your options may be in a different order or location based on the operating system you installed! But don't worry, whatever you installed definitely has the Python 3 IDLE. You may need to look around for it.

Once you're in the Python 3 IDLE, you need to open the hearts.py file.

  1. Click the "File" menu, then click "Open".
  2. Double click on the Desktop folder.
  3. Double-click on the pi-rainbow-hearts folder.
  4. Finally, select the hearts.py file and click on the "Open" button.

A new (empty) window should appear, which is where we will write our Python program!

In this window that we just opened, which is actually our hearts.py file, we need to import two modules: 1) The SenseHAT library, so we can interact with the SenseHAT, and 2) The Time library, so we can have our hearts flash on the LED matrix for a specified amount of time. Accomplish this by typing the following code into the file:

# hearts.py

from sense_hat import SenseHat
import time

Note that the # sign creates a comment in Python, and any line of code that starts with a # will not be run. Programmers use this feature to write notes about their code. Here, the note we see is just telling us which file we are in.

When we import SenseHat, as above, we are importing an "object" called SenseHat. Objects can have special functions attached to them (called "methods"), and we can use these special functions to make the objects do different things. We'll come back to this idea later. For right now, we want to save this SenseHat object as a variable so we can refer to the SenseHat object simply by using the variable name:

# hearts.py

from sense_hat import SenseHat
import time

sense = SenseHat( )

If you're curious about how or why we begin our file this way, have a look at the quick set-up guide the Raspberry Pi Foundation provides for the SenseHAT.

Along with methods, objects can also have special characteristics which we call "attributes". For example, if we created a "Dog" object, the object might have attributes such as "breed" or "weight". We can store values inside these attributes, so in this example we could set
Dog.breed = "Golden Retriever"

Let's get back to the topic of writing Python code so we can interact with our SenseHAT. The LEDs are quite bright, so to make them a little dimmer, we can change the SenseHat object's "low_light" attribute to True (the default is False), as shown below:

# hearts.py

from sense_hat import SenseHat
import time

sense = SenseHat( )
sense.low_light = True

How do we know we can change the brightness of the LEDs? Are there any other things about the SenseHAT we could change or customize? For answers to these questions, browse the SenseHAT API documentation!

Now's a good time to save your file, either by holding down the < Ctrl > key and then the < s > key, or by opening the File menu and clicking on "Save..."

If the topics of objects, methods and attributes are confusing right now, don't worry! You can still have fun and complete this tutorial even if you skip the stuff about objects. Keep going!


Choose Your Colors

Alright. We've taken care of importing things and setting up our SenseHat object. Time to choose some colors using the Red-Green-Blue (RGB) format!


RGB is a way of creating colors by mixing very specific quantities of red, green and blue. Each color (red, green or blue) can have a quantity, or concentration, of up to 255. For example, the RGB value for red is (255, 0, 0) because we list the concentrations in (RGB) order, and pure red will have no green or blue in it. This means there's a 100% concentration of red and a 0% concentration of the other colors. Likewise, the color green would have an RGB value of (0, 255, 0) and the color blue would have an RGB value of (0, 0, 255).

We'll be using colors from the rainbow for this tutorial. If you'd like to choose different colors, you can experiment with an RGB calculator to make custom colors or copy and paste the RGB codes for some common colors.

To use the rainbow colors, copy and paste this Python code into your hearts.py file, under the code we have already written.

Remember, the lines of code that begin with the # sign will not be run. In our case, we are writing these comments to remind ourselves which color is being coded in the line below.

Normally, we'd want to use variable names that are as descriptive as possible (full color names, in our case). If our variable names are really descriptive, we don't have to write comments about them! The reason we're only using 1 or 2 characters as variable names is because we're going to create lists that hold these colors in the shape of our 8x8 LED matrix. Using single characters allows us to present the lists in a near-square pattern, which mirrors the LED matrix. If we were to use the full color names, our lists would appear as long rectangles instead. It wouldn't be as easy to understand at-a-glance which of our LED bulbs are going to light up and which are not.


# Create variables to hold each RGB color we want to use # red
r = (255, 0, 0)

# pink
p = (204, 0, 204)

# orange
o = (255, 128, 0)

# yellow
y = (255, 255, 0)

# green
g = (0, 255, 0)

# aqua
a = (0, 255, 255)

# blue
b = (0, 0, 255)

# purple
pr = (128, 0, 255)

# empty (no color)
e = (0, 0, 0)

Remember to save your file every time you add a new chunk of code to it!

In the code above, we are creating a new and unique variable name for each color. To keep our variable names short, we are using just the first letter of each color (with the exception of purple, because the color pink already took the "p"). Each variable stores that color's RGB value as a tuple.

A tuple is a way to store several different pieces of data as one. Python knows we're using a tuple because tuples start and end with parentheses, and contain more than one thing inside. (Even though we may see one RGB value, this RGB value is made up of 3 separate integers, each separated by commas.) When we store data in tuples, we have to separate each data point with a comma. Read more about tuples. if you're curious about how they work.


Prepare the LEDs

The SenseHAT's LED matrix forms a square with 8 LEDs on each side, for 64 LEDs total. This 8x8 grid is the geometric space we have to work with for making the hearts appear.




Each time we want to show something on the LED matrix, we have to tell the LED matrix which (if any) of the 64 LEDs should light up, and what color they should be. In other words, we have to specify one-by-one which of the 64 tiny LEDs should light up.

The way we do this is with a list that contains 64 values inside of it -- one value per LED! Now, just observe the following code snippet (don't put this into hearts.py.) We could code a Python list with 64 values in it like this:

led_list = [o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o]

But this way of doing it would make it hard to see at a glance what our picture would turn out like, because the data telling which LEDs to light up is basically in one straight line. This is fine for the computer, but not so friendly for humans. Read more about Python lists.]

Luckily, Python allows us to break up the values in a list into a format that is more human-readable. Again, just observe the following code; don't write this code yet. We can code the list as 8 rows of 8 values, like this:

led_list = [
o, o, o, o, o, o, o, o,
o, o, o, o, o, o, o, o,
o, o, o, o, o, o, o, o,
o, o, o, o, o, o, o, o,
o, o, o, o, o, o, o, o,
o, o, o, o, o, o, o, o,
o, o, o, o, o, o, o, o,
o, o, o, o, o, o, o, o
]

That is so much easier to read AND we'll get a better idea of the picture that is taking shape on the LED matrix, since the shape of the list resembles the surface area made by the 64 LEDs.

Before we go any further, we need to figure out which values in this list are going to tell the LEDs to light up, and which values in this list are going to tell the LEDs not to light up. An easy and fun way to plan your image is to simply color in squares on an 8x8 grid, like so:



We can now create a variable that will hold a list, and this list will hold the 64 LED values just as we saw above. Looking back to the code you wrote in your hearts.py file which assigned RGB values to different variables, we see that the variable "e" means "empty" (or no color) and the variable "r" means "red".

So, anywhere in our list where we want an LED to not turn on, we type "e". And anywhere in our list where we want an LED to turn on, we type the letter of the variable that contains the color we want to display. Here is what the code looks like for creating a variable called red_heart that stores the LED values following the sketch above:

red_heart = [
e, e, e, e, e, e, e, e,
e, r, r, e, r, r, e, e,
r, r, r, r, r, r, r, e,
r, r, r, r, r, r, r, e,
r, r, r, r, r, r, r, e,
e, r, r, r, r, r, e, e,
e, e, r, r, r, e, e, e,
e, e, e, r, e, e, e, e
]

Take a minute to walk through both the grid with the heart in it and the red_heart list. Notice that each blank space in the grid is represented by an "e" in the red_heart list, and each red space in the grid is represented by an "r" in the red_heart list. Notably, the entire top row and the entire far-right column are both empty, meaning none of those LEDs will light up.

Time to code the variables for the rest of our colors! Using the red_heart list as a guide, create a new variable for each heart color you want to display on your LED matrix. Here are some things to keep in mind, especially if you are going to copy and paste:



If you get stuck, you can view the sample code here, which contains all the colors of the rainbow.

Your hearts.py file should now look similar to the file shown below. Remember to save your file!

# hearts.py

from sense_hat import SenseHat
import time

sense = SenseHat( )
sense.low_light = True

# Create variables to hold each RGB color we want to use

# red
r = (255, 0, 0)

# pink
p = (204, 0, 204)

# orange
o = (255, 128, 0)

# yellow
y = (255, 255, 0)

# green
g = (0, 255, 0)

# aqua
a = (0, 255, 255)

# blue
b = (0, 0, 255)

# purple
pr = (128, 0, 255)

# empty (no color)
e = (0, 0, 0)

red_heart = [
e, e, e, e, e, e, e, e,
e, r, r, e, r, r, e, e,
r, r, r, r, r, r, r, e,
r, r, r, r, r, r, r, e,
r, r, r, r, r, r, r, e,
e, r, r, r, r, r, e, e,
e, e, r, r, r, e, e, e,
e, e, e, r, e, e, e, e
]

pink_heart = [
e, e, e, e, e, e, e, e,
e, p, p, e, p, p, e, e,
p, p, p, p, p, p, p, e,
p, p, p, p, p, p, p, e,
p, p, p, p, p, p, p, e,
e, p, p, p, p, p, e, e,
e, e, p, p, p, e, e, e,
e, e, e, p, e, e, e, e
]

orange_heart = [
e, e, e, e, e, e, e, e,
e, o, o, e, o, o, e, e,
o, o, o, o, o, o, o, e,
o, o, o, o, o, o, o, e,
o, o, o, o, o, o, o, e,
e, o, o, o, o, o, e, e,
e, e, o, o, o, e, e, e,
e, e, e, o, e, e, e, e
]


Lighting Up the LEDs

We've done a lot of prep work, and now we're in the home stretch! It's time to make our SenseHAT light up!

One strategy we could use is to write a for-loop to iterate through all of our <color>_heart variables (which hold the data about which LEDs to turn on) and have each heart light up one by one. To do this, we need to create a new variable that's going to hold a list of all of the <color>_heart variables inside.

Add the following code underneath the other code you have in your hearts.py file, making sure to replace the sample variable names with your own variable names, if the variable names you have chosen for each of your hearts are different than what is shown below. [Note: There are more colors used in the full sample code. The colors below refer only to the colors demonstrated in this tutorial.]

heart_colors = [red_heart, pink_heart, orange_heart]

Next, we need to write a function that can loop through the items in the heart_colors list, and flash them on the SenseHAT's LED maxtrix one-by-one. Type the following code at the bottom of your hearts.py file, making sure to replicate the indentation. In the next section, we'll walk through what each line of code is doing.

def rainbow_hearts():

for color in heart_colors:

sense.set_pixels(color)
time.sleep(1)

# Clear the LED display
sense.clear()



We only have one more line of code we need to write! We need to call the rainbow_hearts function, so that all the code inside it will be run by the hearts.py file. So far, all we've done is define the rainbow_hearts function. If we don't tell Python that it's OK to run the function, our LEDs won't light up. Add this line of code to the very end of your file, and then save it:

rainbow_hearts()

Run Your File

Now that our file is complete, we need to run it in order to make the LEDs display our colorful hearts. Go back to the window showing the Raspberry Pi's Terminal and run the file by typing in this command:

$ python3 hearts.py

If your Terminal is not still running from the session we started at the beginning of this tutorial, navigate to the directory that contains the hearts.py file by typing in this command, then try running the file:

$ cd pi/Desktop/pi_rainbow_hearts/hearts.py
$ python3 hearts.py

via GIPHY

What's Next?

If you enjoyed making the Rainbow Hearts project, here are some things you can try next: