Isi kandungan:

Infinity Bike - Latihan Bike Indoor Permainan Video: 5 Langkah
Infinity Bike - Latihan Bike Indoor Permainan Video: 5 Langkah

Video: Infinity Bike - Latihan Bike Indoor Permainan Video: 5 Langkah

Video: Infinity Bike - Latihan Bike Indoor Permainan Video: 5 Langkah
Video: Starting and riding off rollers… #shorts 2024, September
Anonim
Image
Image
Bahan
Bahan

Pada musim musim sejuk, hari-hari sejuk dan cuaca buruk, peminat basikal hanya mempunyai beberapa pilihan untuk bersukan melakukan sukan kegemaran mereka. Kami sedang mencari cara untuk membuat latihan dalaman dengan persediaan basikal / pelatih sedikit lebih menghiburkan tetapi kebanyakan produk yang ada sama ada mahal atau hanya membosankan untuk digunakan. Inilah sebabnya mengapa kami mula mengembangkan Infinity Bike sebagai permainan video latihan Open Source. Basikal infiniti membaca kelajuan dan arah dari basikal anda dan menawarkan tahap interaktiviti yang tidak dapat dijumpai dengan mudah dengan pelatih basikal.

Kami memanfaatkan kesederhanaan yang tersedia dari mikrokontroler Arduino dan beberapa bahagian 3D yang dicetak untuk mendapatkan sensor yang murah ke basikal yang dipasang di pelatih. Maklumat disampaikan kepada permainan video yang dibuat dengan mesin pembuat permainan popular, Unity. Pada akhir arahan ini, anda seharusnya dapat memasang sensor anda sendiri di basikal anda dan memindahkan maklumat sensor anda ke Unity. Kami juga menyertakan trek di mana anda boleh menunggang dan menguji susunan baru anda. Sekiranya anda berminat untuk menyumbang, anda boleh melihat GitHub kami.

Langkah 1: Bahan

Bahan
Bahan

Senarai bahan yang anda perlukan mungkin sedikit berbeza; untuk

contohnya, saiz basikal anda akan menentukan panjang kabel pelompat yang anda perlukan tetapi berikut adalah bahagian utama yang anda perlukan. Anda mungkin dapat menemukan harga yang lebih murah untuk setiap keping di laman web seperti AliExpress tetapi menunggu 6 bulan untuk penghantaran tidak selalu menjadi pilihan, jadi menggunakan bahagian yang sedikit lebih mahal sehingga anggaran tidak condong.

1 x Arduino nano ($ 22.00)

1 x Papan Roti Mini ($ 1.33 / unit)

1 x 220 Ohm perintang ($ 1.00 / kit)

Potensiometer 1 x 10K ($ 1.80 / unit)

1 x Sensor dewan ($ 0.96)

Tali pinggang pencetak 3D 20 cm x 6 mm ($ 3,33)

1 kit x Pelbagai skru dan baut Panjang M3 ($ 6.82)

1 x Magnet speedometer basikal ($ 0.98)

Kami memasang bahan di atas dengan bahagian bercetak 3D. Fail yang kami gunakan disenaraikan di bawah dan diberi nombor dengan konvensyen yang sama seperti gambar pada awal bahagian ini. Semua fail boleh didapati di Thingiverse. Anda boleh menggunakannya sebagaimana mestinya tetapi pastikan dimensi yang kami gunakan sesuai dengan basikal anda.

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

Langkah 2: Membaca dan Memindahkan Data ke Perpaduan

Membaca dan Memindahkan Data ke Perpaduan
Membaca dan Memindahkan Data ke Perpaduan

Kod Arduino dan Unity akan bekerjasama untuk mengumpulkan, memindahkan dan memproses data dari sensor pada basikal. Unity akan meminta nilai dari Arduino dengan mengirim rentetan melalui siri dan menunggu Arduino bertindak balas dengan nilai yang diminta.

Pertama, kami menyiapkan Arduino dengan Serial Command perpustakaan yang digunakan untuk mengatur permintaan dari Unity dengan memasangkan string permintaan dengan fungsi. Penyediaan asas untuk perpustakaan ini boleh dibuat seperti berikut;

#sertakan "SerialCommand.h"

SerialCommand sCmd; batal persediaan () {sCmd.addCommand ("TRIGG", TriggHanlder); Serial.begin (9600); } gelung void () {while (Serial.available ()> 0) {sCmd.readSerial (); }} batal TriggHandler () {/ * Baca dan hantarkan sensor di sini * /}

Fungsi TriggHandler dilekatkan pada objek SCmd. Sekiranya siri ini menerima rentetan yang sesuai dengan perintah yang dilampirkan (dalam hal ini TRIGG), fungsi TriggHandler dijalankan.

Kami menggunakan potensiometer untuk mengukur arah kemudi dan sensor ruang untuk mengukur putaran per minit basikal. Pembacaan dari potensiometer dapat dibuat dengan mudah menggunakan fungsi bawaan dari Arduino. Fungsi TriggHandler kemudian dapat mencetak nilai ke serial dengan perubahan berikut.

batal TriggHandler () {

/ * Membaca nilai potensiometer * / Serial.println (analogRead (ANALOGPIN)); }

Sensor Hall mempunyai sedikit persediaan sebelum kita dapat melakukan pengukuran yang berguna. Berbeza dengan potensiometer, nilai segera sensor ruang tidak begitu berguna. Oleh kerana cuba mengukur kelajuan roda, waktu antara pemicu adalah perkara yang diminati.

Setiap fungsi yang digunakan dalam kod Arduino memerlukan masa dan jika magnet berbaris dengan sensor Hall pada waktu yang salah, pengukuran dapat ditunda paling baik atau dilewati sepenuhnya pada tahap terburuk. Ini jelas buruk kerana Arduino dapat melaporkan kelajuan yang jauh lebih besar daripada kelajuan roda sebenarnya.

Untuk mengelakkan ini, kami menggunakan fitur Arduino yang disebut attach interrupt yang memungkinkan kami memicu fungsi setiap kali pin digital yang ditentukan dipicu dengan isyarat yang meningkat. Fungsi rpm_fun dilampirkan pada gangguan dengan satu baris kod yang ditambahkan ke kod persediaan.

batal persediaan () {

sCmd.addCommand ("TRIGG", TriggHanlder); attachInterrupt (0, rpm_fun, RISING); Serial.begin (9600); } // Fungsi rpm_fun digunakan untuk mengira kelajuan dan didefinisikan sebagai; LastRevolTime long unsigned = 0; revolSpeed long unsigned = 0; batal rpm_fun () {revolTime panjang yang tidak ditandatangani = millis (); deltaTime panjang yang tidak ditandatangani = revolTime - lastRevolTime; / * revolSpeed adalah nilai yang dihantar ke kod Arduino * / revolSpeed = 20000 / deltaTime; lastRevolTime = revolTime; } TriggHandler kemudian dapat menghantar maklumat selebihnya apabila diminta. batal TriggHanlder () {/ * Membaca nilai potensiometer * / Serial.println (analogRead (ANALOGPIN)); Serial.println (revolSpeed); }

Kami sekarang memiliki semua blok bangunan yang dapat digunakan untuk membangun kod Arduino yang akan memindahkan data melalui serial ke saat permintaan dibuat oleh Unity. Sekiranya anda ingin mempunyai salinan kod penuh, anda boleh memuat turunnya di GitHub kami. Untuk menguji sama ada kod telah disiapkan dengan betul, anda boleh menggunakan monitor bersiri untuk menghantar TRIGG; pastikan anda menetapkan garis yang berakhir dengan Carriage return. Bahagian seterusnya akan memberi tumpuan kepada bagaimana skrip Unity kami dapat meminta dan menerima maklumat dari Arduino.

Langkah 3: Menerima dan Memproses Data

Menerima dan Memproses Data
Menerima dan Memproses Data

Unity adalah perisian hebat yang tersedia secara percuma untuk penggemar

berminat membuat permainan; ia dilengkapi dengan sebilangan besar fungsi yang benar-benar dapat mengurangkan masa mengatur perkara-perkara tertentu seperti threading atau pengaturcaraan GPU (AKA shading) tanpa menyekat apa yang dapat dilakukan dengan skrip C #. Mikrokontroler Unity dan Arduino dapat digunakan bersama untuk mewujudkan pengalaman interaktif yang unik dengan anggaran yang agak kecil.

Fokus arahan ini adalah untuk membantu mengatur komunikasi antara Unity dan Arduino sehingga kami tidak akan menyelami lebih banyak fitur yang tersedia dengan Unity. Terdapat banyak tutorial HEBAT untuk perpaduan dan komuniti luar biasa yang dapat melakukan pekerjaan yang lebih baik untuk menerangkan bagaimana Unity berfungsi. Walau bagaimanapun, ada hadiah khas bagi mereka yang berjaya melalui instruksi ini yang berfungsi sebagai pameran kecil mengenai apa yang dapat dilakukan. Anda boleh memuat turun di Github percubaan pertama kami membuat trek dengan fizik basikal yang realistik.

Pertama, mari kita teliti minimum yang harus dilakukan untuk berkomunikasi dengan Arduino melalui siri ini. Tampaknya dengan cepat bahawa kod ini tidak sesuai untuk permainan tetapi ada baiknya menjalani setiap langkah dan mengetahui batasannya.

Di Unity, buat pemandangan baru dengan GameObject kosong tunggal bernama ArduinoReceive di lampiran skrip C # juga bernama ArduinoReceive. Skrip ini adalah tempat kita akan menambahkan semua kod yang menangani komunikasi dengan Arduino.

Terdapat perpustakaan yang mesti diakses sebelum kita dapat berkomunikasi dengan port bersiri komputer anda; Perpaduan mesti dibentuk untuk membolehkan perpustakaan tertentu digunakan. Pergi ke Edit-> ProjectSerring-> Player dan di sebelah Tahap Keserasian Api di bawah suis Konfigurasi. NET 2.0 Subset ke. NET 2.0. Sekarang tambahkan kod berikut di bahagian atas skrip;

menggunakan System. IO. Ports;

Ini akan membolehkan anda mengakses kelas SerialPort yang dapat anda tentukan sebagai objek ke ArduinoReceive Class. Jadikan ia peribadi untuk mengelakkan gangguan dari skrip lain.

SerialPort arduinoPort peribadi;

Objek arduinoPort dapat dibuka dengan memilih port yang betul (mis. Di mana USB yang Arduino disambungkan) dan laju baud (iaitu kecepatan di mana maklumat dihantar). Sekiranya anda tidak pasti di mana port Arduino dipasang, anda boleh mengetahui sama ada di pengurus peranti atau dengan membuka Arduino IDE. Untuk kadar baud, nilai lalai pada kebanyakan peranti adalah 9600, pastikan anda mempunyai nilai ini dalam kod Arduino anda dan ia mesti berfungsi.

Kini kodnya kelihatan seperti ini;

menggunakan System. Collections;

menggunakan System. Collections. Generic; menggunakan UnityEngine; menggunakan System. IO. Ports; kelas awam ArduinoReceive: MonoBehaviour {peribadi SerialPort arduinoPort; // Gunakan ini untuk inisialisasi batal Mula () {arduinoPort = SerialPort baru ("COM5", 9600); arduinoPort. Open (); WriteToArduino ("TRIGG"); }}

Nombor COM anda kemungkinan besar berbeza. Sekiranya anda menggunakan MAC, nama COM anda mungkin mempunyai nama yang kelihatan seperti ini /dev/cu.wchusbserial1420. Pastikan kod dari bahagian 4 dimuat ke Arduino dan monitor bersiri ditutup untuk bahagian ini dan kod ini menyusun tanpa masalah.

Sekarang mari kita kirim permintaan ke Arduino setiap bingkai dan tulis hasilnya ke tetingkap konsol. Tambahkan fungsi WriteToArduino ke kelas ArduinoReceive. Perjalanan pulang dan barisan baru diperlukan agar kod Arduino menguraikan arahan masuk dengan betul.

kekosongan peribadi WriteToArduino (mesej rentetan)

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

Fungsi ini kemudian boleh dipanggil dalam gelung Update.

batal Kemas kini ()

{WriteToArduino ("TRIGG"); Debug. Log ("Nilai Pertama:" + arduinoPort. ReadLine ()); Debug. Log ("Nilai Kedua:" + arduinoPort. ReadLine ()); }

Kod di atas adalah minimum yang anda perlukan untuk membaca data dari Arduino. Sekiranya anda memperhatikan FPS yang diberikan oleh kesatuan, anda akan melihat penurunan prestasi yang ketara. Dalam kes saya, ia bermula dari sekitar 90 FPS tanpa membaca / menulis hingga 20 FPS. Sekiranya projek anda tidak memerlukan kemas kini yang kerap mungkin mencukupi tetapi untuk permainan video, 20 FPS terlalu rendah. Bahagian seterusnya akan merangkumi bagaimana anda dapat meningkatkan prestasi dengan menggunakan multi threading.

Langkah 4: Mengoptimumkan Pemindahan Data

Bahagian sebelumnya merangkumi cara mengatur asas

komunikasi antara program Arduino dan Unity. Masalah utama kod ini adalah prestasi. Dalam pelaksanaannya sekarang, Unity harus menunggu Arduino menerima, memproses dan menjawab permintaan tersebut. Selama masa itu, kod Unity harus menunggu permintaan dibuat dan tidak melakukan apa-apa lagi. Kami menyelesaikan masalah ini dengan membuat utas yang akan menangani permintaan dan menyimpan pemboleh ubah pada utas utama.

Untuk memulakan, kita mesti memasukkan perpustakaan utas dengan menambahkan;

menggunakan System. Threading;

Seterusnya, kita menetapkan fungsi yang kita mulakan dalam utas. AsynchronousReadFromArduino bermula dengan menulis permintaan ke Arduino dengan fungsi WrtieToArduino. Pembacaan dilampirkan dalam blok try-catch, jika habis waktu baca, pemboleh ubah tetap kosong dan fungsi OnArduinoInfoFail dipanggil sebagai ganti OnArduinoInfoReceive.

Seterusnya kita menentukan fungsi OnArduinoInfoFail dan OnArduinoInfoReceive. Untuk arahan ini, kami mencetak hasilnya ke konsol tetapi anda dapat menyimpan hasilnya ke dalam pemboleh ubah yang anda perlukan untuk projek anda.

kekosongan peribadi OnArduinoInfoFail ()

{Debug. Log ("Membaca gagal"); } kekosongan peribadi OnArduinoInfoReceived (putaran tali, kelajuan rentetan) {Debug. Log ("Readin Sucessfull"); Debug. Log ("Nilai Pertama:" + putaran); Debug. Log ("Nilai Kedua:" + kelajuan); }

Langkah terakhir adalah memulakan dan menghentikan utas yang akan meminta nilai dari Arduino. Kita mesti memastikan bahawa urutan terakhir dilakukan dengan tugas terakhir sebelum memulakan yang baru. Jika tidak, banyak permintaan dapat dilakukan kepada Arduino dalam satu masa yang boleh membingungkan Arduino / Unity dan menghasilkan hasil yang tidak dapat diramalkan.

Thread peribadi aktifThread = null;

batal Kemas kini () {if (activeThread == null ||! activeThread. IsAlive) {activeThread = Thread baru (AsynchronousReadFromArduino); aktifThread. Start (); }}

Sekiranya anda membandingkan prestasi kod dengan yang kami tulis di bahagian 5, prestasi harus ditingkatkan dengan ketara.

kekosongan peribadi OnArduinoInfoFail ()

{Debug. Log ("Membaca gagal"); }

Langkah 5: Di mana Seterusnya?

Di mana Seterusnya?
Di mana Seterusnya?

Kami menyediakan demo yang boleh anda muat turun di Github kami (https://github.com/AlexandreDoucet/InfinityBike), muat turun kod dan permainan dan jalan melalui trek kami. Semuanya disiapkan untuk senaman yang cepat dan kami harap ia dapat memberi anda rasa apa yang dapat anda bina sekiranya anda menggunakan apa yang kami ajarkan kepada anda dengan petunjuk ini.

Kredit

Penyumbang projek

Alexandre Doucet (_Doucet_)

Maxime Boudreau (MxBoud)

Sumber luaran [Mesin permainan Unity] (https://unity3d.com)

Projek ini dimulakan setelah kami membaca tutorial oleh Allan Zucconi "bagaimana mengintegrasikan Arduino dengan Unity" (https://www.alanzucconi.com/2015/10/07/how-to-int…)

Permintaan dari Arduino ditangani menggunakan perpustakaan SerialCommand (https://github.com/kroimon/Arduino-SerialCommand)

Disyorkan: