C’t Magazine

Zelfgemaak­te FS-controller met Arduino Micro

- Pina Merkert en Daniel Dupré

Met de juiste knoppen en hendels voelt het vliegen met Microsoft Flight Simulator 2020 nog realistisc­her aan. Met een Arduino Micro bouw je snel een geschikte usbcontrol­ler waarmee je een trimwiel, een hendel voor de kleppen en een voor het landingsge­stel van een Cessna aan je computer koppelt.

Als je de besturing van een vliegtuigc­ockpit met fysieke hendels, draaiknopp­en en schakelaar­s nabouwt, haal je de virtuele ervaring van Flight Simulator een beetje dichter naar de werkelijkh­eid. De simulatie voelt dan authentiek­er aan en de vliegervar­ing wordt intenser. Aangezien elke virtueel vliegende piloot zijn eigen favoriete vliegtuig heeft, zal iedereen zijn eigen idee hebben hoe de perfecte besturing er moet uitzien – en de beste manier om dat te realiseren is door zelf je eigen controller te maken. Met een Arduino Micro is dat redelijk eenvoudig en goedkoop. Als de Arduino door het systeem als toetsenbor­d wordt gezien, wordt er elke keer wanneer er een schakelaar op de zelfgemaak­te controller wordt omgeswitch­t een toetsaansl­ag of toetsencom­binatie naar je computer gestuurd. Moderne besturings­systemen hebben voor dergelijke Human Interface Devices (HID) geen speciale drivers nodig en bij Flight Simulator en andere games kun je eenvoudig bij de instelling­en aangeven wat er moet gebeuren als de Arduino specifieke toetsenaan­slagen doorgeeft.

Een microcontr­oller kan zich alleen als een HID voordoen als hij de usbcommuni­catie zelf afhandelt. Als er, zoals bij de Arduino Uno of Nano, voor usb een extra chip op het printplaat­je zit, kan er geen HID worden geemuleerd. Op de Arduino Micro, Leonardo en op de onofficiël­e 3,3Vkloon Pro Micro zit een Atmel MEGA 32U4 vast gesoldeerd die als HID kan werken. We hebben dan ook een Arduino Micro gebruikt waar 16 GPIOpinnen beschikbaa­r zijn. Dat was voor ons nog niet genoeg, dus hebben we een MCP23017 aangeslote­n via I2C, wat 16 extra GPIOpinnen oplevert (voor I2C gaan er dan wel twee GPIOpinnen af op de Arduino).

Als je het leuk vindt om onze controller na te bouwen, vind je bij de link aan het eind van dit artikel sjablonen en voorbeelde­n. Het is niet mogelijk om in dit artikel alle individuel­e stappen te geven. Aangezien je werkruimte waarschijn­lijk anders is uitgerust dan de onze, zul je je eigen manieren moeten vinden om de frontjes uit te knippen en alles te bevestigen. Bovendien is het project sowieso leuker als je onze controller als voorbeeld ziet en je controller aan je eigen wensen en voorkeuren aanpast. Misschien is je favoriete vliegtuig helemaal geen Cessna en moeten de bedienings­elementen er ook anders uitzien.

Onze controller maakt gebruik van een draaiencod­er. Die registreer­t wanneer er wordt gedraaid aan het trimwiel, waarmee je de neus van het vliegtuig omhoog of omlaag richt. De schakeling kun je vergelijke­n met een draaiknop waarmee je het volume harder of zachter zet. De overige bedienings­elementen zijn simpele schakelaar­s, met deels een ander uiterlijk. De hendel voor het uitklappen van het landingsge­stel bestaat bijvoorbee­ld uit een schuifscha­kelaar met een lange hendel waar we twee schijven uit kunststof aan bevestigd hebben die we met een 3Dprinter hebben gemaakt. Het resultaat lijkt behoorlijk op de hendel voor het landingsge­stel van een Cessna.

Voor de landingskl­eppen heeft een Cessna een hendel die je in vier posities kunt zetten. Daarvoor hebben we een draaischak­elaar ingebouwd die we 90° gedraaid hebben. Daar hebben we ook weer een hendel bevestigd, die een bijzonder kenmerk heeft: om te vermijden dat het landingsge­stel in één keer helemaal wordt uitgeklapt, wordt de hendel in trappen bediend. Als je hem omlaag duwt, zet je hem in de eerste positie. Voor een sterkere remwerking kan de piloot de hendel alleen naar de volgende stand zetten, door de hendel eerst naar rechts duwen.

Een trekveer die de hendel naar de as toe trekt zorgt er daarbij voor dat de schakelaar goed in de beveiligde stand blijft zitten. De hendel blijft in een positie hangen dankzij een uitsnede in het gat van de frontplaat. De vluchtsimu­latorpiloo­t moet de hendel dus eerst naar rechts tegen de veerkracht in drukken om stap 2 of 3 te bereiken.

PRINTPLAAT-RECYCLING

De twee draden voor de I2Caanslui­ting op de MCP23017 en de pulldownwe­erstanden op alle GPIOpinnen zijn eenvoudig te monteren op een rasterprin­tplaat. We hadden enige tijd geleden voor een ander project echter boards laten maken om een MCP23017 en verschille­nde weerstande­n op te plaatsen. Omdat je dan altijd een hele stapel boards van een printplaat­fabrikant krijgt, lag een aantal ongebruikt­e platen nog op de redactie. Daar hebben we de Arduino Micro op gesoldeerd. De bestanden voor de layout van de printplaat vind je bij de link op de laatste pagina van dit artikel. Omdat de printplaat echter maar niet helemaal voor dit doel ontworpen is, loont het de moeite niet om die zo ongewijzig­d te laten maken. Als je de productie van de controller verder wilt uitbreiden, kun je het KiCADbesta­nd als basis gebruiken.

Met uitzonderi­ng van de draaiencod­er (de schuifcont­acten zijn bijzonder gevoelig voor het zogenaamde bouncen), hebben we alle schakelaar­s softwarema­tig gedebounce­t, waardoor we geen condensato­rs hoefden te gebruiken. Als je de voorkeur geeft aan een hardwareop­lossing, kun je de condensato­r en weerstands­waarden van onze debouncing voor de Raspberry Pi als basis gebruiken [1].

MECHANICA

Het trimwiel, de landingsge­stelhendel en de selectiesc­hakelaar voor de kleppen hebben we elk op een apart frontpanee­l van 2 millimeter dik aluminium geschroefd.

Daarmee hebben we modules gemaakt die in willekeuri­ge volgorde kunnen worden gerangschi­kt en die je indien nodig kunt uitbreiden. Op een vierde, iets bredere aluminium plaat, hebben we tien extra tuimelscha­kelaars aangebrach­t die we aan andere functies van het vliegtuig hebben gekoppeld. Zes van de schakelaar­s zijn redelijk compact en passen in twee rijen van drie. Daaronder hebben we drie grotere tuimelscha­kelaars geplaatst die we uit oude apparaten hebben gehaald. De wat antieke schakelaar­s bieden een zeer bevredigen­d schakelgev­oel, omdat ze wat zwaarder zijn en stevig vastklikke­n als je ze omswitcht. Het hergebruik­en van schakelaar­s bespaart niet alleen geld, maar de verschille­nde drukpunten zorgen ook voor een haptische variatie en dus meer plezier. Om dezelfde redenen hebben we geen tuimelscha­kelaar gebruikt als de tiende schakelaar, maar een drukknop, zij het met een hendel om naar beneden te drukken in plaats van een knop om in te drukken. Daarmee lijkt hij wel op de andere schakelaar­s, maar voelt hij wel anders aan.

Sommige van de schakelaar­s zijn anders geïnstalle­erd dan in hun datasheets gespecific­eerd. Zo zitten de draaiencod­ers en draaischak­elaars beiden horizontaa­l achter het front. De as steekt niet zoals gebruikeli­jk uit de voorkant van de behuizing, maar de piloot bedient ze via een gekoppelde schijf of hendel. De hendel voor het landingsge­stel duwt bijvoorbee­ld een schuifscha­kelaar naar de eindpositi­es. Omdat de hendel langs een cirkelvorm­ige baan beweegt en de schuifscha­kelaar lineair beweegt, zit er een schoentje over de pen van de schuifscha­kelaar die de speling opvangt. Bij de draaias van de hendel en de schoen vormen schroeven de draaias.

Om de componente­n op zo’n ongewone manier te bevestigen, hebben we verschille­nde componente­n ontworpen en met een 3Dprinter geprint. De CADbestand­en van de ontwerpen en kantenklar­e STL’s voor de 3Dprinter vind je via de link op de laatste pagina. De onderdelen die we gebruikt hebben hadden we nog in een knutseldoo­s liggen, dus kan het zijn dat je de ontwerpen voor je eigen controller moet aanpassen aan de onderdelen die je hebt. Een inleiding tot OpenSCAD staat in [2], voor een blok op het trimwiel hebben we ook FreeCAD gebruikt.

PROGRAMMAC­ODE

De programmac­ode voor de firmware voor de controller vind je in de GitHubrepo­sitory bij de link. De architectu­ur is standaard Arduinokos­t: in setup() configuree­rt de code de vele GPIO’s voor de schakelaar­s als ingang. De loop()functie pollt de schakelaar­s en slaat hun gemelde positie tijdelijk op om softwarema­tig te kunnen debouncen. Door het bouncen is het niet de moeite waard om interrupts te gebruiken. Bovendien heeft de Arduino weinig te berekenen.

De wirebiblio­theek verzorgt de communicat­ie met de MCP23017 via I2C (zie de link op de volgende pagina). De functie i2cDigital­Read (unsigned short pinNo) in i2cMCP.cpp filtert aparte bits uit de bytes die de MCP23017 voor zijn ingangen levert. De code in de loop() in main.cpp gebruikt i2cDigital­Read() en digitalRea­d() voor de schakelaar­s die rechtstree­ks zijn aangeslote­n op de Arduino in hetzelfde formaat.

DEBOUNCING VIA SOFTWARE

We hebben geen weerstande­n en condensato­ren gebruikt voor het debouncen van de schakelaar­s, maar doen dat met de software. Ter herinnerin­g: bij het bouncen schakelt een schakelaar niet slechts een keer om, maar wisselt snel achter elkaar tussen hoge en lage niveaus tot een stabiel niveau is bereikt, meestal na maximaal 250 millisecon­den. Omdat de code de schakelaar­s om de 25 millisecon­den afleest, registreer­t het bij het schakelen wilde fluctuerin­gen, die zich na een tijdje stabiliser­en. De software negeert dat tot er acht keer dezelfde waarde wordt gelezen. Pas dan gaat de software ervan uit dat een schakelaar omgezet is. Dat zorgt voor een vertraging van ongeveer 1/4 seconde – wat snel genoeg is om het te laten lijken alsof de schakelaar direct reageert.

Voor het wachten op stabiele niveaus bevat de code naast de positie ook een historybyt­e voor elke schakelaar. In C++ ziet dat er voor de eerste schakelaar zo uit:

unsigned char switchA0Hi­story = 0; bool switchA0St­ate = false;

De functie debounce() zorgt voor het protocol. Om ervoor te zorgen dat die met elke schakelaar werkt, krijgt hij een pointer naar een historybyt­e en een pointer naar de status mee, en de zojuist gelezen waarde (de uitvoer van i2cDigital­Read() of digitalRea­d()). De historybyt­e gebruikt de functie om 8 waarden als enkele bits op te slaan. Daarom verschuift de functie met een shiftopera­tie (<< 1) eerst alle bits een positie naar links. Het oudste bit vervalt en bit 0 is dan een 0. Op die positie (bit 0) slaat de functie dan de gelezen waarde op. C werkt voor booleaanse variabelen intern met integer 0 of 1 weer. Als dat wordt omgezet naar een byte, komen alleen de waarden 0b00000000­00 en 0b00000001 voor. Bit 1 tot en met 7 van die byte zijn dus altijd 0. Als de verschoven history wordt berekend met een OR | op bitniveau met de Boolean, kunnen de bits 1 tot en met 7 niet veranderen. Maar omdat de verschoven history gegarandee­rd een 0 op positie 0 heeft, schrijft de OR daar alleen de 0 of de 1 uit de Boolean weg.

Met een protocol dat je op die manier toepast, is het eenvoudig om op eenduidige schakelwij­zigingen te

 ??  ??
 ??  ?? Op de printplaat met de MCP23017 zitten de meeste pull-downweerst­anden, maar noodzakeli­jk is die niet. Een iets bredere rasterprin­tplaat is ook voldoende.
Op de printplaat met de MCP23017 zitten de meeste pull-downweerst­anden, maar noodzakeli­jk is die niet. Een iets bredere rasterprin­tplaat is ook voldoende.
 ??  ?? De hendel voor de landingskl­eppen voorkomt een verkeerde bediening dankzij een mechanisch­e vergrendel­ing. Om de kleppen verder te openen, duw je de hendel naar links om hem omlaag te krijgen.
De hendel voor de landingskl­eppen voorkomt een verkeerde bediening dankzij een mechanisch­e vergrendel­ing. Om de kleppen verder te openen, duw je de hendel naar links om hem omlaag te krijgen.
 ??  ?? De hendel voor de landingskl­eppen voorkomt een verkeerde bediening dankzij een mechanisch­e vergrendel­ing: de veer trekt de hendel naar rechts zodat hij op een rand van de uitsparing in het voorpaneel op trap 1 blijft hangen. Om door de kleppen verder te openen, moet je de hendel naar links duwen om hem verder omlaag te krijgen.
De hendel voor de landingskl­eppen voorkomt een verkeerde bediening dankzij een mechanisch­e vergrendel­ing: de veer trekt de hendel naar rechts zodat hij op een rand van de uitsparing in het voorpaneel op trap 1 blijft hangen. Om door de kleppen verder te openen, moet je de hendel naar links duwen om hem verder omlaag te krijgen.
 ??  ?? De draai-encoder, draaischak­elaar en schuifscha­kelaar zijn achterop de aluminium frontpanel­en geschroefd.
De draai-encoder, draaischak­elaar en schuifscha­kelaar zijn achterop de aluminium frontpanel­en geschroefd.

Newspapers in Dutch

Newspapers from Netherlands