Inhoudsopgave:

Infinity Bike - Indoor Bike Training Videogame - Ajarnpa
Infinity Bike - Indoor Bike Training Videogame - Ajarnpa

Video: Infinity Bike - Indoor Bike Training Videogame - Ajarnpa

Video: Infinity Bike - Indoor Bike Training Videogame - Ajarnpa
Video: Infinity Bike - Indoors bike training video game 2024, Juni-
Anonim
Image
Image
Materialen
Materialen

Tijdens de winterseizoenen, koude dagen en slecht weer hebben wielrenners maar een paar mogelijkheden om hun favoriete sport te beoefenen. We waren op zoek naar een manier om indoortraining met een fiets/trainer-opstelling wat leuker te maken, maar de meeste beschikbare producten zijn ofwel duur ofwel gewoon saai om te gebruiken. Daarom zijn we begonnen met het ontwikkelen van Infinity Bike als een Open Source-trainingsvideogame. Infinity Bike leest de snelheid en richting van uw fiets en biedt een niveau van interactiviteit dat niet gemakkelijk te vinden is met fietstrainers.

We profiteren van de eenvoud van de Arduino-microcontroller en een paar 3D-geprinte onderdelen om goedkope sensoren te bevestigen aan een fiets die op een trainer is gemonteerd. De informatie wordt doorgegeven aan een videogame die is gemaakt met de populaire engine voor het maken van games, Unity. Aan het einde van deze instructie zou je in staat moeten zijn om je eigen sensoren op je fiets in te stellen en de informatie van je sensoren naar Unity over te dragen. We hebben zelfs een circuit toegevoegd waarop je kunt rijden en je nieuwe set-up kunt testen. Als je geïnteresseerd bent om bij te dragen, kun je onze GitHub bekijken.

Stap 1: Materialen

Materialen
Materialen

De materiaallijst die je nodig hebt, kan een beetje variëren; voor

de maat van je fiets bepaalt bijvoorbeeld de lengte van de startkabels die je nodig hebt, maar hier zijn de belangrijkste onderdelen die je nodig hebt. Je zou waarschijnlijk goedkopere prijzen kunnen vinden voor elk stuk op websites zoals AliExpress, maar 6 maanden wachten op verzending is niet altijd een optie, dus gebruikten we de iets duurdere onderdelen, zodat de schatting niet scheef is.

1 x Arduino nano ($ 22,00)

1 x mini-broodplank ($ 1,33 / eenheid)

1 x 220 Ohm weerstand ($ 1,00/kit)

1 x 10K Potentiometer ($1,80/eenheid)

1 x Hall-sensor ($ 0,96)

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

1 kit x M3-schroeven en bouten met verschillende lengtes ($ 6,82)

1 x Fietssnelheidsmetermagneet ($ 0,98)

Bovenstaand materiaal hebben we gemonteerd met 3D geprinte onderdelen. De bestanden die we hebben gebruikt, worden hieronder weergegeven en zijn genummerd met dezelfde conventie als de afbeelding aan het begin van dit gedeelte. Alle bestanden zijn te vinden op Thingiverse. Je kunt ze gewoon gebruiken, maar zorg ervoor dat de afmetingen die we hebben gebruikt overeenkomen met je fiets.

1. FrameConnection_PotentiometerHolder_U_Holder.stl

2. FrameConnection_Spacer.stl

3. BreadboardFrameHolder.stl

4. Pulley_PotentiometerSide.stl

5. Pot_PulleyConnection.stl

6. FrameConnection.stl

7. Pulley_HandleBarSide_Print2.stl

8. FrameToHallSensorConnector.stl

9. Pannenlap.stl

10. HallSensorAttach.stl

Stap 2: Gegevens lezen en overbrengen naar Unity

Gegevens lezen en overbrengen naar Unity
Gegevens lezen en overbrengen naar Unity

De Arduino- en Unity-code werken samen om te verzamelen, de gegevens van de sensoren op de fiets overdragen en verwerken. Unity zal de waarde van de Arduino opvragen door een string door de serie te sturen en te wachten tot de Arduino reageert met de gevraagde waarden.

Eerst bereiden we de Arduino voor met de bibliotheek Serial Command die wordt gebruikt om de verzoeken van Unity te beheren door een verzoekreeks aan een functie te koppelen. Een basisconfiguratie voor deze bibliotheek kan als volgt worden gemaakt;

#include "SerialCommand.h"

SerialCommand sCmd; void setup() { sCmd.addCommand("TRIGG", TriggHanlder); Serieel.begin(9600); } void loop() { while (Serial.available() > 0) { sCmd.readSerial(); } } void TriggHandler () { /*Lees en verzend de sensoren hier*/}

De functie TriggHandler is gekoppeld aan het object SCmd. Als het serienummer een string ontvangt die overeenkomt met het bijgevoegde commando (in dit geval TRIGG), wordt de functie TriggHandler uitgevoerd.

We gebruiken een potentiometer om de stuurrichting te meten en een hallensensor om de rotatie per minuut van de fiets te meten. De uitlezingen van de potentiometer kunnen eenvoudig worden gedaan met behulp van de ingebouwde functies van de Arduino. De functie TriggHandler kan vervolgens de waarde naar het serienummer afdrukken met de volgende wijziging.

ongeldige TriggHandler (){

/*De waarde van de potentiometer lezen*/ Serial.println(analogRead(ANALOGPIN)); }

De Hall-sensor heeft wat meer instellingen voordat we bruikbare metingen kunnen doen. In tegenstelling tot de potmeter is de instant waarde van de halls-sensor niet erg handig. Omdat we probeerden de snelheid van het wiel te meten, was de tijd tussen triggers waar we in geïnteresseerd waren.

Elke functie die in de Arduino-code wordt gebruikt, kost tijd en als de magneet op het verkeerde moment op één lijn ligt met de Hall-sensor, kan de meting op zijn best worden vertraagd of in het slechtste geval helemaal worden overgeslagen. Dit is duidelijk slecht omdat de Arduino een snelheid kan melden die VEEL anders is dan de werkelijke snelheid van het wiel.

Om dit te voorkomen, gebruiken we een functie van Arduinos genaamd attach interrupt waarmee we een functie kunnen activeren wanneer een aangewezen digitale pin wordt geactiveerd met een stijgend signaal. De functie rpm_fun is gekoppeld aan een interrupt met een enkele regel code toegevoegd aan de setup-code.

ongeldige setup(){

sCmd.addCommand ("TRIGG", TriggHanlder); attachInterrupt(0, rpm_fun, RISING); Serieel.begin(9600); } //De functie rpm_fun wordt gebruikt om de snelheid te berekenen en is gedefinieerd als; niet-ondertekend lang lastRevolTime = 0; niet-ondertekende lange omwentelingssnelheid = 0; void rpm_fun() { unsigned long revolTime = millis(); unsigned long deltaTime = revolTime - lastRevolTime; /*revolSpeed is de waarde die naar de Arduino-code wordt verzonden*/ revolSpeed = 20000 / deltaTime; lastRevolTime = revolTime; } TriggHandler kan vervolgens de rest van de informatie verzenden wanneer daarom wordt gevraagd. void TriggHanlder () { /* Lezen van de waarde van de potentiometer*/ Serial.println (analogRead (ANALOGPIN)); Serial.println(revolSpeed); }

We hebben nu alle bouwstenen die kunnen worden gebruikt om de Arduino-code te bouwen die gegevens via het serienummer zal overbrengen naar wanneer een verzoek wordt gedaan door Unity. Als u een kopie van de volledige code wilt hebben, kunt u deze downloaden op onze GitHub. Om te testen of de code goed is ingesteld, kunt u de seriële monitor gebruiken om TRIGG te verzenden; zorg ervoor dat u de regel die eindigt op Carriage return instelt. De volgende sectie zal zich richten op hoe onze Unity-scripts de informatie van de Arduino kunnen opvragen en ontvangen.

Stap 3: Gegevens ontvangen en verwerken

Gegevens ontvangen en verwerken
Gegevens ontvangen en verwerken

Unity is een geweldige software die gratis beschikbaar is voor hobbyisten

geïnteresseerd in het maken van games; het wordt geleverd met een groot aantal functionaliteiten die de tijd aanzienlijk kunnen verkorten bij het instellen van bepaalde dingen, zoals threading of GPU-programmering (AKA-shading) zonder te beperken wat er met de C#-scripts kan worden gedaan. Unity- en Arduino-microcontrollers kunnen samen worden gebruikt om met een relatief klein budget unieke interactieve ervaringen te creëren.

De focus van deze instructable is om te helpen bij het opzetten van de communicatie tussen Unity en de Arduino, zodat we niet te diep ingaan op de meeste functies die beschikbaar zijn met Unity. Er zijn tal van GEWELDIGE tutorials voor unity en een ongelooflijke community die veel beter zou kunnen uitleggen hoe Unity werkt. Er is echter een speciale prijs voor degenen die erin slagen zich een weg te banen door deze instructable die dient als een kleine demonstratie van wat er zou kunnen worden gedaan. Je kunt op onze Github onze eerste poging downloaden om een circuit te maken met realistische fietsfysica.

Laten we eerst het absolute minimum doornemen dat moet worden gedaan om via de seriële met een Arduino te communiceren. Het zal snel duidelijk zijn dat deze code niet geschikt is voor gameplay, maar het is goed om elke stap te doorlopen en te leren wat de beperkingen zijn.

Maak in Unity een nieuwe scène met een enkel leeg GameObject genaamd ArduinoReceive bij een C#-script dat ook ArduinoReceive heet. Dit script is waar we alle code zullen toevoegen die de communicatie met de Arduino afhandelt.

Er is een bibliotheek die toegang moet hebben voordat we kunnen communiceren met de seriële poorten van uw computer; Unity moet worden ingesteld om het gebruik van bepaalde bibliotheken mogelijk te maken. Ga naar Bewerken->ProjectSerring->Player en naast het Api-compatibiliteitsniveau onder Configuratie switch. NET 2.0 Subset naar. NET 2.0. Voeg nu de volgende code toe bovenaan het script;

met behulp van System. IO. Ports;

Dit geeft je toegang tot de SerialPort-klasse die je zou kunnen definiëren als een object voor de ArduinoReceive-klasse. Maak het privé om interferentie van een ander script te voorkomen.

privé SerialPort arduinoPort;

Het object arduinoPort kan worden geopend door de juiste poort te selecteren (bijvoorbeeld in welke USB de Arduino is aangesloten) en een baudrate (d.w.z. de snelheid waarmee de informatie wordt verzonden). Als u niet zeker weet op welke poort de Arduino is aangesloten, kunt u dit achterhalen in Apparaatbeheer of door de Arduino IDE te openen. Voor de baudrate is de standaardwaarde op de meeste apparaten 9600, zorg er gewoon voor dat je deze waarde in je Arduino-code hebt en het zou moeten werken.

De code zou er nu zo uit moeten zien;

met behulp van System. Collections;

met behulp van System. Collections. Generic; met behulp van UnityEngine; met behulp van System. IO. Ports; openbare klasse ArduinoReceive: MonoBehaviour {private SerialPort arduinoPort; // Gebruik dit voor initialisatie void Start() { arduinoPort = new SerialPort("COM5", 9600); arduinoPort. Open(); WriteToArduino("TRIGG"); } }

Uw COM-nummer zal hoogstwaarschijnlijk anders zijn. Als je een MAC gebruikt, kan je COM-naam een naam hebben die er zo uitziet /dev/cu.wchusbserial1420. Zorg ervoor dat de code uit sectie 4 is geüpload naar de Arduino en dat de seriële monitor is gesloten voor de rest van deze sectie en dat deze code probleemloos wordt gecompileerd.

Laten we nu elk frame een verzoek naar de Arduino sturen en de resultaten naar het consolevenster schrijven. Voeg de functie WriteToArduino toe aan de klasse ArduinoReceive. De regelterugloop en nieuwe regel zijn nodig om de Arduino-code de inkomende instructie correct te laten ontleden.

privé leegte WriteToArduino (stringbericht)

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

Deze functie kan dan in de Update-lus worden aangeroepen.

ongeldige update ()

{ WriteToArduino ("TRIGG"); Debug. Log("Eerste waarde: " + arduinoPort. ReadLine()); Debug. Log("Tweede waarde: " + arduinoPort. ReadLine()); }

De bovenstaande code is het absolute minimum dat je nodig hebt om de gegevens van een Arduino te lezen. Als je goed let op de FPS die door unity wordt gegeven, zou je een aanzienlijke prestatievermindering moeten zien. In mijn geval gaat het van ongeveer 90 FPS zonder lezen/schrijven naar 20 FPS. Als uw project geen frequente updates vereist, is het misschien voldoende, maar voor een videogame is 20 FPS veel te laag. In het volgende gedeelte wordt beschreven hoe u de prestaties kunt verbeteren door multithreading te gebruiken.

Stap 4: Gegevensoverdracht optimaliseren

In het vorige gedeelte werd besproken hoe u de basis

communicatie tussen het Arduino- en Unity-programma. Het grootste probleem met deze code zijn de prestaties. In de huidige implementatie moet Unity wachten tot de Arduino het verzoek ontvangt, verwerkt en beantwoordt. Gedurende die tijd moet de Unity-code wachten tot het verzoek is gedaan en doet niets anders. We hebben dit probleem opgelost door een thread te maken die de verzoeken afhandelt en de variabele op de hoofdthread opslaat.

Om te beginnen moeten we de threading-bibliotheek opnemen door toe te voegen;

met behulp van System. Threading;

Vervolgens stellen we de functie in die we starten in de threads. AsynchronousReadFromArduino begint met het schrijven van het verzoek naar de Arduino met de functie WrtieToArduino. De uitlezing is ingesloten in een try-catch-blok, als de leestime-out, blijven de variabelen nul en wordt de functie OnArduinoInfoFail aangeroepen in plaats van de OnArduinoInfoReceive.

Vervolgens definiëren we de functies OnArduinoInfoFail en OnArduinoInfoReceive. Voor deze instructable drukken we de resultaten af naar de console, maar u kunt de resultaten opslaan in de variabelen die u nodig hebt voor uw project.

privé leegte OnArduinoInfoFail()

{ Debug. Log ("Lezen mislukt"); } private void OnArduinoInfoReceived (stringrotatie, stringsnelheid) { Debug. Log ("Readin Sucessfull"); Debug. Log("Eerste waarde: " + rotatie); Debug. Log ("Tweede waarde: " + snelheid); }

De laatste stap is het starten en stoppen van de threads die de waarden van de Arduino zullen opvragen. We moeten ervoor zorgen dat de laatste thread klaar is met zijn laatste taak voordat we een nieuwe starten. Anders zouden er meerdere verzoeken tegelijk aan de Arduino kunnen worden gedaan, wat de Arduino/Unity zou kunnen verwarren en onvoorspelbare resultaten zou opleveren.

privé-thread activeThread = null;

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

Als je de prestaties van de code vergelijkt met degene die we in sectie 5 hebben geschreven, zou de prestatie aanzienlijk moeten worden verbeterd.

privé leegte OnArduinoInfoFail()

{ Debug. Log ("Lezen mislukt"); }

Stap 5: Waar nu?

Waar volgende?
Waar volgende?

We hebben een demo voorbereid die je kunt downloaden op onze Github (https://github.com/AlexandreDoucet/InfinityBike), download de code en het spel en rijd door onze baan. Het is allemaal ingesteld voor een snelle training en we hopen dat het je een voorproefje kan geven van wat je zou kunnen bouwen als je gebruikt wat we je hebben geleerd met deze instructable.

Credits

Projectmedewerkers

Alexandre Doucet (_Doucet_)

Maxime Boudreau (MxBoud)

Externe bronnen [De Unity-game-engine](https://unity3d.com)

Dit project begon nadat we de tutorial van Allan Zucconi "hoe Arduino met Unity te integreren" hadden gelezen (https://www.alanzuccini.com/2015/10/07/how-to-int…)

Het verzoek van de Arduino wordt afgehandeld met behulp van de SerialCommand-bibliotheek (https://github.com/kroimon/Arduino-SerialCommand)

Aanbevolen: