Sadržaj:

Infinity Bike - Video igra za trening bicikala u zatvorenom prostoru: 5 koraka
Infinity Bike - Video igra za trening bicikala u zatvorenom prostoru: 5 koraka

Video: Infinity Bike - Video igra za trening bicikala u zatvorenom prostoru: 5 koraka

Video: Infinity Bike - Video igra za trening bicikala u zatvorenom prostoru: 5 koraka
Video: Мега заброшенный курорт Майами-Бич - здесь выступали The Beatles! 2024, Rujan
Anonim
Image
Image
Materijali
Materijali

Tijekom zimskih sezona, hladnih dana i lošeg vremena, ljubitelji biciklizma imaju samo nekoliko mogućnosti za vježbanje baveći se svojim omiljenim sportom. Tražili smo način da učinimo trening u zatvorenom prostoru s postavkom bicikla/trenera malo zabavnijim, ali većina dostupnih proizvoda je ili skupa ili jednostavno dosadna za korištenje. Zbog toga smo počeli razvijati Infinity Bike kao video igricu za vježbanje otvorenog koda. Infinity bike čita brzinu i smjer s vašeg bicikla i nudi razinu interaktivnosti koju nije lako pronaći s trenerima za bicikle.

Iskoristimo jednostavnost koja je dostupna od Arduino mikrokontrolera i nekoliko 3D ispisanih dijelova za pričvršćivanje jeftinih senzora na bicikl montiran na trenažeru. Podaci se prenose u videoigru napravljenu s popularnom mašinom za izradu igara, Unity. Do kraja ovog uputstva trebali biste moći postaviti vlastite senzore na svoj bicikl i prenijeti podatke svojih senzora na Unity. Uključili smo čak i stazu na kojoj se možete provozati i isprobati svoju novu postavu. Ako ste zainteresirani za doprinos, možete posjetiti naš GitHub.

Korak 1: Materijali

Materijali
Materijali

Popis materijala koji će vam trebati može se malo razlikovati; za

na primjer, veličina vašeg bicikla ovisit će o duljini prespojnih kabela koji su vam potrebni, ali evo glavnih dijelova koji će vam trebati. Vjerojatno biste mogli pronaći jeftinije cijene za svaki komad na web stranici poput AliExpressa, ali čekanje 6 mjeseci na isporuku nije uvijek opcija, pa ste koristili nešto skuplje dijelove pa procjena nije iskrivljena.

1 x Arduino nano (22,00 USD)

1 x Mini Breadboard (1,33 USD/jedinici)

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

1 x 10K potenciometar (1,80 USD/jedinici)

1 x Hall senzor (0,96 USD)

Razvodni remen za 3D pisač 20 cm x 6 mm (3,33 USD)

1 komplet x M3 vijci i vijci različite duljine (6,82 USD)

1 x magnet za brzinomjer bicikla (0,98 USD)

Gornji smo materijal montirali s 3D tiskanim dijelovima. Datoteke koje smo koristili navedene su ispod i numerirane su istim ugovorom kao slika na početku ovog odjeljka. Sve datoteke mogu se pronaći na Thingiverseu. Možete ih koristiti kakve jesu, ali pazite da dimenzije koje smo koristili odgovaraju vašem biciklu.

1. FrameConnection_PotenciometerHolder_U_Holder.stl

2. FrameConnection_Spacer.stl

3. BreadboardFrameHolder.stl

4. Bočna strana remenice_potenciometra.stl

5. Povezivanje_povezivanja remenice.stl

6. FrameConnection.stl

7. Remenica_RučkaBarSide_Print2.stl

8. FrameToHallSensorConnector.stl

9. PotHolder.stl

10. HallSensorAttach.stl

Korak 2: Čitanje i prijenos podataka u Unity

Čitanje i prijenos podataka u Unity
Čitanje i prijenos podataka u Unity

Kod Arduino i Unity zajedno će prikupljati, prijenos i obrada podataka sa senzora na biciklu. Unity će zatražiti vrijednost od Arduina slanjem niza kroz serijski broj i pričekati da Arduino odgovori sa traženim vrijednostima.

Prvo pripremamo Arduino s serijskom naredbom knjižnice koja se koristi za upravljanje zahtjevima iz Unityja uparivanjem niza zahtjeva s funkcijom. Osnovno postavljanje za ovu knjižnicu može se izvesti na sljedeći 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 () { /*Ovdje pročitajte i prenesite senzore* /}

Funkcija TriggHandler pridružena je objektu SCmd. Ako serijski broj primi niz koji odgovara priloženoj naredbi (u ovom slučaju TRIGG), izvršava se funkcija TriggHandler.

Koristimo potenciometar za mjerenje smjera upravljanja, a Hallsov senzor za mjerenje rotacije bicikla u minuti. Očitavanja s potenciometra mogu se jednostavno izvršiti pomoću ugrađenih funkcija iz Arduina. Funkcija TriggHandler tada može ispisati vrijednost u serijski broj sa sljedećom promjenom.

void TriggHandler () {

/*Očitavanje vrijednosti potenciometra*/ Serial.println (analogno čitanje (ANALOGPIN)); }

Hall senzor ima malo više postavki prije nego što možemo imati korisna mjerenja. Za razliku od potenciometra, trenutna vrijednost senzora u predvorju nije jako korisna. Budući da su pokušavali mjeriti brzinu kotača, vrijeme između okidača je ono što je zanimalo.

Svaka funkcija korištena u Arduino kodu zahtijeva vrijeme, a ako se magnet poravna s Hall -ovim senzorom u pogrešno vrijeme, mjerenje bi se u najboljem slučaju moglo odgoditi ili u najgorem slučaju preskočiti. To je očito loše jer bi Arduino mogao prijaviti brzinu koja se MNOGO razlikuje od stvarne brzine kotača.

Da bismo to izbjegli, koristimo značajku Arduinosa koja se naziva attach interrupt koja nam omogućuje da pokrenemo funkciju kad god se naznačeni digitalni pin aktivira s rastućim signalom. Funkcija rpm_fun pridružena je prekidu s jednim retkom koda koji je dodan u kod za postavljanje.

void setup () {

sCmd.addCommand ("TRIGG", TriggHanlder); attachInterrupt (0, rpm_fun, RISING); Serial.begin (9600); } // Funkcija rpm_fun koristi se za izračun brzine i definirana je kao; unsigned long lastRevolTime = 0; unsigned long revolSpeed = 0; void rpm_fun () {unsigned long revolTime = millis (); unsigned long deltaTime = revolTime - lastRevolTime; /*revolSpeed je vrijednost prenesena u Arduino kod* / revolSpeed = 20000 / deltaTime; lastRevolTime = revolTime; } TriggHandler tada može prenijeti ostatak informacija na zahtjev. void TriggHanlder () { /*Očitavanje vrijednosti potenciometra* / Serial.println (analogRead (ANALOGPIN)); Serial.println (revolSpeed); }

Sada imamo sve građevne blokove koji se mogu koristiti za izradu Arduino koda koji će prenositi podatke kroz serijsku jedinicu do trenutka kada Unity uputi zahtjev. Ako želite imati kopiju cijelog koda, možete ga preuzeti na našem GitHubu. Da biste provjerili je li kôd pravilno postavljen, možete koristiti serijski monitor za slanje TRIGG-a; svakako postavite redak koji završava na Carriage return. Sljedeći odjeljak fokusirat će se na to kako naše Unity skripte mogu zatražiti i primiti informacije od Arduina.

Korak 3: Primanje i obrada podataka

Prijem i obrada podataka
Prijem i obrada podataka

Unity je izvrstan softver dostupan besplatno ljubiteljima

zainteresiran za izradu igara; dolazi s velikim brojem funkcionalnosti koje doista mogu skratiti vrijeme postavljanja određenih stvari, kao što su niti ili programiranje GPU -a (AKA zasjenjivanje) bez ograničenja onoga što se može učiniti s C# skriptama. Mikrokontroleri Unity i Arduino mogu se koristiti zajedno za stvaranje jedinstvenih interaktivnih iskustava s relativno malim proračunom.

Fokus ovog uputstva je pomoći u uspostavljanju komunikacije između Unityja i Arduina tako da nećemo zaroniti preduboko u većinu značajki dostupnih s Unityjem. Postoji mnogo VELIKIH vodiča za jedinstvo i nevjerojatnu zajednicu koja bi mogla puno bolje objasniti kako Unity funkcionira. Međutim, postoji posebna nagrada za one koji se uspiju snaći u ovoj instrukciji koja služi kao mala izložba onoga što bi se moglo učiniti. Na našem Githubu možete preuzeti naš prvi pokušaj stvaranja staze s realnom fizikom bicikla.

Prvo, prijeđimo na najmanji minimum koji je potrebno učiniti da biste komunicirali s Arduinom putem serije. Brzo će biti jasno da ovaj kôd nije prikladan za igranje, ali dobro je proći svaki korak i naučiti koja su ograničenja.

U Unity -u stvorite novu scenu s jednim praznim GameObjektom pod imenom ArduinoReceive i priložite C# skriptu koja se također naziva ArduinoReceive. Ova skripta će dodati sav kod koji upravlja komunikacijom s Arduinom.

Postoji biblioteka kojoj je potrebno pristupiti prije nego što možemo komunicirati sa serijskim portovima vašeg računala; Unity mora biti postavljen kako bi se omogućilo korištenje određenih knjižnica. Idite na Uredi-> ProjectSerring-> Player i pored razine kompatibilnosti API-ja u odjeljku Konfiguracijski prekidač. Podskup. NET 2.0 na. NET 2.0. Sada dodajte sljedeći kôd na vrh skripte;

pomoću System. IO. Ports;

To će vam omogućiti pristup klasi SerialPort koju možete definirati kao objekt klase ArduinoReceive. Neka bude privatno kako biste izbjegli smetnje iz druge skripte.

privatni SerialPort arduinoPort;

Objekt arduinoPort može se otvoriti odabirom ispravnog priključka (npr. Na koji je USB priključen Arduino) i brzine prijenosa (tj. Brzine kojom se informacije šalju). Ako niste sigurni u koji je priključak priključen Arduino, to možete saznati u upravitelju uređaja ili otvaranjem Arduino IDE -a. Za brzinu prijenosa, zadana vrijednost na većini uređaja je 9600, samo provjerite imate li tu vrijednost u svom Arduino kodu i trebala bi raditi.

Kôd bi sada trebao izgledati ovako;

pomoću System. Collections;

pomoću System. Collections. Generic; koristeći UnityEngine; pomoću System. IO. Ports; javna klasa ArduinoReceive: MonoBehaviour {privatni SerialPort arduinoPort; // Koristi ovo za inicijalizaciju void Start () {arduinoPort = new SerialPort ("COM5", 9600); arduinoPort. Open (); WriteToArduino ("TRIGG"); }}

Vaš COM broj najvjerojatnije će biti drugačiji. Ako ste na MAC -u, vaše COM ime može imati naziv koji izgleda ovako /dev/cu.wchusbserial1420. Provjerite je li kôd iz odjeljka 4 postavljen na Arduino i je li serijski monitor zatvoren za ostatak ovog odjeljka i da li se ovaj kod bez problema kompilira.

Pošaljimo sada zahtjev za svaki okvir Arduinu i zapisujmo rezultate u prozor konzole. Dodajte funkciju WriteToArduino u klasu ArduinoReceive. Povratak nosača i nova linija neophodni su za Arduino kôd za pravilno raščlanjivanje dolazne upute.

private void WriteToArduino (niz poruka)

{poruka = poruka + "\ r / n"; arduinoPort. Write (poruka); arduinoPort. BaseStream. Flush (); }

Ova se funkcija tada može pozvati u petlji ažuriranja.

void Update ()

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

Gornji kôd je minimum koji vam je potreban za čitanje podataka s Arduina. Ako pažljivo obratite pozornost na FPS -ove date jedinstvom, trebali biste vidjeti značajan pad performansi. U mom slučaju, ide sa oko 90 FPS bez čitanja/pisanja do 20 FPS. Ako vaš projekt ne zahtijeva česta ažuriranja, to bi moglo biti dovoljno, ali za videoigru 20 FPS je premalo. Sljedeći odjeljak pokazat će kako možete poboljšati performanse korištenjem više niti.

Korak 4: Optimiziranje prijenosa podataka

U prethodnom je odjeljku opisano kako postaviti osnovni program

komunikacija između programa Arduino i Unity. Glavni problem ovog koda su performanse. U svojoj trenutnoj implementaciji, Unity mora pričekati da Arduino primi, obradi i odgovori na zahtjev. Za to vrijeme Unity kôd mora čekati da se zahtjev izvrši i ne radi ništa drugo. Riješili smo ovaj problem stvaranjem niti koja će obrađivati zahtjeve i spremati varijablu u glavnu nit.

Za početak, moramo uključiti knjižnicu threadinga dodavanjem;

pomoću System. Threading;

Zatim postavljamo funkciju koju pokrećemo u niti. AsynchronousReadFromArduino počinje pisanjem zahtjeva u Arduino s funkcijom WrtieToArduino. Očitavanje je zatvoreno u blok try-catch, ako je vremensko ograničenje čitanja, varijable ostaju null, a funkcija OnArduinoInfoFail se poziva umjesto OnArduinoInfoReceive.

Zatim definiramo funkcije OnArduinoInfoFail i OnArduinoInfoReceive. Za ovu uputu ispisujemo rezultate na konzolu, ali možete spremiti rezultate u varijable koje su vam potrebne za vaš projekt.

privatna praznina OnArduinoInfoFail ()

{Debug. Log ("Čitanje nije uspjelo"); } private void OnArduinoInfoReceived (rotacija niza, brzina niza) {Debug. Log ("Uspješno čitanje"); Debug. Log ("Prva vrijednost:" + rotacija); Debug. Log ("Druga vrijednost:" + brzina); }

Zadnji korak je pokretanje i zaustavljanje niti koje će zahtijevati vrijednosti od Arduina. Moramo osigurati da je zadnja nit završena s njezinim zadnjim zadatkom prije nego započnemo novu. Inače bi se moglo poslati više zahtjeva Arduinu u isto vrijeme što bi moglo zbuniti Arduino/Unity i donijeti nepredvidive rezultate.

privatna nit activeThread = null;

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

Usporedite li izvedbu koda s onom koju smo napisali u odjeljku 5, izvedbu bi trebalo značajno poboljšati.

privatna praznina OnArduinoInfoFail ()

{Debug. Log ("Čitanje nije uspjelo"); }

Korak 5: Gdje dalje?

Gdje dalje?
Gdje dalje?

Pripremili smo demo koji možete preuzeti na našem Githubu (https://github.com/AlexandreDoucet/InfinityBike), preuzeti kod i igru te se provozati našom stazom. Sve je pripremljeno za brzi trening i nadamo se da će vam dati dojam o tome što biste mogli izgraditi ako upotrijebite ono što smo vas naučili ovim uputstvom.

Zasluge

Suradnici na projektu

Alexandre Doucet (_Doucet_)

Maxime Boudreau (MxBoud)

Vanjski izvori [Unity engine za igre] (https://unity3d.com)

Ovaj je projekt započeo nakon što smo pročitali vodič Allana Zucconija "Kako integrirati Arduino s jedinstvom" (https://www.alanzucconi.com/2015/10/07/how-to-int…)

Zahtjev iz Arduina obrađuje se pomoću biblioteke SerialCommand (https://github.com/kroimon/Arduino-SerialCommand)

Preporučeni: