Tijdens de corona pandemic bespaarde ik een hoop reistijd. Met deze tijd heb ik een sjoeltafel omgebouwd tot een arcade spel. Zie hier Pandemic de Arcade-stijl Sjoeltafel...
English version is on my website. This is a little more detailed with links to components used.
:strip_exif()/f/image/nDL55vrAw0PAYcuTvERJlAPh.png?f=user_large)
Het idee voor de puntentelling was om dit te doen met infrarood LEDs en sensors. Dit had ik nog niet eerder gedaan en ik wist ook niet zeker of het goed zou werken. Eerst heb ik uitgerekend hoe ik de sensor het best kan plaatsen om pucks langs te zien komen bij de poorten. In het midden is geen goed idee, omdat twee pucks elkaar kunnen duwen waardoor ze elkaar raken en de sensor het verschil tussen de twee pucks niet kan zien. Ook langs de zijkant van de poort is geen goed idee omdat er speling zit tussen de diameter van de puck en de breedte van de poort. Dus zou een puck ongezien kunnen passeren.
Om er zeker van te zijn dat dit gaat werken heb ik een test opstelling gemaakt. Dit bestaat uit een mini sjoeltafel met 1 poort die even breed is als een normale poort. Een Arduino met LEDs en een sensor moet de puck detecteren.
Uit de test bleek dat de pucks soms meer dan 1 keer geteld worden wanneer ze door het poortje gaan. Dit komt omdat de pucks half in de poort nog over de “Y” as kunnen bewegen en zo de sensor meer dan 1 keer kunnen doorbreken. De oplossing hier voor was om 2 sensors achter elkaar te gebruiken.
:strip_exif()/f/image/nDL55vrAw0PAYcuTvERJlAPh.png?f=user_large)
Voor het ontwerp heb ik voor Fusion 360 gekozen. Dit omdat het gratis is en mijn collegas er ook gebruik van maken (en er lovend over zijn). Ik had het nog nooit gebruikt, maar met tips van mijn collegas kwam ik een heel eind. Zodoende heb ik de originele sjoeltafel nauwkeurig opgemeten en een 3D model van gemaakt.
Onder de sjoeltafel heb ik een houten behuizing toegevoegd wat de hele tafel 5.5 cm hoger maakt. Dit geeft ruimte voor de elektronica, de speakers en de knoppen.
Een van de minpunten van de originele sjoeltafel is dat de sleuven achter de poorten niet genoeg ruimte bieden om pucks naast elkaar kwijt te kunnen. Er moet altijd iemand pucks gaan stapelen achter de poorten om te voorkomen dat de sleuven vol zitten. Dit heb ik opgelost door de sleuven voor een groot deel weg te halen (vanaf 15 cm achter de poorten) en de pucks in een bak te laten vallen. Dankzij de extra 5.5 cm hoogte was dit goed mogelijk.
Het display wilde ik boven de poorten hebben, zodat het display ook poorten kan “aanwijzen”. Tevens is dat een mooie afstand voor de speler om het display goed te kunnen zien. Ik heb gekozen voor 2 LED Matrix displays van Adafruit van ieder 64x32 pixels voor een totale resolutie van 128x32 pixels. Deze zijn net iets minder breed dan de sjoeltafel zelf, een perfecte grootte!
Om het geheel netjes te maken print ik een plastic frame waar ze netjes in passen. Het frame is ontworpen om los over de poorten te zetten, zodat het gehele display gemakkelijk verwijderd kan worden voor transport. Er zit een gleuf aan de voorkant van het frame voor een plexiglas plaat die de LEDs beschermt tegen vliegende pucks. Het display is een paar graden gekanteld voor betere zichtbaarheid vanuit de positie van de speler. Ook loopt de onderkant schuin af zodat deze mooi overlapt over de originele stippen boven de poorten (en dit geeft ook extra stevigheid).
Ook heb ik de elektronica in kaart gebracht en nagedacht over de werking er van. Voor de aansturing van de displays heb ik een HAT op de Raspberry Pi gebruikt. Deze gebruikt bijna alle GPIO pinnen (inclusief alle PWM pinnen) en de software gebruikt een interne timer die ook gebruikt wordt voor de standard audio output. Dit betekent dat er geen pinnen over blijven voor de sensors en dat ik geen audio output heb.
De sensors sluit ik daarom aan op een Arduino. Deze is dan ook dedicated, real-time bezig met het uitlezen van de sensors, zodat iedere snelle verandering opgepikt wordt. De Arduino maakt simpele berichten die via de seriële interface (over USB) naar de Raspberry Pi gestuurd worden. Deze berichten hoeven dan niet real-time opgepakt te worden. Er zijn 10 infrarood LEDs, waarvan 2 high power, om de sensors te belichten. Bij elkaar hebben deze te veel stroom nodig om dat uit de (USB-powered) Arduino te trekken. Daarom voed ik deze direct vanuit de PSU. Ze staan dan wel continue aan (wat de levensduur verminderd), maar mocht het ooit zo ver komen dan kan ik de LEDs altijd nog vervangen.
Voor de audio sluit ik via USB een audio module aan (PCM DAC chip) welke een analoge output geeft. Deze haal ik door een kleine versterker voor de 3W stereo speakers.
De 2 displays samen verbruiken (als alle LEDs aan staan) een kleine 16A op 5V (80W) dus koos ik voor een 100W voeding. Meestal staan niet alle LEDs aan (wit op volle sterkte), maar better safe than sorry.
In Fusion 360 heb ik alles een plek gegeven en nagedacht over mogelijkheden tot reparatie indien nodig. De elektronica zit daarom op aparte latten met inslagmoeren onder de tafel en is altijd los te schroeven. Hier onder is een overzicht van de onderkant en detail foto’s van verschillende delen.
:strip_exif()/f/image/nDL55vrAw0PAYcuTvERJlAPh.png?f=user_large)
Eerst zaag ik de achterkant van de originele sjoeltafel af, want daar moeten de pucks in een bak vallen. Dit viel erg tegen, want de schotjes tussen de poorten zitten niet aan de bodemplaat vast en gaan dus alle kanten op bewegen tijdens het zagen. Ik heb het vanuit verschillende richtingen geprobeerd maar het bleef klungelen. Het resultaat is dan ook matig en mocht ik ooit nog eens een dergelijke sjoeltafel bouwen dan moet dit anders.
Verschillende hardhout latten van 5.5 cm breed heb ik op maat gezaagd en voorbereid met gaten waar nodig. Sommige onderdelen zoals de speakers en kabelgoten bevestig ik nu al op deze latten. Dat is makkelijker dan wanneer het frame in elkaar zit.
Met een sterkte houtlijm/kit plak ik de “wandjes” aan elkaar. Dit kost meerdere dagen omdat ze niet allemaal tegelijk kunnen en ze wel 24 uur vast moeten zitten om goed te hechten. Om het geheel nog iets steviger te maken schroef ik er ook verstevigingshoekjes in. Deze heb ik zelf geprint omdat ik daar heel enthousiast mee was, maar in het vervolg kan ik ze net zo goed kopen. Die zijn verkrijgbaar van ijzer (steviger) en het is geen duur onderdeel. In de video hier boven (bij het ontwerp) kun je zien wat de volgorde is waarin de latten gemonteerd worden.
Voor het boren van de nodige gaten in de poortjes heb ik twee hulpstukken gemaakt om het boren te begeleiden. Zo weet ik zeker dat de gaten nauwkeurig op de juiste plek zitten en recht geboord worden. Helaas heb ik geen kolomboormachine thuis staan.
De LEDs en de sensors bevestig ik met (wederom) 3D-geprinte covers/bevestigingsstukken.
In het ontwerp heb ik 10 cm tussen de twee brug sensors gehouden, omdat ik bang was dat het licht van de LEDs de sensor kruislings zou bereiken. Dan zouden beide sensors niet meer werken.
Uiteraard nadat ik de sensors al had gemonteerd kwam ik pas op het idee dat ik 1 paar om zou kunnen draaien (LED en sensor omwisselen) waardoor het licht van die LED nooit de andere sensor (dan aan dezelfde zijde) zou kunnen bereiken. Dan hadden de sensors dichter bij elkaar geplaatst kunnen worden en blijft er meer speelruimte op het bord vrij waar pucks mogen landen zonder dat ze afgekeurd worden. Laat dit een tip zijn voor hij die de volgende arcade sjoeltafel bouwt.
Dan het plaatsen en aansluiten van alle elektronica: de PSU, Raspberry Pi, Arduino, Audio chip en de versterker. En de bedrading natuurlijk netjes vast zetten en in de kabelgoten stoppen.
Het display was een kwestie van 3D printen en in elkaar schroeven/lijmen. Dit was makkelijker gezegd dan gedaan, want het is best een groot geheel om te printen en het bestaat uit 4 stukken die naadloos op elkaar moeten aansluiten. Voor een beginner met 3D printen een hele uitdaging, maar na 3 pogingen was ik tevreden met het resultaat.
Als laatste heb ik de onderkant dicht gemaakt met dunne multiplex platen welke in 3D geprinte gleuven schuiven. Deze voorkomen beschadiging van zowel de elektronica als kindervingertjes en kunnen open geschoven worden wanneer nodig.
:strip_exif()/f/image/nDL55vrAw0PAYcuTvERJlAPh.png?f=user_large)
De Arduino software heeft 3 modi waarin het kan verkeren: Idle, Normal en Testing. Deze kunnen gekozen worden door de Raspberry Pi waar de hoofd-software draait. De Idle mode is voor het opstarten (zolang de hoofd-software nog niet gestart is) en zorgt voor het knipperen van de gele knop om aan te geven dat het opstarten onderweg is. De Normal mode houdt alle sensors in de gaten en rapporteert gebeurtenissen naar de hoofd-software in simpele berichten zoals “Er ging een puck door poort 2”. De Testing mode houdt ook alle sensors in de gaten maar geeft low-level rapportage zoals “Voorste poort 2 sensor hoog”. Dit wordt gebruikt voor de system test functie.
Voor de communicatie over USB (serieel) gebruik ik Protobuf. Dit is een lichtgewicht en simpel protocol en ik heb hier al ervaring mee, dus het was snel te implementeren.
De hoofd-software draait op de Raspberry Pi en doet het meeste werk. Het bestaat uit een aantal state-machines en heeft veel code rond het renderen van het beeld. Deze code heb ik zelf geschreven, omdat het nogal een niche is met veel eisen zoals pixel-perfectie op lage resolutie. Ook is de rekenkracht op een Raspberry Pi beperkt. Voor de communicatie met de displays heb ik de “rpi-rgb-led-matrix” library van Henner Zeller gebruikt. Deze code is te vinden op github.com/hzeller/rpi-rgb-led-matrix en is goed gedocumenteerd. Voor het mixen van de audio (muziek en geluidseffecten) gebruik ik fmod (fmod.com).
De software heeft een systeem test functie waarmee alle sensoren in beeld gebracht worden. Dit is handig om te controleren of alles naar behoren werkt (na bijvoorbeeld vervoer).
De software is niet perfect. Er zijn een aantal bekende bugs en een aantal dingen die ik moet refactoren om het netter en foutloos te maken. Verder beoordeel ik (als ervaren programmeur en software architect) de software natuurlijk van hobby-niveau, omdat het totaal geen (unit)tests bevat en alleen te gebruiken is op de machine zelf (er zijn geen simulators/emulators/stubs). Maar dit is een hobby project, dus vandaar. Mocht je toch interesse hebben in de source code, dan kun je deze vinden op https://github.com/klapstoelpiloot/pandemic
:strip_exif()/f/image/nDL55vrAw0PAYcuTvERJlAPh.png?f=user_large)
English version is on my website. This is a little more detailed with links to components used.
:strip_exif()/f/image/nDL55vrAw0PAYcuTvERJlAPh.png?f=user_large)
Het Concept
Mijn idee was om een arcade-stijl (zoals bij flipperkasten) sjoeltafel te maken. Het moest aan deze eisen voldoen:- LED Matrix display met tekst, animaties, menu, score, etc.
- Geluidseffecten.
- Verlichte knoppen voor de besturing.
- Puntentelling.
Het idee voor de puntentelling was om dit te doen met infrarood LEDs en sensors. Dit had ik nog niet eerder gedaan en ik wist ook niet zeker of het goed zou werken. Eerst heb ik uitgerekend hoe ik de sensor het best kan plaatsen om pucks langs te zien komen bij de poorten. In het midden is geen goed idee, omdat twee pucks elkaar kunnen duwen waardoor ze elkaar raken en de sensor het verschil tussen de twee pucks niet kan zien. Ook langs de zijkant van de poort is geen goed idee omdat er speling zit tussen de diameter van de puck en de breedte van de poort. Dus zou een puck ongezien kunnen passeren.
Om er zeker van te zijn dat dit gaat werken heb ik een test opstelling gemaakt. Dit bestaat uit een mini sjoeltafel met 1 poort die even breed is als een normale poort. Een Arduino met LEDs en een sensor moet de puck detecteren.
Uit de test bleek dat de pucks soms meer dan 1 keer geteld worden wanneer ze door het poortje gaan. Dit komt omdat de pucks half in de poort nog over de “Y” as kunnen bewegen en zo de sensor meer dan 1 keer kunnen doorbreken. De oplossing hier voor was om 2 sensors achter elkaar te gebruiken.
:strip_exif()/f/image/nDL55vrAw0PAYcuTvERJlAPh.png?f=user_large)
Het Ontwerp
Omdat ik maar 1 sjoeltafel heb (en het liefst geen meerdere aanschaf) werk ik zoveel mogelijk volgens het waterfall model (first-time-right). Dit betekent dat ik eerst een redelijk goed ontwerp moet hebben voordat ik begin met zagen en boren.Voor het ontwerp heb ik voor Fusion 360 gekozen. Dit omdat het gratis is en mijn collegas er ook gebruik van maken (en er lovend over zijn). Ik had het nog nooit gebruikt, maar met tips van mijn collegas kwam ik een heel eind. Zodoende heb ik de originele sjoeltafel nauwkeurig opgemeten en een 3D model van gemaakt.
Onder de sjoeltafel heb ik een houten behuizing toegevoegd wat de hele tafel 5.5 cm hoger maakt. Dit geeft ruimte voor de elektronica, de speakers en de knoppen.
Een van de minpunten van de originele sjoeltafel is dat de sleuven achter de poorten niet genoeg ruimte bieden om pucks naast elkaar kwijt te kunnen. Er moet altijd iemand pucks gaan stapelen achter de poorten om te voorkomen dat de sleuven vol zitten. Dit heb ik opgelost door de sleuven voor een groot deel weg te halen (vanaf 15 cm achter de poorten) en de pucks in een bak te laten vallen. Dankzij de extra 5.5 cm hoogte was dit goed mogelijk.
Het display wilde ik boven de poorten hebben, zodat het display ook poorten kan “aanwijzen”. Tevens is dat een mooie afstand voor de speler om het display goed te kunnen zien. Ik heb gekozen voor 2 LED Matrix displays van Adafruit van ieder 64x32 pixels voor een totale resolutie van 128x32 pixels. Deze zijn net iets minder breed dan de sjoeltafel zelf, een perfecte grootte!
Om het geheel netjes te maken print ik een plastic frame waar ze netjes in passen. Het frame is ontworpen om los over de poorten te zetten, zodat het gehele display gemakkelijk verwijderd kan worden voor transport. Er zit een gleuf aan de voorkant van het frame voor een plexiglas plaat die de LEDs beschermt tegen vliegende pucks. Het display is een paar graden gekanteld voor betere zichtbaarheid vanuit de positie van de speler. Ook loopt de onderkant schuin af zodat deze mooi overlapt over de originele stippen boven de poorten (en dit geeft ook extra stevigheid).
Ook heb ik de elektronica in kaart gebracht en nagedacht over de werking er van. Voor de aansturing van de displays heb ik een HAT op de Raspberry Pi gebruikt. Deze gebruikt bijna alle GPIO pinnen (inclusief alle PWM pinnen) en de software gebruikt een interne timer die ook gebruikt wordt voor de standard audio output. Dit betekent dat er geen pinnen over blijven voor de sensors en dat ik geen audio output heb.
De sensors sluit ik daarom aan op een Arduino. Deze is dan ook dedicated, real-time bezig met het uitlezen van de sensors, zodat iedere snelle verandering opgepikt wordt. De Arduino maakt simpele berichten die via de seriële interface (over USB) naar de Raspberry Pi gestuurd worden. Deze berichten hoeven dan niet real-time opgepakt te worden. Er zijn 10 infrarood LEDs, waarvan 2 high power, om de sensors te belichten. Bij elkaar hebben deze te veel stroom nodig om dat uit de (USB-powered) Arduino te trekken. Daarom voed ik deze direct vanuit de PSU. Ze staan dan wel continue aan (wat de levensduur verminderd), maar mocht het ooit zo ver komen dan kan ik de LEDs altijd nog vervangen.
Voor de audio sluit ik via USB een audio module aan (PCM DAC chip) welke een analoge output geeft. Deze haal ik door een kleine versterker voor de 3W stereo speakers.
De 2 displays samen verbruiken (als alle LEDs aan staan) een kleine 16A op 5V (80W) dus koos ik voor een 100W voeding. Meestal staan niet alle LEDs aan (wit op volle sterkte), maar better safe than sorry.
In Fusion 360 heb ik alles een plek gegeven en nagedacht over mogelijkheden tot reparatie indien nodig. De elektronica zit daarom op aparte latten met inslagmoeren onder de tafel en is altijd los te schroeven. Hier onder is een overzicht van de onderkant en detail foto’s van verschillende delen.
:strip_exif()/f/image/nDL55vrAw0PAYcuTvERJlAPh.png?f=user_large)
Het Bouwen
Na een hoop ontwerpen, puzzelen, zoeken, passen en meten is het dan eindelijk tijd om het apparaat ook echt te gaan bouwen.Eerst zaag ik de achterkant van de originele sjoeltafel af, want daar moeten de pucks in een bak vallen. Dit viel erg tegen, want de schotjes tussen de poorten zitten niet aan de bodemplaat vast en gaan dus alle kanten op bewegen tijdens het zagen. Ik heb het vanuit verschillende richtingen geprobeerd maar het bleef klungelen. Het resultaat is dan ook matig en mocht ik ooit nog eens een dergelijke sjoeltafel bouwen dan moet dit anders.
Verschillende hardhout latten van 5.5 cm breed heb ik op maat gezaagd en voorbereid met gaten waar nodig. Sommige onderdelen zoals de speakers en kabelgoten bevestig ik nu al op deze latten. Dat is makkelijker dan wanneer het frame in elkaar zit.
Met een sterkte houtlijm/kit plak ik de “wandjes” aan elkaar. Dit kost meerdere dagen omdat ze niet allemaal tegelijk kunnen en ze wel 24 uur vast moeten zitten om goed te hechten. Om het geheel nog iets steviger te maken schroef ik er ook verstevigingshoekjes in. Deze heb ik zelf geprint omdat ik daar heel enthousiast mee was, maar in het vervolg kan ik ze net zo goed kopen. Die zijn verkrijgbaar van ijzer (steviger) en het is geen duur onderdeel. In de video hier boven (bij het ontwerp) kun je zien wat de volgorde is waarin de latten gemonteerd worden.
Voor het boren van de nodige gaten in de poortjes heb ik twee hulpstukken gemaakt om het boren te begeleiden. Zo weet ik zeker dat de gaten nauwkeurig op de juiste plek zitten en recht geboord worden. Helaas heb ik geen kolomboormachine thuis staan.
De LEDs en de sensors bevestig ik met (wederom) 3D-geprinte covers/bevestigingsstukken.
In het ontwerp heb ik 10 cm tussen de twee brug sensors gehouden, omdat ik bang was dat het licht van de LEDs de sensor kruislings zou bereiken. Dan zouden beide sensors niet meer werken.
Uiteraard nadat ik de sensors al had gemonteerd kwam ik pas op het idee dat ik 1 paar om zou kunnen draaien (LED en sensor omwisselen) waardoor het licht van die LED nooit de andere sensor (dan aan dezelfde zijde) zou kunnen bereiken. Dan hadden de sensors dichter bij elkaar geplaatst kunnen worden en blijft er meer speelruimte op het bord vrij waar pucks mogen landen zonder dat ze afgekeurd worden. Laat dit een tip zijn voor hij die de volgende arcade sjoeltafel bouwt.
Dan het plaatsen en aansluiten van alle elektronica: de PSU, Raspberry Pi, Arduino, Audio chip en de versterker. En de bedrading natuurlijk netjes vast zetten en in de kabelgoten stoppen.
Het display was een kwestie van 3D printen en in elkaar schroeven/lijmen. Dit was makkelijker gezegd dan gedaan, want het is best een groot geheel om te printen en het bestaat uit 4 stukken die naadloos op elkaar moeten aansluiten. Voor een beginner met 3D printen een hele uitdaging, maar na 3 pogingen was ik tevreden met het resultaat.
Als laatste heb ik de onderkant dicht gemaakt met dunne multiplex platen welke in 3D geprinte gleuven schuiven. Deze voorkomen beschadiging van zowel de elektronica als kindervingertjes en kunnen open geschoven worden wanneer nodig.
:strip_exif()/f/image/nDL55vrAw0PAYcuTvERJlAPh.png?f=user_large)
Het Programmeren
De software is geschreven in C++, zowel op de Raspberry Pi als op de Arduino. Op de Arduino is dat natuurlijk beperkt omdat het bare-metal programmeren is (geen operating system). Voor het ontwikkelen gebruik is Visual Studio met de Visual Micro plugin (www.visualmicro.com). Visual Studio is al hands-down de koning der ontwikkelomgevingen en kan remote een Linux applicatie bouwen en debuggen op de Raspberry Pi. Met de Visual Micro plugin kan ik datzelfde doen op de Arduino en heb ik de Arduino IDE niet nodig. Dit is geen vereiste, de software is ook gewoon met de Arduino IDE te compileren en uploaden.De Arduino software heeft 3 modi waarin het kan verkeren: Idle, Normal en Testing. Deze kunnen gekozen worden door de Raspberry Pi waar de hoofd-software draait. De Idle mode is voor het opstarten (zolang de hoofd-software nog niet gestart is) en zorgt voor het knipperen van de gele knop om aan te geven dat het opstarten onderweg is. De Normal mode houdt alle sensors in de gaten en rapporteert gebeurtenissen naar de hoofd-software in simpele berichten zoals “Er ging een puck door poort 2”. De Testing mode houdt ook alle sensors in de gaten maar geeft low-level rapportage zoals “Voorste poort 2 sensor hoog”. Dit wordt gebruikt voor de system test functie.
Voor de communicatie over USB (serieel) gebruik ik Protobuf. Dit is een lichtgewicht en simpel protocol en ik heb hier al ervaring mee, dus het was snel te implementeren.
De hoofd-software draait op de Raspberry Pi en doet het meeste werk. Het bestaat uit een aantal state-machines en heeft veel code rond het renderen van het beeld. Deze code heb ik zelf geschreven, omdat het nogal een niche is met veel eisen zoals pixel-perfectie op lage resolutie. Ook is de rekenkracht op een Raspberry Pi beperkt. Voor de communicatie met de displays heb ik de “rpi-rgb-led-matrix” library van Henner Zeller gebruikt. Deze code is te vinden op github.com/hzeller/rpi-rgb-led-matrix en is goed gedocumenteerd. Voor het mixen van de audio (muziek en geluidseffecten) gebruik ik fmod (fmod.com).
De software heeft een systeem test functie waarmee alle sensoren in beeld gebracht worden. Dit is handig om te controleren of alles naar behoren werkt (na bijvoorbeeld vervoer).
De software is niet perfect. Er zijn een aantal bekende bugs en een aantal dingen die ik moet refactoren om het netter en foutloos te maken. Verder beoordeel ik (als ervaren programmeur en software architect) de software natuurlijk van hobby-niveau, omdat het totaal geen (unit)tests bevat en alleen te gebruiken is op de machine zelf (er zijn geen simulators/emulators/stubs). Maar dit is een hobby project, dus vandaar. Mocht je toch interesse hebben in de source code, dan kun je deze vinden op https://github.com/klapstoelpiloot/pandemic
:strip_exif()/f/image/nDL55vrAw0PAYcuTvERJlAPh.png?f=user_large)
[Voor 99% gewijzigd door klapstoelpiloot op 11-01-2022 09:13. Reden: Software source code link]