Infinithon: Infi’s RaceStoel

Achter de schermen

Tijdens de Infinithon bouwden we zelf een Racesimulator! Lees hier Eriks verslag.

Bij Infi houden we eens per jaar een programmeerhackaton voor alle werknemers, genaamd de Infinithon. Het idee is dat je in ongeveer 36 uur iets vets bouwt met een paar collega’s waarmee je een team vormt. Elk idee is goed, het hoeft niet per se software te zijn (*SPOILERS* er is altijd software), als het maar cool is.

Als je wel eens een racegame gespeeld hebt, weet je misschien dat er sturen en pedalen bestaan die je op je computer of je console kan aansluiten en die je het gevoel geven dat je echt zelf een auto bestuurt. De echte fanatiekelingen hebben soms zelfs een stoel die meebeweegt als je een scherpe bocht maakt, of ineens hard accelereert. Het idee van Henri was om zo’n stoel zelf eventjes te bouwen. Natuurlijk dan niet een of ander bouwpakket dat je kunt kopen, maar gewoon zelf zagen, schroeven en vloeken. Adolfo, Steven, Mark, Dirk en ik houden wel van een uitdaging, en wij sloten ons aan bij Henri.

Het uiteindelijke plan was zo:

  • Zet een stoel in elkaar die aangestuurd wordt door 2 motoren
  • Programmeer een Arduino die de motoren aanstuurt
  • Maak een programma dat data ontvangt van een race spel, en op basis daarvan signalen naar de Arduino stuurt

Hieronder beschrijf ik voor die drie punten wat we ongeveer gedaan hebben.

De constructie van de stoel

De stoel bestaat in de meest simpele vorm uit een rechthoekige plank die aan de onderkant op het zwaartepunt door een scharnier gekoppeld wordt aan een statisch fundament (bijvoorbeeld de vloer). Dit scharnier kan zowel in de lengte als in de breedte bewegen, waardoor de plank dus in 2 richtingen balanceert op het fundament daaronder. Het scharnier dat wij gebruiken is ongeveer 10 centimeter hoog. Het verschil tussen de plank en het fundament is een limiet voor de maximale hoek die de plank kan krijgen.

Om de plank te laten draaien / balanceren, monteren we 2 motoren (aan de as) aan de achterste korte zijde van de plank. Een leuk feitje is dat de motoren die we gebruiken bedoeld zijn voor ruitenwissers van auto’s.

De motoren monteren we zodat ze de plank omhoog en naar beneden tillen als ze dezelfde rotatie maken. Als de motoren asymmetrisch roteren, kantelt de plank over de lengte (links en rechts op en neer).

Als je met je handen een lange plank aan een uiteinde vasthoudt bij de hoeken, kun je je voorstellen dat je de achterkant kunt optillen en laten zakken door je beide handen omhoog of omlaag te doen. Je kunt de plank kantelen door je ene hand omlaag te doen, en je andere omhoog, of andersom. Op die manier werken onze motoren ook op de plank.

We monteren ook een stoel zonder poten op de bovenkant van de plank, en een frame waarop een racestuur geplaatst wordt. Aan het uiteinde van de plank waar geen motoren zijn, monteren we racepedalen die horen bij het stuur. Op deze manier kan iemand gaan zitten in de stoel, en het stuur en de pedalen gebruiken.

De Arduino

Om de motoren te laten roteren is er iets nodig dat een signaal naar de motoren stuurt. Dit is goed te regelen met een Arduino. Een Arduino is eigenlijk een soort micromoederbord dat je kunt gebruiken om simpele dingetjes supersnel te laten uitvoeren. Je kunt programmeren wat zo’n Arduino doet wanneer je hem aanzet. Lees meer: https://www.Arduino.cc.

Onze Arduino programmeren we zo dat hij kan luisteren naar een seriele poort (USB), en signalen kan uitzenden naar een andere IO poort waaraan de motor zit. De Arduino luistert elke frame naar de seriele poort en ontvangt daarop informatie die zegt naar welke stand de motoren moeten. De Arduino pompt dus plat gezegd de informatie die hij binnenkrijgt, door naar de motoren.

Een belangrijk detail is echter, dat de motoren niet zelf onthouden waar ze op dat moment geroteerd staan, en de signalen die de Arduino binnenkrijgt betreft de absolute gewenste motorstand. De Arduino moet dus bijhouden wat de huidige stand is van de motors, en het verschil tussen de huidige stand en de gewenste stand als signaal uitsturen.

Gelukkig is het zo dat de motoren zelf deze feedback uitsturen naar nog een poort op de Arduino. De Arduino berekent dus voordat hij het signaal uitstuurt naar de motoren eerst het verschil tussen de huidige stand van de motoren en de gewenste stand.

De RaceDecoder

Nu hebben we een Arduino die signalen naar de motoren kan sturen, maar de Arduino heeft ook input nodig. Deze input komt uit het race spel (wij kozen Dirt Rally 2 op Steam), maar deze input is nog niet geschikt voor de Arduino. Het racespel stuurt namelijk UDP pakketjes uit naar IP adressen die je kunt configureren in een bestandje dat bij het spel hoort. We bouwen een programma (de RaceDecoder) dat naar deze UDP pakketjes luistert zodat we met die pakketjes kunnen werken. Deze pakketjes bevatten ontzettend veel data over het spel dat je op dat moment speelt. Het bevat bijvoorbeeld de snelheid van de auto, de stand van de benzine, de kwaliteit van de banden, etc. De informatie uit de pakketjes die wij gebruiken bestaat uit de de G-krachten (krachten die je voelt als je in de achtbaan zit) in de lengte en de breedte.

Als de auto veel G-krachten in de lengte ervaart, betekent dat waarschijnlijk dat de auto heel hard optrekt, of juist remt. G-krachten in de breedte betekenen dat de auto waarschijnlijk een scherpe bocht maakt. Dit, plus de kennis dat we weten hoe de motoren de plank bewegen, geeft ons de mogelijkheid om de G-krachten uit het spel om te zetten naar een gewenste motorstand.

Bijvoorbeeld, als de auto heel hard remt, krijgen we een hoge G-kracht in de lengte van het spel. Een hoge G-kracht in de lengte betekent dat onze racestoel flink naar voren moet kantelen. Om de stoel naar voren te laten kantelen, moeten beide motoren de stoel omhoog tillen. Dat betekent dus dat als de auto hard remt, we een pakket naar de Arduino moeten sturen waarin de gewenste stand voor beide motoren hoog is.

Omdat de G-krachten en de motorstanden allemaal getallen zijn, kan onze RaceDecoder dat voor ons automatiseren. De RaceDecoder luistert naar de UDP pakketjes van het spel, rekent ze om naar motorstanden die de Arduino begrijpt, en stuurt ze naar de Arduino.

Conclusie

De RaceDecoder krijgt dus constant (ongeveer 10 keer per seconde) informatie over de raceauto van het spel binnen. Deze informatie zet de RaceDecoder om naar gewenste motorstanden en stuurt die naar de Arduino. De Arduino gebruikt deze informatie en verrekent het met de huidige motorstanden. De huidige motorstanden worden geleverd door de motoren zelf. De Arduino berekent dus de rotatie die door de motoren moet worden gemaakt, en stuurt dit als een signaal naar de motoren. Dit zorgt ervoor dat de motoren hun assen bewegen, wat er weer voor zorgt dat de plank in een bepaalde richting kantelt. Dit gaat allemaal ontzettend snel, waardoor je bijna direct naar voren wordt gekanteld in je stoel als je het rempedaal indrukt!

Tot slot nog een paar opmerkingen

We hadden natuurlijk erg weinig tijd, en testen of de standen die de RaceDecoder doorgaf kon natuurlijk pas als de stoel klaar was. Dit was een probleem, want de stoel werd natuurlijk nog gebouwd. We hebben om onszelf daarmee te helpen een webinterface gebouwd die via een websocket in de RaceDecoder de standinformatie ontving. Deze informatie konden we in de interface plotten zodat we konden vergelijken wat voor motorstanden correspondeerde met wat voor G-krachten die we uit het spel ontvingen.

Wat we later ook vonden hierdoor, is dat botsingen tegen bijvoorbeeld een muur, een hele grote maar hele korte G-kracht uitsturen. Omdat het zo is dat het spel constant data uitstuurt, en we deze informatie direct doorgeven naar de motoren, wordt deze piek eigenlijk direct overschreven door het volgende pakket. Daarom merk je eigenlijk niets van de stoel als je ineens tot stilstand komt. De stoel werkt dus vooral goed met g-krachten die wat langer blijven bestaan, zoals die bij een bocht of bij het remmen.

We zouden dit kunnen oplossen door gebruik te maken van een sliding window waarvan we een gemiddelde G-kracht gebruiken als de input waarvan we een motorstand maken. Omdat een piek in de data dan niet ineens verdwijnt, maar een ‘tijdje’ onderdeel blijft van de sliding window, zullen de motoren reageren op de piek.

Onze racestoel is wat ons betreft een groot succes. De stoel reageert heel aardig op wat er in je spel gebeurt. We hadden aan het begin van de Infinithon niet gedacht dat we zo ver zouden komen, maar we zijn trots dat het toch gelukt is. Het is misschien zo dat het er niet zo mooi eruit ziet, en ja de stoel rust op bierkratten, maar technisch is het gewoon hartstikke mooi. Als je zelf een handige klusser bent, en een beetje kunt programmeren is dit een erg leuk project om te doen. Ook qua kosten viel het reuze mee (in ieder geval stukken goedkoper dan een racestoel op het internet kopen).

Als je na het lezen hiervan vragen hebt, stuur ons dan een mailtje op info[at]infi.nl: we zijn apentrots dus we willen er graag over vertellen. Als je een keertje wil komen racen ben je uiteraard van harte welkom op ons kantoor in Utrecht.

Een afspraak maken bij ons op kantoor of wil je even iemand spreken? Stuur ons een mail of geef een belletje.