Taula de continguts:

Infinity Bike: videojoc d'entrenament de bicicletes a l'interior: 5 passos
Infinity Bike: videojoc d'entrenament de bicicletes a l'interior: 5 passos

Vídeo: Infinity Bike: videojoc d'entrenament de bicicletes a l'interior: 5 passos

Vídeo: Infinity Bike: videojoc d'entrenament de bicicletes a l'interior: 5 passos
Vídeo: GTA 5 LONGEST WATERSLIDE From Space Into Lava Pool! 2024, Setembre
Anonim
Image
Image
Materials
Materials

Durant les estacions d’hivern, els dies freds i el mal temps, els aficionats als ciclistes només tenen algunes opcions per fer exercici fent el seu esport favorit. Estàvem buscant una manera de fer l’entrenament interior amb una configuració de bicicleta / entrenador una mica més entretinguda, però la majoria dels productes disponibles són costosos o simplement avorrits d’utilitzar. Per això, vam començar a desenvolupar Infinity Bike com un videojoc de formació de codi obert. La bicicleta infinita llegeix la velocitat i la direcció de la vostra bicicleta i ofereix un nivell d’interactivitat que no es pot trobar fàcilment amb els entrenadors de bicicletes.

Aprofitem la simplicitat que ofereix el microcontrolador Arduino i algunes peces impreses en 3D per assegurar uns sensors econòmics a una bicicleta muntada en un entrenador. La informació es transmet a un videojoc fet amb el popular motor de fabricació de jocs, Unity. Al final d'aquesta instrucció, hauríeu de ser capaç de configurar els vostres propis sensors a la vostra bicicleta i transferir la informació dels vostres sensors a Unity. Fins i tot hem inclòs una pista per on podeu circular i provar la vostra nova configuració. Si esteu interessats a contribuir, podeu consultar el nostre GitHub.

Pas 1: materials

Materials
Materials

La llista de materials que necessiteu pot variar una mica; per

per exemple, la mida de la vostra bicicleta dictarà la longitud dels cables de pont que necessiteu, però aquí teniu les parts principals que necessiteu. Probablement podríeu trobar preus més econòmics per a cada peça al lloc web com AliExpress, però esperar 6 mesos per a l’enviament no sempre és una opció, de manera que s’utilitzaven peces lleugerament més cares, de manera que l’estimació no és esbiaixada.

1 x Arduino nano (22,00 dòlars)

1 x Mini tauler de pa (1,33 $ / unitat)

1 resistència de 220 Ohm (1,00 dòlars / kit)

Potenciòmetre 1 x 10K (1,80 dòlars / unitat)

1 x sensor Hall (0,96 dòlars)

Cinturó de distribució de la impressora 3D de 20 cm x 6 mm (3,33 dòlars)

1 kit x cargols i cargols M3 de llarga durada (6,82 dòlars)

1 x imant velocímetre de bicicleta (0,98 dòlars)

Vam muntar el material anterior amb peces impreses en 3D. Els fitxers que hem utilitzat apareixen a la llista següent i estan numerats amb la mateixa convenció que la imatge al començament d’aquesta secció. Tots els fitxers es poden trobar a Thingiverse. Podeu utilitzar-les tal qual, però assegureu-vos que les dimensions que hem utilitzat coincideixin amb la vostra bicicleta.

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

Pas 2: llegir i transferir dades a Unity

Lectura i transferència de dades a Unity
Lectura i transferència de dades a Unity

El codi Arduino i Unity treballaran junts per recollir, transferiu i processeu les dades dels sensors de la moto. Unity sol·licitarà el valor a l'Arduino enviant una cadena a través del serial i esperarà que Arduino respongui amb els valors sol·licitats.

En primer lloc, preparem l'Arduino amb la biblioteca Serial Command, que s'utilitza per gestionar les sol·licituds d'Unity emparellant una cadena de sol·licitud amb una funció. Una configuració bàsica per a aquesta biblioteca es pot fer de la següent manera;

#include "SerialCommand.h"

SerialCommand sCmd; void setup () {sCmd.addCommand ("TRIGG", TriggHanlder); Serial.begin (9600); } void loop () {while (Serial.available ()> 0) {sCmd.readSerial (); }} void TriggHandler () {/ * Llegiu i transmeteu els sensors aquí * /}

La funció TriggHandler està connectada a l'objecte SCmd. Si el serial rep una cadena que coincideix amb l'ordre adjunta (en aquest cas TRIGG), s'executa la funció TriggHandler.

Utilitzem un potenciòmetre per mesurar la direcció de la direcció i un sensor de passadissos per mesurar la rotació per minut de la bicicleta. Les lectures del potenciòmetre es poden fer fàcilment mitjançant les funcions integrades de l’Arduino. La funció TriggHandler pot imprimir el valor al serial amb el següent canvi.

void TriggHandler () {

/ * Lectura del valor del potenciòmetre * / Serial.println (analogRead (ANALOGPIN)); }

El sensor Hall té una mica més de configuració abans de poder fer mesures útils. Contràriament al potenciòmetre, el valor instantani del sensor de les sales no és gaire útil. Atès que intentàvem mesurar la velocitat de la roda, el temps entre disparadors és el que més ens interessava.

Totes les funcions que s’utilitzen al codi Arduino requereixen temps i, si l’imant s’alinea amb el sensor Hall en un moment equivocat, la mesura es podria retardar en el millor dels casos o saltar-se completament en el pitjor. Evidentment, això és dolent perquè l’Arduino podria informar d’una velocitat molt diferent de la velocitat real de la roda.

Per evitar-ho, fem servir una funció d’Arduinos anomenada attach interrupt que ens permet activar una funció sempre que s’activi un pin digital designat amb un senyal ascendent. La funció rpm_fun s’adjunta a una interrupció amb una única línia de codi afegida al codi de configuració.

configuració nul·la () {

sCmd.addCommand ("TRIGG", TriggHanlder); attachInterrupt (0, rpm_fun, RISING); Serial.begin (9600); } // La funció rpm_fun s’utilitza per calcular la velocitat i es defineix com; unsigned long lastRevolTime = 0; revolucionari llarg sense signar = 0; void rpm_fun () {unsigned long revolTime = millis (); unsigned long deltaTime = revolTime - lastRevolTime; / * revolSpeed és el valor transmès al codi Arduino * / revolSpeed = 20000 / deltaTime; lastRevolTime = revolTime; } TriggHandler pot transmetre la resta de la informació quan se li sol·liciti. void TriggHanlder () {/ * Lectura del valor del potenciòmetre * / Serial.println (analogRead (ANALOGPIN)); Serial.println (revolSpeed); }

Ara tenim tots els blocs de construcció que es poden utilitzar per construir el codi Arduino que transferirà les dades a través del serial quan Unity faci una sol·licitud. Si voleu tenir una còpia del codi complet, podeu descarregar-lo al nostre GitHub. Per provar si el codi s'ha configurat correctament, podeu utilitzar el monitor sèrie per enviar TRIGG; assegureu-vos d’establir la línia que finalitza en retorn de carro. La següent secció se centrarà en com els nostres scripts Unity poden sol·licitar i rebre la informació de l’Arduino.

Pas 3: Recepció i processament de dades

Recepció i tractament de dades
Recepció i tractament de dades

Unity és un fantàstic programari disponible gratuïtament per als aficionats

interessat en la creació de jocs; ve amb un gran nombre de funcionalitats que poden reduir el temps en configurar certes coses, com ara el threading o la programació de GPU (ombreig AKA), sense restringir el que es pot fer amb els scripts C #. Els microcontroladors Unity i Arduino es poden utilitzar junts per crear experiències interactives úniques amb un pressupost relativament reduït.

El focus d’aquest instructiu és ajudar a configurar la comunicació entre Unity i Arduino, de manera que no ens endinsarem massa en la majoria de les funcions disponibles amb Unity. Hi ha un munt de GRANS tutorials per a la unitat i una comunitat increïble que podria fer una feina molt millor explicant com funciona Unity. No obstant això, hi ha un premi especial per a aquells que aconsegueixen obrir-se camí a través d’aquest instructiu que serveix com un petit aparador del que es podria fer. Podeu descarregar al nostre Github el nostre primer intent de fer una pista amb física realista de la bicicleta.

En primer lloc, passem pel mínim necessari per comunicar-nos amb un Arduino a través del serial. Ràpidament es veurà que aquest codi no és adequat per al joc, però és bo passar tots els passos i conèixer quines són les limitacions.

A Unity, creeu una nova escena amb un únic GameObject buit anomenat ArduinoReceive a adjunt, un script C # també anomenat ArduinoReceive. Aquest script és on afegirem tot el codi que gestiona la comunicació amb l'Arduino.

Hi ha una biblioteca a la qual cal accedir abans de poder comunicar-nos amb els ports sèrie del vostre ordinador; Cal configurar Unity per permetre l'ús de determinades biblioteques. Aneu a Edita-> ProjectSerring-> Reproductor i al costat del nivell de compatibilitat Api a l'interruptor de configuració. Subconjunt. NET 2.0 a. NET 2.0. Ara afegiu el següent codi a la part superior de l'script;

utilitzant System. IO. Ports;

Això us permetrà accedir a la classe SerialPort que podeu definir com a objecte de la classe ArduinoReceive. Feu-lo privat per evitar interferències d'un altre script.

private SerialPort arduinoPort;

L'objecte arduinoPort es pot obrir seleccionant el port correcte (per exemple, en quin USB està connectat l'Arduino) i una velocitat de transmissió (és a dir, la velocitat a la qual s'envia la informació). Si no esteu segur de quin port està connectat l’Arduino, podeu esbrinar-lo al gestor de dispositius o bé obrint l’IDE Arduino. Per a la velocitat de transmissió, el valor per defecte de la majoria de dispositius és 9600, només cal que assegureu-vos que tingueu aquest valor al vostre codi Arduino i que funcioni.

El codi ara hauria de ser així;

utilitzant System. Collections;

utilitzant System. Collections. Generic; utilitzant UnityEngine; utilitzant System. IO. Ports; classe pública ArduinoReceive: MonoBehaviour {private SerialPort arduinoPort; // Utilitzeu això per a la inicialització void Start () {arduinoPort = new SerialPort ("COM5", 9600); arduinoPort. Open (); WriteToArduino ("TRIGG"); }}

El vostre número COM probablement serà diferent. Si utilitzeu un MAC, el vostre nom COM pot tenir un nom que sembli aquest /dev/cu.wchusbserial1420. Assegureu-vos que el codi de la secció 4 es penja a l’Arduino i que el monitor sèrie estigui tancat durant la resta d’aquesta secció i que aquest codi es compili sense problemes.

Enviem una sol·licitud a Arduino cada fotograma i escrivim els resultats a la finestra de la consola. Afegiu la funció WriteToArduino a la classe ArduinoReceive. El retorn del carro i la nova línia són necessàries perquè el codi Arduino analitzi correctament la instrucció entrant.

private void WriteToArduino (missatge de cadena)

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

Aquesta funció es pot anomenar al bucle d'actualització.

void Update ()

{WriteToArduino ("TRIGG"); Debug. Log ("Primer valor:" + arduinoPort. ReadLine ()); Debug. Log ("Segon valor:" + arduinoPort. ReadLine ()); }

El codi anterior és el mínim necessari per llegir les dades d’un Arduino. Si presteu molta atenció als FPS donats per la unitat, hauríeu de veure una disminució significativa del rendiment. En el meu cas, passa d’uns 90 FPS sense llegir / escriure a 20 FPS. Si el vostre projecte no requereix actualitzacions freqüents, pot ser que sigui suficient, però per a un videojoc, 20 FPS és massa baix. La següent secció descriurà com podeu millorar el rendiment mitjançant l'ús de múltiples fils.

Pas 4: Optimització de la transferència de dades

A la secció anterior es tractava com configurar bàsicament

comunicació entre el programa Arduino i Unity. El principal problema d’aquest codi és el rendiment. En la seva implementació actual, Unity ha d’esperar que l’Arduino rebi, processi i respongui la sol·licitud. Durant aquest temps, el codi Unity ha d’esperar a que es faci la sol·licitud i no fa res més. Hem resolt aquest problema creant un fil que gestionarà les sol·licituds i emmagatzemarà la variable al fil principal.

Per començar, hem d’incloure la biblioteca de fils afegint;

utilitzant System. Threading;

A continuació, configurem la funció que estem iniciant en els fils. AsynchronousReadFromArduino comença escrivint la sol·licitud a Arduino amb la funció WrtieToArduino. La lectura s’inclou en un bloc try-catch, si el temps d’espera de lectura, les variables romanen nul·les i es crida la funció OnArduinoInfoFail en lloc de l’OnArduinoInfoReceive.

A continuació, definim les funcions OnArduinoInfoFail i OnArduinoInfoReceive. Per a aquesta instrucció, imprimim els resultats a la consola, però podeu emmagatzemar-los a les variables que necessiteu per al vostre projecte.

private void OnArduinoInfoFail ()

{Debug. Log ("No s'ha pogut llegir"); } private void OnArduinoInfoReceived (rotació de cadena, velocitat de cadena) {Debug. Log ("Llegit amb èxit"); Debug. Log ("Primer valor:" + rotació); Debug. Log ("Segon valor:" + velocitat); }

L’últim pas és iniciar i aturar els fils que demanaran els valors a l’Arduino. Hem d’assegurar-nos que l’últim fil es realitzi amb la seva última tasca abans d’iniciar-ne una de nova. En cas contrari, es podrien fer diverses sol·licituds a l'Arduino alhora, cosa que podria confondre l'Arduino / Unity i produir resultats imprevisibles.

Fil privat activeThread = nul;

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

Si compareu el rendiment del codi amb el que hem escrit a la secció 5, s’hauria de millorar significativament el rendiment.

private void OnArduinoInfoFail ()

{Debug. Log ("No s'ha pogut llegir"); }

Pas 5: a continuació?

On següent?
On següent?

Hem preparat una demostració que podeu descarregar al nostre Github (https://github.com/AlexandreDoucet/InfinityBike), descarregar el codi i el joc i recórrer la nostra pista. Tot està preparat per a un entrenament ràpid i esperem que us pugui donar una idea del que podríeu construir si utilitzeu el que us hem ensenyat amb aquest instructiu.

Crèdits

Col·laboradors del projecte

Alexandre Doucet (_Doucet_)

Maxime Boudreau (MxBoud)

Recursos externs [El motor de jocs Unity] (https://unity3d.com)

Aquest projecte va començar després de llegir el tutorial d'Allan Zucconi sobre "com integrar Arduino amb Unity" (https://www.alanzucconi.com/2015/10/07/how-to-int…)

La sol·licitud d'Arduino es gestiona mitjançant la biblioteca SerialCommand (https://github.com/kroimon/Arduino-SerialCommand)

Recomanat: