Indholdsfortegnelse:

Infinity Bike - Indendørs cykeltræning videospil: 5 trin
Infinity Bike - Indendørs cykeltræning videospil: 5 trin

Video: Infinity Bike - Indendørs cykeltræning videospil: 5 trin

Video: Infinity Bike - Indendørs cykeltræning videospil: 5 trin
Video: Новый ультра-тихий домашний фитнес-центр Exercise Bike! 2021 г.... 2024, Juni
Anonim
Image
Image
Materialer
Materialer

I vintersæsonen, kolde dage og dårligt vejr har cyklistentusiaster kun få muligheder for at dyrke deres yndlingssport. Vi ledte efter en måde at gøre indendørs træning med en cykel/træner opsætning lidt mere underholdende, men de fleste tilgængelige produkter er enten dyre eller simpelthen kedelige at bruge. Derfor begyndte vi at udvikle Infinity Bike som et Open Source træningsvideospil. Infinity bike læser hastigheden og retningen fra din cykel og tilbyder et niveau af interaktivitet, der ikke let kan findes med cykeltrænere.

Vi drager fordel af den enkle tilgængelighed fra Arduino mikrokontroller og et par 3D -printede dele til at sikre billige sensorer til en cykel monteret på en træner. Oplysningerne videresendes til et videospil, der er lavet med den populære spilfremstillingsmotor, Unity. Ved afslutningen af denne instruktive skulle du være i stand til at opsætte dine egne sensorer på din cykel og overføre oplysningerne om dine sensorer til Unity. Vi inkluderede endda et spor, som du kan køre med på og teste dit nye setup. Hvis du er interesseret i at bidrage, kan du tjekke vores GitHub.

Trin 1: Materialer

Materialer
Materialer

Den materialeliste, du får brug for, kan variere en smule; til

for eksempel vil størrelsen på din cykel diktere længderne på de jumperkabler, du har brug for, men her er de vigtigste dele, du skal bruge. Du kan sandsynligvis finde billigere priser for hvert stykke på webstedet som AliExpress, men at vente 6 måneder på forsendelse er ikke altid en mulighed, så brugte de lidt dyrere dele, så estimatet ikke er skævt.

1 x Arduino nano ($ 22,00)

1 x Mini Breadboard ($ 1,33/enhed)

1 x 220 Ohm modstand ($ 1,00/sæt)

1 x 10K potentiometer ($ 1,80/enhed)

1 x Hall -sensor ($ 0,96)

20 cm x 6 mm 3D -printer tandrem ($ 3,33)

1 sæt x forskellige længder M3 skruer og bolte ($ 6,82)

1 x Cykelhastighedsmåler ($ 0,98)

Vi monterede materialet ovenfor med 3D -printede dele. Filerne, vi brugte, er angivet nedenfor, og de er nummereret med samme konvention som billedet i begyndelsen af dette afsnit. Alle filerne kan findes på Thingiverse. Du kan bruge dem som de er, men sørg for, at de dimensioner, vi brugte, matcher din cykel.

1. FrameConnection_PotentiometerHolder_U_Holder.stl

2. FrameConnection_Spacer.stl

3. BreadboardFrameHolder.stl

4. Remskive_PotentiometerSide.stl

5. Pot_PulleyConnection.stl

6. FrameConnection.stl

7. Pulley_HandleBarSide_Print2.stl

8. FrameToHallSensorConnector.stl

9. PotHolder.stl

10. HallSensorAttach.stl

Trin 2: Læsning og overførsel af data til enhed

Læsning og overførsel af data til enhed
Læsning og overførsel af data til enhed

Arduino og Unity -koden fungerer sammen for at indsamle, overføre og behandle data fra sensorerne på cyklen. Unity vil anmode om værdien fra Arduino ved at sende en streng gennem serien og vente på, at Arduino reagerer med de ønskede værdier.

Først forbereder vi Arduino med bibliotekets serielle kommando, der bruges til at administrere anmodningerne fra Unity ved at parre en anmodningsstreng med en funktion. En grundlæggende opsætning for dette bibliotek kan foretages som følger;

#include "SerialCommand.h"

SerialCommand sCmd; void setup () {sCmd.addCommand ("TRIGG", TriggHanlder); Serial.begin (9600); } void loop () {while (Serial.available ()> 0) {sCmd.readSerial (); }} ugyldiggør TriggHandler () { /*Læs og transmitter sensorerne her* /}

Funktionen TriggHandler er knyttet til objektet SCmd. Hvis føljetonen modtager en streng, der matcher den vedhæftede kommando (i dette tilfælde TRIGG), udføres funktionen TriggHandler.

Vi bruger potentiometer til at måle styreretningen og en hallsensor til at måle cyklens rotation pr. Minut. Aflæsningerne fra potentiometeret kan let foretages ved hjælp af de indbyggede funktioner fra Arduino. Funktionen TriggHandler kan derefter udskrive værdien til føljetonen med følgende ændring.

ugyldig TriggHandler () {

/*Aflæsning af værdien af potentiometeret*/ Serial.println (analogRead (ANALOGPIN)); }

Hall -sensoren har lidt mere opsætning, før vi kan have nyttige målinger. I modsætning til potentiometeret er øjeblikkelig værdi af hallsensoren ikke særlig nyttig. Siden forsøgte at måle hjulets hastighed, var tiden mellem udløsere det, der var interesseret i.

Hver funktion, der bruges i Arduino -koden, tager tid, og hvis magneten stemmer overens med Hall -sensoren på det forkerte tidspunkt, kan målingen i bedste fald blive forsinket eller springe helt i værste fald over. Dette er naturligvis dårligt, fordi Arduino kunne rapportere en hastighed, der er meget anderledes end hjulets faktiske hastighed.

For at undgå dette bruger vi en funktion i Arduinos kaldet attach interrupt, som giver os mulighed for at udløse en funktion, når en udpeget digital pin udløses med et stigende signal. Funktionen rpm_fun er knyttet til en afbrydelse med en enkelt kodelinje tilføjet til opsætningskoden.

ugyldig opsætning () {

sCmd.addCommand ("TRIGG", TriggHanlder); attachInterrupt (0, rpm_fun, RISING); Serial.begin (9600); } // Funktionen rpm_fun bruges til at beregne hastigheden og er defineret som; unsigned long lastRevolTime = 0; usigneret lang revolSpeed = 0; void rpm_fun () {unsigned long revolTime = millis (); usigneret lang deltaTime = revolTime - lastRevolTime; /*revolSpeed er værdien, der overføres til Arduino -koden* / revolSpeed = 20000 / deltaTime; lastRevolTime = revolTime; } TriggHandler kan derefter sende resten af oplysningerne, når det bliver anmodet om det. void TriggHanlder () { /*Læsning af værdien af potentiometeret* / Serial.println (analogRead (ANALOGPIN)); Serial.println (revolSpeed); }

Vi har nu alle de byggesten, der kan bruges til at bygge Arduino -koden, som vil overføre data gennem serienummeret til, når der fremsættes en anmodning fra Unity. Hvis du vil have en kopi af den fulde kode, kan du downloade den på vores GitHub. For at teste, om koden er konfigureret korrekt, kan du bruge den serielle skærm til at sende TRIGG; sørg for at indstille linjen, der slutter til vognretur. Det næste afsnit vil fokusere på, hvordan vores Unity -scripts kan anmode om og modtage oplysningerne fra Arduino.

Trin 3: Modtagelse og behandling af data

Modtagelse og behandling af data
Modtagelse og behandling af data

Unity er en fantastisk software tilgængelig gratis for hobbyfolk

interesseret i spilfremstilling; den kommer med et stort antal funktioner, der virkelig kan skære ned på tiden med at konfigurere visse ting, såsom trådning eller GPU -programmering (AKA -skygge) uden at begrænse, hvad der kan gøres med C# -scripts. Unity og Arduino mikrokontrollere kan bruges sammen til at skabe unikke interaktive oplevelser med et relativt lille budget.

Fokus for denne instruktive er at hjælpe med at opsætte kommunikationen mellem Unity og Arduino, så vi ikke dykker for dybt ned i de fleste af de funktioner, der er tilgængelige med Unity. Der er masser af GREAT tutorials for enhed og et utroligt fællesskab, der kunne gøre et meget bedre stykke arbejde med at forklare, hvordan Unity fungerer. Der er dog en særlig præmie til dem, der formår at arbejde sig igennem denne instruktive, der fungerer som et lille udstillingsvindue for, hvad der kunne gøres. Du kan downloade vores første forsøg på at lave et spor med realistisk cykelfysik på vores Github.

Lad os først gå igennem det minimale minimum, der skal gøres for at kommunikere med en Arduino gennem serien. Det vil hurtigt fremgå, at denne kode ikke er egnet til gameplay, men det er godt at gå igennem hvert trin og lære, hvad begrænsningerne er.

Opret i Unity en ny scene med et enkelt tomt GameObject ved navn ArduinoReceive ved vedhæftning af et C# script også kaldet ArduinoReceive. Dette script er, hvor vi tilføjer al den kode, der håndterer kommunikationen med Arduino.

Der er et bibliotek, der skal have adgang, før vi kan kommunikere med seriens porte på din computer; Der skal oprettes enhed for at tillade visse biblioteker at blive brugt. Gå til Edit-> ProjectSerring-> Player og ved siden af Api-kompatibilitetsniveauet under konfigurationskontakten. NET 2.0-undersæt til. NET 2.0. Tilføj nu følgende kode øverst i scriptet;

ved hjælp af System. IO. Ports;

Dette giver dig adgang til SerialPort -klassen, som du kan definere som et objekt for ArduinoReceive -klassen. Gør det privat for at undgå interferens fra et andet script.

private SerialPort arduinoPort;

Objektet arduinoPort kan åbnes ved at vælge den korrekte port (f.eks. I hvilken USB Arduino er tilsluttet) og en baudhastighed (dvs. den hastighed, hvormed oplysningerne sendes). Hvis du ikke er sikker på, hvilken port Arduino er tilsluttet, kan du finde ud af det enten i enhedshåndteringen eller ved at åbne Arduino IDE. For baudhastigheden er standardværdien på de fleste enheder 9600, bare sørg for at have denne værdi i din Arduino -kode, og den skal fungere.

Koden skal nu se sådan ud;

ved hjælp af System. Collections;

ved hjælp af System. Collections. Generic; ved hjælp af UnityEngine; ved hjælp af System. IO. Ports; public class ArduinoReceive: MonoBehaviour {private SerialPort arduinoPort; // Brug dette til initialisering void Start () {arduinoPort = ny SerialPort ("COM5", 9600); arduinoPort. Open (); WriteToArduino ("TRIGG"); }}

Dit COM -nummer vil sandsynligvis være anderledes. Hvis du er på en MAC, har dit COM -navn muligvis et navn, der ligner dette /dev/cu.wchusbserial1420. Sørg for, at koden fra afsnit 4 uploades til Arduino, og at den serielle skærm er lukket for resten af dette afsnit, og at denne kode kompileres uden problemer.

Lad os nu sende en anmodning til Arduino hver ramme og skrive resultaterne til konsolvinduet. Tilføj funktionen WriteToArduino til klassen ArduinoReceive. Vognretur og ny linje er nødvendige for, at Arduino -koden kan analysere den indgående instruktion korrekt.

private void WriteToArduino (strengbesked)

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

Denne funktion kan derefter kaldes i opdateringssløjfen.

ugyldig opdatering ()

{WriteToArduino ("TRIGG"); Debug. Log ("Første værdi:" + arduinoPort. ReadLine ()); Debug. Log ("Anden værdi:" + arduinoPort. ReadLine ()); }

Koden ovenfor er det minimale minimum, du har brug for for at læse dataene fra en Arduino. Hvis du er meget opmærksom på FPS givet af enhed, bør du se et betydeligt fald i ydelsen. I mit tilfælde går det fra omkring 90 FPS uden at læse/skrive til 20 FPS. Hvis dit projekt ikke kræver hyppige opdateringer, kan det være tilstrækkeligt, men for et videospil er 20 FPS alt for lavt. Det næste afsnit vil dække, hvordan du kan forbedre ydelsen ved at bruge multi -threading.

Trin 4: Optimering af dataoverførsel

Det foregående afsnit dækkede, hvordan du opsætter basic

kommunikation mellem Arduino og Unity -programmet. Det største problem med denne kode er ydelsen. I den nuværende implementering skal Unity vente på, at Arduino modtager, behandler og besvarer anmodningen. I løbet af denne tid skal Unity -koden vente på, at anmodningen er udført og gør intet andet. Vi løste dette problem ved at oprette en tråd, der håndterer anmodningerne og gemmer variablen på hovedtråden.

For at begynde skal vi inkludere trådbiblioteket ved at tilføje;

ved hjælp af System. Threading;

Derefter opsætter vi den funktion, vi starter i trådene. AsynchronousReadFromArduino starter med at skrive anmodningen til Arduino med funktionen WrtieToArduino. Aflæsningen er omsluttet af en try-catch-blok. Hvis timeout for læsning forbliver variablerne nul, og OnArduinoInfoFail-funktionen kaldes i stedet for OnArduinoInfoReceive.

Dernæst definerer vi funktionerne OnArduinoInfoFail og OnArduinoInfoReceive. Til denne instruktive udskriver vi resultaterne til konsollen, men du kan gemme resultaterne i de variabler, du har brug for til dit projekt.

privat tomrum OnArduinoInfoFail ()

{Debug. Log ("Læsning mislykkedes"); } private void OnArduinoInfoReceived (strengrotation, strenghastighed) {Debug. Log ("Readin Sucessfull"); Debug. Log ("Første værdi:" + rotation); Debug. Log ("Anden værdi:" + hastighed); }

Det sidste trin er at starte og stoppe de tråde, der vil anmode om værdierne fra Arduino. Vi skal sikre, at den sidste tråd er færdig med den sidste opgave, før vi starter en ny. Ellers kunne flere anmodninger udføres til Arduino på et enkelt tidspunkt, hvilket kunne forvirre Arduino/Unity og give uforudsigelige resultater.

private Thread activeThread = null;

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

Hvis du sammenligner kodens ydelse med den, vi skrev i afsnit 5, bør ydelsen forbedres betydeligt.

privat tomrum OnArduinoInfoFail ()

{Debug. Log ("Læsning mislykkedes"); }

Trin 5: Hvor næste?

Hvor næste?
Hvor næste?

Vi udarbejdede en demo, som du kan downloade på vores Github (https://github.com/AlexandreDoucet/InfinityBike), downloade koden og spillet og køre gennem vores spor. Det hele er klar til en hurtig træning, og vi håber, at det kan give dig en forsmag på, hvad du kunne bygge, hvis du bruger det, vi lærte dig med dette instruerbare.

Credits

Projektbidragsydere

Alexandre Doucet (_Doucet_)

Maxime Boudreau (MxBoud)

Eksterne ressourcer [Unity -spilmotoren] (https://unity3d.com)

Dette projekt startede, efter at vi havde læst vejledningen af Allan Zucconi "hvordan man integrerer Arduino med Unity" (https://www.alanzucconi.com/2015/10/07/how-to-int…)

Anmodningen fra Arduino håndteres ved hjælp af SerialCommand-biblioteket (https://github.com/kroimon/Arduino-SerialCommand)

Anbefalede: