Pronguino

Introduction

OK, so we have our basic Prong game, it’s time to transform it into Pronguino, by adding Arduino paddle controllers, its going to be a simple circuit, but a great start to learn about voltage dividing, serial communications and bitwise operations.

Getting Started

First, we will focus on building the circuit and programming the Arduino UNO, making sure everything compiles and uploads OK.

Recommended

I recommend that you read and run through ‘Project 14 – Tweak the Logo’ in the Arduino Projects Book, as this will give a bit more background on what we are doing here.

Components

All the components that you need listed here are in the Arduino Starter Kit.

PartQuantity
Arduino UNO Rev 31
USB Cable1
Breadboard1
Potentiometer 10k Ohms2
Jumper Wires6
Black Stranded Jumper Wire 1
Red Stranded Jumper Wire1
Components

The Circuit

Assembly

These instruction steps are used to assemble the circuit as shown above, quite straight forward with some added tips…

StepInstruction
1Ensure you have unplugged from power source and at least one end of USB cable is removed from either the UNO / computer.
2Connect the red stranded jumper wire to one of the bus lines on the breadboard marked with + to the 5V pin on the UNO.
3Connect the black stranded jumper wire to the adjacent bus line marked with to the GND (Ground) pin on the UNO.
4The potentiometers that come with the kit (at time of publishing this), have to straddle the centre of the breadboard, so place one on the left of the board so the side with two legs is facing the bus line where you connected the power. Place the other on the right hand side. Make sure you press them in firmly, so they don’t wobble.
5Connect one of the smaller jumper wires (15mm blue ones seem to do trick), from a board socket aligned with the left leg of potentiometer to the socket on the bus line where you have connected black wire. Do the same with the other potentiometer.
6Connect another of the smaller wires (the 5mm orange one), from a board socket aligned with the right leg of potentiometer to the + socket on the bus line where you have connected red wire. Do the same with the other potentiometer.
7On the other side of the board where the single legs (wipers) of the potentiometers are, connect a green jumper wire from a socket aligned with the wipers, to the Analog-In A1 pin on the UNO, for the left hand side potentiometer, and A2 for the one on the right.
Assembly Instructions

The Code

Download
Arduino

We could write this code in a few lines in one file, but as I want to make the code more readable, understandable and extendable, I have broken down into the main file pronguino, along with a library called Controller.

In the main file, similar to Processing, there is setup() where the serial communications and controllers are initialized, and the loop() is continuously reading and writing the value from the controllers.

The library is made up of a header file Controller.h which is then implemented in a c++ file Controller.cpp, I will cover the subject of Library Packaging in a later post. I will let the code speak for itself, and take a deeper dive into some areas below.

Plug the Arduino into your PC, upload sketch, and we are ready for the next step

Testing

Note: If you have a mobile phone or similar attached to your computer via USB, you may get some spurious results, bear this in mind if you are getting strange movement from paddles with or without Arduino attached.

So, we have the controllers built, code uploaded, and usually you would update the Processing code as below, and spend the next few hours playing Pronguino, right? or maybe the next few hours debugging two sets of code, and an electronic circuit?

OK, we haven’t got the luxury of a user interface on the UNO, but what we do have while connected to the PC is the Serial Monitor, which is opened from the Arduino IDE .. Tools -> Serial Monitor.

I have added a constant called TESTING, and when set to false, on upload of code, you should see something like this, as you turn the potentiometers, which is the data being written to the serial port.

⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮ѡ⸮⸮⸮⸮pppppP@A23#$$# @PP``acD4$#

If you change TESTING to be true, upload the new code, the setup() will call function resultsHeader() to print some headings, and loop() will continuously print the data being read from each controller via the function resultsDetail(), and the data that would be written, you should see something like below under various conditions ..

Both potentiometers turned to far left

controllerValue1	controllerValue2	highNibble	lowNibble	data	
0			0			0		0		0
0			0			0		0		0
0			0			0		0		0

Both potentiometers turned to far right

controllerValue1	controllerValue2	highNibble	lowNibble	data	
15			15			240		15		255
15			15			240		15		255
15			15			240		15		255

Both potentiometers turning to somewhere in the middle

controllerValue1	controllerValue2	highNibble	lowNibble	data	
11			10			176		10		186
8			10			128		10		138
8			8			128		8		136
Troubleshooting

Hopefully, with the circuit being quite simple, there is not much to go wrong, but the common things to check are as follows ..

IssueResolution
Nothing is workingCheck Arduino is plugged in securely
Check red & black wires on board are secure
Random data (without change potentiometer)Check potentiometers are firmly pushed in
Check the data wires are securely connected
Getting 15 instead of 0 as a nibble value, when potentiometer, turned all way to left.Check the left pin of potentiometer is connected to GND, and right to 5V
Troubleshooting Guide
Program Storage Space

Just a quick note to those worried about testing code taking up valuable space on the Arduino, the compiler will not include any unreachable code, so when TESTING = false;, the functions resultsHeader() and resultsDetail(...) are not compiled, check console after compiling …

Sketch uses 1952 bytes (6%) of program storage space. Maximum is 32256 bytes.
Global variables use 188 bytes (9%) of dynamic memory, leaving 1860 bytes for local variables. Maximum is 2048 bytes.

… in comparison to having TESTING = true;

Sketch uses 2424 bytes (7%) of program storage space. Maximum is 32256 bytes.
Global variables use 260 bytes (12%) of dynamic memory, leaving 1788 bytes for local variables. Maximum is 2048 bytes.
Processing

Time to add the “uino” to Prong, below is the updated Processing code to include functionality that reads data from the controller and moves the paddles accordingly…

Experiment: The paddle movement seems OK when you just turning the potentiometers at a steady rate, but can sometimes get out of sync, have a tinker with checkController() in Player class and/or the timing of the outgoing data in Arduino code or incoming data in the Processing code, to see if it can be improved.

What’s New ?
FileDescription
ControllerContains a new class Controller, which encapsulates the values received from Arduino controllers.
FunctionsA new static class Functions, which contains functions that can be called from anywhere in the package, initially used for some bitwise calculations.
Whats Changed ?
FileDescription
pronguinoImports serial library
Initializes serial port in setup()
Added serialEvent()
ConstantsAdded controller related constants
OptionsAdded serial port related options
PlayerAdded Controller instantiation to constructor
Added setController(int value) method
Added checkController() method

Play

Take a break, and play one long (we will look into that soon) game of Pronguino.

Challenge: Currently, when turning controller to left the paddle moves up, and turning right, moves it down. If you prefer the opposite, without changing the circuit, just edit either the Processing or Arduino code.

Potentiometers

In the context of this circuit the potentiometers are being used as voltage dividers.

Potentiometer
Potentiometer

Terminal 1 (T_1) connected to GND
Terminal 2 (T_2) connected to 5V
Terminal 3 (T_3) connected to A1 or A2

Given that …

SymbolDescriptionFromToEquationValue
VVoltage SupplyT_1T_25 Volts
RTotal ResistanceT_1T_2R_1 + R_210k Ohms

… and turning the potentiometer to various positions, we would get the voltage drop required

SymbolDescriptionFromToEquationLeftMiddleRight
R_1Resistance T_2T_310k\Omega5k\Omega0\Omega
R_2Resistance T_1T_30\Omega5k\Omega10k\Omega
V\scriptsize outVoltageT_1T_3{R_2 \over R_1 + R_2}V0V2.5V5V

.. .which is then measured by analog inputs A1 or A2 and converted by the ADC (Analog-to-Digital Converter) into to a resolution of 10 bits (0000000000 – 1111111111) or 0 – 1023.

Learn: I find it important to get to know your components, and how they work, it helps when things don’t work as planned, learn some of the equations such as Ohms Law and Voltage Division Rule etc.

Bitwise Operations

Reference
OperatorNameDescriptionExampleResult
&ANDIf both are 11 & 11
1 & 00
|ORIf either is 11 | 01
0 | 00
^eXclusive ORif both different1 ^ 01
1 ^ 10
~NOTChanges to oppositeNOT 01
NOT 10
<<Left ShiftShifts n bits to left00001000 << 200100000
>>Right ShiftShifts n bits to right01000000 >> 300001000
Bitwise Operators
TermMeaningBinaryHexadecimalDecimal
Bit1 bit0 to 10x0 to 0x10 to 1
Nibble4 bits0000 to 11110x0 to 0xF0 to 15
Byte8 bits00000000 to 111111110x00 to 0xFF0 to 255
Terms
0123456789ABCDEF
0123456789101112131415
Hexadecimal Values
High
Low
bit8bit7bit6bit5bit4bit3bit2bit1
Nibbles
bit8bit7bit6bit5bit4bit3bit2bit1
1286432168421
Bit Values (when set)

Arduino

In the Arduino code we have the following lines in the pronguino loop()

// Convert to nibbles byte highNibble = (byte) controllerValue1 << 4; byte lowNibble = (byte) controllerValue2; // Combine the two nibbles to make a byte byte data = highNibble | lowNibble;

… where we have read the two values (ranging from 0 – 15) from each controller, and rather than sending these values individually, we will combine them into one byte to send…

Given that …

BinaryHexadecimalDecimal
controllerValue1000010000x088
controllerValue2000010100x0A10

… to get the highNibble we shift controllerValue1 left 4 bits …

BinaryHexadecimalDecimal
controllerValue1000010000x088
<< 4
highNibble100000000x80128

… we are only changing data type of controllerValue2 to get lowNibble, so to get data we bitwise OR highNibble and lowNibble

BinaryHexadecimalDecimal
highNibble100000000x80128
| lowNibble000010100x0A10
data100010100x8A138

Processing

In the Processing code we have two functions in the Functions file …

/** * Extracts a high nibble (first four bits) from a byte * * @param data byte to extract nibble from */ static int getHighNibble(byte data) { return (int) ((data >> 4) & (byte) 0x0F); } /** * Extracts a low nibble (last four bits) from a byte * * @param data byte to extract nibble from */ static int getLowNibble(byte data) { return (int) (data & 0x0F); }

… when the serialEvent()function receives the data sent from the Arduino, it needs to be split up to identify the movement of each of the controllers … for controller 1, getHighNibble(byte data) is called…

First the data needs shifting to the right 4 bits …

BinaryHexadecimalDecimal
data100010100x8A138
>> 4
result000010000x088

… and then apply a bitwise AND with 0x0F

BinaryHexadecimalDecimal
result000010000x088
& 0x0F00001111
highNibble000010000x088

.. and to get value for controller 2 we call getLowNibble(byte data) .. and bitwise AND data with 0x0F ..

BinaryHexadecimalDecimal
data100010100x8A138
& 0x0F00001111
lowNibble000010100x0A10

Fritzing

Fritzing provides a software tool that allows to you draw schematics, mock up your breadboard, upload code to devices, design PCB layouts and also offering service to print PCBs. I have used this to produce the schematic and breadboard mock-up for the “controllers” …

Fritzing - Schematic
Schematic
Fritzing - Breadboard
Breadboard

Learn: It is definitely worth getting to grips with circuit design and prototyping with tools such as Fritzing, even for the simplest of circuits, as when they become more complex, you want to be focusing on the circuit and not how to use the tool!

… the cool thing about doing this using Fritzing, is the schematic and breadboard are continuously checking and modifying each other, for example if you started with the breadboard and just add the required components on, without any wires, then go to schematic, connect everything up logically, switching back to the breadboard will show dashed lines from pins to sockets as a guide to where the wires should go (known as a ratsnest) , and will disappear as wires are added…

Fritzing - Breadboard - Ratsnest
Breadboard – Ratsnest
Fritzing - Schematic - Ratsnest
Schematic – Ratsnest

Note, as the ratsnest is being created from a logic diagram, they will take the most direct route i.e. joining pins from from potentiometer to the other as they are both connected to GND, and as we just don’t wont all the wires going from component to component, in this case we would take a wire from each component to a GND socket on board.

Similarly, if you started with a fully wired up breadboard, and then switched to create schematic, you have to re-arrange the connections and components to create a tidy looking diagram, the connections will highlight red, where no connected as been made, and green when all good, ratsnest guides are also created in this view.

This Fritzing file is included in the download for this post.

Tinkercad

Flipped your LED?, fried your chips? or toasted your breadboard ? … if you haven’t yet and you’re paranoid about forgetting to put that resistor in, then it is worth taking a look at Tinkercad, whilst Fritzing suits my needs for schematic and breadboards, I search around for some free simulation software, and for basic Arduino circuits, this fitted the bill.

Tinkercad - Pronguino

It has all the components from Arduino Starter Kit, and more. As you get more daring with your circuits (I have seen posts about weird noises, strange smells and smoke!), you may want to try it out first with TinkerCad, it will show you when something blows. Also useful for measuring resistance / voltage etc as you can add a multi-meter …

Tinkercad - Flipped LED
Flipped LED
Tinkercad - Measure Resistance

Measure Resistance

There are a couple of limitations that can be worked around …

LimitationWorkaround
As it is web based you cannot communicate with a physical serial port.If you look at the code below, you will see that TESTING = true; and as you can see a virtual serial monitor, this should be enough to tinker with.
You cannot add files to code window, i.e. in our case we cannot add Controller.cpp and Controller.hAgain, have a look at the code below, I have implemented the class Controller at the top of the file.
Tinkercad Limitations
Code

This TinkerCad code is included in the download for this post.

Conclusion

OK, so we now have the basic Pronguino game being controlled by a couple of potentiometers, I have learnt how to use Fritzing and TinkerCad to help in the design and testing of the circuit. Hopefully provided some hints and tips on coding and testing, remember I am new to Arduino, Processing and electronics, and have presented my findings in such a way that helps me remember and look back on, and hope that it will help you too.