جدول المحتويات:

Infinity Bike - لعبة فيديو للتدريب على الدراجة في الداخل: 5 خطوات
Infinity Bike - لعبة فيديو للتدريب على الدراجة في الداخل: 5 خطوات

فيديو: Infinity Bike - لعبة فيديو للتدريب على الدراجة في الداخل: 5 خطوات

فيديو: Infinity Bike - لعبة فيديو للتدريب على الدراجة في الداخل: 5 خطوات
فيديو: اهم 7 اخطاء يجب تجنبها عند ركوب الدراجة 2024, شهر نوفمبر
Anonim
Image
Image
المواد
المواد

خلال مواسم الشتاء والأيام الباردة والطقس السيئ ، لا يتوفر لعشاق ركوب الدراجات سوى عدد قليل من الخيارات لممارسة الرياضة المفضلة لديهم. كنا نبحث عن طريقة لجعل التدريب الداخلي مع إعداد الدراجة / المدرب أكثر تسلية قليلاً ولكن معظم المنتجات المتاحة إما مكلفة أو مملة للاستخدام. هذا هو السبب في أننا بدأنا في تطوير Infinity Bike كلعبة فيديو تدريب مفتوحة المصدر. تقرأ الدراجة اللانهائية السرعة والاتجاه من دراجتك وتقدم مستوى من التفاعل لا يمكن العثور عليه بسهولة مع مدربي الدراجات.

نحن نستفيد من البساطة المتاحة من متحكم Arduino وبعض الأجزاء المطبوعة ثلاثية الأبعاد لتأمين أجهزة استشعار غير مكلفة لدراجة مثبتة على جهاز تدريب. يتم نقل المعلومات إلى لعبة فيديو تم إنشاؤها باستخدام محرك صنع الألعاب الشهير ، Unity. بحلول نهاية هذا الدليل ، يجب أن تكون قادرًا على إعداد أجهزة الاستشعار الخاصة بك على دراجتك ونقل معلومات أجهزة الاستشعار الخاصة بك إلى Unity. لقد قمنا أيضًا بتضمين مضمار يمكنك الركوب عليه واختبار إعدادك الجديد. إذا كنت مهتمًا بالمساهمة ، يمكنك التحقق من GitHub.

الخطوة 1: المواد

المواد
المواد

قد تختلف قائمة المواد التي ستحتاج إليها قليلاً ؛ ل

على سبيل المثال ، سيحدد حجم دراجتك أطوال كبلات العبور التي تحتاجها ولكن إليك الأجزاء الرئيسية التي ستحتاج إليها. من المحتمل أن تجد أسعارًا أرخص لكل قطعة على موقع الويب مثل AliExpress ولكن الانتظار لمدة 6 أشهر للشحن ليس دائمًا خيارًا ، لذلك كنت تستخدم الأجزاء الأكثر تكلفة قليلاً حتى لا يكون التقدير منحرفًا.

1 × اردوينو نانو (22.00 دولارًا)

1 × لوح توصيل صغير (1.33 دولار / وحدة)

1 × 220 أوم المقاوم (1.00 دولار / مجموعة)

1 × 10K مقياس جهد (1.80 دولار / وحدة)

1 × مستشعر هول (0.96 دولار)

حزام توقيت الطابعة 20 سم × 6 مم (3.33 دولار)

مجموعة واحدة × براغي ومسامير بطول M3 مختلف (6.82 دولارًا)

1 × مغناطيس عداد السرعة للدراجة (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

الخطوة الثانية: قراءة البيانات ونقلها إلى الوحدة

قراءة ونقل البيانات إلى الوحدة
قراءة ونقل البيانات إلى الوحدة

سيعمل كود Arduino و Unity معًا لجمع ،

نقل البيانات من المستشعرات الموجودة على الدراجة ومعالجتها. ستطلب الوحدة القيمة من Arduino عن طريق إرسال سلسلة عبر المسلسل وانتظر استجابة Arduino بالقيم المطلوبة.

أولاً ، نقوم بإعداد Arduino باستخدام الأمر التسلسلي للمكتبة والذي يتم استخدامه لإدارة الطلبات من الوحدة عن طريق إقران سلسلة طلب بوظيفة. يمكن إجراء إعداد أساسي لهذه المكتبة على النحو التالي ؛

# تضمين "SerialCommand.h"

SerialCommand sCmd ؛ إعداد باطل () {sCmd.addCommand ("TRIGG" ، TriggHanlder) ؛ Serial.begin (9600) ؛ } حلقة فارغة () {while (Serial.available ()> 0) {sCmd.readSerial () ؛ }} void TriggHandler () {/ * اقرأ وأرسل أجهزة الاستشعار هنا * /}

يتم إرفاق الوظيفة TriggHandler بالكائن SCmd. إذا تلقى المسلسل سلسلة تطابق الأمر المرفق (في هذه الحالة TRIGG) ، يتم تنفيذ الوظيفة TriggHandler.

نستخدم مقياس الجهد لقياس اتجاه التوجيه ومستشعر القاعات لقياس دوران الدراجة في الدقيقة. يمكن إجراء القراءات من مقياس الجهد بسهولة باستخدام وظائف البناء من Arduino. يمكن لوظيفة TriggHandler بعد ذلك طباعة القيمة إلى المسلسل بالتغيير التالي.

TriggHandler () باطل {

/ * قراءة قيمة مقياس الجهد * / Serial.println (analogRead (ANALOGPIN)) ؛ }

يحتوي مستشعر Hall على إعدادات أكثر قليلاً قبل أن نتمكن من الحصول على قياسات مفيدة. على عكس مقياس الجهد ، فإن القيمة الفورية لمستشعر القاعات ليست مفيدة جدًا. نظرًا لأننا كنا نحاول قياس سرعة العجلة ، فإن الوقت بين المشغلات هو ما يهمنا.

تستغرق كل وظيفة مستخدمة في كود Arduino وقتًا ، وإذا كان المغناطيس يصطف مع مستشعر Hall في وقت خاطئ ، فقد يتأخر القياس في أحسن الأحوال أو يتم تخطيه تمامًا في أسوأ الأحوال. من الواضح أن هذا سيء لأن Arduino يمكنه الإبلاغ عن سرعة تختلف كثيرًا عن السرعة الفعلية للعجلة.

لتجنب ذلك ، نستخدم ميزة في Arduinos تسمى attach interrupt والتي تتيح لنا تشغيل وظيفة كلما تم تشغيل دبوس رقمي معين بإشارة متزايدة. يتم إرفاق الوظيفة rpm_fun بمقاطعة بسطر واحد من التعليمات البرمجية يضاف إلى كود الإعداد.

الإعداد باطل(){

sCmd.addCommand ("TRIGG" ، TriggHanlder) ؛ attachInterrupt (0، rpm_fun، RISING) ؛ Serial.begin (9600) ؛ } // تُستخدم الدالة rpm_fun لحساب السرعة وتُعرَّف على أنها ؛ lastRevolTime طويل بدون توقيع = 0 ؛ revolspeed طويل بدون توقيع = 0 ؛ void rpm_fun () {unsigned long revolTime = millis () ؛ deltaTime طويل بدون توقيع = revolTime - lastRevolTime ؛ / * revolSpeed هي القيمة المرسلة إلى كود Arduino * / revolSpeed = 20000 / deltaTime ؛ lastRevolTime = revolTime ، } يمكن لـ TriggHandler إرسال بقية المعلومات عند الطلب. باطل TriggHanlder () {/ * قراءة قيمة مقياس الجهد * / Serial.println (analogRead (ANALOGPIN)) ؛ Serial.println (revolSpeed) ؛ }

لدينا الآن جميع اللبنات الأساسية التي يمكن استخدامها لبناء كود Arduino الذي سينقل البيانات من خلال المسلسل إلى عندما يتم تقديم طلب بواسطة Unity. إذا كنت ترغب في الحصول على نسخة من الكود الكامل ، يمكنك تنزيله على GitHub الخاص بنا. لاختبار ما إذا تم إعداد الكود بشكل صحيح ، يمكنك استخدام الشاشة التسلسلية لإرسال TRIGG ؛ تأكد من تعيين نهاية السطر على حرف إرجاع. سيركز القسم التالي على كيفية قيام برامج Unity النصية الخاصة بنا بطلب المعلومات واستلامها من Arduino.

الخطوة الثالثة: استلام ومعالجة البيانات

استلام ومعالجة البيانات
استلام ومعالجة البيانات

Unity هو برنامج رائع متاح مجانًا للهواة

مهتم بصنع اللعبة ؛ يأتي مع عدد كبير من الوظائف التي يمكن أن تقلل حقًا من الوقت في إعداد أشياء معينة مثل خيوط المعالجة أو برمجة GPU (تظليل AKA) دون تقييد ما يمكن فعله باستخدام البرامج النصية لـ C #. يمكن استخدام متحكمات Unity و Arduino معًا لإنشاء تجارب تفاعلية فريدة بميزانية صغيرة نسبيًا.

ينصب تركيز هذا الدليل على المساعدة في إعداد الاتصال بين Unity و Arduino حتى لا نتعمق كثيرًا في معظم الميزات المتوفرة مع Unity. هناك الكثير من دروس GREAT للوحدة ومجتمع رائع يمكنه القيام بعمل أفضل بكثير في شرح كيفية عمل Unity. ومع ذلك ، هناك جائزة خاصة لأولئك الذين تمكنوا من شق طريقهم من خلال هذه التعليمات التي تعمل بمثابة عرض صغير لما يمكن القيام به. يمكنك تنزيل محاولتنا الأولى على جيثب لعمل مسار بفيزياء الدراجة الواقعية.

أولاً ، دعنا ننتقل إلى الحد الأدنى الذي يجب القيام به للتواصل مع Arduino من خلال المسلسل. سيتضح بسرعة أن هذا الرمز غير مناسب للعب ولكن من الجيد متابعة كل خطوة ومعرفة ماهية القيود.

في Unity ، أنشئ مشهدًا جديدًا باستخدام كائن GameObject واحد فارغ باسم ArduinoReceive في الملحق ، وهو نص C # يسمى أيضًا ArduinoReceive. هذا البرنامج النصي هو المكان الذي سنضيف فيه كل التعليمات البرمجية التي تتعامل مع الاتصال مع Arduino.

توجد مكتبة يجب الوصول إليها قبل أن نتمكن من الاتصال بالمنافذ التسلسلية لجهاز الكمبيوتر الخاص بك ؛ يجب إنشاء الوحدة للسماح باستخدام مكتبات معينة. انتقل إلى تحرير-> ProjectSerring-> المشغل وبجوار مستوى توافق واجهة برمجة التطبيقات (Api Compatibility Level) ضمن مفتاح التكوين. NET 2.0 Subset إلى. NET 2.0. الآن أضف التعليمات البرمجية التالية في الجزء العلوي من البرنامج النصي ؛

باستخدام System. IO. Ports ؛

سيتيح لك ذلك الوصول إلى فئة SerialPort التي يمكنك تحديدها ككائن في فئة ArduinoReceive. اجعله خاصًا لتجنب أي تدخل من نص برمجي آخر.

منفذ تسلسلي خاص arduinoPort ؛

يمكن فتح منفذ كائن arduinoPort عن طريق تحديد المنفذ الصحيح (على سبيل المثال الذي يتم فيه توصيل USB بأردوينو) ومعدل الباود (أي السرعة التي يتم بها إرسال المعلومات). إذا لم تكن متأكدًا من المنفذ الذي تم توصيل Arduino به ، فيمكنك معرفة ذلك إما في مدير الجهاز أو عن طريق فتح Arduino IDE. بالنسبة لمعدل الباود ، القيمة الافتراضية على معظم الأجهزة هي 9600 ، فقط تأكد من أن لديك هذه القيمة في كود Arduino الخاص بك ويجب أن تعمل.

يجب أن يبدو الرمز الآن على هذا النحو ؛

باستخدام System. Collections.

باستخدام System. Collections. Generic ؛ باستخدام UnityEngine ؛ باستخدام System. IO. Ports ؛ فئة عامة ArduinoReceive: MonoBehaviour {private SerialPort arduinoPort؛ // استخدم هذا لتهيئة الفراغ Start () {arduinoPort = new SerialPort ("COM5"، 9600)؛ arduinoPort. Open () ، WriteToArduino ("TRIGG") ؛ }}

من المرجح أن يكون رقم COM الخاص بك مختلفًا. إذا كنت تستخدم جهاز MAC ، فقد يكون لديك اسم COM يشبه هذا /dev/cu.wchusbserial1420. تأكد من تحميل الكود من القسم 4 إلى Arduino وأن الشاشة التسلسلية مغلقة لبقية هذا القسم وأن هذا الرمز يتم تجميعه دون مشكلة.

دعنا الآن نرسل طلبًا إلى Arduino كل إطار ونكتب النتائج إلى نافذة وحدة التحكم. أضف وظيفة WriteToArduino إلى فئة ArduinoReceive. يعد حرف الإرجاع والخط الجديد ضروريين لكود Arduino لتحليل التعليمات الواردة بشكل صحيح.

WriteToArduino باطلة خاصة (رسالة سلسلة)

{message = message + "\ r / n" ؛ arduinoPort. Write (رسالة) ؛ arduinoPort. BaseStream. Flush () ، }

يمكن بعد ذلك استدعاء هذه الوظيفة في حلقة التحديث.

تحديث باطل ()

{WriteToArduino ("TRIGG") ؛ Debug. Log ("القيمة الأولى:" + arduinoPort. ReadLine ()) ؛ Debug. Log ("القيمة الثانية:" + arduinoPort. ReadLine ()) ؛ }

الكود أعلاه هو الحد الأدنى الذي تحتاجه لقراءة البيانات من Arduino. إذا كنت تولي اهتمامًا وثيقًا لـ FPS التي قدمتها الوحدة ، فمن المفترض أن ترى انخفاضًا كبيرًا في الأداء. في حالتي ، ينتقل من حوالي 90 إطارًا في الثانية دون قراءة / كتابة إلى 20 إطارًا في الثانية. إذا كان مشروعك لا يتطلب تحديثات متكررة ، فقد يكون ذلك كافيًا ولكن بالنسبة إلى لعبة فيديو ، فإن 20 إطارًا في الثانية منخفضة جدًا. سيغطي القسم التالي كيف يمكنك تحسين الأداء باستخدام خيوط المعالجة المتعددة.

الخطوة 4: تحسين نقل البيانات

تناول القسم السابق كيفية إعداد الأساسي

التواصل بين برنامج Arduino و Unity. المشكلة الرئيسية في هذا الرمز هي الأداء. في التطبيق الحالي ، يتعين على الوحدة انتظار Arduino لتلقي الطلب ومعالجته والإجابة عليه. خلال ذلك الوقت ، يجب أن ينتظر كود الوحدة تنفيذ الطلب ولا يفعل شيئًا آخر. لقد قمنا بحل هذه المشكلة عن طريق إنشاء مؤشر ترابط يتعامل مع الطلبات ويخزن المتغير في الخيط الرئيسي.

للبدء ، يجب أن نقوم بتضمين مكتبة الخيوط بإضافة ؛

باستخدام System. Threading.

بعد ذلك ، نقوم بإعداد الوظيفة التي بدأناها في المواضيع. يبدأ AsynchronousReadFromArduino بكتابة الطلب إلى Arduino باستخدام وظيفة WrtieToArduino. يتم تضمين القراءة في كتلة try-catch ، إذا انتهت مهلة القراءة ، تظل المتغيرات فارغة ويتم استدعاء وظيفة OnArduinoInfoFail بدلاً من OnArduinoInfoReceive.

بعد ذلك نحدد وظائف OnArduinoInfoFail و OnArduinoInfoReceive. بالنسبة لهذا التوجيه ، نقوم بطباعة النتائج على وحدة التحكم ولكن يمكنك تخزين النتائج في المتغيرات التي تحتاجها لمشروعك.

باطل خاص OnArduinoInfoFail ()

{Debug. Log ("فشلت القراءة") ؛ } الفراغ الخاص OnArduinoInfoReceived (دوران السلسلة ، سرعة السلسلة) {Debug. Log ("Readin Sucessfull")؛ Debug. Log ("القيمة الأولى:" + تدوير) ؛ Debug. Log ("القيمة الثانية:" + السرعة) ؛ }

الخطوة الأخيرة هي بدء وإيقاف الخيوط التي ستطلب القيم من Arduino. يجب أن نتأكد من أن آخر سلسلة رسائل قد تم إنجازها مع آخر مهمة لها قبل البدء في سلسلة جديدة. خلاف ذلك ، يمكن إجراء طلبات متعددة إلى Arduino في وقت واحد مما قد يربك Arduino / Unity ويسفر عن نتائج غير متوقعة.

مؤشر ترابط خاص activeThread = فارغ ؛

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

إذا قارنت أداء الكود بالأداء الذي كتبناه في القسم 5 ، فيجب تحسين الأداء بشكل ملحوظ.

باطل خاص OnArduinoInfoFail ()

{Debug. Log ("فشلت القراءة") ؛ }

الخطوة الخامسة: أين بعد ذلك؟

حيث المقبل؟
حيث المقبل؟

لقد أعددنا عرضًا توضيحيًا يمكنك تنزيله على Github الخاص بنا (https://github.com/AlexandreDoucet/InfinityBike) ، وقم بتنزيل الكود واللعبة وركوب مسارنا. تم إعداد كل شيء من أجل تمرين سريع ونأمل أن يمنحك طعمًا لما يمكنك بناءه إذا استخدمت ما علمناه لك بهذه التعليمات.

الاعتمادات

المساهمون في المشروع

الكسندر دوسيه (_Doucet_)

Maxime Boudreau (MxBoud)

مصادر خارجية [محرك ألعاب الوحدة] (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)

موصى به: