Πίνακας περιεχομένων:

Infinity Bike - Βίντεο Παιχνίδι εκπαίδευσης ποδηλάτων εσωτερικού χώρου: 5 βήματα
Infinity Bike - Βίντεο Παιχνίδι εκπαίδευσης ποδηλάτων εσωτερικού χώρου: 5 βήματα

Βίντεο: Infinity Bike - Βίντεο Παιχνίδι εκπαίδευσης ποδηλάτων εσωτερικού χώρου: 5 βήματα

Βίντεο: Infinity Bike - Βίντεο Παιχνίδι εκπαίδευσης ποδηλάτων εσωτερικού χώρου: 5 βήματα
Βίντεο: Η γκουγκου δεν σεβεται τον πατερα της 2024, Σεπτέμβριος
Anonim
Image
Image
Υλικά
Υλικά

Κατά τη διάρκεια των χειμερινών περιόδων, των κρύων ημερών και των κακών καιρικών συνθηκών, οι λάτρεις των ποδηλάτων έχουν μόνο μερικές επιλογές για άσκηση κάνοντας το αγαπημένο τους άθλημα. Άχναμε για έναν τρόπο να κάνουμε την εσωτερική προπόνηση με ένα ποδήλατο/εκπαιδευτή λίγο πιο διασκεδαστικό, αλλά τα περισσότερα διαθέσιμα προϊόντα είναι είτε δαπανηρά είτε απλά βαρετά για χρήση. Αυτός είναι ο λόγος για τον οποίο ξεκινήσαμε να αναπτύσσουμε το Infinity Bike ως εκπαιδευτικό βιντεοπαιχνίδι ανοιχτού κώδικα. Το ποδήλατο Infinity διαβάζει την ταχύτητα και την κατεύθυνση από το ποδήλατό σας και προσφέρει ένα επίπεδο διαδραστικότητας που δεν μπορεί να βρεθεί εύκολα με τους εκπαιδευτές ποδηλάτων.

Εκμεταλλευόμαστε την απλότητα που διαθέτει ο μικροελεγκτής Arduino και μερικά τρισδιάστατα εξαρτήματα για να εξασφαλίσουμε φθηνούς αισθητήρες σε ένα ποδήλατο τοποθετημένο σε εκπαιδευτή. Οι πληροφορίες μεταδίδονται σε ένα βιντεοπαιχνίδι κατασκευασμένο με τη δημοφιλή μηχανή κατασκευής παιχνιδιών, Unity. Μέχρι το τέλος αυτού του οδηγού, θα πρέπει να μπορείτε να ρυθμίσετε τους δικούς σας αισθητήρες στο ποδήλατό σας και να μεταφέρετε τις πληροφορίες των αισθητήρων σας στην Unity. Περιλάβαμε ακόμη και ένα κομμάτι στο οποίο μπορείτε να οδηγήσετε και να δοκιμάσετε τη νέα σας ρύθμιση. Εάν ενδιαφέρεστε να συνεισφέρετε, μπορείτε να ελέγξετε το GitHub.

Βήμα 1: Υλικά

Υλικά
Υλικά

Η λίστα υλικών που θα χρειαστείτε μπορεί να διαφέρει λίγο. Για

Για παράδειγμα, το μέγεθος του ποδηλάτου σας θα καθορίσει τα μήκη των καλωδίων άλματος που χρειάζεστε, αλλά εδώ είναι τα κύρια μέρη που θα χρειαστείτε. Πιθανότατα θα μπορούσατε να βρείτε φθηνότερες τιμές για κάθε κομμάτι στον ιστότοπο όπως το AliExpress, αλλά η αναμονή 6 μηνών για αποστολή δεν είναι πάντα μια επιλογή, οπότε χρησιμοποιήσατε τα ελαφρώς πιο ακριβά ανταλλακτικά, ώστε η εκτίμηση να μην είναι στρεβλή.

1 x Arduino nano ($ 22,00)

1 x Mini Breadboard (1,33 $/μονάδα)

1 αντίσταση 220 Ohm (1,00 $/κιτ)

1 x 10K Ποτενσιόμετρο (1,80 $/μονάδα)

1 x αισθητήρας Hall (0,96 $)

Ζώνη χρονισμού 3D εκτυπωτή 20 cm x 6 mm (3,33 $)

1 κιτ x Διάφορες βίδες και μπουλόνια μήκους M3 (6,82 $)

1 x μαγνήτης ταχύμετρου ποδηλάτου (0,98 $)

Τοποθετήσαμε το παραπάνω υλικό με τρισδιάστατα τυπωμένα μέρη. Τα αρχεία που χρησιμοποιήσαμε παρατίθενται παρακάτω και είναι αριθμημένα με την ίδια σύμβαση με την εικόνα στην αρχή αυτής της ενότητας. Όλα τα αρχεία μπορούν να βρεθούν στο Thingiverse. Μπορείτε να τα χρησιμοποιήσετε ως έχουν, αλλά βεβαιωθείτε ότι οι διαστάσεις που χρησιμοποιήσαμε ταιριάζουν με το ποδήλατό σας.

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

Βήμα 2: Ανάγνωση και μεταφορά δεδομένων στην ενότητα

Ανάγνωση και μεταφορά δεδομένων στην ενότητα
Ανάγνωση και μεταφορά δεδομένων στην ενότητα

Ο κώδικας Arduino και Unity θα συνεργαστούν για τη συλλογή, μεταφορά και επεξεργασία των δεδομένων από τους αισθητήρες στο ποδήλατο. Η Unity θα ζητήσει την τιμή από το Arduino στέλνοντας μια συμβολοσειρά μέσω του σειριακού και περιμένει το Arduino να απαντήσει με τις ζητούμενες τιμές.

Αρχικά, προετοιμάζουμε το Arduino με τη σειριακή εντολή της βιβλιοθήκης που χρησιμοποιείται για τη διαχείριση των αιτημάτων από την Unity, συνδυάζοντας μια συμβολοσειρά αιτήματος με μια συνάρτηση. Μια βασική ρύθμιση για αυτήν τη βιβλιοθήκη μπορεί να γίνει ως εξής.

#include "SerialCommand.h"

SerialCommand sCmd; void setup () {sCmd.addCommand ("TRIGG", TriggHanlder); Serial.begin (9600); } void loop () {while (Serial.available ()> 0) {sCmd.readSerial (); }} void TriggHandler () { /*Διαβάστε και μεταδώστε τους αισθητήρες εδώ* /}

Η συνάρτηση TriggHandler είναι προσαρτημένη στο αντικείμενο SCmd. Εάν το σήριαλ λαμβάνει μια συμβολοσειρά που ταιριάζει με τη συνημμένη εντολή (στην περίπτωση αυτή TRIGG), εκτελείται η συνάρτηση TriggHandler.

Χρησιμοποιούμε ποτενσιόμετρο για τη μέτρηση της κατεύθυνσης του τιμονιού και έναν αισθητήρα αίθουσας για τη μέτρηση της περιστροφής ανά λεπτό του ποδηλάτου. Οι ενδείξεις από το ποτενσιόμετρο μπορούν εύκολα να γίνουν χρησιμοποιώντας τις ενσωματωμένες λειτουργίες του Arduino. Η συνάρτηση TriggHandler μπορεί στη συνέχεια να εκτυπώσει την τιμή στο σειριακό με την ακόλουθη αλλαγή.

void TriggHandler () {

/*Ανάγνωση της τιμής του ποτενσιόμετρου*/ Serial.println (analogRead (ANALOGPIN)); }

Ο αισθητήρας Hall έχει λίγο περισσότερη ρύθμιση προτού μπορέσουμε να κάνουμε χρήσιμες μετρήσεις. Σε αντίθεση με το ποτενσιόμετρο, η άμεση τιμή του αισθητήρα χώρων δεν είναι πολύ χρήσιμη. Δεδομένου ότι προσπαθούσαν να μετρήσουν την ταχύτητα του τροχού, ο χρόνος μεταξύ των ενεργοποιητών είναι αυτό που τους ενδιέφερε.

Κάθε συνάρτηση που χρησιμοποιείται στον κώδικα Arduino απαιτεί χρόνο και εάν ο μαγνήτης ευθυγραμμιστεί με τον αισθητήρα Hall σε λάθος χρόνο, η μέτρηση θα μπορούσε να καθυστερήσει στην καλύτερη περίπτωση ή να παραλειφθεί εντελώς στη χειρότερη. Αυτό είναι προφανώς κακό επειδή το Arduino θα μπορούσε να αναφέρει ταχύτητα που είναι ΠΟΛΥ διαφορετική από την πραγματική ταχύτητα του τροχού.

Για να αποφευχθεί αυτό, χρησιμοποιούμε μια δυνατότητα του Arduinos που ονομάζεται διακοπή σύνδεσης, η οποία μας επιτρέπει να ενεργοποιούμε μια λειτουργία κάθε φορά που ενεργοποιείται ένα καθορισμένο ψηφιακό pin με ένα ανερχόμενο σήμα. Η συνάρτηση rpm_fun προσαρτάται σε μια διακοπή με μία γραμμή κώδικα προστιθέμενη στον κωδικό εγκατάστασης.

void setup () {

sCmd.addCommand ("TRIGG", TriggHanlder); attachInterrupt (0, rpm_fun, RISING); Serial.begin (9600); } // Η συνάρτηση rpm_fun χρησιμοποιείται για τον υπολογισμό της ταχύτητας και ορίζεται ως; χωρίς υπογραφή long lastRevolTime = 0; ανυπόγραφο μακρύ revolSpeed = 0; void rpm_fun () {unsigned long revolTime = millis (); unsigned long deltaTime = revolTime - lastRevolTime; /*revolSpeed είναι η τιμή που μεταδίδεται στον κωδικό Arduino* / revolSpeed = 20000 / deltaTime; lastRevolTime = revolTime; } Το TriggHandler μπορεί στη συνέχεια να μεταδώσει τις υπόλοιπες πληροφορίες όταν ζητηθεί. void TriggHanlder () { /*Ανάγνωση της τιμής του ποτενσιόμετρου* / Serial.println (analogRead (ANALOGPIN)); Serial.println (revolSpeed); }

Έχουμε τώρα όλα τα δομικά στοιχεία που μπορούν να χρησιμοποιηθούν για την κατασκευή του κώδικα Arduino, ο οποίος θα μεταφέρει δεδομένα μέσω του σειριακού, όταν υποβάλλεται ένα αίτημα από την Unity. Αν θέλετε να έχετε ένα αντίγραφο του πλήρους κώδικα, μπορείτε να το κατεβάσετε στο GitHub. Για να ελέγξετε αν ο κώδικας έχει ρυθμιστεί σωστά, μπορείτε να χρησιμοποιήσετε τη σειριακή οθόνη για να στείλετε το TRIGG. βεβαιωθείτε ότι έχετε ορίσει τη γραμμή που τελειώνει σε Επιστροφή μεταφοράς. Η επόμενη ενότητα θα επικεντρωθεί στον τρόπο με τον οποίο τα σενάρια μας Unity μπορούν να ζητήσουν και να λάβουν τις πληροφορίες από το Arduino.

Βήμα 3: Λήψη και επεξεργασία δεδομένων

Λήψη και Επεξεργασία Δεδομένων
Λήψη και Επεξεργασία Δεδομένων

Το Unity είναι ένα εξαιρετικό λογισμικό που διατίθεται δωρεάν για χομπίστες

ενδιαφέρεται για την κατασκευή παιχνιδιών. Έρχεται με μεγάλο αριθμό λειτουργιών που μπορούν πραγματικά να μειώσουν εγκαίρως τη ρύθμιση ορισμένων πραγμάτων, όπως το νήμα ή τον προγραμματισμό GPU (σκίαση AKA) χωρίς να περιορίζουν τι μπορεί να γίνει με τα σενάρια C#. Οι μικροελεγκτές Unity και Arduino μπορούν να χρησιμοποιηθούν μαζί για να δημιουργήσουν μοναδικές διαδραστικές εμπειρίες με σχετικά μικρό προϋπολογισμό.

Το επίκεντρο αυτού του οδηγού είναι να βοηθήσει στη δημιουργία της επικοινωνίας μεταξύ της Unity και του Arduino, ώστε να μην καταδυθούμε πολύ στα περισσότερα από τα διαθέσιμα χαρακτηριστικά με την Unity. Υπάρχουν πολλά υπέροχα σεμινάρια για την ενότητα και μια απίστευτη κοινότητα που θα μπορούσε να κάνει πολύ καλύτερη δουλειά εξηγώντας πώς λειτουργεί η Unity. Ωστόσο, υπάρχει ένα ειδικό βραβείο για εκείνους που καταφέρνουν να δουλέψουν με αυτόν τον τρόπο διδασκαλίας, που χρησιμεύει ως μια μικρή έκθεση για το τι θα μπορούσε να γίνει. Μπορείτε να κατεβάσετε στο Github την πρώτη μας προσπάθεια να κάνουμε ένα κομμάτι με ρεαλιστική φυσική ποδηλάτου.

Πρώτον, ας περάσουμε από το ελάχιστο που πρέπει να γίνει για να επικοινωνήσουμε με ένα Arduino μέσω του σίριαλ. Θα φανεί γρήγορα ότι αυτός ο κώδικας δεν είναι κατάλληλος για παιχνίδι, αλλά είναι καλό να περνάτε από κάθε βήμα και να μαθαίνετε ποιοι είναι οι περιορισμοί.

Στο Unity, δημιουργήστε μια νέα σκηνή με ένα μόνο κενό GameObject που ονομάζεται ArduinoReceive και επισυνάψτε ένα σενάριο C# που ονομάζεται επίσης ArduinoReceive. Αυτό το σενάριο είναι όπου θα προσθέσουμε όλο τον κώδικα που χειρίζεται την επικοινωνία με το Arduino.

Υπάρχει μια βιβλιοθήκη στην οποία πρέπει να έχετε πρόσβαση για να μπορέσουμε να επικοινωνήσουμε με τις σειριακές θύρες του υπολογιστή σας. Η ενότητα πρέπει να ρυθμιστεί ώστε να επιτρέπεται η χρήση ορισμένων βιβλιοθηκών. Μεταβείτε στην επιλογή Επεξεργασία-> ProjectSerring-> Player και δίπλα στο Επίπεδο συμβατότητας Api στο διακόπτη Configuration. NET 2.0 Subset σε. NET 2.0. Τώρα προσθέστε τον ακόλουθο κώδικα στο επάνω μέρος του σεναρίου.

χρησιμοποιώντας System. IO. Ports.

Αυτό θα σας επιτρέψει να αποκτήσετε πρόσβαση στην κλάση SerialPort την οποία θα μπορούσατε να ορίσετε ως αντικείμενο στην κλάση ArduinoReceive. Κάντε το ιδιωτικό για να αποφύγετε τυχόν παρεμβολές από άλλο σενάριο.

ιδιωτικό SerialPort arduinoPort;

Το αντικείμενο arduinoPort μπορεί να ανοίξει επιλέγοντας τη σωστή θύρα (π.χ. σε ποιο USB είναι συνδεδεμένο το Arduino) και έναν ρυθμό baud (δηλαδή την ταχύτητα με την οποία αποστέλλονται οι πληροφορίες). Εάν δεν είστε σίγουροι σε ποια θύρα είναι συνδεδεμένο το Arduino, μπορείτε να το μάθετε είτε από τη διαχείριση συσκευών είτε ανοίγοντας το Arduino IDE. Για το ρυθμό baud, η προεπιλεγμένη τιμή στις περισσότερες συσκευές είναι 9600, απλώς βεβαιωθείτε ότι έχετε αυτήν την τιμή στον κωδικό Arduino και ότι πρέπει να λειτουργεί.

Ο κώδικας πρέπει τώρα να μοιάζει με αυτόν.

χρησιμοποιώντας System. Collections;

χρησιμοποιώντας System. Collections. Generic; χρησιμοποιώντας το UnityEngine. χρησιμοποιώντας System. IO. Ports. δημόσια τάξη ArduinoReceive: MonoBehaviour {private SerialPort arduinoPort; // Χρησιμοποιήστε αυτό για αρχικοποίηση κενό Έναρξη () {arduinoPort = νέο SerialPort ("COM5", 9600); arduinoPort. Open (); WriteToArduino ("TRIGG"); }}

Ο αριθμός COM σας πιθανότατα θα είναι διαφορετικός. Εάν χρησιμοποιείτε MAC, το όνομα COM μπορεί να έχει όνομα που μοιάζει με αυτό /dev/cu.wchusbserial1420. Βεβαιωθείτε ότι ο κωδικός από την ενότητα 4 έχει μεταφορτωθεί στο Arduino και ότι η σειριακή οθόνη είναι κλειστή για το υπόλοιπο αυτής της ενότητας και ότι αυτός ο κώδικας μεταγλωττίζεται χωρίς πρόβλημα.

Ας στείλουμε τώρα ένα αίτημα στο Arduino κάθε πλαίσιο και γράφουμε τα αποτελέσματα στο παράθυρο της κονσόλας. Προσθέστε τη συνάρτηση WriteToArduino στην κλάση ArduinoReceive. Η επιστροφή μεταφοράς και η νέα γραμμή είναι απαραίτητες για τον κωδικό Arduino για την σωστή ανάλυση της εισερχόμενης οδηγίας.

ιδιωτικό κενό WriteToArduino (μήνυμα συμβολοσειράς)

{μήνυμα = μήνυμα + "\ r / n"; arduinoPort. Write (μήνυμα); arduinoPort. BaseStream. Flush (); }

Αυτή η λειτουργία μπορεί στη συνέχεια να κληθεί στον βρόχο Ενημέρωση.

άκυρη ενημέρωση ()

{WriteToArduino ("TRIGG"); Debug. Log ("Πρώτη τιμή:" + arduinoPort. ReadLine ()); Debug. Log ("Δεύτερη τιμή:" + arduinoPort. ReadLine ()); }

Ο παραπάνω κωδικός είναι το ελάχιστο που χρειάζεστε για να διαβάσετε τα δεδομένα από ένα Arduino. Εάν δώσετε μεγάλη προσοχή στο FPS που δίνεται από την ενότητα, θα πρέπει να δείτε μια σημαντική πτώση στην απόδοση. Στην περίπτωσή μου, πηγαίνει από περίπου 90 FPS χωρίς ανάγνωση/εγγραφή σε 20 FPS. Εάν το έργο σας δεν απαιτεί συχνές ενημερώσεις, μπορεί να είναι αρκετό, αλλά για ένα βιντεοπαιχνίδι, τα 20 FPS είναι πολύ χαμηλά. Η επόμενη ενότητα θα καλύψει πώς μπορείτε να βελτιώσετε την απόδοση χρησιμοποιώντας πολλαπλές κλωστές.

Βήμα 4: Βελτιστοποίηση μεταφοράς δεδομένων

Η προηγούμενη ενότητα κάλυψε τον τρόπο ρύθμισης των βασικών

επικοινωνία μεταξύ του προγράμματος Arduino και Unity. Το κύριο πρόβλημα με αυτόν τον κώδικα είναι η απόδοση. Στην τρέχουσα εφαρμογή του, η Unity πρέπει να περιμένει το Arduino να λάβει, να επεξεργαστεί και να απαντήσει στο αίτημα. Κατά τη διάρκεια αυτής της περιόδου, ο κώδικας Unity πρέπει να περιμένει να γίνει το αίτημα και δεν κάνει τίποτα άλλο. Λύσαμε αυτό το ζήτημα δημιουργώντας ένα νήμα που θα χειρίζεται τα αιτήματα και θα αποθηκεύει τη μεταβλητή στο κύριο νήμα.

Αρχικά, πρέπει να συμπεριλάβουμε τη βιβλιοθήκη νημάτων προσθέτοντας?

χρησιμοποιώντας System. Threading.

Στη συνέχεια, ρυθμίζουμε τη συνάρτηση που ξεκινάμε στα νήματα. Το AsynchronousReadFromArduino ξεκινά γράφοντας το αίτημα στο Arduino με τη συνάρτηση WrtieToArduino. Η ανάγνωση περικλείεται σε ένα μπλοκ try-catch, εάν το χρονικό όριο ανάγνωσης, οι μεταβλητές παραμένουν μηδενικές και η συνάρτηση OnArduinoInfoFail καλείται αντί του OnArduinoInfoReceive.

Στη συνέχεια ορίζουμε τις συναρτήσεις OnArduinoInfoFail και OnArduinoInfoReceive. Για αυτό το διδακτικό, εκτυπώνουμε τα αποτελέσματα στην κονσόλα, αλλά μπορείτε να αποθηκεύσετε τα αποτελέσματα στις μεταβλητές που χρειάζεστε για το έργο σας.

ιδιωτικό κενό OnArduinoInfoFail ()

{Debug. Log ("Η ανάγνωση απέτυχε"); } private void OnArduinoInfoReceived (περιστροφή συμβολοσειράς, ταχύτητα συμβολοσειράς) {Debug. Log ("Readin Successfull"); Debug. Log ("Πρώτη τιμή:" + περιστροφή); Debug. Log ("Δεύτερη τιμή:" + ταχύτητα); }

Το τελευταίο βήμα είναι να ξεκινήσετε και να σταματήσετε τα νήματα που θα ζητήσουν τις τιμές από το Arduino. Πρέπει να διασφαλίσουμε ότι το τελευταίο νήμα έχει ολοκληρωθεί με την τελευταία του εργασία πριν ξεκινήσετε ένα νέο. Διαφορετικά, θα μπορούσαν να γίνουν πολλαπλά αιτήματα στο Arduino ταυτόχρονα, τα οποία θα μπορούσαν να μπερδέψουν το Arduino/Unity και να δώσουν απρόβλεπτα αποτελέσματα.

ιδιωτικό νήμα activeThread = null;

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

Εάν συγκρίνετε την απόδοση του κώδικα με αυτόν που γράψαμε στην ενότητα 5, η απόδοση θα πρέπει να βελτιωθεί σημαντικά.

ιδιωτικό κενό OnArduinoInfoFail ()

{Debug. Log ("Η ανάγνωση απέτυχε"); }

Βήμα 5: Πού στη συνέχεια;

Πού Επόμενο
Πού Επόμενο

Ετοιμάσαμε ένα demo που μπορείτε να κατεβάσετε στο Github (https://github.com/AlexandreDoucet/InfinityBike), να κατεβάσετε τον κώδικα και το παιχνίδι και να περπατήσετε στην πίστα μας. Είναι όλα έτοιμα για μια γρήγορη προπόνηση και ελπίζουμε ότι μπορεί να σας δώσει μια γεύση από αυτό που θα μπορούσατε να φτιάξετε αν χρησιμοποιήσετε αυτά που σας διδάξαμε με αυτό το διδακτικό.

Μονάδες

Συντελεστές του έργου

Alexandre Doucet (_Doucet_)

Maxime Boudreau (MxBoud)

Εξωτερικές πηγές [The Unity game engine] (https://unity3d.com)

Αυτό το έργο ξεκίνησε αφού διαβάσαμε το σεμινάριο του Allan Zucconi "πώς να ενσωματώσετε το Arduino με την Unity" (https://www.alanzucconi.com/2015/10/07/how-to-int…)

Το αίτημα από το Arduino χειρίζεται χρησιμοποιώντας τη βιβλιοθήκη SerialCommand (https://github.com/kroimon/Arduino-SerialCommand)

Συνιστάται: