So far we’ve gotten most of the grunt work out of the way: we’ve designed the LED message board and got the circuit up and running. I can happily say the next portion of the project doesn’t require any soldering! Instead, we’ll be entering the world of Python programming. If you’re not much of a programmer, don’t worry — I’ve supplied everything you’ll need for this project here. You will, however, need to know basic object-oriented programming principles and understand Python syntax. Review the Readme.md of the project to see how to get the message board working for your specific setup. For an explanation of the code and how I wrote all of it, continue reading the secitons below.
Now that we have a working circuit, we need to start thinking about how we want to design the program. We need to design it in such a way that it is easily applicable to any message board, any message, any coloring scheme, etc. A couple of things that come to mind are the following:
- How can we write the board for any size? While it would be nice if we knew that everyone who uses this program will be using a 5×48 LED Message Board, this is not the case. We need to write the program to be as robust as possible and handle multiple sizes.
- How are we going to animate the sign? While the most logical animation is to move the words from left to right for easy readability, we could just as easily drop the words from the top and then scroll the words to the left when they are in full view. We shouldn’t limit ourselves to a single type of animation.
- How are we going to choose the colors of the words? It would be very simple to choose a single color to display all words on the board, but it wouldn’t be that interesting. It also wouldn’t be that interesting to choose between a select amount of colors. We have to design a system that allows us to dynamically change the colors of the board.
Keeping all of the above in mind, we will proceed to design a program that is easily adjustable. This list doesn’t cover all the bases, but it is a good starting point. The more robust the program is, the wider variety of animations, coloring, and board sizes we will have available to us.
The following article assumes you have some programming experience, understand object-oriented programming principles, and can read Python. If you do not have some of these skills you may find it difficult to follow along. While I write this article, I do not explain syntax specific to Python and assume you have the ability to navigate a Python program. For the most part, the first section of this article teaches you how to use the following Python libraries, while the latter section teaches you common design patterns for object-oriented programming.
Before we start programming, we need to install two Python libraries and Python 3. The first of the libraries is necessary only if you are using an LED strip of the form WS281X, where X represents any digit (e.g. WS2812). You can download the rpi_ws281x library here. This will install drivers the raspberry pi needs to communicate with the strip. The second Python library to install is BiblioPixel, which wraps around the WS281X driver and makes it much easier to control the LEDs. It also packages it’s own drivers we will need if we want to communicate with an LPD8806 or an APA102 model strip.
3. Installing BiblioPixel
You are able to install BiblioPixel with one line as below:
tylermckay@rPi$ sudo pip3 install BiblioPixel
If you later run into issues finding the bibliopixel library, then try the same command without sudo. If you don’t have the
pip3 command, you can install it with the following command:
tylermckay@rPi$ sudo apt-get install pip3
Now that we have BiblioPixel installed, we can control multiple model LEDs! Plus this library is not only useful for designing a message board, but also anything from lighting up a simple strip to displaying an image to the board.
Note: You should already have
pip3 installed on your Pi. The Pi should have two types of Python install commands,
pip3. The regular
pip command installs Python 2 modules, while the
pip3 command installs Python 3 modules.
Orienting the Board
Great! It looks like we’re ready to start programming now that everything is installed. This section will deal with testing out some of the libraries we’ve installed, making sure everything works as expected. Then in the next section, we’ll actually start writing the full program to write messages to the board.
Let’s create a file called
animateMessageBoard.py and change the permissions to be executable:
tylermckay@rPi$ touch animateMessageBoard.py
tylermckay@rPi$ chmod 0755 animateMessageBoard.py
Writing the Program
If you’ve gotten to this point, you’re board should be properly outputting a default bibliopixel animation
MatrixCalibrationTest(). This is a nice step forward, but we still have yet to draw a single letter to the screen. Maybe you want to just download the program already and be done with it. If so, go ahead. If you want to see how the program works though, let’s start by making an animation.
Cleaning Up the Code
We can draw any phrase we want to the board now, but it’s not a very robust process. Everything would be very hard to maintain if we tried to apply this program to another board, or another type of animation for that matter. Here’s some problems I notice right off the bat:
- If we wanted to change the character set to different dimensions, we would have to write an entirely new parser.
- If we wanted to perform another type of animation, then we would have to make a completely different file.
- If we wanted to change the color of a certain animation but keep the mechanics of the same animation, then we would have to create a completely different file.
As you can see, there are a lot of issues that arise from our original design. We’ll need to start cleaning up the files we use, so we can make a more robust program.
Let’s address the first issue. The first thing we need to do to the
step() function is separate the word from the animation algorithm. We should really be getting the phrase in the
animateMessageBoard.py file, and initializing the
MessageBoardAnimation class with the phrase. This will remove the dependency for the animation to have the phrase hard coded; instead, we can change the phrase dynamically during runtime (if we desire). Let’s change our
MessageBoardAnimation.py as so:
As you can see we’ve separated the creation of the
word matrix from the
step() function and initialized the
MessageBoardAnimation class with it. This allows us to retrieve the
word matrix in any way we want. For now we are hard coding our message, “Hello World!”, and creating the
word matrix by initializing a parser.
We still have the issue of changing character sets and having to rewrite the
StandardMessageParser to accept that character set. Solving this problem is fairly simple, as we just need to pass a neutral character set to the parser. The neutral character set will take the form of any character set we choose. We need to create another file
MessageCharacters.py in the same directory as
MessageCharacters5x3.py, and we’ll need to modify the
MessageCharacters5x3.py file as so:
Here we’ve just made
MessageCharacters5x3 a subclass of
MessageCharacters. This allows us to pass any character set under the
MessageCharacters type. This type simply stores the matrix representation of a character.
If you were wondering how to draw a message to a board with different dimensions, then wonder no further. All you need to do is create a new file in the
messageBoard/characters directory and subclass it under the
MessageCharacters type. After that you’ll need to create the matrix representation for each character in the character set.
For example, if you’re board is 8×48 and you want characters 5 pixels wide, you’ll need to create a file
MessageCharacters8x5.py, create the class
MessageCharacters8x5 that subclasses
MessageCharacters.py within that file, and create the matrix representation for each character.
This should have pretty much solved our first issue, so let’s move onto the second issue. Here’s the real problem: if we wanted to animate the movement of the words differently, then we would have to create an entirely new animation. The new animation would have most of the code we already using in
MessageBoardAnimation.py. To solve this, we need to encapsulate the animation algorithm inside of an object. This will allow us to separate the movement algorithm from the rest of the animation. Go ahead and create a new directory
messageBoard/algorithms/ and within this folder create files called
animateMessageBoard files should also be modified as so:
The first thing we did was create a class
MessageAlgorithm that is meant to be subclassed. The function
animateLED() is the one that needs to implement the algorithm. The
ScrollLeftMessageAlgorithm overrides this method to perform the scroll left animation. This is called in our
step() function every iteration. The
MessageBoardAnimation class is now initialized with a
MessageAlgorithm object, so the algorithm can change at runtime by setting a new algorithm object.
Now if we wanted to make another animation, then we can still keep the
MessageBoardAnimation class as is. We just need to create another message algorithm class that inherits from the
MessageAlgorithm class and overrides the
The final issue is very similar to issue #2, except this issue deals with color animations versus moving animations. If we want the animation that changes color to be dynamic, we have to do the same approach as the moving animation. The only exception to this is since the color is changed within the
MessageAlgorithm class heiarchy, we need to modify this class, not the
Why don’t you create files
RainbowColorAlgorithm.py within the
messageBoard/algorithms/ directory. The
animateMessageBoard files should also be modified like this:
Now we have a more manageable program! A few classes here or there to encapsulate logic and resources, and now we have a plug and play style message board. If you want to create your own message algoritm, then subclass the
MessageAlgorithm class; if you want to create your own color algorithm class, then sublcass the
ColorAlgorithm class. The bigger picture should be a lot more customizeable.
I should mention that this really doesn’t solve all of our problems. This really solves the practical issues we can think of at face value. Some things to consider with our current design: the color algorithm isn’t completely independent of the message algorithm, we may want to pass different parameters to the algorithms in the future, and we only have 2 methods to subclass for the color algorithm and 1 for the message algorithm. With a little toying around we could improve some of these weaknesses, but this design will suffice for our purposes.
With all that out of the way, we are left with the final task of creating a small web service to read data into the board. The bulk of the work is out of the way, so we can start finalizing the project. The source code in the previous sections will be available on my GitHub page. Feel free to download the files and modify them as you would like. The structure of the program, as explained above, is meant to be customized to fit the needs of your design.