İçindekiler:

Infinity Bike - İç Mekan Bisiklet Eğitimi Video Oyunu: 5 Adım
Infinity Bike - İç Mekan Bisiklet Eğitimi Video Oyunu: 5 Adım

Video: Infinity Bike - İç Mekan Bisiklet Eğitimi Video Oyunu: 5 Adım

Video: Infinity Bike - İç Mekan Bisiklet Eğitimi Video Oyunu: 5 Adım
Video: 30 saniyede Tekteker Yapmayı Öğren #shorts #bike #bisiklet 2024, Eylül
Anonim
Image
Image
Malzemeler
Malzemeler

Kış mevsiminde, soğuk günlerde ve kötü havalarda, bisiklet tutkunları en sevdikleri sporu yaparak egzersiz yapmak için yalnızca birkaç seçeneğe sahiptir. Bir bisiklet/antrenör kurulumu ile iç mekan antrenmanını biraz daha eğlenceli hale getirmenin bir yolunu arıyorduk ama mevcut ürünlerin çoğu ya pahalı ya da kullanımı sıkıcı. Bu nedenle Infinity Bike'ı bir Açık Kaynak eğitim video oyunu olarak geliştirmeye başladık. Infinity bisiklet, bisikletinizin hızını ve yönünü okur ve bisiklet eğitmenleriyle kolayca bulunamayacak bir etkileşim düzeyi sunar.

Ucuz sensörleri bir eğiticiye monte edilmiş bir bisiklete sabitlemek için Arduino mikrodenetleyicisinin sunduğu basitlikten ve birkaç 3D baskılı parçadan yararlanıyoruz. Bilgi, popüler oyun yapma motoru Unity ile yapılan bir video oyununa aktarılır. Bu eğitimin sonunda, bisikletinize kendi sensörlerinizi kurabilmeli ve sensörlerinizin bilgilerini Unity'ye aktarabilmelisiniz. Hatta üzerine binebileceğiniz ve yeni kurulumunuzu test edebileceğiniz bir parkur bile ekledik. Katkıda bulunmakla ilgileniyorsanız GitHub'ımıza göz atabilirsiniz.

Adım 1: Malzemeler

Malzemeler
Malzemeler

İhtiyaç duyacağınız malzeme listesi biraz değişebilir; için

Örneğin, bisikletinizin boyutu, ihtiyacınız olan jumper kablolarının uzunluklarını belirleyecektir, ancak ihtiyacınız olacak ana parçalar burada. Muhtemelen AliExpress gibi web sitelerinde her parça için daha ucuz fiyatlar bulabilirsiniz, ancak nakliye için 6 ay beklemek her zaman bir seçenek değildir, bu nedenle tahminin çarpık olmaması için biraz daha pahalı parçaları kullanıyorduk.

1 x Arduino nano (22.00 $)

1 x Mini Breadboard (1,33$/birim)

1 x 220 Ohm direnç (1.00$/kit)

1 x 10K Potansiyometre (1.80$/birim)

1 x Hall sensörü (0,96 $)

20 cm x 6 mm 3D yazıcı triger kayışı (3,33 $)

1 takım x Çeşitli Uzunlukta M3 vidalar ve cıvatalar (6,82 $)

1 x Bisiklet hız göstergesi mıknatısı (0,98 $)

Yukarıdaki malzemeyi 3D baskılı parçalarla monte ettik. Kullandığımız dosyalar aşağıda listelenmiştir ve bu bölümün başındaki resim ile aynı kurala göre numaralandırılmıştır. Tüm dosyalar Thingiverse'de bulunabilir. Bunları olduğu gibi kullanabilirsiniz, ancak kullandığımız boyutların bisikletinize uygun olduğundan emin olun.

1. FrameConnection_PotantiometerHolder_U_Holder.stl

2. FrameConnection_Spacer.stl

3. BreadboardFrameHolder.stl

4. Pulley_PotantiometerSide.stl

5. Pot_PulleyConnection.stl

6. FrameConnection.stl

7. Pulley_HandleBarSide_Print2.stl

8. FrameToHallSensorConnector.stl

9. PotHolder.stl

10. HallSensorAttach.stl

Adım 2: Verileri Okumak ve Unity'ye Aktarmak

Unity'ye Veri Okuma ve Aktarma
Unity'ye Veri Okuma ve Aktarma

Arduino ve Unity kodu toplamak için birlikte çalışacak, Bisikletteki sensörlerden gelen verileri aktarın ve işleyin. Unity, seri üzerinden bir dizi göndererek Arduino'dan değeri isteyecek ve Arduino'nun istenen değerlerle yanıt vermesini bekleyecektir.

İlk olarak, bir istek dizesini bir işlevle eşleştirerek Unity'den gelen istekleri yönetmek için kullanılan Seri Komut kitaplığı ile Arduino'yu hazırlıyoruz. Bu kütüphane için temel bir kurulum aşağıdaki gibi yapılabilir;

#include "SerialCommand.h"

SeriKomut sCmd; geçersiz kurulum() { sCmd.addCommand("TRIGG", TriggHanlder); Seri.başla(9600); } void loop() { while (Serial.available() > 0) { sCmd.readSerial(); } } void TriggHandler () { /*Sensörleri buradan okuyun ve iletin*/ }

TriggHandler işlevi SCmd nesnesine eklenir. Seri, ekli komutla eşleşen bir dize alırsa (bu durumda TRIGG), TriggHandler işlevi yürütülür.

Direksiyon yönünü ölçmek için potansiyometre ve bisikletin dakikadaki dönüşünü ölçmek için bir halls sensörü kullanıyoruz. Potansiyometreden okumalar, Arduino'nun yerleşik fonksiyonları kullanılarak kolayca yapılabilir. TriggHandler işlevi daha sonra değeri aşağıdaki değişiklikle seriye yazdırabilir.

geçersiz TriggHandler (){

/*Potansiyometrenin değerini okuma*/ Serial.println(analogRead(ANALOGPIN)); }

Kullanışlı ölçümler yapabilmemiz için Hall sensörünün biraz daha ayarı var. Potansiyometrenin aksine halls sensörünün anlık değeri çok kullanışlı değildir. Tekerleğin hızını ölçmeye çalıştıkları için, ilgilenilen şey tetikleyiciler arasındaki zamandı.

Arduino kodunda kullanılan her fonksiyon zaman alır ve mıknatıs Hall sensörü ile yanlış zamanda hizalanırsa, ölçüm en iyi ihtimalle ertelenebilir veya en kötü ihtimalle tamamen atlanabilir. Bu açıkça kötü çünkü Arduino, tekerleğin gerçek hızından ÇOK farklı bir hız bildirebilir.

Bundan kaçınmak için, atanmış bir dijital pin yükselen bir sinyalle tetiklendiğinde bir işlevi tetiklememize izin veren ek kesme adı verilen bir Arduino özelliğini kullanıyoruz. rpm_fun işlevi, kurulum koduna eklenen tek bir kod satırıyla bir kesmeye eklenir.

geçersiz kurulum(){

sCmd.addCommand("TRIGG", TriggHanlder); ataşeKesme(0, rpm_fun, YÜKSELEN); Seri.başla(9600); } // rpm_fun fonksiyonu hızı hesaplamak için kullanılır ve şu şekilde tanımlanır; imzasız uzun lastRevolTime = 0; unsigned long revolSpeed = 0; void rpm_fun() { unsigned long revolTime = millis(); imzasız uzun deltaTime = revolTime - lastRevolTime; /*revolSpeed, Arduino koduna iletilen değerdir*/ revolSpeed = 20000 / deltaTime; lastRevolTime = revolTime; } TriggHandler istendiğinde bilgilerin geri kalanını iletebilir. void TriggHanlder () { /*Potansiyometrenin değerini okuma*/ Serial.println(analogRead(ANALOGPIN)); Serial.println(devir Hızı); }

Artık Unity tarafından bir istek yapıldığında seri üzerinden veri aktaracak Arduino kodunu oluşturmak için kullanılabilecek tüm yapı taşlarına sahibiz. Kodun tamamının bir kopyasına sahip olmak istiyorsanız, GitHub'ımızdan indirebilirsiniz. Kodun doğru şekilde kurulup kurulmadığını test etmek için, TRIGG göndermek için seri monitörü kullanabilirsiniz; Satırın sonunu Satır başı olarak ayarladığınızdan emin olun. Bir sonraki bölüm, Unity betiklerimizin Arduino'dan nasıl bilgi talep edip alabileceğine odaklanacaktır.

3. Adım: Verilerin Alınması ve İşlenmesi

Veri Alma ve İşleme
Veri Alma ve İşleme

Unity, hobi sahipleri için ücretsiz olarak sunulan harika bir yazılımdır.

oyun yapımıyla ilgilenen; C# komut dosyalarıyla yapılabilecekleri kısıtlamadan iş parçacığı oluşturma veya GPU programlama (AKA gölgelendirme) gibi belirli şeyleri ayarlama süresini gerçekten kısaltabilen çok sayıda işlevsellik ile birlikte gelir. Unity ve Arduino mikro denetleyicileri, nispeten küçük bir bütçeyle benzersiz etkileşimli deneyimler oluşturmak için birlikte kullanılabilir.

Bu talimatın odak noktası, Unity ile Arduino arasındaki iletişimi kurmaya yardımcı olmaktır, böylece Unity'de bulunan özelliklerin çoğuna çok fazla dalmayacağız. Birlik için çok sayıda BÜYÜK öğretici ve Unity'nin nasıl çalıştığını açıklayan çok daha iyi bir iş çıkarabilecek inanılmaz bir topluluk var. Bununla birlikte, neler yapılabileceğinin küçük bir vitrini olarak hizmet eden bu talimatla yollarını bulmayı başaranlar için özel bir ödül var. Gerçekçi bisiklet fiziği ile ilk parkur yapma denememizi Github'dan indirebilirsiniz.

İlk olarak, bir Arduino ile seri üzerinden iletişim kurmak için yapılması gereken minimum şeyden geçelim. Bu kodun oynanışa uygun olmadığı çabucak anlaşılacaktır, ancak her adımdan geçmek ve sınırlamaların ne olduğunu öğrenmek iyidir.

Unity'de, ArduinoReceive adlı bir C# betiği ekinde ArduinoReceive adlı tek bir boş GameObject ile yeni bir sahne oluşturun. Bu betik, Arduino ile iletişimi yöneten tüm kodları ekleyeceğimiz yerdir.

Bilgisayarınızın seri portları ile haberleşebilmemiz için önce erişilmesi gereken bir kütüphane vardır; Unity, belirli kitaplıkların kullanılmasına izin verecek şekilde ayarlanmalıdır. Düzenle->ProjectSerring->Player'a gidin ve Yapılandırma anahtarı. NET 2.0 Subset to. NET 2.0 altında Api Uyumluluk Düzeyi'nin yanında. Şimdi scriptin başına aşağıdaki kodu ekleyin;

System. IO. Port'ları kullanarak;

Bu, ArduinoReceive Sınıfına bir nesne olarak tanımlayabileceğiniz SerialPort sınıfına erişmenizi sağlayacaktır. Başka bir komut dosyasından herhangi bir müdahaleyi önlemek için özel yapın.

özel SeriPort arduinoPort;

arduinoPort nesnesi, doğru bağlantı noktası (örneğin Arduino'nun hangi USB'ye bağlı olduğu) ve bir baud hızı (yani bilginin gönderildiği hız) seçilerek açılabilir. Arduino'nun hangi bağlantı noktasına takılı olduğundan emin değilseniz, cihaz yöneticisinden veya Arduino IDE'yi açarak öğrenebilirsiniz. Baud hızı için çoğu cihazdaki varsayılan değer 9600'dür, Arduino kodunuzda bu değere sahip olduğunuzdan ve çalışması gerektiğinden emin olun.

Kod şimdi şöyle görünmelidir;

System. Collections'ı kullanarak;

System. Collections. Generic kullanarak; UnityEngine'i kullanarak; System. IO. Port'ları kullanarak; public class ArduinoReceive: MonoBehaviour { private SerialPort arduinoPort; // Başlatma için bunu kullanın void Start() { arduinoPort = new SerialPort("COM5", 9600); arduinoPort. Open(); WriteToArduino("TRIGG"); } }

COM numaranız büyük olasılıkla farklı olacaktır. MAC kullanıyorsanız, COM adınız /dev/cu.wchusbserial1420 gibi görünen bir ada sahip olabilir. 4. bölümdeki kodun Arduino'ya yüklendiğinden ve bu bölümün geri kalanı için seri monitörün kapalı olduğundan ve bu kodun sorunsuz bir şekilde derlendiğinden emin olun.

Şimdi her karede Arduino'ya bir istek gönderelim ve sonuçları konsol penceresine yazalım. WriteToArduino işlevini ArduinoReceive sınıfına ekleyin. Arduino kodunun gelen talimatı doğru şekilde ayrıştırması için satır başı ve yeni satır gereklidir.

özel geçersiz WriteToArduino(dize mesajı)

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

Bu işlev daha sonra Güncelleme döngüsünde çağrılabilir.

geçersiz Güncelleme ()

{ WriteToArduino ("TRIGG"); Debug. Log("İlk Değer: " + arduinoPort. ReadLine()); Debug. Log("İkinci Değer: " + arduinoPort. ReadLine()); }

Yukarıdaki kod, bir Arduino'dan gelen verileri okumak için ihtiyacınız olan minimum değerdir. Unity'nin verdiği FPS'ye çok dikkat ederseniz performansta ciddi bir düşüş görmelisiniz. Benim durumumda, okuma/yazma yapmadan yaklaşık 90 FPS'den 20 FPS'ye çıkıyor. Projeniz sık güncelleme gerektirmiyorsa yeterli olabilir ancak bir video oyunu için 20 FPS çok düşük. Sonraki bölüm, çoklu iş parçacığı kullanarak performansı nasıl iyileştirebileceğinizi ele alacaktır.

4. Adım: Veri Aktarımını Optimize Etme

Önceki bölüm, temel ayarların nasıl yapıldığını ele aldı.

Arduino ve Unity programı arasındaki iletişim. Bu kodla ilgili en büyük sorun performanstır. Şu anki uygulamasında Unity, Arduino'nun talebi almasını, işlemesini ve yanıtlamasını beklemek zorundadır. Bu süre zarfında Unity kodu, isteğin yapılmasını beklemek zorundadır ve başka hiçbir şey yapmaz. Bu sorunu, istekleri işleyecek ve değişkeni ana iş parçacığında saklayacak bir iş parçacığı oluşturarak çözdük.

Başlamak için threading kütüphanesini ekleyerek;

System. Threading kullanarak;

Daha sonra threadlerde başlattığımız fonksiyonu ayarlıyoruz. AsynchronousReadFromArduino, isteği WrtieToArduino işleviyle Arduino'ya yazarak başlar. Okuma, bir try-catch bloğu içine alınır, eğer okuma zaman aşımı, değişkenler boş kalır ve OnArduinoInfoReceive yerine OnArduinoInfoFail işlevi çağrılır.

Daha sonra OnArduinoInfoFail ve OnArduinoInfoReceive fonksiyonlarını tanımlıyoruz. Bu talimat için sonuçları konsola yazdırıyoruz ancak sonuçları projeniz için ihtiyaç duyduğunuz değişkenlerde saklayabilirsiniz.

özel boşluk OnArduinoInfoFail()

{ Debug. Log("Okuma başarısız"); } private void OnArduinoInfoReceived(dize döndürme, dize hızı) { Debug. Log("Başarılı Okuma"); Debug. Log("İlk Değer: " + döndürme); Debug. Log("İkinci Değer: " + hız); }

Son adım, Arduino'dan değerleri talep edecek iş parçacıklarını başlatmak ve durdurmaktır. Yeni bir iş parçacığına başlamadan önce son iş parçacığının son göreviyle yapıldığından emin olmalıyız. Aksi takdirde, Arduino'ya aynı anda birden fazla istek yapılabilir, bu da Arduino/Unity'nin kafasını karıştırabilir ve öngörülemeyen sonuçlar verebilir.

özel Konu activeThread = null;

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

Kodun performansını 5. bölümde yazdığımız kodla karşılaştırırsanız, performansın önemli ölçüde artması gerekir.

özel boşluk OnArduinoInfoFail()

{ Debug. Log("Okuma başarısız"); }

Adım 5: Sonraki Nerede?

Sıradaki nerede?
Sıradaki nerede?

Github'umuzdan (https://github.com/AlexandreDoucet/InfinityBike) indirebileceğiniz, kodu ve oyunu indirebileceğiniz ve parkurumuzda gezinebileceğiniz bir demo hazırladık. Her şey hızlı bir antrenman için ayarlandı ve umarız bu talimatla size öğrettiklerimizi kullanırsanız neler yapabileceğinize dair bir fikir verebilir.

Kredi

Projeye katkıda bulunanlar

Alexandre Doucet (_Doucet_)

Maxime Boudreau (MxBoud)

Harici kaynaklar [Unity oyun motoru](https://unity3d.com)

Bu proje, Allan Zucconi'nin "Arduino ile Unity'yi nasıl entegre ederiz" (https://www.alanzucconi.com/2015/10/07/how-to-int…) öğreticisini okuduktan sonra başladı.

Arduino'dan gelen istek, SerialCommand kitaplığı kullanılarak işlenir (https://github.com/kroimon/Arduino-SerialCommand)

Önerilen: