jo-ruether / led_table

LED table
5 stars 0 forks source link

LED Table

This repository contains software to drive games and apps on a 12x12 Matrix of WS2812B-LEDs. It handles different inputs such as USB hardware or Telegram bots and displays the output on a real LED matrix or a simulation.

  1. Features
  2. Project description
  3. Setup
  4. Developer's Guide

LED Table with controller

Features

Project description

Games and programs

Spotify Pong
Clock Tetris
Snake Colorfade

Hardware architecture

A Raspberry Pi Zero W is used to control the table and to manage user interactions. The small single-board computer with a footprint of only 65mm x 35mm lets you hide the control unit in a small box unobtrusively attached to the table. Despite of its size it features a fully functional Linux system perfectly fitted for Python scripts while providing necessary interfaces like wireless LAN and USB.

Hardware architecture

Software architecture

There are different kinds of classes making up the software as a whole. Each program part has its own function and each part can be (de-)activated separately (excluding core). main.py starts up to three threads and creates the instances of the core classes.

Sotware architecture

Application

The main thread executing the games has its entry point in Menu.py. Besides printing the game's icons, the Menu class also starts all other games and then waits for their return. The application thread is mainly manipulating the output matrix.

Core

The core modules are simply class instances passed to the threads. Note that there are no threads wrapping the core modules.

The Postman handles the communcation between the threads.

The ConfigHandler provides read and write access for all program parts to the central config file.

The Output is a intermediate layer for writing Pixels to the table. There are two different output classes available in the submodule output. Either the hardware table is controlled or the output can be redirected to a simulator.

Input Classes

Currently there are two ways of receiving user input. Either a game controller can be attached to the Pi via USB or commands can be send to the table via Telegram. Just call the TelegramBot running on your table (every table needs its own Bot id) and he/she/it will explain everything to you.

Both input classes publish input events via the Postman.

Setup

Dependencies

If you use conda, you can create an environment with all the necessary packages using the environment.yml file:
conda env create -f environment.yml

Setting up the Telegram Bot

Create a new Telegram bot using the Telegram's BotFather. It provides you with an individual token that allows you to access messages that are sent to it. In order to control the LED matrix using this bot, insert the token into the config file. In Telegram, address the bot by the handle that you chose at bot creation to send it commands.

Setting up the Spotify Connection

In order to use the spotify functionality, create a spotify web app using the developer dashboard. Insert the provided client id and the client secret into the config file. In the settings of your newly created app, add a redirect URI such as https://www.google.com and paste it into the config file.
At first use of the Spotify app on the table, users click a link and login to their Spotify account. After pressing "Authenticate", they get redirected to the specified URI and an authentication code appended to it. Users are asked to paste this URI with the included code into the bot, allowing the table to interact with Spotify on the user's behalf.

Setting up the USB Gamepad

The hardware address of the controller should be persistent (using udev rules). Then, usb input can be enabled via the settings file. The necessary keys are already part of the config template config_sample.json.

How to make usb address persistent

  1. Plug in USB device
  2. Collect information about device
    • Find device in lsusb
    • Gather more information with sudo lsusb -vs <BUS>:<DEVICE>, for example sudo lsusb -vs 002:017
    • Best suited for udev rules are idVendor, idProduct and iSerial (if available) For the USB SNES Gamepad I find:
      • idVendor 0x0810 Personal Communication Systems, Inc.
      • idProduct 0xe501 SNES Gamepad
  3. Write udev rules with root editor in /etc/udev/rules.d/
    • Use comments and prefer a high-numbered file name, for example 73-gamepad.rules
    • Write udev rules. SUBSYSTEM=="input", ATTRS{idProduct}=="e501", ATTRS{idVendor}=="0810", SYMLINK+="gamepad", OWNER="<USERNAME>"
  4. Unplug and reconnect the controller from the Pi. Now, you should find a device named /dev/gamepad. You can test it with cat or simply activate this controller address in the table's config. Have fun!

Notes: It may happen that the user doesn't have read access on the created symlink. If that happens, add the OWNER attribute. For debugging you can use sudo udevadm test /sys/class/input/eventX.

Developer's Guide

The python PIP guidelines are followed.

Naming convention

Use under_score_names, not CamelCase.

Pixel addressing

The origin of the LED Matrix is located in the upper left corner starting with position (0,0). It is most intuitive to think of a mathematical matrix and therefore use row and col indices. Clearly speaking, don't use x-y coordinates as this could be confusing. Contrasting to our addressing convetion, coordinate systems usually set their origin in the bottom left corner and the first index is along the horizontal axis.