Servuino

Introduction

Time to add a few more components to the circuit, add some additional functionality and have a bit more of a tidy up in the code, adding game state and “event” driven in areas. Also introducing two-way communications between PC and Arduino UNO and building a code library.

Currently the the game just starts automatically and the ball moving part-randomly and beginning, so adding the ability for user to control the serve, pause and resume the game.

Getting Started

Recommended

I recommend reading through the Pronguino post, as we are building circuit on top of the result of this.

Components

All the components that you need listed here are in the Arduino Starter Kit, as mentioned above, this is being built on top of previously built circuit, see existing components list, as well as the following …

PartQuantity
Button (Tactile Switch)2
Resistor 10k Ohm2
Yellow LED2
Resistor 220 Ohm2
10mm Green wire2
100mm Yellow wire2
75mm Orange wire2
50mm Red wire2

Note: I have been specific on the length in particular on the above wires, mainly for the smaller ones that are used just on the breadboard, so they are as flat as possible.

The Circuit

Fritzing Diagram – Servuino
Assembly

These instruction steps are used to assemble the circuit as shown above, a little more tricky than previous, you need a steady hand.

StepInstruction
1
2Take each of the 50mm red wires and connect the two bus lines + to + and to respectively.
3The switches that come with the kit (at time of publishing this), are best to straddle the centre of the breadboard, so place one on the left of the board next to the potentiometer. Only one orientation of the button should fit. Place the other on the right hand side. Make sure you press them in firmly, so they don’t wobble.
4Take one of the 10k Ohm resistors, place one pin into a board socket aligned with the top left pin of switch on left (leaving at least one socket between), and the other pin into a socket on the top bus line. Repeat for the other 10k Ohm resistor for right side switch.
5Insert one end of a 100mm yellow wire into a board socket in between the switch and resistor placed in previous step, and the other end into digital pin D2*. Repeat for the other 100mm yellow wire for right side switch, placing the other end of wire into digital pin D3*.
6Insert one end of a 10mm green wire into a board socket aligned with the top right pin of the switch on left, and the other end into a + socket on the top bus line. Repeat for the other 10mm green wire for right side switch.
7Identify two clear strips of board sockets, just to the right of the left side potentiometer, and place one of the LEDs across these strips around the middle, I have put the long pin (anode) of the LED to the right in this case, just remember which. Repeat for the right side of board with other LED.
8Take one of the 220 Ohm resistors, and place one pin into a socket aligned with the left pin of LED (cathode) , and the other into a socket on the bus line. Repeat for other 220 Ohm resistor on other side of board.
9Insert one end of a 75mm orange wire into a board socket aligned with the right pin (anode) of the LED on left, and the other end into digital pin D4. Repeat for the other 75mm orange wire for right side LED, placing the other end of wire into digital pin D5.
* It is recommended not to use digital pins 0 and 1, due to them being used by USB serial communication.

The Code

Download

Arduino

Component Library

As some new components have been introduced, I have added a low level library containing classes to encapsulate basic components called Component

Pronguino Library

… also a new project specific library called Pronguino, that utilizes the Component library, for example, to convert raw data from components into usable data i.e. controller value …

Pronguino Sketch

Creating libraries has a number of benefits, such as, being able to re-use code, keep the main sketch a lot less cluttered, easier to read …

Within the code download, there is a folder called arduino/libraries, inside there are two folders called Component and Pronguino, copy these to the libraries folder in the location specified from IDE menu option … File -> Preferences -> Settings -> Sketchbook location ….

Now, you should only need to open the Pronguino sketch and compile, you may have to restart IDE. You won’t see these libraries in the Library Manager as they are just local. maybe in time I will publish a library, and talk you through that.

Whats New
FileDescription
Component.inoDummy sketch for library.
Component.hHeader file for Component library.
Component.cppC++ implementation of Component.h
– Potentiometer class
– Switch class
– LED class
Component Library
FileDescription
Pronguino.inoDummy sketch for library
Pronguino.hHeader file for Pronguino library (replaces Controller.h)
Pronguino.cppC++ implementation of Pronguino.h (replaces Controller.cpp)
– Controller class
Pronguino Library
Whats Changed
FileDescription
pronguino.inoUses new Pronguino library
Refactored slightly
Only writes serial data on change of values
Pronguino Sketch

Testing

As previously, if you change TESTING to be true, upload the new code, the setup() will call function resultsHeader() to print some headings, and will also read the initial values of the two controllers, and the state of the buttons, so if you turn both potentiometers to the left, clear the serial monitor, and press the reset button on UNO .. you should see the following result …

controllerValue1    buttonState1    highNibble  controllerValue2    buttonState2    lowNibble   data
1                   0               16          1                   0               1           17
1                   0               16          1                   0               1           17

.. the loop()  function is now continuously reading from each controller and button, checking for a change in any of the values, when a change is detected,  resultsDetail() will print the values, note the bold values that change, so …

Turn left potentiometer to right a bit …

controllerValue1    buttonState1    highNibble  controllerValue2    buttonState2    lowNibble   data
...                 ...             ...         ...                 ...             ...         ...
1                   0               16          1                   0               1           17
2                   0               32          1                   0               1           33
3                   0               48          1                   0               1           49

Press and release the left button ...

controllerValue1    buttonState1    highNibble  controllerValue2    buttonState2    lowNibble   data
...                 ...             ...         ...                 ...             ...         ...
3                   0               48          1                   0               1           49
3                   1               176         1                   0               1           177
3                   0               48          1                   0               1           49

Turn right potentiometer to right a bit …

controllerValue1    buttonState1    highNibble  controllerValue2    buttonState2    lowNibble   data
...                 ...             ...         ...                 ...             ...         ...
3                   0               48          1                   0               1           49
3                   0               48          2                   0               2           50
3                   0               48          3                   0               3           51

Press and release the right button ...

controllerValue1    buttonState1    highNibble  controllerValue2    buttonState2    lowNibble   data
...                 ...             ...         ...                 ...             ...         ...
3                   0               48          3                   0               3           51
3                   0               48          3                   1               11          59
3                   0               48          3                   0               3           51

Note: So the they can be tested and make sure wired up OK, the relevant LED will light up when pressing either of the buttons, this only happens when in test mode.

Troubleshooting

A little more fiddly this circuit, a few more components and wires to check ..

IssueResolution
Nothing is workingCheck Arduino is plugged in securely.
Check red & black wires on board are secure.
Check wires connecting bus lines.
Random data in Serial Monitor (without change potentiometer)Check potentiometers are firmly pushed in.
Check the data wires are securely connected.
Check buttons are firmly pushed in along with data wires and resistors.
LED not emitting light (when button pressed in test mode, or when player waiting to serve)Check LEDs and resistors firmly pushed in.
Check the data wires are connected.
Troubleshooting Guide

Processing

In line with the Arduino code above, have add Button and Indicator classes to encapsulate the state, had quite a bit of a tidy up in the code, made adjustments for the lower range of values coming in from the controller, and removed the previous random start position / direction of ball, putting the player in control…

Whats New
FileDescription
ButtonContains a new class Button, which encapsulates the state received from the switches.
IndicatorContains a new class Indicator, which encapsulates the setting of state of the LEDs.
Whats Changed
FileDescription
BallRemoved random start direction.
ConstantsAdded more constants for state, button, indicator and data bit masks.
ControllerAdded Button as a child
Added Indicator as a child
Added connected flag
Refactoring
DebugRename of a flag
FunctionsUse of data bit mask constants
New function to create outgoing data
PaddleAdded speed factor.
PlayerRemoved “wrapper” methods for child objects
Refactoring
pronguinoAdded game state (i.e. paused, ended etc ..)
Added game actions (i.e. pause, resume etc ..)
Added new event methods i.e. buttonPressed
Refactoring

Challenge: As I was finishing the code for this stage of project, I saw a need for another class to help keep things tidy … Game … have a go at creating and implementing this class, maybe include state ? … and the actions ?

Rules

As this project progresses, these will be reviewed and improved to get closer to the real rules of ping pong. The game rules that have been implemented so far, are as follows …

RuleDescription
Game OverThe first player to SCORE_MAX wins the game.
Opening ServePLAYER_ONE has the first service.
Player MissesThe same player serves.
Serve DirectionIf the player serving has paddle in top half of surface, the direction will be down/left or right depending on player.

If the player serving has paddle in bottom half of surface, the direction will be up/left or right depending on player.

Play

Break time … Turn off testing mode, and re-upload …. kept the rules simple for now, when player misses the other player serves next, while the player has the ball the relevant LED should light, and will turn off, when they serve, either using the keyboard or “controller”…

DirectionPlayer 1Player 2
Upqp
Downal
Pause/Resume
Serve
spacespace
Key Controls

Fixed Resistors

At a basic level, resistors are used in circuits to reduce current flow, in the context of this circuit, I will describe the use of the fixed resistors along with switches and LEDs below.

Switches

The switches used in this circuit are momentary switches, so they close the circuit when pressed, and open circuit when released, for example, S1 is connected as follows …

Terminal 1 (T_1) connected to digital pin D2 and also, through a pull-down resistor (10k\Omega) to GND.

Terminal 2 (T_2) connected to 5V

The digital pins, when mode is set to INPUT , will either read as HIGH (~5V), or LOW (~0V).

When the pins are not connected to anything there is a small input leakage current, looking at the datasheet on page 259, both the low/high max current is 1\mu{A} (0.001mA), and the input would float between HIGH and LOW.

In order to guarantee a small enough voltage, say 0.01V to register as LOW when the switch is unpressed, we need to connect the pin to GND through a resistor known as a pull-down.

Using Ohm’s Law, we would calculate the required resistance with the following equation …

R = {V \over I}

… so, given the values from above …

R = {0.01V \over 0.001mA}

.. would give a result of …

R = 10k\Omega

LEDs

An LED (Light-Emitting Diode) is a component that emits light when current flows through it, also electricity only flows in one direction, in this circuit we have, for example, LED1 wired as follows …

Terminal 1 (T_1) connected to digital pin D4

Terminal 2 (T_2) connected to GND through a 220\Omega resistor.

Digital pin D4 has been configured as OUTPUT, when this pin is set to HIGH, the LED will light up.

So the LED doesn’t burn out too quickly, we need to put a resistor in series with LED, reduce the current, to calculate the Ohm value of this resistor, we would use the formula …

R = (V_s - V_f) * {N \over I_f}

… where …

SymbolDescriptionValue
V_sVoltage Supply5V
V_fForward Voltage (LED)2.1V*
NNo. of LEDS1
I_fForward Current (LED)20mA (0.02A)*
* These values where take from the datasheet, using the typical forward voltage, and test conditions.

… so …

R = (5 - 2.1) * {1 \over 0.02}

… resulting in …

R = 145\Omega

… but, there is no single 145\Omega standard value resistor, the nearest value would be 150\Omega*, however, the smallest value resistor in the Starter Kit is 220\Omega, so as we are using this, the forward current will be calculated as ..
* Based on similar resistors available at ±5% tolerance in datasheet

I_f = {(5 - 2.1) \over 220}

… giving …

I_f = ~0.013A = 13mA

.. which is more than enough to light it up, which is worth bearing in mind with LEDs, even though the datasheet states a maximum of 30mA, you don’t really need it that bright for most applications.

Learn: I find it important to get to know your components, and how they work, it helps when things don’t work as planned, look up the datasheets of the components to get data to be used to equations such as Ohms law to make sure you choose correctly.

Bitwise Operations

As this circuit is still using 8-bits to communicate with the serial port, thought a quick note on what has changed to accommodate the new switches and LEDs …

We are now only using the first three less significant bits to store the controller value (1 – 7), previously (0-15), with the fourth bit being used to store the button state.

Arduino

This code is a snippet from the createData(...) function in the main pronguino.ino file, it receives the values read from the potentiometers and states from the switches, and creates the data to be written to the serial port…

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

.. so when both potentiometers turned to left and the left button is pressed …function is given …

Binary Hexadecimal Decimal
controllerValue1 00000001 0x01 1
controllerValue2 00000001 0x011
buttonState1000000010x011
buttonState2000000000x000

.. to calculate the highNibble, first we need to left shift the buttonState1 3 positions ..

BinaryHexadecimalDecimal
buttonState1000000010x011
<< 3
result000010000x088

.. and then bitwise OR result and controllerValue1 …

BinaryHexadecimalDecimal
result000010000x088
| controllerValue1000000010x011
result000010010x099

.. then left shift four bits …

BinaryHexadecimalDecimal
result000010010x099
<< 4
highNibble100100000x90144

… in this example the controllerValue2 is 1, and button is not pressed, so, for simplicity lowNibble would be just 1, and to calculate data to send …

BinaryHexadecimalDecimal
lowNibble000000010x011
| highNibble100100000x90144
data100100010x91145

In the main pronguino.ino file, inside function serialEvent(), which will get called when any data received on serial port, there is the following snippet of code …

... // Read Data byte dataIn = (byte)Serial.read(); // Get State int state = bitRead(dataIn,0); // Get Index int index = bitRead(dataIn,1); ...

.. thinking I was going to write a few lines of code to extract the bits needed to identify LED state, and player index, a quick scan of the language reference revealed a function called bitRead, which does the job for me.

Learn: Sometimes you might find yourself writing lines and lines of code when there is function or method already available. Always worth a check in reference if you start thinking there must be a better way of doing this.

Processing

Have made some changes to the serialEvent() function in main Pronguino file, so it can now breakdown the data received from the UNO further, getting the highNibble and lowNibble haven’t changed …

... // Set the value of each controller (first 3 bits of nibble ... 0-7) players[Constants.PLAYER_ONE].controller.setValue(highNibble & Constants.DATA_BITS_VALUE); players[Constants.PLAYER_TWO].controller.setValue(lowNibble & Constants.DATA_BITS_VALUE); // Set the state of each controllers button (4th or most significant bit of each nibble ... 0-1) players[Constants.PLAYER_ONE].controller.button.setState((highNibble & Constants.DATA_BITS_STATE) >> 3); players[Constants.PLAYER_TWO].controller.button.setState((lowNibble & Constants.DATA_BITS_STATE) >> 3); ...

.. and by adding a few more constants for bit masks …

... static final int DATA_BITS_VALUE = 0x07; // Bit mask used to extract value of controller from nibble (00000111) static final int DATA_BITS_STATE = 0x08; // Bit mask used to extract state of button from nibble (00001000) ...

.. we will go through just the highNibble, as both same calculations for each, so given …

BinaryHexadecimalDecimal
highNibble000010110x0B11

.. to get the value of the controller …

BinaryHexadecimalDecimal
highNibble000010110x0B11
& DATA_BITS_VALUE000001110x077
value000000110x033

.. and to get the button state, first use mask to get bit value…

BinaryHexadecimalDecimal
highNibble000010110x0B11
& DATA_BITS_STATE000010000x088
result000010000x088

.. and then right shift three places …

BinaryHexadecimalDecimal
result000010000x088
>> 3
state000000010x011

When a player misses the ball, the ball is “given” to other player to serve, at this point we send a data byte to the UNO, to indicate which LED to light up, this data is calculated and returned from the following function in Functions file ..

static int getIndicatorData(int playerIndex, int indicatorState) { return (playerIndex << 1) | indicatorState; }

… so if we had …

BinaryHexadecimalDecimal
playerIndex000000010x011
indicatorState000000010x011

… first the playerIndex is shift 1 bit to left …

BinaryHexadecimalDecimal
playerIndex000000010x011
<< 1
result000000100x022

.. then bitwise OR result with indicatorState …

BinaryHexadecimalDecimal
result000000100x022
| indicatorState000000010x011
data000000110x033

Challenge: Create some more generic functions, a new functions file, say, Bitwise, similar to the Arduino bitwise functions i.e. bitSet(), lowByte(), to replace those in the Functions file, maybe highNibble(), lowNibble() ?

Conclusion

Had a bit of a shake up in the code, learned about some new functions, and new components, added some libraries, and touched on Ohm’s Law. One thing for sure knowledge certainly sinks in when documenting. Next up … adding a few more features to the game.