The PortaBrick Arcade is a fully functional portable arcade game console made of 100% LEGO® and Python/MicroPython. The project originated from a university project and is now available for voting as a product idea on LEGO® Ideas.
Yesterday it finally worked out: One of my MOCs was approved on LEGO Ideas! My first Ideas project is up and running! Time to introduce the PortaBrick Arcade here as well.
The PortaBrick Arcade is a fully functional mobile arcade game console built entirely from LEGO® bricks. The PortaBrick Arcade consists of 432 components and weighs around 520 grams including the battery. The software is based on the Pybricks project.
The game console has two large mechanical input buttons based on pressure sensors, which are used for game control. The four buttons on the central unit, which also houses the microprocessor and battery, are used for menu control. The PortaBrick Arcade has two displays. The upper display can show millions of colors and is made up of four individual modules á three by three pixels. The total resolution is six by six pixels. The lower display is integrated into the central unit and can display five by five pixels in monochrome. On the back of the device is a flap that provides access to the micro-USB port for firmware updates and battery charging.
The software of the PortaBrick Arcade includes the menus and their flow control, a driver for the upper display, a pixel image library and two games. These are conversions of the arcade classics Snake and Pong. Basically, the PortaBrick Arcade can be extended by any games, as long as they do not require a higher resolution.
I wrote the software in MicroPython. The individual components are structured in classes. The code I wrote – where it was appropriate – object-oriented. The remaining parts of the games as well as the menu navigation were implemented procedurally. To extend the selection of games, programmers can access the classes. All code components are extensively documented. The complete source code of PortaBrick Arcade and Pixel Art Painter is published in a GitHub repository under the MIT license.
There were two challenges in developing the PortaBrick Arcade: First, I needed a driver to power the aggregate display of four individual ColorLightMatrix modules. Second, it became apparent during development that I needed some sort of multitasking or multithreading.
Multi Matrix Driver
The first challenge in the project was the development of a driver that allows to control a display formed by any number of ColorLightMatrix modules. The difficulty was to translate given coordinates in a way that the correct matrix module is addressed. In a first approach I used if-then-queries, which converted the x- and y-coordinate depending on the given display size. However, this solution was too inflexible. For each configuration of the display I would have had to create new conversion functions and add them to the driver. Therefore I decided to find a mathematical solution.
In total I needed three equations to calculate the three unknown “New x”, New y” and “Module ID”. In a combination of trial and error and setting up equations, I arrived at a working result after some time. The equations are:
(1) x_new = x mod 3
(2) y_new = y mod 3
(3) module_id = ⎣y/3⎦* x_max +⎣x/3⎦
With the help of the three equations it is now possible to drive an arbitrary rectangular display of 3×3 pixel modules. After I found a solution for the pixel-accurate calculation, I gradually developed the functions for displaying the content. Currently the following functions can be used with the driver:
- Control of any pixel in any color
- Switch off any pixel
- Displaying a pixel graphic in any color
- Switching off the entire display
The MicroPython implementation in Pybricks lacks (on the LEGO Spike PrimeHub) the possibility to work in threads, i.e. to process instructions simultaneously or in parallel. This led in my implementation of the games to the fact that the state of the input buttons was read only once per loop. In the break between the program runs, no input could be read out. Therefore, the players had the impression that the game console reacted delayed or not at all to inputs. You had to wait for the exact moment of the readout to see a reaction on the displays.
After research, I found a solution in the use of so-called generators. I used an example from the Pybricks community. Generators in Python are special functions. Unlike traditional functions that return a value and finish the function call, generators can return multiple values in succession, then stop and resume at a later time to generate the next value.
Generators are defined in Python with the keyword “yield” instead of the “return” statement used in conventional functions. The “yield” statement returns a value and freezes the current state of the function. Each time the generator is called, the next value is generated and the generator runs until the next “yield” statement. In this way, generators can produce values step by step without taking up all the memory at once.
In the PortaBrick Arcade games I use the generator principle for a non-blocking wait function. Non-blocking means that only a single function call waits and the rest of the program flow can continue unhindered. Per game, this type of non-blocking wait occurs exactly once. I use the function to control the game speed by slowing down the core function of the respective game. The remaining functions like input recognition or drawing the screen content run unbraked with the execution speed of the microprocessor. The game speed can be set via variable. In this way, it is possible to recognize and process the inputs via button at any time.
Besides the multi-thread programming I used other individual solutions. So I changed the behavior of the big central button. In Pybricks as well as in the LEGO Spike Prime firmware this button is used to switch on and off, to confirm the selected program and to cancel the running program. I put the cancel function on the button marked with the Bluetooth symbol in the upper right corner. This way I was able to integrate the central button into the menu control. It is now used to confirm the entries in the dialogs of the menu.
Regardless of the outcome of the LEGO® Ideas vote, here’s what I have planned for the future of the game console: