Inhaltsverzeichnis:

Infinity Bike - Indoor Bike Training Videospiel - Gunook
Infinity Bike - Indoor Bike Training Videospiel - Gunook

Video: Infinity Bike - Indoor Bike Training Videospiel - Gunook

Video: Infinity Bike - Indoor Bike Training Videospiel - Gunook
Video: How to remove hands easily from rope . 📝👐🙌🙏↗️➰🤩😎👍. 2024, Juni
Anonim
Image
Image
Materialien
Materialien

In der Wintersaison, an kalten Tagen und bei schlechtem Wetter haben Radsportbegeisterte nur wenige Möglichkeiten, ihren Lieblingssport auszuüben. Wir suchten nach einer Möglichkeit, das Indoor-Training mit einem Fahrrad-/Trainer-Setup etwas unterhaltsamer zu gestalten, aber die meisten verfügbaren Produkte sind entweder kostspielig oder einfach nur langweilig in der Verwendung. Aus diesem Grund haben wir begonnen, Infinity Bike als Open-Source-Trainingsvideospiel zu entwickeln. Infinity Bike liest die Geschwindigkeit und Richtung von Ihrem Fahrrad und bietet ein Maß an Interaktivität, das mit Fahrradtrainern nicht leicht zu finden ist.

Wir nutzen die Einfachheit des Arduino-Mikrocontrollers und einige 3D-gedruckte Teile, um kostengünstige Sensoren an einem auf einem Trainer montierten Fahrrad zu befestigen. Die Informationen werden an ein Videospiel weitergeleitet, das mit der beliebten Game-Making-Engine Unity erstellt wurde. Am Ende dieser Anleitung sollten Sie in der Lage sein, Ihre eigenen Sensoren an Ihrem Fahrrad einzurichten und die Informationen Ihrer Sensoren an Unity zu übertragen. Wir haben sogar eine Strecke eingebaut, auf der Sie mitfahren und Ihr neues Setup testen können. Wenn Sie daran interessiert sind, einen Beitrag zu leisten, können Sie unseren GitHub besuchen.

Schritt 1: Materialien

Materialien
Materialien

Die Materialliste, die Sie benötigen, kann etwas variieren; zum

Beispielsweise bestimmt die Größe Ihres Fahrrads die Länge der Überbrückungskabel, die Sie benötigen, aber hier sind die wichtigsten Teile, die Sie benötigen. Sie könnten wahrscheinlich günstigere Preise für jedes Stück auf Websites wie AliExpress finden, aber 6 Monate auf den Versand zu warten ist nicht immer eine Option, also haben wir die etwas teureren Teile verwendet, damit die Schätzung nicht verzerrt ist.

1 x Arduino-Nano (22,00 $)

1 x Mini-Breadboard (1,33 $/Einheit)

1 x 220 Ohm Widerstand ($1.00/Kit)

1 x 10.000 Potentiometer (1,80 $/Einheit)

1 x Hall-Sensor (0,96 $)

20 cm x 6 mm 3D-Drucker-Zahnriemen ($3,33)

1 Kit x M3-Schrauben und -Schrauben mit verschiedenen Längen ($ 6,82)

1 x Fahrradtachomagnet (0,98 $)

Wir haben das obige Material mit 3D-gedruckten Teilen montiert. Die von uns verwendeten Dateien sind unten aufgelistet und mit der gleichen Konvention wie das Bild am Anfang dieses Abschnitts nummeriert. Alle Dateien sind auf Thingiverse zu finden. Sie können sie unverändert verwenden, aber stellen Sie sicher, dass die von uns verwendeten Abmessungen zu Ihrem Fahrrad passen.

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. PotHolder.stl

10. HallSensorAttach.stl

Schritt 2: Lesen und Übertragen von Daten an Unity

Lesen und Übertragen von Daten an Unity
Lesen und Übertragen von Daten an Unity

Der Arduino- und Unity-Code arbeiten zusammen, um zu sammeln, übertragen und verarbeiten die Daten der Sensoren am Fahrrad. Unity fordert den Wert vom Arduino an, indem es eine Zeichenfolge durch die serielle Schnittstelle sendet und wartet, bis der Arduino mit den angeforderten Werten antwortet.

Zuerst bereiten wir das Arduino mit der Bibliothek Serial Command vor, die verwendet wird, um die Anfragen von Unity zu verwalten, indem wir einen Anfragestring mit einer Funktion koppeln. Eine grundlegende Einrichtung für diese Bibliothek kann wie folgt vorgenommen werden;

#include "SerialCommand.h"

SerialCommand sCmd; Void setup () { sCmd.addCommand ("TRIGG", TriggHanlder); Serial.begin (9600); aufrechtzuerhalten. Void Schleife () { während (Serial.available () > 0) { sCmd.readSerial (); } } void TriggHandler () {/*Lesen und übertragen Sie die Sensoren hier*/ }

Die Funktion TriggHandler wird an das Objekt SCmd angehängt. Erhält die Serielle einen String, der dem angehängten Befehl (in diesem Fall TRIGG) entspricht, wird die Funktion TriggHandler ausgeführt.

Wir verwenden Potentiometer, um die Lenkrichtung zu messen und einen Halls-Sensor, um die Umdrehungen pro Minute des Fahrrads zu messen. Die Messwerte des Potentiometers können einfach mit den eingebauten Funktionen des Arduino vorgenommen werden. Die Funktion TriggHandler kann dann den Wert mit der folgenden Änderung in die Seriennummer ausgeben.

void TriggHandler (){

/*Wert des Potentiometers lesen*/ Serial.println (analogRead (ANALOGPIN)); }

Der Hall-Sensor muss etwas mehr eingerichtet werden, bevor wir nützliche Messungen durchführen können. Im Gegensatz zum Potentiometer ist der Momentanwert des Hallssensors wenig aussagekräftig. Da wir versuchten, die Geschwindigkeit des Rades zu messen, interessierte die Zeit zwischen den Triggern.

Jede im Arduino-Code verwendete Funktion braucht Zeit und wenn der Magnet zum falschen Zeitpunkt mit dem Hall-Sensor ausgerichtet ist, kann die Messung bestenfalls verzögert oder im schlimmsten Fall ganz übersprungen werden. Dies ist offensichtlich schlecht, da der Arduino eine Geschwindigkeit melden könnte, die sich VIEL von der tatsächlichen Geschwindigkeit des Rads unterscheidet.

Um dies zu vermeiden, verwenden wir eine Funktion von Arduinos namens Attach Interrupt, die es uns ermöglicht, eine Funktion auszulösen, wenn ein bestimmter digitaler Pin mit einem ansteigenden Signal ausgelöst wird. Die Funktion rpm_fun wird an einen Interrupt mit einer einzelnen Codezeile angehängt, die dem Setup-Code hinzugefügt wird.

Void-Setup () {

sCmd.addCommand("TRIGG", TriggHanlder); attachInterrupt(0, rpm_fun, RISING); Serial.begin (9600); } //Die Funktion rpm_fun wird verwendet, um die Geschwindigkeit zu berechnen und ist definiert als; unsigned long lastRevolTime = 0; unsigned long revolSpeed = 0; Void rpm_fun () { unsigned long revolTime = millis (); unsigned long deltaTime = revolTime - lastRevolTime; /*revolSpeed ist der an den Arduino-Code übertragene Wert*/ revolSpeed = 20000 / deltaTime; lastRevolTime = revolTime; } TriggHandler kann dann auf Anfrage die restlichen Informationen übertragen. void TriggHanlder () {/*Wert des Potentiometers lesen*/Serial.println (analogRead (ANALOGPIN)); Serial.println (revolSpeed); }

Wir haben jetzt alle Bausteine, die zum Erstellen des Arduino-Codes verwendet werden können, der Daten über die serielle Schnittstelle überträgt, wenn eine Anfrage von Unity gestellt wird. Wenn Sie eine Kopie des vollständigen Codes haben möchten, können Sie ihn auf unserem GitHub herunterladen. Um zu testen, ob der Code richtig eingerichtet wurde, können Sie den seriellen Monitor verwenden, um TRIGG zu senden; Stellen Sie sicher, dass Sie das Zeilenende auf Wagenrücklauf setzen. Der nächste Abschnitt konzentriert sich darauf, wie unsere Unity-Skripte die Informationen vom Arduino anfordern und empfangen können.

Schritt 3: Daten empfangen und verarbeiten

Empfangen und Verarbeiten von Daten
Empfangen und Verarbeiten von Daten

Unity ist eine großartige Software, die für Bastler kostenlos erhältlich ist

Interesse am Spielemachen; es kommt mit einer großen Anzahl von Funktionalitäten, die die Zeit beim Einrichten bestimmter Dinge wie Threading oder GPU-Programmierung (AKA-Shading) wirklich verkürzen können, ohne die Möglichkeiten mit den C#-Skripten einzuschränken. Unity- und Arduino-Mikrocontroller können zusammen verwendet werden, um mit relativ geringem Budget einzigartige interaktive Erlebnisse zu schaffen.

Der Fokus dieser Anleitung besteht darin, die Kommunikation zwischen Unity und dem Arduino einzurichten, damit wir nicht zu tief in die meisten der mit Unity verfügbaren Funktionen eintauchen. Es gibt viele GROSSARTIGE Tutorials für Unity und eine unglaubliche Community, die viel besser erklären könnte, wie Unity funktioniert. Es gibt jedoch einen Sonderpreis für diejenigen, die es schaffen, sich durch dieses instructable zu arbeiten, das als kleines Schaufenster dessen dient, was getan werden könnte. Sie können auf unserem Github unseren ersten Versuch herunterladen, eine Strecke mit realistischer Fahrradphysik zu erstellen.

Lassen Sie uns zuerst das Nötigste durchgehen, das getan werden muss, um mit einem Arduino über die Serie zu kommunizieren. Es wird schnell klar, dass dieser Code nicht für das Gameplay geeignet ist, aber es ist gut, jeden Schritt durchzugehen und zu lernen, was die Einschränkungen sind.

Erstellen Sie in Unity eine neue Szene mit einem einzelnen leeren GameObject namens ArduinoReceive, indem Sie ein C#-Skript mit dem Namen ArduinoReceive anhängen. In diesem Skript fügen wir den gesamten Code hinzu, der die Kommunikation mit dem Arduino verarbeitet.

Es gibt eine Bibliothek, auf die zugegriffen werden muss, bevor wir mit den seriellen Ports Ihres Computers kommunizieren können. Unity muss eingerichtet werden, damit bestimmte Bibliotheken verwendet werden können. Gehen Sie zu Bearbeiten->ProjectSerring->Player und wechseln Sie neben dem Api Compatibility Level unter Configuration von. NET 2.0 Subset zu. NET 2.0. Fügen Sie nun den folgenden Code oben im Skript hinzu;

Verwenden von System. IO. Ports;

Dadurch können Sie auf die SerialPort-Klasse zugreifen, die Sie als Objekt für die ArduinoReceive-Klasse definieren können. Machen Sie es privat, um Störungen durch ein anderes Skript zu vermeiden.

privater SerialPort arduinoPort;

Das Objekt arduinoPort kann geöffnet werden, indem der richtige Port (z. B. an welchem USB der Arduino angeschlossen ist) und eine Baudrate (d. h. die Geschwindigkeit, mit der die Informationen gesendet werden) ausgewählt werden. Wenn Sie sich nicht sicher sind, an welchem Port das Arduino angeschlossen ist, können Sie dies entweder im Gerätemanager oder durch Öffnen der Arduino IDE herausfinden. Für die Baudrate ist der Standardwert bei den meisten Geräten 9600. Stellen Sie nur sicher, dass Sie diesen Wert in Ihrem Arduino-Code haben und es sollte funktionieren.

Der Code sollte jetzt so aussehen;

Verwenden von System. Collections;

mit System. Collections. Generic; mit UnityEngine; Verwenden von System. IO. Ports; öffentliche Klasse ArduinoReceive: MonoBehaviour { privater SerialPort arduinoPort; // Verwenden Sie dies für die Initialisierung void Start () { arduinoPort = new SerialPort ("COM5", 9600); arduinoPort. Open(); WriteToArduino("TRIGG"); } }

Ihre COM-Nummer wird höchstwahrscheinlich anders sein. Wenn Sie einen MAC verwenden, hat Ihr COM-Name möglicherweise einen Namen, der wie folgt aussieht /dev/cu.wchusbserial1420. Stellen Sie sicher, dass der Code aus Abschnitt 4 auf den Arduino hochgeladen und der serielle Monitor für den Rest dieses Abschnitts geschlossen ist und dass dieser Code problemlos kompiliert wird.

Senden wir nun bei jedem Frame eine Anfrage an den Arduino und schreiben die Ergebnisse in das Konsolenfenster. Fügen Sie die WriteToArduino-Funktion zur Klasse ArduinoReceive hinzu. Der Wagenrücklauf und die neue Zeile sind für den Arduino-Code erforderlich, um die eingehende Anweisung richtig zu analysieren.

private void WriteToArduino(String-Nachricht)

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

Diese Funktion kann dann in der Update-Schleife aufgerufen werden.

ungültig Aktualisieren ()

{ WriteToArduino ("TRIGG"); Debug. Log("Erster Wert: " + arduinoPort. ReadLine()); Debug. Log("Zweiter Wert: " + arduinoPort. ReadLine()); }

Der obige Code ist das absolute Minimum, das Sie benötigen, um die Daten von einem Arduino zu lesen. Wenn Sie die FPS von Unity genau beachten, sollten Sie einen deutlichen Leistungsabfall feststellen. In meinem Fall geht es von etwa 90 FPS ohne Lesen/Schreiben auf 20 FPS. Wenn Ihr Projekt keine häufigen Updates erfordert, kann es ausreichen, aber für ein Videospiel sind 20 FPS viel zu niedrig. Im nächsten Abschnitt erfahren Sie, wie Sie die Leistung mithilfe von Multi-Threading verbessern können.

Schritt 4: Optimieren der Datenübertragung

Im vorherigen Abschnitt wurde die grundlegende Einrichtung beschrieben

Kommunikation zwischen Arduino und Unity-Programm. Das Hauptproblem bei diesem Code ist die Leistung. In der aktuellen Implementierung muss Unity warten, bis das Arduino die Anfrage empfängt, verarbeitet und beantwortet. Während dieser Zeit muss der Unity-Code auf die Ausführung der Anfrage warten und tut nichts anderes. Wir haben dieses Problem gelöst, indem wir einen Thread erstellt haben, der die Anfragen verarbeitet und die Variable im Hauptthread speichert.

Zu Beginn müssen wir die Threading-Bibliothek hinzufügen, indem wir hinzufügen;

Verwenden von System. Threading;

Als nächstes richten wir die Funktion ein, die wir in den Threads starten. AsynchronousReadFromArduino beginnt mit dem Schreiben der Anfrage an den Arduino mit der Funktion WrtieToArduino. Das Lesen wird in einen Try-Catch-Block eingeschlossen, wenn das Lese-Timeout abgelaufen ist, bleiben die Variablen null und die OnArduinoInfoFail-Funktion wird anstelle von OnArduinoInfoReceive aufgerufen.

Als nächstes definieren wir die Funktionen OnArduinoInfoFail und OnArduinoInfoReceive. Für dieses anweisbare drucken wir die Ergebnisse an die Konsole, aber Sie könnten die Ergebnisse in den Variablen speichern, die Sie für Ihr Projekt benötigen.

privat void OnArduinoInfoFail()

{ Debug. Log("Lesen fehlgeschlagen"); } private void OnArduinoInfoReceived(String-Rotation, String-Geschwindigkeit) { Debug. Log("Readin Sucessfull"); Debug. Log("Erster Wert: " + Drehung); Debug. Log("Zweiter Wert: " + Geschwindigkeit); }

Der letzte Schritt besteht darin, die Threads zu starten und zu stoppen, die die Werte vom Arduino anfordern. Wir müssen sicherstellen, dass der letzte Thread mit seiner letzten Aufgabe fertig ist, bevor wir einen neuen starten. Andernfalls könnten mehrere Anfragen gleichzeitig an das Arduino gestellt werden, was das Arduino/Unity verwirren und unvorhersehbare Ergebnisse liefern könnte.

privater Thread activeThread = null;

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

Wenn Sie die Leistung des Codes mit dem vergleichen, den wir in Abschnitt 5 geschrieben haben, sollte die Leistung erheblich verbessert werden.

privat void OnArduinoInfoFail()

{ Debug. Log("Lesen fehlgeschlagen"); }

Schritt 5: Wohin als nächstes?

Wohin als nächstes?
Wohin als nächstes?

Wir haben eine Demo vorbereitet, die Sie auf unserem Github (https://github.com/AlexandreDoucet/InfinityBike) herunterladen, den Code und das Spiel herunterladen und durch unsere Strecke fahren können. Es ist alles für ein schnelles Training eingerichtet und wir hoffen, dass es Ihnen einen Vorgeschmack darauf geben kann, was Sie bauen könnten, wenn Sie das verwenden, was wir Ihnen mit dieser Anleitung beigebracht haben.

Credits

Projektmitarbeiter

Alexandre Doucet (_Doucet_)

Maxime Boudreau (MxBoud)

Externe Ressourcen [The Unity Game Engine](https://unity3d.com)

Dieses Projekt begann, nachdem wir das Tutorial von Allan Zucconi "wie man Arduino mit Unity integriert" gelesen hatte (https://www.alanzucconi.com/2015/10/07/how-to-int…)

Die Anfrage vom Arduino wird über die SerialCommand-Bibliothek (https://github.com/kroimon/Arduino-SerialCommand) abgewickelt.

Empfohlen: