STEAM blog

Computing, maths and art in education

Virtual LED Hat - setting up

A Raspberry Pi HAT is a circuit board that sits above the RPi board, connecting via the GPIO pins. Various HATs are available which provide extra functions such as audio input and output, cameras, or sensors. If you are wondering, HAT stands for Hardware Attached on Top.

There are several HATs available which provide a bank of RGB LEDs. You can control the colour of each LED in Python, to make patterns, display scrolling text, or even play simple games.

hat

(Pi Sense Hat image by Ben Nuttall)

That is all very nice, but kitting out a classroom with LED HATs can be expensive, and the novelty soon wears off. Which is where the virtual LED HAT comes in. It is just a Python/Tkinter program which displays a simulation of a real LED HAT on your computer screen.

Aside form being cheaper and easier, you can also choose the number of rows and columns in your grid of fake LEDs.

Here we will see how to set up the virtual LEDHat, and create a simple rainbow display

Setting up

You can find the source code on github. The code is all in the ledhat.py file (there really isn’t much code required to draw a few circles in a Tkinter window!). The remaining files in the folder are examples.

Just copy the files into a working folder on your disk, and run an example file. You should see a small window open up, with coloured circles representing the LEDs. The examples are animated.

example.py

Here is the code:

import ledhat

WIDTH = 8
HEIGHT = 4

def draw(hat, frame):
    hat.clear_pixels()
    x = frame % WIDTH
    y = (frame // WIDTH) % HEIGHT
    hat.set_pixel(x, y, (255, 0, 0))

ledhat.LEDHat(draw, WIDTH, HEIGHT)

Taking the final line first:

ledhat.LEDHat(draw, WIDTH, HEIGHT)

This code creates a HAT with the required number of LEDs (WIDTH by HEIGHT). It displays the LEDs in a window:

hat1

This image shows the black LEDs against a dark grey background.

Notice that we pass a parameter draw into the LEDHat function. This is a function we define which controls the animation:

def draw(hat, frame):
    hat.clear_pixels()
    x = frame % WIDTH
    y = (frame // WIDTH) % HEIGHT
    hat.set_pixel(x, y, (255, 0, 0))

This function is a callback. When LEDHat runs, it calls the draw function several times a second to allow us to control the colours of the LEDS.

draw() takes two parameters:

  • hat - the LEDHat object itself
  • frame - an integer which starts at 0 and increments by 1 each time draw is called. This incrementing variable can be used to control the animation by deciding the colour of each LED over time.

The hat object has two important methods:

  • hat.clear_pixels() clears all the LEDs to black.
  • hat.set_pixel(x, y, color) sets the LED at position (x, y) to a particular colour. The colour i a 3 element tuple where each element has a value 0 to 255 controlling the amount of red, green and blue in the LED.

Our particular draw function calculates x and y based on the frame number, and colours that one LED in red:

hat2

Each time draw is called, frame increments in value. This changes x and y, so each time a different LED turns red. If you look at the equations, the cause the red LED to move one place to the right each time. Each time the red LED reaches the end of the line, it jumps back to the start of the next line down.

rainbow-example.py

This example is slightly different. It colours every LED, with a colour that changes with time. Here is the code:

import ledhat

WIDTH = 16
HEIGHT = 16

rainbow = (
    (255, 0, 0),
    (255, 128, 0),
    (255, 255, 0),
    (0, 255, 0),
    (0, 255, 128),
    (0, 255, 255),
    (0, 0, 255),
    (128, 0, 255)
)

def draw(hat, frame):
    hat.clear_pixels()
    for x in range(WIDTH):
        for y in range(HEIGHT):
            n = (x + y + frame) // 2 % 8
            hat.set_pixel(x, y, rainbow[n])

ledhat.LEDHat(draw, WIDTH, HEIGHT, led_size=30)

Here is what it looks like (the code animates it):

hat3

The colours are contained in the rainbow list. The code causes the coloured bands to move diagonally across the display.

Notice that we set the LED size to 30 pixels in the LEDHat call. This makes the circles smaller (the default size is 50 pixels) so that the window isn’t too large.

Creating your own display

Make a copy of the file example.py. Save it with a new name, in the same folder. This will be your working file, feel free to experiment with it. Try changing to draw function to set the LED colours according to your own pattern.