Съдържание:

Infinity Bike - Видео игра за обучение на велосипеди на закрито: 5 стъпки
Infinity Bike - Видео игра за обучение на велосипеди на закрито: 5 стъпки

Видео: Infinity Bike - Видео игра за обучение на велосипеди на закрито: 5 стъпки

Видео: Infinity Bike - Видео игра за обучение на велосипеди на закрито: 5 стъпки
Видео: Беслан. Помни / Beslan. Remember (english & español subs) 2024, Септември
Anonim
Image
Image
Материали
Материали

През зимните сезони, студените дни и лошото време, ентусиастите на колоездачи имат само няколко възможности да упражняват любимия си спорт. Търсехме начин да направим тренировките на закрито с настройка на велосипед/треньор малко по -забавни, но повечето налични продукти са или скъпи, или просто скучни за използване. Ето защо започнахме да разработваме Infinity Bike като тренировъчна видео игра с отворен код. Infinity bike чете скоростта и посоката от вашия велосипед и предлага ниво на интерактивност, което не може лесно да се намери с обучители за велосипеди.

Ние се възползваме от простотата, достъпна от микроконтролера Arduino и няколко 3D отпечатани части, за да закрепим евтини сензори към велосипед, монтиран на обувка. Информацията се предава към видео игра, направена с популярния двигател за създаване на игри Unity. До края на тази инструкция трябва да можете да настроите свои собствени сензори на вашия мотор и да прехвърлите информацията за вашите сензори към Unity. Дори включихме писта, по която можете да карате и да тествате новата си настройка. Ако се интересувате от принос, можете да разгледате нашия GitHub.

Стъпка 1: Материали

Материали
Материали

Списъкът с материали, от който се нуждаете, може да варира малко; за

например размерът на вашия велосипед ще диктува дължините на джъмперните кабели, от които се нуждаете, но ето основните части, от които ще се нуждаете. Вероятно бихте могли да намерите по -евтини цени за всяко парче на уебсайта като AliExpress, но чакането 6 месеца за доставка не винаги е опция, затова използвахме малко по -скъпите части, така че оценката да не се изкриви.

1 x Arduino nano ($ 22.00)

1 x Mini Breadboard ($ 1,33/единица)

1 x 220 ома резистор ($ 1,00/комплект)

1 x 10K потенциометър ($ 1,80/единица)

1 х сензор на Хол ($ 0,96)

20 cm x 6 mm колан за зъбен 3D принтер ($ 3.33)

1 комплект x винтове и болтове с различна дължина M3 ($ 6.82)

1 x магнит за скоростомер на велосипед ($ 0,98)

Монтирахме материала по -горе с 3D отпечатани части. Файловете, които използвахме, са изброени по -долу и са номерирани със същата конвенция като изображението в началото на този раздел. Всички файлове могат да бъдат намерени в 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

Стъпка 2: Четене и прехвърляне на данни към Unity

Четене и прехвърляне на данни към Unity
Четене и прехвърляне на данни към Unity

Кодът Arduino и Unity ще работят заедно за събиране, прехвърляне и обработка на данните от сензорите на мотора. Unity ще поиска стойността от Arduino, като изпрати низ през сериала и ще изчака Arduino да отговори със заявените стойности.

Първо, ние подготвяме Arduino с библиотечна серийна команда, която се използва за управление на заявките от Unity чрез сдвояване на низ за заявка с функция. Основната настройка за тази библиотека може да бъде направена, както следва;

#include "SerialCommand.h"

SerialCommand sCmd; void setup () {sCmd.addCommand ("TRIGG", TriggHanlder); Serial.begin (9600); } void loop () {while (Serial.available ()> 0) {sCmd.readSerial (); }} void TriggHandler () { /*Прочетете и предайте сензорите тук* /}

Функцията TriggHandler е прикрепена към обекта SCmd. Ако сериалът получи низ, който съответства на приложената команда (в този случай TRIGG), се изпълнява функцията TriggHandler.

Използваме потенциометър за измерване на посоката на кормилното управление и сензор на залата за измерване на въртенето в минута на велосипеда. Показанията от потенциометъра могат лесно да бъдат направени с помощта на вградените функции от Arduino. След това функцията TriggHandler може да отпечата стойността в сериала със следната промяна.

void TriggHandler () {

/*Отчитане на стойността на потенциометъра*/ Serial.println (analogRead (ANALOGPIN)); }

Сензорът на Хол има малко повече настройка, преди да можем да имаме полезни измервания. Противно на потенциометъра, моментната стойност на сензора на залите не е много полезна. Тъй като се опитваха да измерват скоростта на колелото, времето между спусъците е това, което се интересува.

Всяка функция, използвана в кода на Arduino, отнема време и ако магнитът се подреди с датчика на Хол в неподходящо време, измерването може да бъде забавено в най -добрия случай или напълно пропуснато в най -лошия. Това очевидно е лошо, защото Arduino може да отчете скорост, която е МНОГО различна от действителната скорост на колелото.

За да избегнем това, използваме функция на Arduinos, наречена прикачване на прекъсване, която ни позволява да задействаме функция винаги, когато се задейства определен цифров щифт с нарастващ сигнал. Функцията rpm_fun е прикрепена към прекъсване с един ред код, добавен към кода за настройка.

void setup () {

sCmd.addCommand ("TRIGG", TriggHanlder); attachInterrupt (0, rpm_fun, RISING); Serial.begin (9600); } // Функцията rpm_fun се използва за изчисляване на скоростта и се дефинира като; unsigned long lastRevolTime = 0; unsigned long revolSpeed = 0; void rpm_fun () {unsigned long revolTime = millis (); unsigned long deltaTime = revolTime - lastRevolTime; /*revolSpeed е стойността, предадена на кода на Arduino* / revolSpeed = 20000 / deltaTime; lastRevolTime = revolTime; } TriggHandler може да предава останалата информация, когато бъде поискана. void TriggHanlder () { /*Четене на стойността на потенциометъра* / Serial.println (analogRead (ANALOGPIN)); Serial.println (revolSpeed); }

Вече имаме всички градивни елементи, които могат да се използват за изграждане на кода на Arduino, който ще прехвърля данни през серийния код, когато се направи заявка от Unity. Ако искате да имате копие от пълния код, можете да го изтеглите на нашия GitHub. За да проверите дали кодът е настроен правилно, можете да използвате серийния монитор за изпращане на TRIGG; уверете се, че сте задали реда, завършващ на Carriage return. Следващият раздел ще се фокусира върху това как нашите Unity скриптове могат да изискват и получават информацията от Arduino.

Стъпка 3: Получаване и обработка на данни

Получаване и обработка на данни
Получаване и обработка на данни

Unity е страхотен софтуер, достъпен безплатно за любители

проявява интерес към създаването на игри; той идва с голям брой функционалности, които наистина могат да намалят времето за настройка на някои неща, като например нишки или програмиране на GPU (AKA засенчване), без да ограничават какво може да се направи с C# скриптовете. Микроконтролерите Unity и Arduino могат да се използват заедно за създаване на уникални интерактивни преживявания със сравнително малък бюджет.

Фокусът на тази инструкция е да помогне за установяване на комуникацията между Unity и Arduino, така че да не се гмурнем твърде дълбоко в повечето функции, налични с Unity. Има много страхотни уроци за единство и невероятна общност, които биха могли да свършат много по -добра работа, обяснявайки как работи Unity. Има обаче специална награда за тези, които успеят да проправят път през тази инструкция, която служи като малка демонстрация на това, което може да се направи. Можете да изтеглите на нашия Github първия ни опит да направите песен с реалистична физика на велосипедите.

Първо, нека преминем през минималния минимум, който трябва да се направи, за да комуникираме с Arduino чрез сериала. Бързо ще стане ясно, че този код не е подходящ за игра, но е добре да преминете през всяка стъпка и да научите какви са ограниченията.

В Unity създайте нова сцена с един празен GameObject на име ArduinoReceive при прикачване на C# скрипт, също наречен ArduinoReceive. Този скрипт е мястото, където ще добавим целия код, който обработва комуникацията с Arduino.

Има библиотека, която трябва да има достъп, преди да можем да комуникираме със серийните портове на вашия компютър; Unity трябва да бъде настроен, за да позволи използването на определени библиотеки. Отидете на Редактиране-> ProjectSerring-> Плейър и до нивото на съвместимост на Api под превключвателя за конфигурация. Подмножество. NET 2.0 до. NET 2.0. Сега добавете следния код в горната част на скрипта;

използване на System. IO. Ports;

Това ще ви позволи достъп до класа SerialPort, който можете да определите като обект към класа ArduinoReceive. Направете го частно, за да избегнете смущения от друг скрипт.

частен SerialPort arduinoPort;

Обектът arduinoPort може да бъде отворен, като изберете правилния порт (например в кой USB е свързан Arduino) и скорост на предаване (т.е. скоростта, с която се изпраща информацията). Ако не сте сигурни в кой порт е включен Arduino, можете да разберете или в мениджъра на устройства, или като отворите Arduino IDE. За скоростта на предаване, стойността по подразбиране на повечето устройства е 9600, просто се уверете, че имате тази стойност във вашия код на Arduino и тя трябва да работи.

Сега кодът трябва да изглежда така;

използване на System. Collections;

използване на System. Collections. Generic; използване на UnityEngine; използване на System. IO. Ports; публичен клас ArduinoReceive: MonoBehaviour {private SerialPort arduinoPort; // Използвайте това за инициализация void Start () {arduinoPort = new SerialPort ("COM5", 9600); arduinoPort. Open (); WriteToArduino ("TRIGG"); }}

Вашият COM номер най -вероятно ще бъде различен. Ако сте на MAC, вашето COM име може да има име, което изглежда така /dev/cu.wchusbserial1420. Уверете се, че кодът от раздел 4 е качен в Arduino и серийният монитор е затворен за останалата част от този раздел и че този код се компилира без проблем.

Нека сега изпратим заявка до всеки кадър на Arduino и да запишем резултатите в прозореца на конзолата. Добавете функцията WriteToArduino към класа ArduinoReceive. Връщането на каретката и новият ред са необходими, за да може кодът Arduino да анализира правилно входящата инструкция.

private void WriteToArduino (низово съобщение)

{message = message + "\ r / n"; arduinoPort. Write (съобщение); arduinoPort. BaseStream. Flush (); }

След това тази функция може да бъде извикана в цикъла за актуализиране.

void Update ()

{WriteToArduino ("TRIGG"); Debug. Log ("Първа стойност:" + arduinoPort. ReadLine ()); Debug. Log ("Втора стойност:" + arduinoPort. ReadLine ()); }

Горният код е минимумът, от който се нуждаете, за да прочетете данните от Arduino. Ако обърнете голямо внимание на FPS, дадени от единство, трябва да видите значителен спад в производителността. В моя случай той преминава от около 90 FPS без четене/писане до 20 FPS. Ако вашият проект не изисква чести актуализации, може да е достатъчен, но за видео игра 20 FPS е твърде ниско. Следващият раздел ще обхваща как можете да подобрите производителността, като използвате мулти нишки.

Стъпка 4: Оптимизиране на трансфера на данни

Предишният раздел обхваща как да настроите основното

комуникация между програмата Arduino и Unity. Основният проблем с този код е производителността. В текущата си реализация Unity трябва да изчака Arduino да получи, обработи и отговори на искането. През това време кодът на Unity трябва да изчака изпълнението на заявката и не прави нищо друго. Решихме този проблем, като създадохме нишка, която да обработва заявките и да съхранява променливата в основната нишка.

За да започнем, трябва да включим библиотеката с нишки, като добавим;

използване на System. Threading;

След това настройваме функцията, която стартираме в нишките. AsynchronousReadFromArduino започва с писане на заявката към Arduino с функцията WrtieToArduino. Четенето е затворено в блок за опит за улов, ако изчакването за четене променливите остават нулеви и се извиква функцията OnArduinoInfoFail вместо OnArduinoInfoReceive.

След това определяме функциите OnArduinoInfoFail и OnArduinoInfoReceive. За тази инструкция ние отпечатваме резултатите в конзолата, но можете да съхранявате резултатите в променливите, от които се нуждаете за вашия проект.

private void OnArduinoInfoFail ()

{Debug. Log ("Четенето е неуспешно"); } private void OnArduinoInfoReceived (въртене на низ, скорост на низ) {Debug. Log ("Четене успешно"); Debug. Log ("Първа стойност:" + завъртане); Debug. Log ("Втора стойност:" + скорост); }

Последната стъпка е да стартирате и спрете нишките, които ще изискват стойностите от Arduino. Трябва да се уверим, че последната нишка е изпълнена с последната си задача, преди да започнем нова. В противен случай към Arduino могат да бъдат направени множество заявки едновременно, което може да обърка Arduino/Unity и да доведе до непредсказуеми резултати.

частна нишка activeThread = null;

void Update () {if (activeThread == null ||! activeThread. IsAlive) {activeThread = нова нишка (AsynchronousReadFromArduino); activeThread. Start (); }}

Ако сравните ефективността на кода с тази, която написахме в раздел 5, производителността трябва да бъде значително подобрена.

private void OnArduinoInfoFail ()

{Debug. Log ("Четенето е неуспешно"); }

Стъпка 5: Къде по -нататък?

Къде по -нататък?
Къде по -нататък?

Подготвихме демонстрация, която можете да изтеглите на нашия Github (https://github.com/AlexandreDoucet/InfinityBike), да изтеглите кода и играта и да се разходите по нашата писта. Всичко е настроено за бърза тренировка и се надяваме, че може да ви даде представа какво бихте могли да изградите, ако използвате това, което ви научихме с тази инструкция.

Кредити

Участници в проекта

Александър Дъсет (_Doucet_)

Максим Будро (MxBoud)

Външни ресурси [The Unity game engine] (https://unity3d.com)

Този проект започна, след като прочетохме урока на Алън Зукони „как да интегрираме Arduino с Unity“(https://www.alanzucconi.com/2015/10/07/how-to-int…)

Искането от Arduino се обработва с помощта на библиотеката SerialCommand (https://github.com/kroimon/Arduino-SerialCommand)

Препоръчано: