I'm not much of a gamer. When I was a kid, I was more interested in seeing how they worked than I was in playing them. I can count on one hand how many arcade games I regularly played. That being said, it would be easy for someone to find it odd that I would take the time to build an arcade controller. However, it is one of my favorite projects to date. In addition to being challenging to design, code, and build, it is also a reminder of a past era of sturdy mechanical buttons and joysticks.
Gone are the days of the Arcade but you can still have the feel of a classic arcade game right in your own living room. So, here I present to you the Lapcade. If you are like me and enjoy building stuff more than playing, you might enjoy this build. If you have any questions or suggestions not included in the "ideas for version 2" section below, please leave a comment.
Step 1: Overview
What is this thing?
First, please note what the Lapcade is not:
- It isn't a gaming console.
- It has no games nor does it have the ability to load and play games.
- It doesn't connect to a TV or monitor.
The Lapcade is a Bluetooth keyboard. Nothing more, nothing less.
I bring this up because there has been some confusion around this point. I've had a lot of questions about what games can be loaded on it and what kind of video interface it uses - it can't and doesn't! It is entirely dependent on the PC you connect it to and, in that regard, the sky is the limit. If your device can accept a Bluetooth keyboard, then the Lapcade should work with it. I haven't tried it but I've seen other projects that have used the EZ-Key (described below) connected to handheld devices. So, theoretically, you can connect this device to any computer running Windows, Linux, ChromeOS, MAC, etc. as well as Raspberry Pi, Android, iOS, and others that support Bluetooth v2.1. Modification of keycodes may be required, however.
Originally, I found a product called the Adafruit Bluefruit EZ-Key bluetooth HID (Human interface device - think keyboard) that would allow me to connect familiar clicky buttons and send keystrokes like a keyboard. When I first built out a controller based on the EZ-Key, I followed a set of instructions to build a simple and straight forward controller and it worked great. I used the controller in a heavy wooden frame without issue for a few months. However, you are limited to 12 inputs and there is no way to change the keycode transmitted by the device without reprogramming the EZ-Key input pins.
As I was using my Kodi media center to display installed games, I wanted to switch between controlling the media center and game play without having to use multiple controllers / remotes. I also wanted to have the device adjust so my left handed son could use it as he liked.
I was also using 4 AA batteries to power the device and out of the box it didn't appear to have a low power mode. Batteries would be sucked dry in a day or two even if it wasn't being used.
So, at the urging of a friend of mine, I decided to build a programmable version of the same controller that had quick mode changes, would allow me to use the same device to control multiple applications, could also be "flipped" for left hand use and was in a laptop case that was far less than my current 10 lb solution.
It was time for an upgrade.
Version 1 Design
- For Lefties and Righties
- No cords
I wanted this new design to be flexible. The controls need to be changeable on the fly without having to reprogram the components every time a test or change needed to be made. This meant that there needed to be an interface on the controller to choose "modes" of operation. Each button and joystick position would need to have different key-codes associated with it. Those same controls would also need to be used to select the different modes too.
The EZ-Key was not directly programmable in real time so the next solution would be to use a controller like an Arduino to manage functionality. The EZ-Key would solely be used to transmit the keycodes to the PC over Bluetooth. I chose the Arduino Pro Mini due to it's direct compatibility with the UNO (which I already had experience with) and due to it's compact size.
I didn't want to deal with batteries with this new box like I did with the Lapcade's predecessor so, I chose to use a Lithium Polymer rechargeable battery and charger/supply board. This meant that I could just use a standard USB charger. It also meant that I wouldn't have to open the case each time the batteries died. The EZ-Key and the PowerBoost 500C both have indicators that needed to be transferred to the top of the controller for pairing status and low battery indication. I added some LEDs to the design so that I could reflect these handy status indicators to the user during operation.
As testing of my design matured, I discovered that several of my original ideas were not as I had expected. For example, the LBO indicator on the PowerBoost doesn't work as expected when tied to a microcontroller. It will allow current to pass through the common ground from the battery while the device is "off" or disabled, the LBO light will light and stay lit. Others in the Adafruit forum had encountered this issue as well and offered a better solution in sampling the battery voltage directly on an analog input. Once the voltage drops to a certain level, it is time to let the user know that the battery is about to shut down.
Step 2: What You Need
Electronic Parts List
This wound up becoming a fairly complicated build. You don't have to use the same parts I did but if you use a substitute part, make sure you understand how it will interact with the other circuits and code. While I'm happy to offer suggestions, I can't help troubleshoot code or issues for different configurations.
1 Arduino Pro Mini 5V - I like the Pro because it is compact. You can use any Uno pin/interrupt compatible board with the code provided
1 Adafruit Bluefruit EZ-Key bluetooth HID - As described above, this is the bluetooth HID that allows keycodes to be transmitted to the host PC.
1 MCP23017 - i2c 16 input/output port expander -This chip is used to add 16 more inputs to the Arduino through I2C communications protocol
1 Adafruit PowerBoost 500 + Charger - This is the power control board for powering the Lapcade and charging the LiPo
1 Litium Polymer battery (I used 2500mAh, but you can use higher / lower capacity)
1 8-Way Arcade Joystick - Please see the "thoughts for version 2" section below concerning joysticks
9 Arcade Push Buttons - Assorted colors and screenprints
1 Illuminated latching pushbutton I used this for the power button from Adafruit: Green
2 LEDs Used for referencing pairing signal and battery low. I used two RadioShack parts 2760270 and 2760271
1 16 x 2 LCD screen
1 I2C/SPI LCD backpack - Used for I2C communication to the 16x2 display.
1 Panel Mount USB extension cable - Used to extend the PowerBoost's micro-b USB connector to the cabinet wall.
1 Adafruit Perma-Proto Full-sized Breadboard PCB - Not necessary but makes permanent mounting so much easier.
5 220 Ohm Resistors
7 1K Ohm Resistors
2 2.2K Ohm Resistors
1 4.7K Ohm Resistor
18 #10 Female Spade Connectors - For connecting to the arcade button contacts. Recommended over soldering as the buttons will eventually wear out.
22 gauge hookup wire - I used solid hookup wire rather than stranded in order to make free standing wire management. This was purely for demonstration purposes and is not recommended as solid wire is brittle and prone to breaking.
The following items are not required but will make mounging simpler and, in the event you toast a component, make replacement easier:
- IC Socket - for 28-pin 0.3" Chips
- IC Socket - for 28-pin 0.6" Chips
- 0.1" Female header (at least 1 36 pin header)
- 3 12 x 24 1/8th inch birch panels
- 1 12 x 24 1/8th inch clear acrylic panel
- Lapcade V1.xlsx - The spreadsheet mentioned below that has the circuit connections.
- LapcadeV1-code.zip - Zip file containing the Arduino code written for this project.
- Lapcade_v1.zip - Zip file containing the svg drawings for the cabinet.
LapcadeV1-Circuit_Diagram_Large.zip - Zip file containing a high resolution version of the fritzing circuit diagram shown below.
Links to more resources:
Step 3: Assembly - The Cabinet
I wanted to have a very light weight box that could also take a beating. Without getting too exotic with materials, lightweight equals thin and thin usually equals brittle. The primary user of the Lapcade would likely be my young son who likes to "press" the buttons and "navigate" the joystick with extreme enthusiasm. While he's good about not dropping things, he did manage to wear out the industrial micro switches in one joystick within a few months.
To overcome this issue and since the Lapcade is 20" wide, my design added in two vertical ribs that secures the top and left and right sides. During dry fitting the design was able to withstand 70 lbs of books placed on it. Once glued, the box became even more durable. After receiving the cut materials, I initially loose fit all of the panels together to make sure they worked. I then lightly sanded them and air dusted. I used wood glue to attach the pieces together.
The books in the photos below were placed to put pressure on the freshly glued pieces until they set. Once the glue cured, I smooth sanded the edges. My design intentionally offset the panels so they would stick out a bit at the corners. This would allow me to round out the corners during sanding without getting into the joint too much.
After cleaning the surfaces, I then applied several coats of polyurethane - allowing to cure between coats. The result was a lightweight wooden box with an acrylic bottom cover. I had originally wanted an entirely clear box but when he sent me the birch "test" parts, I immediately changed my mind. It was not only lighter, it was a nice throw back to the idea of cabinet gaming. The svg files are below.
Please Note: This is a multi-layer drawing and each layer represents one set of cuts on one sheet of material. When sending a print to your cutter, make sure that all of the other layers are hidden before cutting.
Another Note: When I drew up the area for the LCD display, I used a display I had on hand for measurements. Between the time I made up the drawing and later fitting the parts in the case, I had used the original LCD in another project and ordered a replacement. As it turns out, the mounting holes for the second one were slightly different than the original and wound up not lining up. So, take care before cutting your material to double check that the parts you have fit the holes in the drawing.
A Third Note: I did not include a cutout for the USB charging cord in the original drawing simply because I wasn't sure where I wanted to put it so it would not interfere with use. I later cut the holes for it on the left side very near where you see the word "Lapcade" in the images below. Version 2 will have the charging port in yet a different position. :)
Step 4: Assembly - Electronics
First let's take a look at the wiring diagram shown above.
First thing to note here is that the power and ground rails of the breadboard. The rails with the blue line are ground (-) and the rails with the red line are power (+). This is standard but I'm making a note of it because the common line of the joystick (black wire) is connected to power and not ground. In Fritzing I used the wire color of the joystick rather than the convention color and thought that might cause some confusion - so best to just get that out of the way.
Rather than try to state every connection in long form here (Arduino analog pin 0 goes through a 220 ohm resister to the PowerBoost Bat pin), I created a spreadsheet that contains all of the connections from the point of view of the component. So, on the Arduino tab of the spreadsheet, you'll see APM A0 -> 2.2K OHM -> PB Bat and on the PowerBoost tab you'll see PB BAT -> 2.2K OHM -> APM A0. Please see the resources section below for all of the files associated with this project.
One other note about the spreadsheet is that some devices show two connection columns. This is to show more than one connection to a pin. For example, each of the joystick connections except the common wire uses a pull-down resistor to ensure that the port extender receives a solid high or low signal. To show this for Joystick 2, you will see two columns for connection one being for the joystick wire to the MCP 21 pin and the other for a connection from pin 21 through a resistor to ground. I'm sure there are better ways to document this but I'm afraid you're stuck with my ways of doing things on this one. :)
Each of the arcade buttons have a common (com), a normally open (no) and normally closed (nc) contact. For each of these buttons, I am using com and nc connections.
Step 5: Code
First and foremost, I need to give credit where it's due. I relied heavily on the following article to code the Lapcade:
https://learn.adafruit.com/convert-your-model-m-keyboard-to-bluetooth-with-bluefruit-ez-key-hid Special thanks to Benjamin Gould for a well written and documented project!
So, at the heart of this project is a keyboard. From the point of view of the PC, the Lapcade is simply a keyboard connected via bluetooth which is what the EZ-Key is so good at. It takes the complicated Bluetooth protocols, timings, and codes and encapsulates them so that all I need to do with the arduino is send it keycodes. To do that, I used the code maps in the project above and my own arrays to create operational modes. Each mode changes what the same button presses do on the Lapcade and what gets sent to the PC. There are three "built-in" operational modes and all of the modes after those are application modes.
The following summarizes the operational modes of the Lapcade:
- Startup - This mode checks for connectivity with the PC and sets startup variables. If the EZ-Key isn't paired with a PC then it changes to Pairing Mode
- Pairing - In this mode the EZ-Key is waiting to be paired to a PC.
- Mode Select - This mode allows the user to select which application mode to use. No keycodes are sent to the PC in this mode. There are also quick mode selections based on the previous application mode. For example pressing mode and then the player two button when in Mame player 1 mode simply switches the mode without having to search and select Mame Player 2 on the display.
Application modes are used to send appropriate keycodes to the pc based on which application the user is in. For example in Kodi mode the action 2 key sends "P" which is pause. In Mame, that same button sends the left Alt key. If one wanted use the controller to play Minecraft for the PC, then all that would need to be done is add the appropriate array maps.
Each application needs to be defined in 4 arrays of data.
- mode - This array contains the text that will be presented on the screen for each mode. To use the second line of the display, simply place a ~ in the array as a line break.
- keyModes - This matrix array contains the keycodes sent to the PC. Each line of 14 elements represents individual buttons to keycode mappings.
- keyModifiers - This matrix array contains the keycode modifiers for each keystroke such as holding down the shift key.
- quickMode - This matrix array contains the quick mode selection pattern for the current mode.
When the system is turned on it goes into startup mode where the status of the Bluetooth connection is checked and displayed to the user. The Arduino gets the status of the EZ-Key from counting and timing the pulses from the EZ-Key's L1 pin. There are four sub-statuses for startup mode:
- Pairing - The EZ-Key is in active pairing mode waiting to attach to a device.
- Paired but Not Connected - The EZ-Key has been paired previously but is not currently connected to the host device.
- Paired and Connected - The EZ-Key is paired and the connection has been established with the host. At this point, the system will move on to Mode Select.
- Unknown Status - The EZ-Key is returning an unknown code or there is signal interference that is producing an unknown signal pattern. System will hold and notify the user. Must restart if this occurs.
If the system is paired with but can't connect to the PC, the system will stay in connecting state in startup mode. If the user holds down the escape button while turning on the device, it will skip the Bluetooth connection check and proceed to Mode Select.
If the system has not been previously paired, then Startup Mode will be succeeded by Pairing Mode. In this state the system will broadcast that it is available for pairing. Once it is discovered and attached to by a host, it will move on to Mode Select. The device can be unpaired in Mode Select by pressing the Action 1 button.
In Mode Select, the up and down joystick actions will move you through the available application modes on the LCD display. To select one of the modes, press the enter button (center 5).
Once in an application mode, each of the buttons and the joystick will send keycodes per the keymaps specified in the four arrays as described above.
Once an Application Mode has been selected, it's quick mode definition is set. Put simply, Quick Modes are the Application Modes selectable by the first three center buttons (Center 1-3). These three buttons correspond to the array element across in the matrix.
For example, in the current configuration, when using Mame in player 1 mode (Mode 4 or the fifth mode defined), then pressing the mode button and then the player two button loads the quickmode  array element (Arduino uses 0 base array indexing) which is 5. The system then switches to Application Mode 5 which is Mame, player 2.
Step 6: Ideas for Version 2
Button Display - I guess you can't plan everything but there is one design idea I wish I had early on for version one - individual button LCD panels. It became clear very quickly after building that just knowing what mode you're in doesn't mean you remember what each button does - especially after you've stepped away from it for a couple of days or months. I really wish I had added some kind of small display on or above each button that showed what its current action is. This one is at the top of my list for version 2.
4-Way vs 8-Way Joystick - Another thing that became clear once I began using the joystick was that older games were not meant to use 8-way joysticks. Case in point is pac-man. Since building this controller, I have found that there are joysticks out there that are capable of being switched mechanically from 4-way to 8-way. Yep, that one is on the list and if you are planning on playing classic arcade games, then just skip to one that is changeable. Of course, make sure that you account for the changes in wiring and programming based on the joystick you wind up with. Here are some suppliers of classic arcade controls:
Right & Left Side "Flipper" Buttons - Version 2 will definetly add one button each to the left and right side of the cabinet. One possible use will be for pinball flippers.
Other Controls - I'm looking at the viability of adding other common controls like a trackball and / or a spinner to the next version. Since the EZ-Key is capable of transmitting mouse coordinates, this shouldn't be too difficult.
On-Board Programming - The next version must have the ability to add new configurations without cracking open the case. I wanted to add this to version 1 but it required more time and resources than I had.
Second Prize in the