Projects

Slap Shot

Part 2: Air Hockey Table with Automatic Scoring

Daniel Koch, Rob Bell, & Johann Wyss

Issue 23, June 2019

This article includes additional downloadable resources.
Please log in to access.

Log in

In part 2 of our air hockey table build, we show you how to install the electronics that light the table and score your game. We also present some improved 3D parts that will house the scoring sensors and additional lighting.

BUILD TIME: 8 Hours
DIFFICULTY RATING: Intermediate

In part 1, we detailed the physical build and general electronic concepts for our DIY air hockey table. We also presented the 3D models that would enable the adventurous to gain a working table without further instruction. These were enough to get you going, but this month, we’ll go into more depth and present an insert for the goals, which will house the sensor. We will also detail the small discrete circuits needed to sense the puck in the goals, and present the code to make the whole thing work.

Electronically, the air hockey table is somewhat straightforward, although there are challenges in some of the details. The entire operation is based around an Arduino UNO, with separate circuits to provide sensors in the goals, a relay motor control interface, a pushbutton, and a buzzer output. The buzzer interface and the pushbutton circuit are both built onto a piece of perforated strip board, which also mounts the UNO and handles power supply and distribution connections. The goal sensors are on their own perforated strip board and are mounted in the goals.

GAMEPLAY

The electronics interact during gameplay as follows: When power is first applied, the UNO powers up and waits for a LOW from the pushbutton. When this occurs, the area lights turn on white, and the timer LEDs turn green. There is then a five-second delay to allow players to ready themselves. During this time, no goal triggering can occur.

After the 5 seconds, if either goal is triggered by the puck crossing its light barrier, the game timer pauses for five seconds, the timer LEDs extinguish, the area lights change to the colour of the scorer, and an LED of the appropriate colour lights on the scoring strips. After the 5-second delay, the area lights turn white again, and goal triggering can resume.

The timer LEDs count down the three-minute (180 seconds) game time in 18-second decrements, notwithstanding any downtime for a goal. With 72 seconds left, the LEDs change to yellow. With 36 seconds left, they change to red. Finally, with 18 seconds left and one LED lit, the buzzer begins to beep on and off, warning players that the end of the game is close.

When the game time is over, the area lights change to the colour of the winner based on the highest score. Just in case you have no audience, the buzzer screams out in excitement for 5 seconds, then the motor cuts out. Alternatively, if either player scores ten points before the game time expires, gameplay ends the same way, without the buzzer.

If the timed game ends in a draw, the area lights stay white, but otherwise, the ending is the same.

Finally, if at any time the push button is held for 5 seconds, the game ends with no fanfare, just the scores displayed. This is both to allow a quick end to the game when the kids are called to dinner, and to help resolve arguments. After the game is manually ended, another button push starts a fresh game.

Parts Required: JaycarAltronicsCore Electronics
2 × Perforated Strip Board 95 × 152mmHP9542H0712-
11 × PCB Mount 5.08mm Screw Terminal BlocksHM3172P2040APOLOLU-2440
3 × BC549 NPN TransistorZT2156Z1044-
2 × Infrared LEDZD1945Z0880AADA387
2 × Infrared PhototransistorZD1950Z1913-
1 × Red LED ZD0152Z0860CE05103
1 × Blue LED ZD0185Z0869CE05103
134 × WS2812 LEDs in a Strip, 30/m**--CE04853
20 × Header PinsHM3211P5340PRT-12693
3 × 4-way Header sockets#HM3230P5390POLOLU-1014
1 × 2-way Header Socket#HM3230P5390POLOLU-1012
1 × Jumper Link HM3240P5450001-HDSHCB
4 × 150Ω ResistorRR0552R7538CE05092
4 × 10kΩ ResistorRR0596R7582CE05092
1 × 470Ω ResistorRR0564R7550CE05092
1 × Arduino Uno XC4410Z6240CE05629
1 × Relay ModuleXC4419Z6325CE05137
1 × Pushbutton SwitchSP0669S0914-
1 × Piezo BuzzerAB3462S6109-
150mm Tinned Copper WireWW4032W0420-
8m Light Duty Hook-up Wire WH3015W2255POLOLU-2615
3m Red Medium Duty Hook-Up Wire 7.5A WH3040W2270POLOLU-2652
3m Black Medium Duty Hook-Up Wire 7.5A WH3041W2272POLOLU-2650
5 × Plug To Socket Jumper Wires* WC6028P1017PRT-12794
2 × Plug To Plug Jumper Wires* WC6024P1017PRT-12795
1m Rainbow Ribbon Cable WM4516W2510CAB-10649
400mm 1.5mm Heat Shrink WH5530W0910APRT-09353
50mm × 5mm Heat Shrink WH5533W0913APRT-09353
20 × 100mm Cable TiesHP1200H4031AFIT0343
12 × Tapped Nylon Spacers^HP0924H1348-
24 × Nylon M3 × 12mm Bolts^HP0140H2915-
19 × 4G × 12mm Wood Screws---
4 × 8G × 20mm Wood Screws---
9 × Small Nylon P-ClipsHP0752H4201A-

Parts Required:

* You can use these pre-made, or make your own custom length ones from PCB pins and sockets.

** This is the number of LEDs required. They usually come in a 5 metre strip, and we used 4.42m

# We cut these from a single length of socket strip. One socket is lost for each cut.

^ If you are using the goals with standoffs printed in them, you will only need 8 spacers and 16 bolts. You can also use metal bolts and spacers but be very careful of shorts on the copper side of the boards.

The Electronics:

The main circuit board is assembled on a piece of perforated strip board measuring 95 x 152mm. We have provided an overlay diagram for both top and bottom of the board below. Please note that the diagram for the underside is presented as you would look at it while working on it, not as though you were looking through the board with x-ray vision from the component side.

At the far left of the board are four two-way terminal blocks, two two-way headers, and a four-way header. Also present are some wire links and a resistor. The terminal block at the upper left is for the incoming 5V supply from the ATX PSU. The tracks it is soldered into run the length of the board and so deliver 5V at the other end, as well as on the way there.

The terminal blocks side-by-side in the middle left are for the ground connections, both 5V and 12V. Inside the ATX, these are all connected together anyway. We used so many wires simply for current capacity – our model does not use so much, but with the number of possibilities for those who will modify it, we went down the overengineered route.

The next blue two-way terminal block is for the 12V incoming connection. Again, the tracks here run the length of the board uninterrupted. The same goes for the ground connections already discussed.

Between these two is a four-way header. This is the connection for our pushbutton switch and provides both 12V for the light in the switch, as well as connections to the Uno for the actual switch contacts. See the switch circuit detail diagram for this. Note that the input is LOW-going, so the contacts ground when the button is pushed. Because of this, a 10kΩ resistor is connected from the Uno-side of the switch to ground, to avoid floating. This resistor is the one mounted behind the ground terminal blocks, and the wire links provide ground and 12V connections to the header. The single header pin here connects to the Uno to give the signal.

Finally, for this section of the board, two two-way headers are at the bottom left. The one closest the edge of the board is for the switch contacts for the power supply. The other is for either a jumper, or an external switch, whichever you choose. We went with a jumper.

Moving to the right, the next item on the board is the Uno itself. This is mounted on nylon standoffs above the board, both for insulation reasons and to give better access to the USB port. It also serves as a way to keep cables tidy, as shown later.

To the right of the Uno, from top to bottom, are two four-way header sockets for power take-off, utilising the full-length tracks described above. One is for 5V, the other for ground. Below these are two resistors and a single header pin, a transistor, link, and terminal block. This is the output for the buzzer and transistor to switch it.

The 10kΩ resistor connects between the base and ground, to stop floating. It shouldn’t be necessary, but it is included again for overengineering’s sake. No matter how electronically noisy the power supply or motor, there will be no false triggers.

Below this is a relay module. An off-the-shelf module made sense here because not only are heavy relay contacts hard to fit into perforated board, but relays with a 5V coil which switch decent loads are not as easy to come by as their 12V counterparts. These modules are designed to be controlled from 5V or even 3.3V logic while still switching up to 10 Amps. The prototype is mounted on standoffs again, but it could be mounted straight to the perforated board with nylon nuts and bolts.

Finally, at the far right, are the outputs for power and more ground connections. The upper right terminal is 5V for the LED strips around the table, the joined middle two are common ground, and the lower right block is the 12V for the fan motor.

GOAL CIRCUITS

The next circuit to describe is one which is produced twice, identical each time, save for a different coloured LED. These are mounted on cut-down perforated strip board, and feature three resistors, two wire links, a terminal block, transistor, LED, single jumper pin, and two pairs of wires soldered directly to the board. The upper pair goes to an infrared phototransistor, while the lower right pair goes to an infrared LED. This circuit forms the goal sensor to detect when the puck has landed in the goal. The low-powered phototransistor is amplified through the BC549 NPN transistor, which lights the LED. The 10kΩ resistor is included to stop spurious signals.

As can be seen in the circuit diagram for this, the output to the Uno is taken from the emitter of the transistor, in parallel with the connection to the LED’s limiting resistor. The LED is lit in the normal state, which is why one is red and one is blue – this circuit will be mounted in the semi-transparent goals. When the puck breaks the optical path between the IR LED and the phototransistor, the LED is extinguished. For this reason, the code looks for a LOW on these inputs. Incidentally, there is reason to be careful here. The blue LED circuit mounted in the blue goal gives its input to the section of code responsible for red’s score. Of course, if the puck enters blue’s goal, it’s red’s point, but it is easy to mix these up when constructing. Not to worry, if this happens, a simple unplug-plug operation on the Uno to swap the two fixes everything.

The Build

Now that the electronics are familiar, it is time to start assembling the parts, starting with the main board. Using the overlay diagram, count and mark where the holes will be drilled for mounting the UNO, relay, and the main board itself. These are all 3.5mm holes. Note that one of the holes for the UNO is between holes on the perforated board. Drill and clean the holes.

Now install the wire links and the resistors. Remember to bend their leads at 45° on the underside of the board to hold them in place, then solder and trim them. Next, insert the jumpers and header sockets. It is likely easiest to do these one at a time, as they will need to be held while being soldered. Use small pliers or tweezers for this, to avoid burnt fingers.

Insert and solder the transistor, taking care of which way it faces. This done, insert all of the terminal blocks and solder those too. Be very careful that they line up along the tracks. Now turn the board over and cut several tracks as shown. There is one diagram for the component side of the board, and one for the solder side. The one for the solder side is as you see it, so it is mirrored from the component side. The track cuts are marked with crosses. Use a face cutter or a 3.5mm drill bit to scrape away all the copper around these holes, leaving the track completely broken.

GOAL SENSOR

For the goal sensor boards, count out the appropriate amount of perforated strip board, and score several times along the next row with a sharp knife.

Score in the same place underneath, several times, then snap. Count and mark the mounting holes, then drill and clean them.

Start by inserting the wire links, then the resistors. The transistor and LED can follow. One circuit gets a blue LED, the other a red LED. Now insert the jumper pin and terminal block. As for the main board, there are some track cuts marked with crosses on the diagram for the solder side. Cut as before.

Peel two wires from a length of ribbon cable, long enough to go from the circuit board where it will mount in the goal, to the IR LED, and two more for the phototransistor. Cut the legs of the phototransistor to around 10mm, then solder the ribbon cable to it. Note that the collector is the short lead and the emitter is the long lead. The flat spot on the case rim will help once you trim them. Make sure you heatshrink all your joins. Repeat for the IR LED.

Solder the phototransistor and IR LED leads into place on the board, being careful of polarity.

WIRING IT UP

Now it is time to start wiring some hardware. From a roll of WS2812 RGB LED strip; cut three lengths of 18 LEDs each, six lengths of 10 LEDs each, and four lengths of 5 LEDs.

Attaching these to the superstructure is a little challenging. The 3D print files include some clips that can be printed to hold the finished product, but something more substantial may be required during assembly. We experimented with double-sided tape, which worked ok, but it was not perfect. Because of this, we have included some screw-down clamps in the 3D print files. These mount between the strips with 4G x 12mm screws.

On both of the vertical sides, three strips of 10 LEDs are mounted at equal distances. Align the outer ones with the edge and the middle one in the centre. Take care to ensure that the DI (Data In) lettering is at the bottom of each, with the DO (Data Out) at the top.

On the underside of the top piece of the superstructure, three strips of 18 LEDs each mount the same way, but for one difference. The outer strips have the DIs and DOs at the same ends, while the middle one is reversed, as shown in the diagram and photographs. This is so that they can be wired in series easily.

Using the connection diagrams on the left as a guide, wire the power connections so that the 5V wire leaves via one side of the structure, and the ground wire via the other. We used red and black 7.5Amp hook-up wire here. Note that this means some short connecting wires in each case on the opposite side. Work gently here, as these pads are quite fragile.

Now you can connect the data lines. We used light duty green hook-up wire for ours, and labelled each one with masking tape as we connected it. This is critical later. There is one connection from the area lights (the three strips of 18 LEDs up top) that runs from the top of the superstructure and down one side. We labelled this ‘Area’. All other data connections are attached at the bottom of the superstructure near where it meets the table.

These connections need to end up in parallel, so cut wire long enough to join later somewhere under the table. We labelled the centre wires ‘Timer’ and chose ‘Score A’ and ‘Score B’ to label the outer strips. Tidy the wires and bring them into the corner where the superstructure meets the table side. You will note that the 3D printed cowling has a track down one side for the wires. It’s a tight squeeze on one side with four data wires and a power wire, and not much better on the other side, but they do fit.

Use something like a ruler to tuck them in if need be as you push the cowling into place. Screw it down firmly with 4Gx12mm screws. These cowlings are the side braces described in part 1, and you may already have them mounted.

UNDERNEATH

Bring the wires from one side, around the motor, and to the other side. Find the two ‘Score A’ wires and cut them to meet at a point around 100mm from the edge of the table. Bare about 5mm from the ends and use one of the offcuts to join onto them. See photo for clarity. Solder and cover with heatshrink. Repeat for ‘Score B’ wires and ‘Timer’ wires, but leave the power wires and the area light data wire unmodified. Check the photos to see if you’re on the right track.

The mainboard caddy is a bracket with mounting holes to screw to the table, and stand-offs to mount the board. We have also made ladders for small cable ties to keep the incoming wiring tidy. These mount with 20mm wood screws. The main board mounts upside down on the table so that wiring into the headers on the UNO is easier.

Start by screwing the caddy to the table in the desired location, which is entirely up to you, using 4Gx12mm screws.

Then use more 4Gx12mm screws to mount the main board. Now track the bundle of wires from the superstructure back to the main board. Note that we have ours twisted together. This practice has the advantage of neatness and ease of mounting, but it is hard to trace and remove wires if changes are needed. It is up to you to do so or not.

Additionally, you may see that our prototype does not use the caddy. We just used short standoffs and screwed directly to the base board, which works fine too, but you will need 20mm screws, not 12mm. It also makes anchoring the wires harder if you’re using the ladders.

One at a time so you don’t get mixed up, trim the data wires to length to comfortably reach to the UNO, then bare around 5mm at the end. Solder a single jumper pin to this and cover the join with heat shrink. Label the wire about 100mm back from the end and insert the header into its relevant socket on the UNO. You should have inserted Timer, Area, and Score A and Score B. Score A and Score B will be red and blue, but which is which depends on how you assigned them.

If you get it wrong, you can swap them easily later. While you’re doing this, you can trim and connect the two power wires to their terminals at the output side of the main board.

PUSH BUTTON

Next, you can install the push button. We chose an arcade game button, which has a light as well as normally open and normally closed contacts with a common. Start by deciding where your button will go, then peel four joined wires from a piece of ribbon cable, long enough to reach the main board.

Solder one end to a four-way header socket, adding heatshrink. Plug the socket onto the four-way header between the terminal blocks at the USB end of the UNO and mark one wire with a permanent marker. Place a dot at the same end of the header.

Take note of which wire colour goes where. The wire closest to ground goes to the Common (C) contact, the next goes to the Normally Open (NO) contact, while the next is the ground for the light. The one closest to the 12V screw terminal is the 12V supply for the light. These two connections are the outer tabs on the switch. Which is negative and which is positive depends on the way the LED, which is mounted in a plastic wedge globe base, is installed in the switch. Simply choose, and if the LED does not light during testing, pull it out and turn it around.

When you know which wire goes where, solder them to their relevant tabs on the switch, adding heatshrink.

Now you can install the switch in its bracket and plug the header back into its socket on the main board. You can tidy and clip the ribbon cable in place while you’re at it.

GOALS

The last assembly centres on the goals. These have one data line and two power wires exiting each. Start by inserting the goal inserts temporarily. You’ll need to drill three 8mm holes to let the wires through. Take note of where the wires exit the goal insert to tell you where to drill.

Next, mount the small circuit board that contains the sensor electronics. You can use threaded standoffs and drill through the side, or self-adhesive mounts. If you do drill and screw, using nylon bolts will help reduce the visual signature.

With the board mounted, track the wires and the IR LED and phototransistor attached through the holes. Carefully bring the IR LED through the rearward hole and out far enough to insert into the hole in the goal insert. Fold the legs and wire into the slot, then slide the insert back into place, pulling excess wire as you go. Now add the second half of the goal insert and install the phototransistor. Fold its legs and wire into the recess and withdraw the excess wire.

The final goal sensor task is to attach the data out wire. This is the same light duty green hook-up wire as on the superstructure. You could solder directly to the header pin, but we chose to solder a PCB pin socket onto the wire, heat shrink over it, and slide it onto the jumper pin. Make this wire long enough to reach the main board.

LIGHTING THE GOALS

The goals light with two 5-LED lengths of WS2812 LED strip. Solder power and data connections to each. One data line will connect to the other side of the goal, while the other data line will run back to the main board. Power wires both go to the goal sensor circuit board, where they utilise the screw terminals as a joiner.

Mount the two LED strips using hot melt glue – just don’t be excessive, seeing as the goals are made from a heat-formed material. You will need to drill two holes in the underside of the goals for the wires to pass through. The wires connect to the upper ends, so solder these first before you glue anything.

Be careful of the DI/DO marks on the strip. Just above the sensor circuit board, solder the two LED data wires to a longer wire that will go to the UNO. Label the appropriate wire ‘goal lights red (or blue)’, and the other ‘red (or blue) goal sensor’. Drill one final hole for the power and data wires to exit the assembly. If anything is unclear, refer to the photos.

If you’re happy with the goals and have a grand total of four wires coming out – two for power, two for data – you can mount them to the table. You may wish to drill small holes at the top to add two 4Gx12mm screws to stop the goals moving. Then you can run the power wires from the goal to the main board using the 3D printed clips for neatness and security of your wiring. As with the timer and score lights, you can solder on a PCB pin or a header pin. You could also cut and solder on a jumper lead.

POWER SUPPLY

To power our air hockey table, we chose an ATX power supply, which we raided from an old office computer. You can buy these online or from computer shops for as little as $30, or you can salvage them from old computers that you know the history of. Please do not use roadside pickup computers for these – if there has been any rain or spills (and you don’t know how long it was outside before it was put on the curb), these can be hazardous.

The ATX supply mounts in a 3D printed bracket. The STL file is supplied. It mounts the supply using the existing screw holes and screws, and mounts to the underside of the table with four 4Gx12mm wood screws.

Cut all of the connectors off the wires, then separate the yellow, red, and black wires. Find the green wire, and tape it together with one black wire. Any other wires can be cut about 50mm from the supply and covered with heatshrink.

Next, find the shortest red or yellow wire, and trim all of the others to match. Strip about 10mm from the ends of all the yellow, red, and black wires. Bundle all the red wires, then divide them in half. Twist together all the ends from each half bundle, then repeat for yellow. When it comes to black, the procedure is the same, except that there will be four bundles.

Following the photos and overlay diagram, insert the wire bundles into their respective screw terminals. You may need to trim the ends of the bare wire. If they are too big, you may find twisting with a pair of pliers while pulling away helps both tighten the bundle and stretch it to be narrower.

Finally, the green and black wires can be soldered to a header socket or directly to the two pins below the 12V screw terminal. The two pins close by get either a jumper link or can be connected to a separate switch.

FINAL WIRING

Now it is time to complete the last of the wiring. Start by bringing the power wires from both goals and the superstructure to the output end of the main board. Cut to length and twist the three red wires together. Insert them into their screw terminal and tighten firmly. Repeat for the three black wires.

The motor likely has two short wires on it. Solder more of the 7.5A red and black wire to the positive and negative wires of the motor respectively, taking care to heatshrink the joints. The positive wire goes to the 12V output screw terminal, while the negative goes to the Normally Open (NO) contact on the relay module. The Common (C) terminal of the relay module is connected by a short length of black 7.5A wire to the ground terminals as shown in the photo.

The last installation task is to attach the buzzer to its terminal block, and screw it to the board using 4Gx12mm screws.

Second to last, double check that the data wires are in the right positions before you anchor all of the external wiring with cable ties.

Finally, use jumper leads with a plug one end and a socket on the other to connect the 5V and GND connections for both the UNO and relay board to the relevant sockets on the power supply rail. The same leads can be used to connect the signal line of the relay module to pin 9 of the UNO, the switch signal to pin 10, and the buzzer control pin on the perforated board to pin 4.

If there are any doubts, have a close look at the photos, diagrams, and overlays.

With all of the electronics wired, it's time to look at the code.

THE CODE

We have made the code available on the Resources section of our website.

The code for this project was very much an iterative process. We started out with a simple set of rules; some rules were obvious, such as the game must have a time limit, it must display the time remaining, display the current score and identify who scores. Others, such as that the code had to ignore any goal triggers during the reset time provided after a score, were less obvious. This set the laws so to speak of our project.

The second step was getting the game logic correct. This was done by writing basic pseudocode, which documented the logical steps needed to achieve the game rules.

If (red goal is triggered){
  Blue score ++
}
If (blue goal is triggered){
  Red score ++
}
If (timer = 0){
  If (red score > blue score){
    Red wins
  }
  If (blue score > red score){
    Blue wins
  }
  If (red score == blue score) {
    Game is tied
  }
}
If (blue score == 10){
  Blue wins
}
If (red score == 10){
  Red wins
}

Whilst this code clearly cannot be compiled, it served as a logical map which we used to guide our code. In fact, if you look at the code blocks you can see each of these if statements have been implemented in actual code in the final program / sketch.

After we constructed the games logical boundaries, we set out implementing separate/complementing features, such as the area lighting and displaying the score, etc. This was made remarkably easy thanks to the Adafruit NeoPixels and accompanying library. The LED strip we used was a WS2812 LED strip of individually addressable LEDs. These LEDs are controlled with a single wire interface. Whilst we could control all of the 104 LEDs via one pin, we found it significantly easier to program if we grouped them into functional groups. That is to say, our LEDs are connected as follows:

  • The timer consists of 2 LED strips of 10 LEDs, wired in parallel and sharing the same data input, thus illuminating the same LEDs. This is referred to in code as strip_a and is connected to digital pin 6
  • The red score is displayed on a single strip of 10 LEDs, and referred to as strip_b in the code. It is connected to digital pin 5
  • The blue score also consists of 10 LEDs, and referred to as strip_c in code. It is connected to digital pin 7
  • The area lighting consists of 54 LEDs, which the code refers to as strip_d. Connected to digital pin 11
  • The goals are illuminated with 2 strips of 5 LEDs, wired in parallel with red referred to as strip_e in code and connected to digital pin 12. Blue is referred to as strip_f and is connected to digital pin 8

The Adafruit NeoPixel library can be installed directly through the library manager or downloaded from https://github.com/adafruit/Adafruit_NeoPixel/blob/master/Adafruit_NeoPixel.h

LIGHTING

//Include the Neo pixel Library
#include <Adafruit_NeoPixel.h>
//Name the string, define how many LEDs the
//string has and declare what 
//pin it is attached to
Adafruit_NeoPixel strip_a = 
Adafruit_NeoPixel(64, 2); 
void setup() {
  //tell the strip to begin
  strip_a.begin();
}
void loop() {
  //This line creates a loop that will be repeated 
  //64 times ie the number of LEDs in the strip
  for (int i = 0; i < 64; i++) {
    //This line tells the LED what 
    //colours to illuminate
    strip_a.setPixelColor(i, strip_a.Color
(0, 255, 0));
    //sets the brightness
    strip_a.setBrightness(40);
    //displays the pixel
    strip_a.show();
  }
}

The strip_x.COLOR(x, x, x) line sets the individual pixel colour for the LED in a decimal code, in the following order (Red, Green, Blue). You can control the colour and intensity of a pixel using the three values. If you want red you only need values in the Red segment with 255 being the most intense and 0 being off.

We find using the interactive RGB colour picker on Rapid tables to be very helpful (Just ignore the HSV values). https://www.rapidtables.com/web/color/RGB_Color.html

With this tool, you can very precisely choose any colour you desire using very simple sliders.

SCORING

Scoring was a little trickier. We needed to make sure that the program would detect a goal being scored. In theory, this is very simple, we just need to check the digital pin attached to the sensor each loop of the program, which is called polling. If the sensor changes state we know a goal has been scored.

Of course, in practice it isn’t as straightforward. Microcontrollers operate in a sequential manner, which is to say, they act in a systematic line after line method. This means it’s possible to miss the goal scoring if you’re not checking for the goal when it is scored. Since our program is quite complex, and contains strings of LEDs illuminated via for loops, etc., there is a good chance using the polling technique that we could miss a goal being scored. We had a couple of ways we could overcome this. We could make sure the puck was physically blocking the sensor for longer, or we could use interrupts that cause the program to jump to a special routine if they are triggered.

The best way to explain this process is to think of your letterbox. Let’s imagine you’re waiting for an important letter or package. You can go out and physically check the Post Office box every ten minutes (polling), or you could activate notifications from Australia post that send you a text message or email when your parcel is delivered (interrupts).

When the interrupt is triggered via a changing state on the interrupt pins (digital pin 2 and 3 on the Arduino Nano and UNO), the program jumps into the interrupt service routine ISR. After completing the ISR, the program returns to its last known instruction before the interrupt was triggered.

Our ISRs simply increment the score and flag the team’s goal as true. When the program reaches the score display and goal detection phases, it knows the score has been incremented and that we need to display the lighting of the scoring team. i.e. Red or Blue.

void debounceBlueISR() {
  if ((long)(micros() - prev_period) >= debouncing_duration * 1000) {
    blueISR();
    prev_period = micros();
  }
}
void blueISR() {
  redScore ++;
  redGoal = true;
  delayMicroseconds(100);
}

During testing, we noticed that it was possible to score a second goal very soon after already scoring one. To counter this, we added a debounce function, which is called an interrupt trigger. It then calls the ISR for the appropriate goal. This debounce duration for us was 5 seconds and prevents the ISR from triggering again during the debouncing_duration timeframe.

Our original idea to detect goals was to use an infrared sensor and receiver not dissimilar to what you would find in your television remote control. However, whilst implementing this sensor, we quickly learned that the output was not stable enough and often resulted in erroneous goal triggering. To counter this, we switched to a more reliable UV sensor and receiver which resulted in zero errors.

The remainder of the code is fairly self-explanatory. You will see that the majority of lines are used to control the LEDs.

To help understand and follow the code we have compiled the program into functional blocks, with a separator (seen below) at the beginning of each block. This will provide a basic idea of its function in the overall program, which should make it easier for you to modify the code, if you wish.

/******************************
               Title
 ******************************
*/

That sums up the coding for our game table. Let’s now discuss the 3D printed parts.

3D PRINTED PARTS

Note: The parts letter assignments follow on from Part 1, for clarity. However the updated goals are still noted as print "B" as they replace the originals.

B. GOALS (UPDATED) x 2

The goals themselves do not change in shape from the originals, however we've updated the curve at the back of the goal to help push the puck into the goal insert better.

  • Print time: 12.75hrs (each)
  • Approximate weight: 331g (each)

K. Goal inserts x 2

This is printed in two parts, and positions the infrared goal sensors.

  • Print time: 1.75hrs (each)
  • Approximate weight: 40g (each)

L. start / reset switch housing

A robust switch housing to put the start switch on the side of the table. Easily modified to suit different switches.

  • Print time: 2.5hrs
  • Approximate weight: 56g

M. atx power supply mount

ATX power supplies are a pain to mount usually, while retaining the require airflow around it. It uses industry standard ATX screw patterns for almost universal compatibility.

  • Print time: 6hrs
  • Approximate weight: 134g

N. main board mount (optional)

Mounting for the main veroboard control unit.

  • Print time: 1hr
  • Approximate weight: 20g

O. cable ladders

These aren't essential, but help keep our wiring tidy.

  • Print time: 26hrs
  • Approximate weight: 7g (each)

X. LED Strip clamps (optional)

Used to aid in mounting the LED strips

  • Print time: 5mins (each)
  • Approximate weight: 1g (each)

Last month, we described several 3D print files and used some in the core build. It provided a full finished build you could use by powering up the air blower, but we still had to do the scoring functionality, game timer, and more.

Here for Part 2, we are presenting the additional ones used here, plus some updates for the goals. If you used the previous goal print, don’t worry. The alternatives will be relatively easy to engineer.

Updated Goals

The original goals worked very well, but after some extensive game play (well, we did have to test it... naturally) we discovered a small problem.

If you went for an epic "slap shot" and had a lot of force behind it, the puck could actually bounce back out of the goal after rebounding off the back wall.

We did have a curve in the back of the goal to direct the puck down to avoid this, but its position was too high and it was ineffective.

In the revised version, we have modified this portion in order to direct the puck downward into the goal catch, regardless of the velocity it has. You can see the image below with the original goal on the left, with the modified version on the right.

Note, our image shows a black inner-U part as well. During our prototyping we printed this portion separately so we could work and rework as required, without printing the entire goal again. The inner-U portion is included in the goal file still, as per the original.

If you already printed your goals, you can affect a similar adjustment to your originals by fitting a piece of acrylic, or printing an adaptor.

You just need to look at the height of entry for the puck (ie, the height of the table) when the goal is in position. You'll see that where the puck hits the back of the goal is basically vertical and the curved portion is much too high. You can install your own modification with relative ease.

Goal Inserts

The two-piece goal insert is what catches the puck, and houses our infrared LEDs for the scoring functionality.

The inserts hold the sensors for goal scoring, and also help retrieval of the puck. They are almost a mirror of each other, but look closely - the cable entry channel for the sensor wires is different on each.

The insert fits inside the original goals, with no modification. It is printed separately and not integral to the goal, as it needs to allow wiring. It would also require substantial support material to include it with the main goal, and would be difficult to clean out.

SWITCH HOUSING

The push button switch to start and reset the game is housed in a caddy mounted on the side of the table. It has four flanges for mounting screws, a hole at the top sized for an arcade game button, and a small recess at the bottom for the ribbon cable to exit. It is designed square to minimise supports when printed as suggested. It has a small projection at the top which sits on the top of the table frame, making alignment and installation easy.

ATX Mounting

Mounting ATX power supplies is not as easy as it seems to be. They have a pattern of mounting holes that is not symmetrical, and a substantial cut-out is needed for air flow, switch, and power connector.

The mounting bracket we have designed has four screw holes to make mounting to the table easy, appropriately placed holes for the ATX mounting screws, and ample breathing and access space. It also has a lip at the back which is enough to stop the power supply wanting to swing downward, as it mounts upside down. While we have included a cross-brace for those who feel it's necessary, the frame is rigid enough to hold the supply with no further support.

Main Board Mounting

While not strictly necessary (we didn’t use it in the end, installing our board before we thought of this), the mainboard mounting makes life a bit easier. It has four screw holes for mounting to the table, and four standoffs for screwing the board down.

Cable Ladders

These ladders have screw holes to mount next to the main board. They have slots so that, with the aid of small pliers, you can feed a cable tie around each slat and anchor incoming cables to it. This helps keep your cable inputs nice and neat.

LED Strip Clamp

Finally, we have a small clamp that can be used while constructing the overhead structure - it holds the LED strips. It works by covering all three strips and mounting two screws between them. The pressure is enough to retain the three strips. You can use one of these at each end while installing and soldering the strips, or you can use them permanently as an alternative to the clips provided in part 1.

Have fun with it, play it - enjoy it!

Part 1