תוכן עניינים:

אופני אינפיניטי - משחק וידאו לאימון אופניים בתוך הבית: 5 שלבים
אופני אינפיניטי - משחק וידאו לאימון אופניים בתוך הבית: 5 שלבים

וִידֵאוֹ: אופני אינפיניטי - משחק וידאו לאימון אופניים בתוך הבית: 5 שלבים

וִידֵאוֹ: אופני אינפיניטי - משחק וידאו לאימון אופניים בתוך הבית: 5 שלבים
וִידֵאוֹ: לטייל בארץ ישראל - הילוך מהיר דרך פארק הירקון 2024, יוני
Anonim
Image
Image
חומרים
חומרים

במהלך עונות החורף, הימים הקרים ומזג האוויר הגרוע, לחובבי רוכבי האופניים יש רק כמה אופציות להתעמל בספורט האהוב עליהם. חיפשנו דרך להפוך את האימון הפנימי עם הגדרת אופניים/מאמנים למבדר קצת יותר, אך רוב המוצרים הקיימים הם יקרים או פשוט משעממים לשימוש. זו הסיבה שהתחלנו לפתח את Infinity Bike כמשחק וידאו לאימון קוד פתוח. אופני אינפיניטי קוראים את המהירות והכיוון מהאופניים שלך ומציעים רמת אינטראקטיביות שלא ניתן למצוא בקלות עם מאמני אופניים.

אנו מנצלים את הפשטות הזמינה ממיקרו -בקר Arduino וכמה חלקים מודפסים בתלת -ממד כדי לאבטח חיישנים זולים לאופניים המותקנים על מאמן. המידע מועבר למשחק וידיאו שנעשה בעזרת מנוע ייצור המשחקים הפופולרי, אחדות. בסוף ההנחיה הזו, אתה אמור להיות מסוגל להגדיר חיישנים משלך על האופניים שלך ולהעביר את המידע של החיישנים שלך ליחידות. אפילו כללנו מסלול שעליו תוכל לרכב ולבדוק את המערך החדש שלך. אם אתה מעוניין לתרום תוכל לבדוק את GitHub שלנו.

שלב 1: חומרים

חומרים
חומרים

רשימת החומרים שתזדקק להם עשויה להשתנות מעט; ל

לדוגמה, גודל האופניים שלך יכתיב את אורכי כבלי המגשר שאתה צריך, אך להלן החלקים העיקריים שתזדקק להם. סביר להניח שתוכל למצוא מחירים זולים יותר עבור כל פריט באתר כמו AliExpress, אך המתנה של 6 חודשים למשלוח היא לא תמיד אופציה ולכן השימוש בחלקים מעט יותר יקרים כך שההערכה לא מוטה.

1 x ארדואינו ננו ($ 22.00)

1 x לוח קרש מיני (1.33 $ ליחידה)

1 x 220 אוהם ($ 1.00/ערכה)

1 x 10K פוטנציומטר ($ 1.80 ליחידה)

1 x חיישן אולם ($ 0.96)

חגורת תזמון מדפסת תלת -ממדית 20 ס"מ על 6 מ"מ (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. גלגלת_פוטנציומטר Side.stl

5. Pot_PulleyConnection.stl

6. FrameConnection.stl

7. גלגלת_הנדלבארסייד_הדפסה 2.stl

8. FrameToHallSensorConnector.stl

9. PotHolder.stl

10. HallSensorAttach.stl

שלב 2: קריאה והעברת נתונים לאחדות

קריאה והעברת נתונים לאחדות
קריאה והעברת נתונים לאחדות

קוד Arduino ו- Unity יפעלו יחד לאסוף, להעביר ולעבד את הנתונים מהחיישנים על האופניים. אחדות תבקש את הערך מהארדואינו על ידי שליחת מחרוזת דרך הסידרה ותחכה עד שהארדואינו יגיב עם הערכים המבוקשים.

ראשית, אנו מכינים את ה- Arduino עם הפקודה הסידורי של הספרייה המשמשת לניהול הבקשות מ- Unity על ידי התאמת מחרוזת בקשות לפונקציה. ניתן לבצע התקנה בסיסית לספרייה זו כדלקמן;

#כלול "SerialCommand.h"

SCmd SerialCommand; הגדרת void () {sCmd.addCommand ("TRIGG", TriggHanlder); Serial.begin (9600); } לולאת void () {while (Serial.available ()> 0) {sCmd.readSerial (); }} בטל את TriggHandler () { /*קרא ושדר את החיישנים כאן* /}

הפונקציה TriggHandler מחוברת לאובייקט SCmd. אם הסדרה המקבלת מחרוזת התואמת את הפקודה המצורפת (במקרה זה TRIGG), הפונקציה TriggHandler מבוצעת.

אנו משתמשים בפוטנציומטר למדידת כיוון ההיגוי ובחיישן אולמות למדידת הסיבוב לדקה של האופניים. ניתן לבצע את הקריאות מהפוטנציומטר בקלות באמצעות הפונקציות המובנות מהארדואינו. לאחר מכן הפונקציה TriggHandler יכולה להדפיס את הערך לסדרה בעזרת השינוי הבא.

void TriggHandler () {

/*קריאת ערך הפוטנציומטר*/ Serial.println (analogRead (ANALOGPIN)); }

לחיישן האולם יש קצת יותר הגדרות לפני שנוכל לבצע מדידות שימושיות. בניגוד לפוטנציומטר, הערך המיידי של חיישן האולמות אינו שימושי במיוחד. מכיוון שניסו למדוד את מהירות הגלגל, הזמן בין הטריגרים הוא מה שהתעניין.

כל פונקציה המשמשת את קוד הארדואינו לוקחת זמן ואם המגנט מסתדר עם חיישן האולם בזמן הלא נכון המדידה עלולה להתעכב במקרה הטוב או לדלג לגמרי במקרה הגרוע. ברור שזה רע מכיוון שהארדואינו יכול לדווח על מהירות שהיא שונה בהרבה ממהירות הגלגל בפועל.

כדי להימנע מכך, אנו משתמשים בתכונה של Arduinos הנקראת attach interrupt המאפשרת לנו להפעיל פונקציה בכל פעם שהסיכה הדיגיטלית המיועדת מופעלת עם אות עולה. הפונקציה rpm_fun מחוברת להפסקה כאשר שורה אחת של קוד מתווספת לקוד ההתקנה.

הגדרת בטל () {

sCmd.addCommand ("TRIGG", TriggHanlder); attachInterrupt (0, rpm_fun, RISING); Serial.begin (9600); } // הפונקציה rpm_fun משמשת לחישוב המהירות ומוגדרת כ; unsigned long lastRevolTime = 0; revolSpeed ארוך ללא סימן 0; void rpm_fun () {revoltime long unsigned sign = millis (); deltaTime ארוך ללא סימן = revolTime - lastRevolTime; /*revolSpeed הוא הערך המועבר לקוד הארדואינו* / revolSpeed = 20000 / deltaTime; lastRevolTime = revolTime; } לאחר מכן TriggHandler יכול להעביר את שאר המידע כאשר תתבקש. void TriggHanlder () { /*קריאת ערך הפוטנציומטר* / Serial.println (analogRead (ANALOGPIN)); Serial.println (revolSpeed); }

כעת יש לנו את כל אבני הבניין שניתן להשתמש בהן לבניית קוד הארדואינו שיעביר נתונים דרך הסידרה עד לבקשה של יוניטי. אם אתה רוצה לקבל עותק של הקוד המלא, תוכל להוריד אותו מה- GitHub שלנו. כדי לבדוק אם הקוד הוגדר כראוי, תוכל להשתמש במסך הטורי כדי לשלוח TRIGG; הקפד להגדיר את השורה המסתיימת להחזרת עגלה. החלק הבא יתמקד כיצד סקריפטים של אחדות שלנו יכולים לבקש ולקבל את המידע מהארדואינו.

שלב 3: קבלת ועיבוד נתונים

קבלת ועיבוד נתונים
קבלת ועיבוד נתונים

אחדות היא תוכנה מצוינת הזמינה בחינם לחובבנים

מעוניין בייצור משחקים; הוא מגיע עם מספר רב של פונקציות שיכולות באמת לקצר את הזמן בהגדרת דברים מסוימים כגון שרשור או תכנות GPU (הצללה AKA) מבלי להגביל את מה שניתן לעשות עם סקריפטים של C#. ניתן להשתמש ביחד עם מיקרו -בקרי Unity ו Arduino ליצירת חוויות אינטראקטיביות ייחודיות עם תקציב קטן יחסית.

מוקד ההנחיה הוא לסייע בהתקנת התקשורת בין אחדות לבין הארדואינו, כך שלא נצלול עמוק מדי ברוב התכונות הזמינות עם אחדות. יש הרבה הדרכות נהדרות לאחדות וקהילה מדהימה שיכולה לעשות עבודה טובה בהרבה להסביר כיצד פועלת אחדות. עם זאת, יש פרס מיוחד למי שמצליח להתקדם דרך ההנחיה הזו המשמשת חלון ראווה קטן של מה שאפשר לעשות. אתה יכול להוריד ב- Github שלנו את הניסיון הראשון שלנו לעשות מסלול עם פיזיקת אופניים ריאליסטית.

ראשית, נעבור על המינימום הגרוע שצריך לעשות כדי לתקשר עם ארדואינו דרך הסדרה. מהר יתברר שקוד זה אינו מתאים למשחקיות אך טוב לעבור כל שלב וללמוד מהן המגבלות.

באחדות, צור סצנה חדשה עם GameObject ריק ריק בשם ArduinoReceive בצירוף תסריט C# הנקרא גם ArduinoReceive. סקריפט זה הוא המקום בו נוסיף את כל הקוד המטפל בתקשורת עם הארדואינו.

יש ספרייה שחייבת להיות גישה לפני שנוכל לתקשר עם היציאות הטוריות של המחשב שלך; יש להגדיר אחדות כדי לאפשר שימוש בספריות מסוימות. עבור אל Edit-> ProjectSerring-> Player ולצד רמת תאימות ה- Api תחת מתג התצורה. NET 2.0 תת-קבוצה ל-. NET 2.0. כעת הוסף את הקוד הבא בראש התסריט;

שימוש ב- System. IO. Ports;

זה יאפשר לך לגשת למחלקת SerialPort שתוכל להגדיר כאובייקט למחלקת ArduinoReceive. הפוך את זה לפרטי כדי להימנע מהפרעות מתסריט אחר.

arduinoPort פרטי SerialPort;

ניתן לפתוח את האובייקט arduinoPort על ידי בחירת היציאה הנכונה (למשל שבה USB ה- Arduino מחובר) וקצב שידור (כלומר המהירות שבה נשלח המידע). אם אינך בטוח באיזה יציאה מחובר הארדואינו תוכל לברר זאת במנהל ההתקנים או על ידי פתיחת ה- Arduino IDE. לגבי קצב השידור, ערך ברירת המחדל ברוב המכשירים הוא 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. החזרת הכרכרה והקו החדש נחוצים לקוד הארדואינו כדי לנתח את ההוראה הנכנסת כראוי.

חלל פרטי WriteToArduino (הודעת מחרוזת)

{message = message + "\ r / n"; arduinoPort. Write (הודעה); arduinoPort. BaseStream. Flush (); }

לאחר מכן ניתן לקרוא לפונקציה זו בלולאת העדכון.

עדכון בטל ()

{WriteToArduino ("TRIGG"); Debug. Log ("ערך ראשון:" + arduinoPort. ReadLine ()); Debug. Log ("ערך שני:" + arduinoPort. ReadLine ()); }

הקוד לעיל הוא המינימום הדרוש לך כדי לקרוא את הנתונים מארדואינו. אם אתה מקדיש תשומת לב רבה ל- FPS הניתן על ידי האחדות, אתה אמור לראות ירידה משמעותית בביצועים. במקרה שלי, זה עובר מסביבות 90 FPS ללא קריאה/כתיבה ל- 20 FPS. אם הפרויקט שלך אינו דורש עדכונים תכופים זה עשוי להספיק, אך למשחק וידאו 20 FPS הוא נמוך מדי. הסעיף הבא יעסוק כיצד תוכל לשפר את הביצועים באמצעות ריבוי שרשורים.

שלב 4: ייעול העברת נתונים

הסעיף הקודם סקר כיצד להגדיר בסיסי

תקשורת בין התוכנית Arduino ו- Unity. הבעיה העיקרית בקוד זה היא הביצועים. ביישום הנוכחי שלה, על אחדות לחכות עד שהארדואינו יקבל, יעבד ויענה לבקשה. במהלך הזמן הזה, קוד האחדות צריך לחכות לביצוע הבקשה ואינו עושה דבר אחר. פתרנו בעיה זו על ידי יצירת שרשור שיטפל בבקשות ויאחסן את המשתנה בשרשור הראשי.

כדי להתחיל, עלינו לכלול את ספריית השרשור על ידי הוספת;

שימוש ב- System. Threading;

לאחר מכן, אנו מגדירים את הפונקציה שאנו מתחילים בשרשורים. AsynchronousReadFromArduino מתחיל בכתיבת הבקשה ל- Arduino עם הפונקציה WrtieToArduino. הקריאה סגורה בגוש נסה לתפוס, אם פסק הזמן לקריאה, המשתנים נשארים בטלים והפונקציה OnArduinoInfoFail נקראת במקום OnArduinoInfoReceive.

בשלב הבא אנו מגדירים את הפונקציות OnArduinoInfoFail ו- OnArduinoInfoReceive. לצורך הוראה זו, אנו מדפיסים את התוצאות לקונסולה אך תוכל לאחסן את התוצאות במשתנים הדרושים לפרויקט שלך.

חלל פרטי OnArduinoInfoFail ()

{Debug. Log ("הקריאה נכשלה"); } חלל פרטי OnArduinoInfoReceived (סיבוב מחרוזת, מהירות מחרוזת) {Debug. Log ("Readin Sucessfull"); Debug. Log ("ערך ראשון:" + סיבוב); Debug. Log ("ערך שני:" + מהירות); }

השלב האחרון הוא להתחיל ולעצור את החוטים שיבקשו את הערכים מהארדואינו. עלינו לוודא שהשרשור האחרון מבוצע עם המשימה האחרונה שלו לפני שנפתח אחד חדש. אחרת, ניתן היה לבצע בקשות מרובות ל- Arduino בו זמנית, מה שעלול לבלבל את Arduino/Unity ולהניב תוצאות בלתי צפויות.

שרשור פרטי activeThread = null;

עדכון חלל () {if (activeThread == null ||! activeThread. IsAlive) {activeThread = שרשור חדש (AsynchronousReadFromArduino); activeThread. Start (); }}

אם משווים את ביצועי הקוד לאחד שכתבנו בחלק 5, יש לשפר את הביצועים באופן משמעותי.

חלל פרטי OnArduinoInfoFail ()

{Debug. Log ("הקריאה נכשלה"); }

שלב 5: איפה הלאה?

איפה הלאה?
איפה הלאה?

הכנו הדגמה שתוכל להוריד ב- Github שלנו (https://github.com/AlexandreDoucet/InfinityBike), להוריד את הקוד ואת המשחק ולרכוב במסלול שלנו. הכל מוכן לאימון מהיר ואנו מקווים שזה יכול לתת לך טעימה ממה שאתה יכול לבנות אם תשתמש במה שלימדנו אותך בעזרת ההנחיה הזו.

נקודות זכות

תורמי הפרויקט

אלכסנדר דואט (_דואט_)

מקסים בודראו (MxBoud)

מקורות חיצוניים [מנוע המשחק Unity] (https://unity3d.com)

פרויקט זה התחיל לאחר שקראנו את הדרכתו של אלן צוקוני "כיצד לשלב את ארדואינו עם אחדות" (https://www.alanzucconi.com/2015/10/07/how-to-int…)

הבקשה מהארדואינו מטופלת באמצעות ספריית SerialCommand (https://github.com/kroimon/Arduino-SerialCommand)

מוּמלָץ: