Kazalo:

Infinity Bike - Video igra za usposabljanje koles v zaprtih prostorih: 5 korakov
Infinity Bike - Video igra za usposabljanje koles v zaprtih prostorih: 5 korakov

Video: Infinity Bike - Video igra za usposabljanje koles v zaprtih prostorih: 5 korakov

Video: Infinity Bike - Video igra za usposabljanje koles v zaprtih prostorih: 5 korakov
Video: Физик РАЗВЕРНУЛ Большой Взрыв! Квантовые петли Абхая Аштекара 2024, November
Anonim
Image
Image
Materiali
Materiali

V zimskih časih, hladnih dneh in slabem vremenu imajo ljubitelji kolesarjev le nekaj možnosti za vadbo, ki se jim zdi najljubši šport. Iskali smo način, kako narediti vadbo v zaprtih prostorih s postavitvijo kolesa/trenerja nekoliko bolj zabavno, vendar je večina razpoložljivih izdelkov draga ali preprosto dolgočasna za uporabo. Zato smo začeli razvijati Infinity Bike kot odprtokodno izobraževalno video igro. Infinity bike bere hitrost in smer vašega kolesa in ponuja raven interaktivnosti, ki je pri trenerjih za kolo ni mogoče najti.

Izkoristimo preprostost, ki je na voljo pri mikrokrmilniku Arduino, in nekaj 3D tiskanih delov, da pritrdimo poceni senzorje na kolo, nameščeno na vadbeni enoti. Podatki se posredujejo videoigri, izdelani s priljubljenim motorjem za ustvarjanje iger Unity. Do konca teh navodil bi morali na svojem kolesu nastaviti lastne senzorje in podatke o svojih senzorjih prenesti v Unity. Vključili smo celo stezo, na kateri se lahko peljete in preizkusite svojo novo postavitev. Če želite prispevati, lahko preverite naš GitHub.

1. korak: Materiali

Materiali
Materiali

Seznam materialov, ki ga boste potrebovali, se lahko nekoliko razlikuje; za

na primer, velikost vašega kolesa bo določala dolžino skakalnih kablov, ki jih potrebujete, tukaj pa so glavni deli, ki jih boste potrebovali. Na spletnem mestu, kot je AliExpress, bi verjetno lahko našli cenejše cene za vsak kos, vendar čakanje na pošiljanje 6 mesecev ni vedno možnost, zato ste uporabili nekoliko dražje dele, tako da ocena ni napačna.

1 x Arduino nano (22,00 USD)

1 x Mini plošča (1,33 USD/enoto)

1 x 220 ohmski upor (1,00 USD/komplet)

1 x 10K potenciometer (1,80 USD/enoto)

1 x Hall senzor (0,96 USD)

Zobati jermen za 3D tiskalnik 20 cm x 6 mm (3,33 USD)

1 komplet x Vijaki in vijaki M3 različnih dolžin (6,82 USD)

1 x magnet za merilnik hitrosti kolesa (0,98 USD)

Zgornji material smo namestili s 3D tiskanimi deli. Datoteke, ki smo jih uporabili, so navedene spodaj in so oštevilčene z isto konvencijo kot slika na začetku tega razdelka. Vse datoteke najdete na Thingiverse. Uporabite jih lahko takšne, kot so, vendar pazite, da se dimenzije, ki smo jih uporabili, ujemajo z vašim kolesom.

1. FrameConnection_PotenciometerHolder_U_Holder.stl

2. FrameConnection_Spacer.stl

3. BreadboardFrameHolder.stl

4. Stranski jermen_potenciometra.stl

5. Pot_PulleyConnection.stl

6. FrameConnection.stl

7. Jermenica_Ročna ročicaSrčna_print2.stl

8. FrameToHallSensorConnector.stl

9. PotHolder.stl

10. HallSensorAttach.stl

2. korak: branje in prenos podatkov v Unity

Branje in prenos podatkov v Unity
Branje in prenos podatkov v Unity

Koda Arduino in Unity bosta skupaj zbirali, prenos in obdelava podatkov s senzorjev na kolesu. Unity bo zahteval vrednost od Arduina tako, da bo niz poslal po nizu in počakal, da se Arduino odzove z zahtevanimi vrednostmi.

Najprej pripravimo Arduino s knjižničnim zaporednim ukazom, ki se uporablja za upravljanje zahtev iz Unityja tako, da poveže niz zahtev s funkcijo. Osnovno nastavitev te knjižnice lahko naredite na naslednji način;

#include "SerialCommand.h"

SerialCommand sCmd; void setup () {sCmd.addCommand ("TRIGG", TriggHanlder); Serial.begin (9600); } void loop () {while (Serial.available ()> 0) {sCmd.readSerial (); }} void TriggHandler () { /*Tukaj preberite in prenesite senzorje* /}

Funkcija TriggHandler je pritrjena na objekt SCmd. Če serijski niz prejme niz, ki ustreza priloženemu ukazu (v tem primeru TRIGG), se izvede funkcija TriggHandler.

Za merjenje smeri krmiljenja uporabljamo potenciometer, za merjenje vrtenja kolesa na minuto pa halsov senzor. Odčitke s potenciometra je mogoče enostavno narediti z vgrajenimi funkcijami iz Arduina. Funkcija TriggHandler lahko nato natisne vrednost v serijo z naslednjo spremembo.

void TriggHandler () {

/*Odčitavanje vrednosti potenciometra*/ Serial.println (analogRead (ANALOGPIN)); }

Hallov senzor ima nekoliko več nastavitev, preden lahko uporabimo meritve. V nasprotju s potenciometrom trenutna vrednost senzorja za hodnike ni zelo uporabna. Ker so poskušali izmeriti hitrost kolesa, je čas med sprožilci tisto, kar je zanimalo.

Vsaka funkcija, uporabljena v kodi Arduino, potrebuje čas in če se magnet poravna s Hall -jevim senzorjem ob napačnem času, bi lahko meritev v najboljšem primeru zamudili ali v najslabšem primeru popolnoma preskočili. To je očitno slabo, ker bi lahko Arduino poročal o hitrosti, ki je veliko drugačna od dejanske hitrosti kolesa.

Da bi se temu izognili, uporabljamo funkcijo Arduinosa, imenovano attach prekinitev, ki nam omogoča, da sprožimo funkcijo, kadar se sproži določen digitalni pin z naraščajočim signalom. Funkcija rpm_fun je pritrjena na prekinitev z eno vrstico kode, dodano nastavitveni kodi.

void setup () {

sCmd.addCommand ("TRIGG", TriggHanlder); attachInterrupt (0, rpm_fun, RISING); Serial.begin (9600); } // Funkcija rpm_fun se uporablja za izračun hitrosti in je definirana kot; unsigned long lastRevolTime = 0; brez podpisa dolga revolSpeed = 0; void rpm_fun () {unsigned long revolTime = millis (); nepodpisano dolgo deltaTime = revolTime - lastRevolTime; /*revolSpeed je vrednost, prenesena v kodo Arduino* / revolSpeed = 20000 / deltaTime; lastRevolTime = revolTime; } TriggHandler lahko nato na zahtevo posreduje preostale podatke. void TriggHanlder () { /*Odčitavanje vrednosti potenciometra* / Serial.println (analogRead (ANALOGPIN)); Serial.println (revolSpeed); }

Zdaj imamo vse gradnike, ki jih lahko uporabimo za izdelavo kode Arduino, ki bo prenašala podatke po zaporedju, na zahtevo Unityja. Če želite imeti kopijo celotne kode, jo lahko prenesete na naš GitHub. Če želite preveriti, ali je bila koda pravilno nastavljena, lahko s serijskim monitorjem pošljete TRIGG; preverite, ali ste vrstico, ki se konča, vrnili na prevoz. Naslednji razdelek se bo osredotočil na to, kako lahko naši skripti Unity zahtevajo in prejemajo informacije od Arduina.

3. korak: Prejemanje in obdelava podatkov

Prejemanje in obdelava podatkov
Prejemanje in obdelava podatkov

Unity je odlična programska oprema, ki je na voljo brezplačno za ljubitelje

zanima ustvarjanje iger; prihaja z velikim številom funkcionalnosti, ki lahko resnično skrajšajo čas pri nastavitvi nekaterih stvari, kot so navoji niti programiranje GPU (senčenje AKA), ne da bi omejili, kaj je mogoče storiti s skripti C#. Mikrokrmilnike Unity in Arduino lahko uporabite skupaj za ustvarjanje edinstvenih interaktivnih izkušenj z relativno majhnim proračunom.

Poudarek tega navodila je pomagati vzpostaviti komunikacijo med Unityjem in Arduinom, tako da se ne bomo preveč poglabljali v večino funkcij, ki so na voljo pri Unityju. Obstaja veliko VARNIH vaj za enotnost in neverjetno skupnost, ki bi lahko veliko bolje opravila razlago delovanja Unity. Vendar pa obstaja posebna nagrada za tiste, ki se uspejo prebiti skozi to navodilo, ki služi kot majhen prikaz tega, kar je mogoče storiti. Na našem Githubu lahko prenesete naš prvi poskus ustvarjanja skladbe z realno fiziko koles.

Najprej pojdimo skozi minimalni minimum, ki ga je treba narediti za komunikacijo z Arduinom skozi serijo. Kmalu bo očitno, da ta koda ni primerna za igranje iger, vendar je dobro iti skozi vsak korak in se naučiti, kakšne so omejitve.

V Unityu ustvarite nov prizor z enim samim praznim GameObject z imenom ArduinoReceive in priložite skript C#, imenovan tudi ArduinoReceive. Ta skript bo dodal vso kodo, ki upravlja komunikacijo z Arduinom.

Preden lahko komuniciramo s serijskimi vrati vašega računalnika, je dostopna knjižnica; Unity je treba nastaviti, da se omogoči uporaba določenih knjižnic. Pojdite na Urejanje-> ProjectSerring-> Predvajalnik in zraven ravni združljivosti Api pod stikalom za konfiguracijo. Podmnožica. NET 2.0 na. NET 2.0. Zdaj dodajte naslednjo kodo na vrh skripta;

z uporabo System. IO. Ports;

To vam bo omogočilo dostop do razreda SerialPort, ki bi ga lahko opredelili kot predmet razreda ArduinoReceive. Naj bo zasebno, da se izognete morebitnim motnjam iz drugega skripta.

zasebni SerialPort arduinoPort;

Objekt arduinoPort lahko odprete tako, da izberete ustrezna vrata (na primer, v kateri USB je priključen Arduino) in hitrost prenosa (tj. Hitrost, s katero se informacije pošiljajo). Če niste prepričani, v katera vrata je priključen Arduino, lahko to ugotovite v upravitelju naprav ali tako, da odprete Arduino IDE. Za hitrost prenosa je privzeta vrednost na večini naprav 9600, samo preverite, ali imate to vrednost v kodi Arduino in bi morala delovati.

Koda bi morala izgledati takole;

z uporabo System. Collections;

z uporabo System. Collections. Generic; z uporabo UnityEngine; z uporabo System. IO. Ports; javni razred ArduinoReceive: MonoBehaviour {private SerialPort arduinoPort; // To uporabite za inicializacijo void Start () {arduinoPort = new SerialPort ("COM5", 9600); arduinoPort. Open (); WriteToArduino ("TRIGG"); }}

Vaša številka COM bo najverjetneje drugačna. Če uporabljate MAC, ima lahko ime COM ime, ki izgleda tako /dev/cu.wchusbserial1420. Prepričajte se, da je koda iz razdelka 4 naložena v Arduino, serijski monitor pa je zaprt za preostanek tega razdelka in da se ta koda brez težav sestavi.

Zdaj pošljimo zahtevo vsakemu okvirju Arduina in zapišite rezultate v okno konzole. Dodajte funkcijo WriteToArduino v razred ArduinoReceive. Vrnitev nosilca in nova vrstica sta potrebna, da koda Arduino pravilno razčleni dohodno navodilo.

zasebna praznina WriteToArduino (sporočilo niza)

{message = message + "\ r / n"; arduinoPort. Write (sporočilo); arduinoPort. BaseStream. Flush (); }

To funkcijo lahko nato pokličete v zanki za posodobitev.

void Update ()

{WriteToArduino ("TRIGG"); Debug. Log ("Prva vrednost:" + arduinoPort. ReadLine ()); Debug. Log ("Druga vrednost:" + arduinoPort. ReadLine ()); }

Zgornja koda je minimum, ki ga potrebujete za branje podatkov iz Arduina. Če pozorno spremljate FPS, ki ga daje enotnost, bi morali opaziti pomemben padec zmogljivosti. V mojem primeru gre od približno 90 FPS brez branja/pisanja do 20 FPS. Če vaš projekt ne potrebuje pogostih posodobitev, bo morda dovolj, za videoigre pa je 20 FPS premalo. Naslednji razdelek obravnava, kako lahko izboljšate zmogljivost z uporabo večkratnega navoja.

4. korak: Optimiziranje prenosa podatkov

V prejšnjem razdelku je bilo opisano, kako nastaviti osnovno

komunikacijo med programom Arduino in Unity. Glavna težava te kode je zmogljivost. V trenutni izvedbi mora Unity počakati, da Arduino prejme, obdela in odgovori na zahtevo. V tem času mora koda Unity počakati na izvedbo zahteve in ne stori nič drugega. To težavo smo rešili z ustvarjanjem niti, ki bo obravnavala zahteve in spremenljivko shranila v glavno nit.

Za začetek moramo vključiti knjižnico niti z dodajanjem;

z uporabo System. Threading;

Nato nastavimo funkcijo, ki jo zaženemo v nitih. AsynchronousReadFromArduino se začne s pisanjem zahteve v Arduino s funkcijo WrtieToArduino. Odčitavanje je zaprto v bloku try-catch. Če je časovno omejitev branja, spremenljivke ostanejo ničelne in se namesto OnArduinoInfoReceive pokliče funkcija OnArduinoInfoFail.

Nato določimo funkcije OnArduinoInfoFail in OnArduinoInfoReceive. Za to navodilo rezultate natisnemo na konzolo, rezultate pa lahko shranite v spremenljivke, ki jih potrebujete za svoj projekt.

zasebna praznina OnArduinoInfoFail ()

{Debug. Log ("Branje ni uspelo"); } private void OnArduinoInfoReceived (vrtenje niza, hitrost niza) {Debug. Log ("Readin Successfull"); Debug. Log ("Prva vrednost:" + rotacija); Debug. Log ("Druga vrednost:" + hitrost); }

Zadnji korak je zagon in ustavitev niti, ki bodo zahtevale vrednosti od Arduina. Pred začetkom nove moramo zagotoviti, da je zadnja nit opravljena s svojo zadnjo nalogo. V nasprotnem primeru bi bilo mogoče na Arduino hkrati vnesti več zahtev, kar bi lahko zmedlo Arduino/Unity in prineslo nepredvidljive rezultate.

zasebna nit activeThread = null;

void Update () {if (activeThread == null ||! activeThread. IsAlive) {activeThread = nova nit (AsynchronousReadFromArduino); activeThread. Start (); }}

Če primerjate delovanje kode s tisto, ki smo jo napisali v razdelku 5, bi bilo treba zmogljivost bistveno izboljšati.

zasebna praznina OnArduinoInfoFail ()

{Debug. Log ("Branje ni uspelo"); }

5. korak: Kje naprej?

Kam naprej?
Kam naprej?

Pripravili smo predstavitev, ki jo lahko prenesete na naš Github (https://github.com/AlexandreDoucet/InfinityBike), naložite kodo in igro ter se popeljete po naši skladbi. Vse je pripravljeno za hitro vadbo in upamo, da vam bo dalo okusiti, kaj bi lahko zgradili, če uporabite to, kar smo vas naučili s tem navodilom.

Krediti

Sodelavci projekta

Alexandre Doucet (_Doucet_)

Maxime Boudreau (MxBoud)

Zunanji viri [igralni stroj Unity] (https://unity3d.com)

Ta projekt se je začel, potem ko smo prebrali vadnico Allana Zucconija "kako integrirati Arduino z Unity" (https://www.alanzucconi.com/2015/10/07/how-to-int…)

Zahteve iz Arduina se obravnavajo s knjižnico SerialCommand (https://github.com/kroimon/Arduino-SerialCommand)

Priporočena: