Game Controller V2

This is my make-through for a higher fidelity prototype version of the game controller so let's see what's different this time!

Process Map

Project Ideation

Background

We Are Back

We are here with a new version for our game controller prototype. We'll be attempting to upgrade it to something pretty close to a ready-to-release version of a product. For instance, instead of using breadboards and wires, we'll be using a printed circuit board which will provide a much cleaner look and a more permanent assembly. We'll also redesign our console to include 3D printed parts for the complex parts of the design like the curved edges we previously created with living hinges. It'll be more durable and it'll look much better. There are a few other modifications we'll see along the way but overall the functionality of the game console will remain the same.

Game Console Upgrade

Components and Tools

What Will We Be Needing Here?

We'll be using mostly the same components we used previously but with some few modifications. So here is all we'll be needing:

We'll also be using:

Machines:

  • A laser cutter

  • A 3D printer

  • A PCB milling machine


Software programs:

Note: Not all of the components above are actually required since I went through more than one attempt and some of the components were changed with every attempt but anyway, we'll know more about that as we go.

Electronic Circuit

Let's First Figure Some Things Out

Why ATtiny85?

So in the first game controller prototype, we used an Arduino Leonardo and mentioned that the reason we chose the Leonardo over the UNO even though the UNO is a more popular board was that its chip, the ATmega32u4, allows it to act like a USB mouse, keyboard, etc... So why are we using the ATtiny85 now instead of the ATmega32u4?

The ATtiny85 is smaller and less expensive but that's not really why we chose it. The main reason we went with the ATtiny85 was because the ATmega32u4 isn't actually available in the market here. The ATmega32u4 would have made things easier if we used it since it has 26 GPIO pins compared to the ATtiny85 which has only 6 GPIO pins. The ATtiny85 is a good chip for very small jobs like reading three or four inputs and deciding what output to produce. However, we have more than just 4 inputs in our circuit. If you recall, we had 6 buttons in our game console and thus, we need to think of a way to make it work.



ATtiny85 Pinout

Voltage Divider

We mentioned earlier that we have 6 I/O pins along with 2 power pins for the VCC and GND but actually 2 of those pins will be used for USB communication. Another pin will be used as a RESET. The three pins left can be used as analog pins to get the input from our buttons and sensors. We have two sensors so we'll connect each sensor to a pin. Now, we are left with 6 buttons and 1 pin. So how can we connect our circuit? Have you heard of voltage divider? It is a passive linear circuit that produces an output voltage (Vout) that is a fraction of its input voltage (Vin).

Voltage Divider circuits are used to produce different voltage levels from a common voltage source but the current is the same for all components in a series circuit. We don't need to go into the details, you could read more about it online if you would like to, but all you need to know is that we can use this concept to create our buttons' circuit.


Voltage Divider

Push Buttons' Circuit

So we want to transform our 5V input into 6 analog values to distinguish between the 6 buttons' presses. When the maximum input of 5V is applied to one of the input pins, the maximum numerical value for an analog reading is 1023. We'll arrange our circuit as shown below and for simplicity, we'll be using 1 kΩ for all resistors. We won't be using an Arduino UNO later on, this circuit is just for demonstration purposes. As you can see, we used only one analog pin and yet every button gave a different output value when pressed. We can write down the values from analogRead() for every button and use it when programming our board later on.

Buttons_Circuit_Edited.mp4
Voltage Divider Circuit for Buttons

Now that we got this problem of the way, we can start designing our board.

Trial #1

Designing PCB On Eagle

No More Hassle of Wires

We'll be creating the circuit on a PCB eliminating all those connected wires we had before.

This was my first trial and you could probably gather that it wasn't actually a successful one. However, I'll still be taking you through it and mentioning what went wrong.

What's a PCB?

Before we get started, we need to know what is a PCB. It is a printed circuit board, hence the acronym PCB, that provides an electronic assembly using copper conductors to create electrical connections between components. The components are soldered without using visible wires, which is what facilitates its use.

So now that we know what a PCB is, let's see how can we design one. We'll be using Eagle for this part.

Creating Schematic

One of the first steps is creating a schematic that refers to the design at the electrical level of our board’s purpose and function. You could think of it as a blueprint that'll show us which components are used in our circuit board design and how these components are connected together.

The first part of our schematic includes the ATtiny85 microcontroller, the brains behind the whole operation. We'll be using Digispark which is an ATtiny85 based microcontroller development board that comes with USB interface to help us create create the USB (Universal Serial Bus) and ISP ( In-System-Programmer) communication for our PCB . Most of the schematic wiring was taken from Digispark's but make sure as you add components to your schematics that they suit the actual components you'll be using.

You'll notice for the buttons, we didn't place switches in the schematics. Instead, we added screw terminal blocks since the first plan was that we'll be using the same buttons we used in the first prototype and we were going to connect them with wires to the terminal blocks. We created the buttons' circuit using the voltage divider concept as we explained earlier and connected it on pin 2 as shown in the schematic.

Same thing for the tilt sensors, we added header pins instead since we wanted to place the sensors on header pins. We had a sensor connected to pin 0 and another one to pin 1. In this schematic though, one of the sensors was connected to pin 2 instead of pin 0 and that was actually one of the mistakes that was yet to be discovered later on.

Schematic

Generating Board Layout

Once we are done with our schematic, we'll convert it to a board layout. There we'll find all of the parts we added in the schematic stacked on top of each other, ready to be placed and routed. PCB designing is 90% placement and 10% routing so the way we arrange your parts actually has a huge impact on how easy or hard the next steps will be. I believe I didn't really arrange mine in the best way but it was my first time creating a PCB so this is the best I could come out with given the time I had.

Once the parts are placed, we get a better idea of how the board will look.

Defining Design Rules

We draw a board outline at the dimension layer with an appropriate width of 0.8mm but before going any further, we need to define design rules first that'll suit our PCB milling machine. These rules define some constraints such as the minimum clearance distances, or trace widths, or drill hole sizes... In our case, we set the clearance to 0.5mm and minimum width and drill to 0.5mm and 0.6mm respectively. Again these aren't standard values. It all depends on the machine you'll be using.

With the parts laid out, and the dimension adjusted, we're ready to start routing!

Inserting Drill Holes

Before routing, it is a good idea to place our drill holes first. These drills will allow us to mount our PCB inside our enclosure. So after we have placed the components and drill holes, we are ready to route the traces.

Routing Traces

Routing is the most fun part of this entire process. It's like solving a puzzle! Our job will be turning those yellow airwires into bottom copper traces. In my case, it wasn't easy and was very time consuming but then as I mentioned above, it's probably because I didn't place the components in the best way. At the same time, you also have to make sure not to overlap two different signals.

To make routing easier, we can add a copper pour for the ground signal. We can do that by using the Polygon tool to draw a set of lines on top of the dimension lines. A dotted border should appear around the dimension of the board. After you've drawn the polygon, we'll be prompted to connect it to a net using a name dialog that pops up. We'll type GND, the same name we used in the schematic. The last step is to hit the Ratsnest tool and then watch the pour fill just about the entire area of our board.

Note: If you ever want to hide the polygon, since it's hard to see other traces with it on there, use the Ripup tool on the polygon border you just drew. Don't worry, the polygon is still there and you can just click the Ratsnest tool to bring it back.

Once we have both "No airwires left!" and "DRC: No errors.", our board is ready to be fabricated, and it's time to generate some Gerber files.


Board Layout

Generate Gerber Files

Last thing left is to generate our design files. These files contain all the information pertaining to our printed circuit board, and once they have been generated, our PCB is ready for fabrication.

Gerber files are kind of a "universal language" for PCB designs. Each Gerber file describe single layers of the PCB. We can generate those files by loading up the CAM processor.

We did some further processing on those Gerber files and eventually exported them as PNG images before starting the milling process.


Gerber Files Rendered Into PNG Images

First PCB Problems

  • We decided before that we'll be connecting each sensor to a pin and all the buttons will be connected to a pin but I realized later on that I connected both, one of the sensors and the buttons, to the same pin (Pin 2).


  • Also, we realized that the buttons have to be connected to pin 2 only since we need to read analog values and the ATtiny85 has only three analog input pins, pins 2, 3 and 4 while pins 0 and 1 are analog output pins. We already used pins 3 and 4 for the USB communication and thus, we are left with pin 2.

PCB Milling

Let's Start Drilling Holes

The basic function of PCB milling machines is to selectively mill away a copper layer on the circuit board substrate to form traces and other conductive areas on the surface of the board.

To start our fabrication, we get a suitably sized copper board and mount it to the machine table so it would stay in place throughout the entire milling process. I mounted the board using double sided tape. Next, we set some machine parameters such as the speed, tool diameter, cut depth, number of offsets, XYZ...etc... and once we are done, we are ready to start the milling process. We load each of the PNG files we saved earlier one by one, starting with the bottom one. Once the milling process is done for that file, we load the next one, the drills and change our PCB cutting tool. Last file to load is the profile since it cuts the board outline of the PCB and we change the PCB cutting tool as well.

Note: Always make sure the machine is clean. You might need to vacuum after each milling job to remove the resulting material debris on the PCB and around the machine. You can even use a small paint brush to loosen any debris off the PCB during the milling process and once your PCB is done, to clear off stray copper filings, give the PCB a good scrub with a thick bristle brush or a stainless steel scrub.

PCB Soldering

A Multimeter is Your Best Friend

Once the milling process is done and our PCB is ready, we can start soldering. I've talked about soldering before but in a brief manner so let's talk about it in more details here.

What is Soldering?

Soldering is the process of joining two or more electronic parts together by melting solder around the connection. Solder is a metal alloy and when it cools it creates a strong electrical bond between the parts.

The most basic tool to solder components is the soldering iron. Be very cautious when using the soldering iron because it can become extremely hot. We'll also need solder wire which as mentioned above is an alloy and is usually available as a long, thin wire in spools. In conventional form, solder contains lead, tin, and few other trace metals so try not to inhale the solder fumes when soldering. You'll notice that over a period of time and with continuous use, the tip tends to oxidize and turns black, thus not melting any solder. In this case, we can use a sponge to clean the tip and prevent it from wearing off.


Soldering Process

How To Test a Circuit?

Remember that using a multimeter will help you in troubleshooting your circuit and the simplest way to use a multimeter is to test for continuity which means whether 2 points are electrically connected to one another. This is incredibly useful when checking for solder bridges and other shorts within a circuit. To do that, we connect the leads to each point in the circuit we want to test for continuity. If the points are not electrically connected, there'll be no beep. If they are connected, you'll hear a beep.

Before Soldering (Back)
After Soldering (Front)

First PCB Problems

  • This actually wasn't a soldering problem as much as it was a design problem. So during soldering, I noticed that I placed the block terminals too close to each other, thus making it impossible to use one of them. I resolved this issue by replacing this terminal block with header pins.


  • Another design problem was the sensors. I also didn't leave much space for them on the PCB so I had difficulties placing it on the PCB. This is mainly because I used header pins in my schematic and forgot that the sensors will actually occupy a much larger space than the header pins.

Installing Bootloader

We Are Not There Yet

Coding on our PCB will actually be similar to coding on an Arduino, and we'll use the familiar Arduino IDE for development but before we get to that part, we need to install the bootloader on our PCB. We've talked before about what is a bootloader and how to burn it on a PCB but since we are using an ATtiny85 this time, things are a bit different. So if you recall, a bootloader is a special program that runs in the microcontroller and is a convenient way to load our programs onto the microcontroller. Burning a bootloader is something that you only need to do once and we'll be doing it using an Arduino UNO so this is a one-time process and once it is done, we'll not be needing the Arduino UNO again.

Programming ATtiny85 With Arduino UNO

Configuring Arduino UNO Board as a ISP

Since the ATtiny85 is just a microcontroller, it requires an ISP (In-System Programming) to be programmed. So we need to first configure Arduino Uno as ISP to act as a programmer for the ATtiny85. To do that, we simply connect the Arduino UNO to our laptop, open the Arduino IDE and navigate to File > Example > ArduinoISP and upload the Arduino ISP code.

Opening ArduinoISP code

Connecting the Arduino UNO to the ATtiny85

Next, we'll connect the Arduino UNO to our board. The schematic is given below. The circuit shown is on a breadboard but of course you'll be connecting to the corresponding ATtiny pins on your PCB.

Note: We put a 10uF capacitor between the reset and ground pins to prevent the device from unintentionally resetting itself during an upload.

Circuit Diagram for Programming ATtiny85

Uploading Bootloader to Attiny85

Now, connect the Arduino UNO to the laptop and find what COM port the UNO is connected to. In my case, it's COM5. Afterwards, download the ATtiny85 boot-loader files from https://github.com/ahmedibrrahim/Attiny85-Bootloader-Files. Open "Burn_AT85_bootloader.bat" and change the COM port number "PCOM5" with whatever COM port number your UNO is connected to and save the changes before exiting. Move the edited "Burn_AT85_bootloader.bat" and "ATtiny85.hex" files into the Arduino IDE root folder which is usually in C:\Program Files (x86)\Arduino. After that, right-click on "Burn_AT85_bootloader.bat" and select "Run as Administrator". If all went well, you should receive this message "avrdude done. Thank you. Press any key to continue...".

Bootloader Successfully Installed on ATtiny85

With this, the bootloader is successfully installed onto the ATtiny85 chip and it’s time now to connect the USB with ATtiny85 so that we can program it directly.

First PCB Problems

So I couldn't actually upload the bootloader to my PCB and I was getting instead a "Yikes! Invalid device signature." The device signature read was 0x7f7f7f while the expected signature for the ATtiny85 was 1E 93 0B. There are actually many reasons that could result in an invalid device signature but in my case, it was a foolish mistake in the schematic. I used to mirror some components when placing them on the board and obviously that was not right and I did that with the ATtiny85 which made the chip unrecognizable and caused this error.

Trial #2

Designing PCB On Eagle

Change of Plans

So after I was done fabricating my first PCB and before finding out that it wasn't working right, we were told that we'll be using small push buttons instead of the huge buttons we used in the first prototype. So the initial plan was to do another PCB for the new switches and connect it with the PCB that I already did and thus, end up with two PCBs. Hence I did that but before I got to the milling process, I found out that my first PCB wasn't working. So since I had to redo the first PCB anyway, I decided to just do one PCB with the new switches in the schematic instead of the block connectors as shown below.

Schematic

Placing Switches on Board

The reason for changing the buttons was that with the small buttons, our design can be much smaller since the large buttons' height were taller than usual. However, the small buttons are actually very tiny so we can't use them directly as the game console buttons. Instead, we'll create 3D printed buttons that'll once pressed, press on those small buttons. We'll see that in more details when we get to the CAD part but now, we have to put more thought into how we'll place the switches on the PCB. They have to be placed in a way such that we can easily press down on them with the 3D printed parts. The easiest way is have the 3D printed buttons directly above the switches so we place the switches in the board design exactly how we want the buttons to be placed on the game console's enclosure.


Board Layout

PCB Milling

It's Pretty Mesmerizing to Watch

We follow the same steps we did before. For some reason though, the machine and I don't seem to get along and too many things seem to always go wrong during the milling process but there's no need to talk much about that so let's move on.

PCB_Milling.mp4
Watching the Milling Machine Working is Really Cool

PCB Soldering

No Need To Solder All Components Right Away

This time, I didn't solder all the components like in the first PCB since I realized it's just enough to solder the components required to ensure that our PCB is working and can be programmed. Once we reach that step, it's safe to assume that we can solder the rest of the components such as the buttons and sensors. I even noticed later on that I soldered the buttons' resistors which could've been soldered later as well after testing the PCB.

Before Soldering (Back)
After Soldering (Front)

Installing Bootloader

False Hope

If you can recall, I had difficulties uploading the bootloader on my first PCB and kept getting an invalid device signature. However, this time, after following the same procedure, I was able to install the bootloader on the second PCB and got the success message that includes "avr done". I was glad it finally worked and thought that things are starting to finally look up but I was very wrong.

Connecting PCB

Oops... I Did it Again!

Yup as you probably guessed, this PCB didn't work as well and you'll know why shortly but let's continue with our steps first.


Setting up Arduino IDE for Digispark ATtiny85

After installing the bootloader, there are a few thing left to do before we can program our PCB on Arduino IDE so let's get on with it.


Adding DigiStump Board URL

It turns out that by default, the Arduino IDE lacks the ability to upload directly to an ATtiny since it doesn't include the Digispark boards. Thus, to program our PCB with Arduino IDE, we need to add the Digispark board support to Arduino IDE. For that, go to File > Preferences and add the below link in the "Additional Boards Manager URLs" and click OK.

http://digistump.com/package_digistump_index.json

Adding Digistump Boards to Arduino IDE

InstalIing DigiStump AVR Board Manager

Next, you’ll need to select and install the package from the Boards Manager before the chip becomes visible under the boards list so go to Tools > Board > Board Manager and search for "Digistump AVR" and install the latest version. After installing it, now you would be able to see a new entry in the board menu titled Digispark so go back to Tools -> Board and select the “Digispark (Default – 16.5mhz)” board.

Installing ATtiny85 Device Driver

Download the Digistump Drivers for Windows and unzip the downloaded file. Open the unzipped folder named and double-click either DPinst64.exe on a 64-bit Windows computer, or DPinst.exe on a 32-bit Windows computer to install the drivers. When prompted to install the driver, click the Install button and if a dialog box pops up that displays "Windows can't verify the publisher of this driver software", click the "Install this driver software anyway" button. After the driver installation has finished, click the Finish button in the Device Driver Installation dialog box.

Open Device Manager and now when your board is connected, “lbusb-win32 device” should appear for a few seconds in the devices before disappearing again. If the device isn't shown, click on the View menu and select “Show Hidden option”.

Note: In some cases, you might have a problem installing the drivers and you'll see an "Unknown USB Device" in the Device Manager instead. In this case, you'll have to manually add the drivers by right-clicking on the “Unknown USB device” and select "Update driver" > "Browse my computer for driver". Then, choose the location of the the drivers' folder we just downloaded.

Second PCB Problems

So once we are done with this part, our PCB should be recognized by the laptop. Since we normally hear a sound whenever a device is connected to the USB port indicating that a device has been plugged, we expect to hear this sound now when we connect our PCB to the laptop. If not, then something is wrong. There could be many reasons for that as well, like maybe the drivers weren't installed properly or the PCB's connections aren't right and in my case, the latter was in a way the issue I had.

So when my first PCB didn't work, it took me a while until I found out the reason. So during that time, I was already designing a new PCB. Once I noticed that I mirrored components and that this is probably the reason why my first PCB wasn't working, I was already done designing my new board on Eagle so I just took a quick look at it to make sure that there aren't any other mirrored components that might cause this problem again. There were just some mirrored diodes but I didn't see them as a problem and the ATtiny wasn't mirrored this time so I felt like this PCB was ready to be fabricated and this is why I was able to actually upload the bootloader to the PCB in the previous step. However, silly me, the USB component was mirrored all along even in the first PCB but I didn't see it and unfortunately it took reaching this step to realize it.

Trial #3

Designing PCB On Eagle

I Am Not Doing It Again

To avoid missing any other mirrored components or errors, I redid everything from the start.


Schematic

The schematic is the same as the one above since my issue was with the board layout not the circuit connections. You can download the schematic here.

Schematic

Board

Now, we move on to the board layout. I must say I am still not very good at placing the components on the board in the best way and probably because of that, routing becomes such a nuisance task to me. If only there was a feature on Eagle that'll do all of this for but sadly, one can only hope.

Note: I didn't mention this before but you'll notice that there were always some 0 Ω resistors placed on the board. They are used to connect traces together on a PCB. I used them to connect GNDs. In order to have them shown on the board, I went back to the schematic and just added them as components.

You can download the board file here.


Board Layout

Gerber Files

After we are done with our board, we generate our design files. You can download the Gerber files from here.

Gerber Files Rendered Into PNG Images

PCB Milling

Hopefully That's The Last One

The process went smoothly this time which made me very skeptical at first. One thing I noticed later during the day was that the drills on the PCB didn't go all the way through and I had to come back the following day to fix that. I knew that it was too good to be true. However, all one could hope for was that this would be the last PCB to fabricate.

PCB Milliing Process Finally Done

PCB Soldering

Soldering is Fun But I Think This Is Enough

I mentioned before that I enjoy soldering but I think I've done it enough by now. The good thing to note here though is that my soldering skills seem to have improved a bit and the PCB doesn't look so messy.

Soldered PCB

Installing Bootloader

All Went Well Here

I know I said earlier that this is a one time process and that once done, we won't be needing the Arduino UNO again but then that was before knew that I'll be redoing the PCB several times. It is a fact though that it is done once but as you probably realized, it is a step that you do with every new PCB so we just redid all the steps we mentioned above. However, we don't need to upload the ArduinoISP code on the Arduino again if we are still using the same Arduino board and haven't uploaded another sketch on it.

Installing Bootloader on PCB

Connecting PCB

Third Time's the Charm

We actually don't need to do this part again if we've done it before since we already set up the Arduino IDE for the ATtiny so everything we added or downloaded will still be there. You just need to make sure that when you use the Arduino IDE that you choose the “Digispark (Default – 16.5mhz)” board.

Same goes for the drivers since they were already installed but remember you need to hear a sound when the board is connected to the USB port because if you don't then your laptop doesn't recognize the board and you won't be able to program it. Fortunately, this PCB was recognized by the laptop so I took this as a sign that everything is well and soldered the rest of the components.

Designing On Fusion 360

We Can Finally Move On

Once we have a working PCB, we know its size and we are ready to create a game console enclosure with the suitable dimensions.


What Material Will We Be Using?

Our target was creating an enclosure combining both acrylic and 3D printed parts. If you remember, in our first prototype, we created curved parts using living hinges since wood wasn't naturally flexible to bend. However, creating curved parts with 3D printing couldn't be easier. Therefore, I decided that I'll be creating the curved body part using 3D printing and the top and bottom parts can be acrylic. The buttons of course had to 3D printed as well.

Initial Version
Modified Version

Creating Design

I started with a simple design just to get an idea of how the game console could potentially look like. That was the initial version. However, what I had in mind was a more complex design. I wanted to create the game console with a curved handle grip since it'll be more comfortable to hold and it'll look much better. I wasn't really sure though how to do that on Fusion. I mean I know it's definitely doable but I couldn't figure it out at the time and I didn't have much time to spare. So I tried to create something as close possible to that and this was the modified version. So I'll be talking more about that version.

Body Part

So to create the body part, I tried out the loft feature since as I mentioned above, I sort of didn't want the body part to be vertical. The loft creates a smooth transition between two or more faces. So I made the bottom and top outlines as a sketch and if you'll notice, the bottom outline is larger in size than the top outline. This is what will create a slightly slanted body part. I created an offset for each outline so that when I create the loft, it would be hollow from the inside since that is where our PCB will be kept.

So once we created the loft, I added another inner offset to create some sort of inner wall that'll support the acrylic top part. Since the acrylic we'll be using has a thickness of 3mm, I added afterwards a border of 3mm height to surround to top part when placed in there. All what's left is to add something that'll prevent the top part from coming off. So I just used the same inner offset I made earlier to create another outer wall that'll keep the top part in place. If you couldn't keep up with all of that, just imagine that there are two inner borders with a 3mm gap between them such that the top part can be snapped to fit in there.

The same exact thing was done for the bottom part and once done, I combined all those body parts together to form one component.


Top and Bottom Parts

The top and bottom parts were simply created by extruding the sketches we did above.

We have a useful feature in Eagle that allows us to export PCBs to Fusion. So I exported my PCB and placed it inside the enclosure. Afterwards, I created a sketch from the PCB so I could project the PCB holes that'll mount it to the bottom part. With extrude cut, the bottom part now has holes for the PCB.

We'll also need to create an opening for the USB port so I imported a USB 3D model from GrabCAD and placed it in its exact location. Then, I created a sketch with slightly larger dimensions than the USB size and used extrude cut as well to create the opening.

Last thing I did here was import 3D models from GrabCAD for the switches we were using and placed them in their exact spot on the PCB. As you can see, that's the benefit of having our PCB in Fusion. It helps us know precisely where our components will be and thus, design our enclosure accordingly.


Buttons

All what's left in our design are the buttons. This was actually the easiest part. I created a sketch for how I wanted the buttons to look like and did an extrude cut in the top part. Next, I extruded the same sketch with a height of about 7mm to create the buttons. There'll be about 3mm hidden in the height of the acrylic top part so we are left with about 4mm extruding from the top part. Now, we want the buttons to stay in place such that when they're pulled, they don't come out. So I did an outer offset with an extrude join starting from the lower face of the top part. This will prevent the buttons from being pulled out since this extrusion is larger than the cuts we previously did in the top part. Now, we need to add a little bit of height to the buttons so that they would reach the push buttons on the PCB. Before adding this height, we need to make sure that the PCB is placed at the right distance from the bottom part. Once we are sure of that, we can extrude join the sketch to a suitable height such that it is directly above the push buttons but without putting any pressure on it. So now, when the buttons are pressed from the top part, they'll go down a very small distance to press on the switches.


Preparing Files

We'll be exporting two types of files this time. All 3D printed parts are exported as STL files and the acrylic parts as DXFs. Remember, when exporting the STL files, keep the default format as binary and choose refinement as high.

You can find all the design files here.

3D Printing

You Can Never Go Wrong With Black

We talked about Ultimaker Cura before and that it's a slicing application for 3D printers. So first thing to do is open the STL files on Cura. Next, we choose the 3D printer model, Prusa i3 MK2, and the printing material, PLA. The print settings could be changed but we usually don't change much. I just set the layer height to 0.2mm, infill to 20%, bed temperature to 215 and added support.

Once all is set, we slice the model and when the process finishes, we can move on the preview stage where we can get a better look at our printing process along with an estimated print time and weight based on the material selected.

If everything seems good, we can get the G-code file to start printing.


Preparing First Printing Batch on Ultimaker Cura
3D_Printing.mp4
Printing Black Parts
3D Printed Parts

I was asked a lot why did I choose black since it is such a typical color for a game console and why not make something that stands out but to be honest I just wanted to be on the safe side. I don't have the privilege of trying out different colors and it was important to me that the console ends up looking good. We all know black is classy which is probably why most game consoles are black. Plus it matches with most colors and since I wasn't sure what colors will be available when I print out the buttons, I decided to go with a color that'll probably work with all.

Laser Cutting

Last Thing Left In Design

We'll actually be using the laser cutter machine this time as well but we'll be cutting acrylic instead of wood. So if you recall, we import the DXFs to LaserWorks and set the machine's speed to 15 and power to about 75%. Don't forget to adjust the focus too.

So an issue arose and I couldn't fit the acrylic parts to the 3D printed parts. Even the buttons didn't go in easily through the cuts as expected. The thing is, when I created the design on Fusion, I created all parts to be an exact fit since I was told the acrylic had a kerf of 0.2mm and I thought that'll be enough to make the parts fit together smoothly. So since that didn't happen, I just resized both of the acrylic parts to be smaller. I also increased the buttons' holes with a very small value, about 0.1mm.


Importing DXFs to LaserWorks

LaserCutting.mp4
Laser Cutting Top and Bottom Parts
Acrylic Parts

Assembling Parts

Disappointment Strikes Again

The acrylic and 3D printed parts fitted together as expected so that was great news. However, when I tried mounting the PCB inside the enclosure with all of the components on it, it didn't fit. It turned out one of the sensors was out of the PCB's dimensions by quite some centimeters which would have been fine except the enclosure was sort of compact in size so there was no way the sensor could fit in there. Even putting it upright didn't work due to the height of the sensor being higher than the enclosure's.

Now to be honest, before fabrication, there was a part of me that felt that the sensor won't fit in the enclosure but I told myself don't be paranoid, it's a small sensor, it'll probably fit and since, I know I am an overthinker, I decided to ignore my doubts so in a way, I sort of deserved this. Plus this issue could have easily been avoided if I just imported to Fusion a 3D model for the sensor like I did with the push buttons and the USB port.

But of course there was no way I was going to be redoing the PCB and printing the enclosure again would be sort of an unnecessary expense so I had to think of a workaround and eventually ended up using jumper wires to place the sensor as shown.


PCB Inside Enclosure

Programming PCB

Let's Hope Nothing Goes Wrong Here

Since we chose the Digispark board earlier, we'll be using DigiKeyboard library this time to have the board act as a keyboard so first thing to do is add this library to your code.

Before we start, we need to clear something out. The Digispark is compatible with the Arduino IDE but it is not exactly the same as an Arduino. For Digispark, when it comes to digital inputs, the pin number matches. However, for analog inputs, that's not the case and the analog pins are referenced by their analog port number, not their pin. So according to our PCB design, our sensors are connected to pins 0 and 1 while the buttons are connected to pin 2. Since the sensors are digital, when we read their values, they'll simply be digitalRead(0) and digitalRead(1) but when reading the buttons, we agreed before that they'll be analog values and thus, we can't say that it'll be analogRead(2). We'll use instead analogRead(1) which reads P2. I know that this could be a bit confusing but you could read more about it here.

Buttons

Now if you remember at the beginning, we tried to figure out the circuit for the buttons and ended up doing it using the voltage divider concept. We tested it on TinkerCad and got an analog value of 146 when the first button was pressed, 171 when the second button was pressed, 205 when the third button was pressed, 256 when the fourth button was pressed, 341 when the fifth button was pressed, and finally 511 when the sixth button was pressed. If nothing was pressed, the analog value read was 0. We also mentioned that we'll be using these values for the programming part. So let's see how.

According to our PCB design, the first button is the button labeled O on the game console. Now what I expect is that if I press that button and use analogRead(1), it'll be 146. This is sort of true. However, if you try that yourself, you'll notice that you might not always read 146. You might sometimes read 145 or 144. The value might fluctuate one or two counts and this could be due to fluctuations in the voltage of the +5V from the USB or due to the ADC. So we'll have to take that into consideration when we write our code meaning we'll have a small range of values to compare to instead of just one.

Note: Keep in mind that DigiKeyboard.println() is a really helpful function to use while debugging.


Analog Values For Buttons

Sensors

Since the sensor module we used in the first prototype didn't seem to work properly, we tried a different module this time and it actually worked. So we'll change the code logic a bit here such that we'll now have a button as a mode selector, to select between the two modes, tactile or sensing. As you can see from the video, when the game console isn't tilted, both sensors' readings are HIGH. This is indicated by the red led on the module. When tilted to the left, the right sensor's reading becomes LOW while the left sensor's reading remains HIGH and vice versa, when tilted to the right, the left sensor's reading becomes LOW while the right sensor's reading remains HIGH. Thus, that's the logic we'll be using in our code.


TiltSensors.mp4
Tilt Sensors in Action

Key Codes

So when we used the Keyboard library before, we didn't have to define the codes for the keys since they were already defined in the Keyboard header file. I was expecting the same with the DigiKeyboard library but I used to get an error that the key wasn't declared in this scope. I took a look at the header file which you can find here, and realized that for some reason they didn't define all the key codes. Only the key code for the left arrow key was defined. Therefore, I just declared all keys I'll be using at the beginning of the code.


A Closer Look At The Code

I think we explained the main concepts we need to be familiar with before we start with the code so let's dive in. If you understood all of what we talked about above, you'll find the code to be very simple.

In the setup function, we used the pinMode() function to configure the sensors' pins as INPUT. According to Digispark, for analog inputs, we don't need to set the pin mode which is why we didn't configure the buttons' pin.

As mentioned earlier, we'll be using the sensors this time so now we have two modes to switch between. Therefore, I had a variable defined in the code named mode and set it initially to 1. Mode 0 will be the sensing mode and mode 1 will be the tactile mode. I chose button O to be the mode selector so you'll find in the code that whenever button O is pressed, I toggle the mode variable such that if I was in the sensing mode, I'll switch to the tactile mode and if I was in the tactile mode then I'll switch to the sensing mode. You could add a short delay here if you feel that the mode doesn't always change when you press the button. This is probably because the loop executes really fast and we need to ensure that the mode variable was toggled before the loops starts over.

In the loop function, we have two main conditions to check for the current mode and accordingly inside the conditions, we check for the sensors' readings if we are in the sensing mode and otherwise, we check for the four direction buttons' readings if we are in the tactile mode. We check for the mode selector button, button O, in both conditions in order to be able to change between modes at any time. We can also add button X to be used in both modes in case we want to shoot or jump in a game for instance.

One more thing that you should know is that I used the function sendKeyPress() to press the keys on the keyboard. There is another function sendKeyStroke() that can also be used to press the keys on a keyboard. The difference between them is that sendKeyStroke() releases the key press while sendKeyPress() doesn't. You might think at first that why not use sendKeyStroke() since technically if I press the up button for example once and release it, I'd like the up key on the keyboard to be pressed and then released afterwards as well. However, that's not exactly how this works since if I press and hold the up button on the game console, I'd expect the up key on the keyboard to be pressed without release. sendKeyStroke() can't do that and you'll find that even when you have the up button pressed down for a while, it'll still be like pressing and releasing it several times. So to avoid this issue, we have conditions to check each button and accordingly press the equivalent key on the keyboard if the button is pressed on the game console. Then, there is a necessary condition in both modes that if nothing is pressed, I should release all keys since as we said, sendKeyPress() doesn't release key presses on its own.

You can download the code implementation file by clicking the button below.


Code Implementation

Note: Whenever you upload the code, connect your board to the computer only when the Arduino IDE displays a message saying “Plug in device now...”.

Testing

The Moment We've Been Waiting For

I tried thinking of a game where I could test both, the sensing and the tactile modes in it and I remembered that there were these arcade games where a car would be continuously moving forward and all you had to do was move left and right to dodge the other cars. So I tried searching for a similar game online to test the game console with it.

TopSpeed.mp4
Testing Modes On Game Console

Conclusion

Live and Learn

It's times like these that one learns patience and perseverance. This project was a hectic journey full of surprises but I'm still glad I got to experience it all. There are a few things though that I wished I've had done differently:

  1. Both of the sensors aren't placed appropriately on the PCB. One of them was on top of the reset push button which wouldn't cause a problem now but then it still shouldn't be there. The other sensor didn't even fit inside the enclosure. Thus, the PCB design could be redone with a better arrangement for the components.


  1. I also noticed that if the PCB had the same shape as the enclosure, it would've given me more space to arrange the components in a better way and as a result make the routing process much easier. However, even though Eagle allows importing DXFs from Fusion, I noticed that it only draws simple shapes in the DXF such as lines, circles, arcs...etc.... If the file is a bit complex and involves curves or splines such as in my design, it won't show on Eagle. So I tried resolving this issue and even tried ULP files but I couldn't get anywhere with it and just ended up with a simple PCB design but I guess could have tried drawing it manually on Eagle to get at least a close enough outline.


  1. The design could be a bit improved and the colors used might not be the best. The X and O buttons could have had a different color from the top part. The top and bottom parts could have even had a different color than the body part. I mean black is great and all but there could be a better color combination out there. At the time I didn't want to risk it but I was a bit inclined to try white with some dark color so maybe that could look good as well.


  1. I placed drills in the bottom part to mount the PCB. I could have instead added some sort of inner extensions in the 3D printed to mount the PCB on it and thus, eliminate any visible screws.


  1. I could be a bit clumsy sometimes so I accidently dropped off the console more than once and it was actually sturdy and didn't break but it would be much better if the top and bottom parts were attached to the body part with screws as well for a more robust assembly. However, we probably need to think of a way first to do that without ruining the overall look of the console.

Up-close View

I believe that is all. I know that this was a long one so I hope I didn't bore you and as always if you have any questions, don't hesitate to contact me.