Monday 13 April 2015

LED Matrix. Use your old Model A Raspberry Pi..

Introduction

There is lots of Pi help out there, and a little googling will find you heaps.  All of it helps people with different skill levels.  Sometimes a blog that helps one person will be useless to another.  With that in mind I have created a summary of how to build an LED matrix display from scratch, in the hope that it helps lots of people with similar skill level to mine.

NOTE: Some of this tutorial is MAC based, I apologise and will review later to make it more generic.
I have also done most of this on a newer Pi without any issues.  I have changed this post a little and need to also note that using an original Pi, I had troubles until I updated my version using NOOBs 1_4_2 on an 8GB SD card - without the internet connected - that gave me grief as well!.

Basis for this work - Pete Goss

See Pete's work on the Rasperry Pi site.  I had my Pi for well over a year and was always looking for something to do with it - Pete had the answer!

What are you going to get

An LED matrix display that you can control externally with http posts, updating words, scrolling or patterns, including a range of functions which are best discovered using the test files included with the source code.

Example 1: Actual Tram arrivals at my local stop

Example 2: The Heartbeat

Technology we are going to play with

Raspberry Pi: The driver of our Matrix.  I am using an original Raspberry Pi with the Debian OS so this tutorial is particularly useful if you want to do something with that old Raspberry Pi!

Node.Js: Needed to supply an easy way to communicate with the Pi that I was familiar with (web technologies) and Node.Js is just cool and the easiest thing to implement basic functionality in.

html/css/javascript: Very small bit of HTML and javascript.

Python: Where most of the work if is done in this project.  I took the work of Pete Goss and hacked it to suit my needs.  I also built a range of tools around it to make the Matrix externally interactive.

Lego: How else are you going to protect your new toy!

Building the LED Matrix

Step 1: Get your hardware: You will need the following
  • Raspberry Pi with Debian installed
  • 2 x 5v Power sources
    • 1 for the Pi - you should have this already
    • 1 for the LED matrix.  I got an old usb phone charger and stripped it down to get the positive and negative.  This is not essential as the power in the Pi can drive the LED matrix, but trust me, its heaps better when you give it some juice.
  • LED matrix from Embedded Adventures.
    • The important thing this came with was the 5V connector for the matrix.
  • Network cable.  You could also make it stand-alone wireless, but I prefer to have at least control of the network that is running it.  I also plan to use it at work, so some security was at the back of my mind.
  • Lego.  I was forbidden from using my son's lego, but eBay has an AMAZING range of lego for sale including 1kg, 5kg, 10kg lots.  Just incredible.  I got a 1kg bag and it was mostly small stuff so provided a real challenge in creating my casing.
  • 2 x Lead Jumper set from Jaycar (or anyone else).  I just found this the easiest way to connect the Pi GPIO pins to the LED matrix using female to female connectors.
Step 2: Run your Pi headless.  You will need to
  • Hook the Pi up to 
    • keyboard
    • mouse and 
    • monitor (I had to use my TV because all our computers are laptops)
    • Network (i.e. internet) connection - most routers have at least one spare port.  The router should then dynamically assign an IP address for your Pi.
  • Turn on the Pi and open a terminal session on you Pi and type sudo apt-get install xrdp
    • It is magic.  It installs and sets up remote desktop client to always run on startup.
  • Install a RDC client on your computer.  
    • For a Mac at home I use CoRD - it works fine
    • At work, the native windows RDC also worked without any special help
    • It often asks if you trust certificates - I have always said yes
From this point on all you need to do is have your Pi plugged into a network with power, and you can work on it using a remote desktop client.  This is very handy!  I use 2 techniques for finding the IP address:
  • IPads/IPhones there is an app called Fing - which searches your network and tells you everything on it.  No doubt Android will have something similar.
  • Scan from laptop/PC.  Windows has a range of these tools.  On my Mac I use a free product called LanScan.
Step 3: Hook up your LED matrix to your Raspberry Pi.  I did this using the female to female connectors mentioned in the hardware section above, but you could also use the strip that comes with the LED Matrix, or if you are really keen - solder!

Pete Goss describes this in his ldp.py header quite well.  I have put it here for completeness
###################################################
# ldp python module (ldp.py)
# use: import ldp (in your script)
# A set of functions to make it easier to interface 
# with Embedded Adventures' 80x8 led matrix LDP-8008
# By Pete Goss 14/1/2014
###################################################
# connect Raspberry Pi GPIO to J1 on LDP-8008
###################################################
# GPIO pin       LDP-8008 pin
#      3  ------------>  2  A (Row address)
#      5  ------------>  4  B (Row address)
#      6  ------------>  5  GND
#      7  ------------>  6  C (Row address)
#      8  ------------>  7  EN (Enable Display)
#     10  ------------>  8  D (Row address)
#     11  ------------>  9 \R1 (Red Led)
#     12  ------------> 10 \G1 (Green Led)
#     13  ------------> 14  L (Latch)
#     15  ------------> 16  S (Shift)
###################################################

Also helpful is GPIO pin layout (Physical numbering from GPIO site)





Step 4: Install node.js and some packages.  Again more magic.  Once you are running headless and it is connected to the internet.  Type the next 2 lines
wget http://node-arm.herokuapp.com/node_latest_armhf.deb
sudo dpkg -i node_latest_armhf.deb
This installs node.js ready to run on you Pi.

The next 2 lines install packages using the node packaging tool you just installed.  express is a lightweight html server that among things allows you to build static web pages and the json API's.  nconf is a package that helps with configuration - mainly so we don't have to hardcode some information into our code.
npm install express
npm install nconf –save

Step 5: Deploy the folder src, and its contents to the Pi.
  • Get the src zip from my google docs.
  • Expand it 
  • Create a directory so you have the structure home/pi/led/
    • If you don't have this structure the node server will not work correctly.  You will need to adjust the configuration files.  See details below
  • Copy the src folder across to your Pi under the led folder
    • I use Filezilla for this - see Trevors blog for more detail.
Step 6. Start up python file monitoring and node js to receive http commands.  This is where we actually can start to see something cool!

As shown in the diagram, you will need to open 2 separate windows and enter 2 commands from specific directories
  • Go to the directory home/pi/led/src and type sudo python pi_interface
    • This starts the monitoring of the home/pi/led/src/messages directory for json files with instructions for the LED Matrix
  • Go to the directory home/pi/led/src/node and type nodejs app.js
    • This starts the node web server ready to receive json posts which it will then put in the messages directory for processing by python process we just started.
    • It also makes any web pages under public viewable over port 8080


Running the LED Matrix

Use the archived files (or create your own)

If you look in the archive directory of the files you have deployed on your Pi, there are a set of files (which I explain later).  By simply moving the file up one directory level to messages, the running python script will process the file, move it back to the archive directory, and start presenting the message.

Run python unit tests

I use PyDev, and a plugin for eclipse, which combined has a very simple way of running unit tests.  I do all my coding and testing on my local machine.  The test_node.py is a unit test which I can run locally, either to test the node server (which I also run locally), or using the ip address of the Pi to run it there.

Create your own services

This is really what I did all the work for.  Simple application/json http posts can drive the entire display.  So from any device that has access to your network, you can display messages.  See What is it for below for a detailed explanation of what I want to use it for.

Delete messages

Go to http://<ip adress of pi>:8080/app.html and a simple web page will list messages on the Pi.  This is really not meant to be application grade functionality - but just show using express to create web site functionality. 

Next version

Now I have built an easy way to delete messages, a full blown website to create messages is the next logical step.

What is it for

I have had so many idea's - if you have others, feel free to post them :-).

Managing alerts at work

Imagine you are in a support role and you get e-mails when there is a system issue.  How about the LED Matrix sitting on the wall in front of everyone suddenly lights up with the issue.  That makes it more visible.

Developers and testers often have similar devices such as sirens and flashing lights for when a developer breaks the build.  With this, you can name and shame then in lights!

Managing your mornings

I drop the kids off to school some mornings, and I catch a Tram to drop them off.  How great would it be to have the "next tram" times coming up in your living room!  Sometimes while making lunches, refereeing fights and trying to read the paper, actually having a spare hand to check the phone is not an option.

Sad to say not everyone agrees that an LED would look good as a centrepiece in our living room - but I am hopeful someone out there will have better luck than me..

Obviously this is Melbourne (Aus, not US) specific, but I am sure there are a similar service for many cities around the world)

Cheering up a weary project

We actually used it for a project countdown at work (thus one of the functions) which meant each day the "number of days left" on the project automatically ticked over.  We also showed a joke of the day to keep spirits up, but I didn't automate that - next time.

Sending messages home

I often get the SMS around 5pm "ETA".  If I knew it was going to be displayed on an LED matrix, I reckon I would send it pro-actively each day - now that would be handy.  Another great idea that I am sure will not see the light of day at my house..

And......

So many more....  using the display functionality you could manage multiple devices that needed monitoring (thinking of the networks guys here).  Honestly the list is endless...

Further details about the solution

Intention

When I first started coding, my intention was that you would send the LED matrix messages in a queue and it would rotate the messages until they were deleted.  I only ever built a clear all messages function, and never a delete individual message.  So the ability remains to continually add messages, but only the ability to delete all messages being played.  I am intending to implement that functionality with the web front end in the next version.

The deployed files

The following files are in the src file that is deployed on the Pi for this solution.  I will go through all the src files before I go into the sub directories.

Contents of the src directory

config.txt: contains references for message and archived message directory, as well as the base URL for the tram tracker functionality.
fontv.py: provided by Pete Goss to write ascii characters.  I found it wonderful to understand and can highly recommend looking at it for its simple ingenuity.
ldp.py: provided by Pete Goss to interface with the GPIO on the Pi driving the LED matrix.
pi_inteface_mock.py: A very simple emulator for the LED matrix when testing code on your local machine.  It was not built to emulate the LED matrix functionality, but actually test the functional code before I start using it to drive the LED matrix.
pi_interface.py: This is my real thievery.  I have taken Pete Goss's work and "functionalised" it for my own needs.  Running this now starts a thread that instead of taking direct input, polls a directory looking for messages of a certain format.
test_node.py: unit tests that can be run which send http post requests to a node server running the node_server.js in the src/node directory
messages (directory): Where the python looks for message files to process
node\app.js: The extensive amount of coding required to set up a http receive port using node.  Note my sarcasm with the word extensive...  It also invokes express which does some of the web server heavy lifting.
node\conf.json: Directory configuration for the deployed code.  Development is not done on the Pi and directory structure is different bewteen local running and running on the server.
node\public\app.html: Simple web page for deleting messages on the queue of the Pi.
node\public\js\jquery-1.11.2.min.js: For talking between the web page on the browser client and the node server, jquery makes it all very simple.  The code in app.html uses this library.
pi (directory): Standard python structure for a package.  The majority of my work (versus Pete Goss's work) is done here. All the polling, interpreting of json, and some utils I wrote (probably unnecessarily)
pi\__init__.py: standard pi file for a package.
pi\Display.py: most of my work.  Pythons ability to pass functions made it easy for me to separate Peter's work from mine.
pi\utils.py: simple helper functions I built while coding this solution.  If you are an experienced python developer, you would probably know of existing/better ways to do this stuff.
messages\archive: sample messages to drive the Pi.  Most of them are (hopefully) self explanatory, but I will explain 2 of them
messages\archive\TramResponses.txt: using developer tools in any browser, I looked at the network traffic to get the responses from the tram requests, so I could figure out how to parse the results for the information I wanted.  This is just a couple of the responses I received.
messages\archive\n_display.txt: The only sample file that is not easily self explainable.  I have explained below in its own section.
messages\current\msg.json: This file is written every time the message array is changed.  The Node server on a /led GET call returns this data so the web page knows what is being displayed on the Pi.

Creating personalised displays

Because creating your own display may take a lot of instructions, I have kept the json as brief as possible.  To start with you need to know that the LED is represented by an array, [0..79] of [0..7], each containing one of 0(off), 1(red), 2(green), 3(orange) being an 80x8 matrix.

The data element for the json works like this (apologies if you are looking on a small screen):

[ [ [[x,y,z],[x,y,z],[x,y,z]],t], [ [[x,y,z],[x,y,z]],t] ]
  1 2                       2  1  1 2               2  1

  • It is an array of instructions
  • Each instruction (1) contains 2 elements
    • An array of switches (2)
      • x = [0..79] position
      • y = [0..7] position
      • z = colour (0=off, 1=red, 2=green, 3=red)
    • t = the length of time it should hold the current configuration
Knowing this, have a look at the n_display.txt file now, and the heartbeat video further up the page and you will figure it out.




17 comments:

  1. Have realised the error - hadn't installed node Js. All working now though. Thank you.

    You mentioned that you wanted to use the screen as a live message board. I have been trying to get the script to pick up a Gmail subject line and display that Then check for a new one every five mins or so. All working, except for the five minute updates. Is this something you would be interested in helping with?

    Email me if so, and I can share my ghastly Frankenstein scripting!

    Thanks again,

    Dan

    ReplyDelete
  2. Oops, my previous message has vanished. I was struggling to get this to work. And my email address is dan.allton@gmail.com

    Thanks again

    Dan

    ReplyDelete
  3. Hey Dan,

    Think about https://ifttt.com/ to send a message to the pi instead of polling.

    I am also interested if you have google connecting code using oauth - I have never tried to do it and I think it would be useful - attach the code snippet if you feel like sharing.

    Your question also made me realise that I was doing my tram polling incorrectly, so I have coded a solution for you which I will use in my next release.

    1. create a test file in the archive directory n_poll.txt with the line (poll frequency is in seconds)
    {"messages": [{"type":"poll","current_message":"not polled yet","colour":1, "last_polled":0, "poll_frequency":3,"hold":0.5}]}
    2. Add the following lines into the play_messages function in the Display class
    elif x['type']=='poll':
    x = self.poll(x)
    3. Add the following functions to the Display class - where the function poll_message simply returns whatever you want in the message - you can place whatever code you desire in here!

    def poll(self, msg):
    do_poll=False
    try:
    if (time.time()>(msg["last_polled"]+msg["poll_frequency"])):
    do_poll=True
    except:
    #first instance will fail
    do_poll=True
    if do_poll:
    msg["last_polled"] = time.time()
    msg["current_message"] = self.poll_message()
    self.scroll(msg['current_message'], msg['colour'], msg['hold'])
    return msg

    '''
    Put your function here!
    Returns the message you want displayed polled based on
    poll_frequency in seconds
    '''
    def poll_message(self):
    return str(time.time())

    Good luck and thanks for actually trying out the code. My next release will have a web front end to manipulate what is playing...

    ReplyDelete
  4. I'm new to the Pi and Python. So I need a little help.

    I want to be able to be able to display the date and time but I don't really know how to do it.

    I understand that for custom messages, I would input a text file into the archive directory. Then if I want to display, I just drop it into the messages directory.

    What would the code be for date and time?

    I'm in my second year of C++, so I can understand some of the code, but I'm still lost.

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. Yay! I figured it out. Thanks for this guide!

      Delete
    3. excellent - best way is figuring out yourself. thanks for the idea though - I have added a clock to my own suite of displays!

      Delete
  5. Is this blog still current?
    I get to "npm install express" and I get a can't find message?
    Anybody else get this?
    Help please!

    ReplyDelete
    Replies
    1. it should still be relevant. The only reason it may not work is if node.js did not install properly? Did it install properly?

      Delete
  6. This comment has been removed by the author.

    ReplyDelete
  7. Thank you for this page Rod!
    It was a lot of fun getting this working on my Raspberry Pi 2. The only adjustment I had to make was in the installation of Node.js on a Pi 2.
    (source:http://nodered.org/docs/hardware/raspberrypi)
    (source: http://thisdavej.com/beginners-guide-to-installing-node-js-on-a-raspberry-pi/

    I added the installation of a feedparser which I use in Display.py ("sudo pip install feedparser"). It allows me to grab and parse RSS feeds. From there almost any information can be displayed from local weather to the various build statuses of a build server (as you mentioned above).

    Regards,
    Eric

    ReplyDelete
  8. Hello Rod
    I also had lots of fun getting this working on the Raspberry Pi 3.
    Love the pacman message! great work!

    I added time.sleep(0.01) at the start of the shiftmatrix(matrix) module in pi_interface.pi to slow down scrolling text so it was easier to read.

    I couldn't get the n_display.txt heartbeat to work, I get this error:
    Traceback (most recent call last):
    File "pi_interface", line 282, in
    display.run_matrix(static, scroll, display_pattern, cylon, pacman)
    File "/home/pi/led/src/pi/Display.py", line 47, in run_matrix
    self.play_messages()
    File "/home/pi/led/src/pi/Display.py", line 59, in play_messages
    self.display_pattern(x['data'])
    File "pi_interface", line 181, in display_pattern
    matrix[y[1]][y[0]] = y[2]
    IndexError: list index out of range

    Any ideas to fix this?

    Thanks again for sharing such a brilliant piece of work!

    PeterMoore
    England, UK

    ReplyDelete
    Replies
    1. Ahhh OK I figured out how to use n_display.txt using the x,y,z instructions above -if only I had read the instructions! thanks again!

      Delete
    2. glad you liked it. good to know the 3 also works! I need to get back into some of this fun....

      Delete
    3. Is the source code of this project for Raspberry Pi 3 available?

      Delete
    4. https://drive.google.com/drive/u/0/folders/1-aXBWcn4sSpl4UDd5D4mcXa201zAh9Ra

      I think I deleted the src code in a fit of cleaning up - apologies. I haven't tried it on a later Pi than in the article (or even looked at it in years - but its all pretty common libraries - may need some tweeking for python 3.

      Delete
    5. Thank you very moch Rod. It is a very interesting project.

      Delete