Բովանդակություն:

Infinity Bike - Indoors Bike Training Video Game: 5 Քայլ
Infinity Bike - Indoors Bike Training Video Game: 5 Քայլ

Video: Infinity Bike - Indoors Bike Training Video Game: 5 Քայլ

Video: Infinity Bike - Indoors Bike Training Video Game: 5 Քայլ
Video: Infinity Bike - Indoors bike training video game 2024, Նոյեմբեր
Anonim
Image
Image
Նյութեր
Նյութեր

Ձմռան սեզոնների, ցուրտ օրերի և վատ եղանակի ժամանակ հեծանվորդների սիրահարներն ունեն ընդամենը մի քանի տարբերակ `զբաղվելու իրենց սիրած մարզաձևով: Մենք հնարք էինք փնտրում հեծանիվ/մարզիչ պարապմունքներով փակ մարզումները մի փոքր ավելի զվարճալի դարձնելու համար, սակայն առկա արտադրանքի մեծ մասը կամ ծախսատար են, կամ ուղղակի ձանձրալի: Ահա թե ինչու մենք սկսեցինք զարգացնել Infinity Bike- ը որպես Բաց կոդով ուսուցողական տեսախաղ: Infinity հեծանիվը կարդում է ձեր հեծանիվի արագությունն ու ուղղությունը և առաջարկում է ինտերակտիվության այնպիսի մակարդակ, որը հեշտությամբ չի կարելի գտնել հեծանիվ վարժեցնողների մոտ:

Մենք օգտվում ենք Arduino միկրոկառավարիչից և 3D տպված մի քանի մասերից առկա պարզությունից `մարզիչի վրա տեղադրված հեծանիվին էժան տվիչներ ապահովելու համար: Տեղեկատվությունը փոխանցվում է տեսախաղին, որը պատրաստված է հանրաճանաչ խաղերի ստեղծման շարժիչով ՝ Unity: Այս հրահանգի ավարտին դուք պետք է կարողանաք տեղադրել ձեր սեփական տվիչները ձեր հեծանիվի վրա և փոխանցել ձեր տվիչների տվյալները Unity- ին: Մենք նույնիսկ ներառեցինք մի ուղի, որի վրա կարող եք զբոսնել և փորձարկել ձեր նոր կազմվածքը: Եթե դուք հետաքրքրված եք ներդրում կատարելով, կարող եք ստուգել մեր GitHub- ը:

Քայլ 1: Նյութեր

Նյութեր
Նյութեր

Ձեզ անհրաժեշտ նյութերի ցանկը կարող է մի փոքր տարբեր լինել. համար

Օրինակ, ձեր հեծանիվի չափը կթելադրի ձեզ անհրաժեշտ թռիչքային մալուխների երկարությունները, բայց ահա այն հիմնական մասերը, որոնք ձեզ հարկավոր կլինեն: Ամենայն հավանականությամբ, AliExpress- ի պես կայքում կարող եք գտնել ավելի էժան գներ յուրաքանչյուր կտորի համար, բայց առաքման համար 6 ամիս սպասելը միշտ չէ, որ օգտագործվում էր մի փոքր ավելի թանկ մասերի օգտագործմամբ, այնպես որ գնահատումը շեղված չէ:

1 x Arduino նանո ($ 22.00)

1 x Mini Breadboard ($ 1.33/միավոր)

1 x 220 Օմ դիմադրություն ($ 1.00/հավաքածու)

1 x 10K պոտենցիոմետր ($ 1.80/միավոր)

1 x Hall ցուցիչ ($ 0.96)

20 սմ x 6 մմ 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: Տվյալների ընթերցում և փոխանցում միասնության

Տվյալների ընթերցում և փոխանցում միասնության
Տվյալների ընթերցում և փոխանցում միասնության

Arduino- ն և Unity ծածկագիրը միասին կաշխատեն հավաքել, փոխանցել և մշակել տվյալները հեծանիվի սենսորներից: Unity- ն արժեքը կպահանջի Arduino- ից ՝ սերիայի միջոցով տող ուղարկելով և սպասելով, որ Arduino- ն կպատասխանի պահանջվող արժեքներին:

Նախ, մենք պատրաստում ենք Arduino- ն գրադարանի Serial Command- ով, որն օգտագործվում է Unity- ի հարցումները կառավարելու համար ՝ հարցման տողը գործառույթով զուգակցելով: Այս գրադարանի հիմնական կազմաձևումը կարող է կատարվել հետևյալ կերպ.

#ներառել "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 գործառույթը կարող է արժեքը տպել սերիային հետևյալ փոփոխությամբ.

դատարկ TriggHandler () {

/*Կարդում է պոտենցիոմետրի արժեքը*/ Serial.println (analogRead (ANALOGPIN)); }

Մինչև օգտակար չափումներ կատարելը, Hall սենսորը մի փոքր ավելի կարգավորված է: Ի տարբերություն պոտենցիոմետրի, սրահների տվիչի ակնթարթային արժեքը այնքան էլ օգտակար չէ: Քանի որ փորձում էին չափել անիվի արագությունը, ձգանների միջև եղած ժամանակը հետաքրքրում էր:

Arduino ծածկագրում օգտագործվող յուրաքանչյուր գործառույթ ժամանակ է պահանջում, և եթե մագնիսը սխալ պահին համընկնում է Hall սենսորի հետ, չափումը կարող է լավագույն դեպքում հետաձգվել կամ վատագույն դեպքում ամբողջությամբ բաց թողնել: Սա ակնհայտորեն վատ է, քանի որ Arduino- ն կարող է հաղորդել արագության մասին, որը ՇԱՏ տարբեր է անիվի իրական արագությունից:

Խուսափելու համար մենք օգտագործում ենք Arduinos- ի մի գործառույթ, որը կոչվում է կցել ընդհատում, որը թույլ է տալիս մեզ գործարկել գործառույթը, երբ նշանակված թվային քորոցը միանում է բարձրացող ազդանշանի հետ: Rpm_fun ֆունկցիան կցվում է ընդհատմանը `կարգավորման կոդին ավելացված կոդի մեկ տողով:

void setup () {

sCmd.addCommand ("TRIGG", TriggHanlder); attachInterrupt (0, rpm_fun, RISING); Serial.begin (9600); } // rpm_fun գործառույթը օգտագործվում է արագությունը հաշվարկելու համար և սահմանվում է որպես; անստորագիր երկար lastRevolTime = 0; անստորագիր երկար պտույտ արագություն = 0; void rpm_fun () {unsigned long revolTime = millis (); անստորագիր երկար 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- ի հասանելի հատկանիշների մեծ մասի մեջ: Կան միասնության համար մեծ ՄԵAT ձեռնարկներ և անհավատալի համայնք, որոնք կարող են շատ ավելի լավ աշխատանք կատարել ՝ բացատրելով, թե ինչպես է գործում Միասնությունը: Այնուամենայնիվ, կա հատուկ մրցանակ նրանց համար, ովքեր կկարողանան իրենց ճանապարհը տանել այս ուսանելիի միջոցով, որը ծառայում է որպես փոքր ցուցադրություն, թե ինչ կարելի է անել: Մեր Github- ում կարող եք ներբեռնել մեր առաջին փորձը ՝ իրատեսական հեծանիվների ֆիզիկայով ուղի ստեղծելու համար:

Նախ, եկեք անցնենք նվազագույնը, որը պետք է արվի սերիալի միջոցով Arduino- ի հետ հաղորդակցվելու համար: Շուտով պարզ կդառնա, որ այս կոդը հարմար չէ խաղախաղին, բայց լավ է անցնել յուրաքանչյուր քայլի և սովորել, թե ինչ սահմանափակումներ կան:

Unity- ում ստեղծեք նոր տեսարան ArduinoReceive անունով մեկ դատարկ GameObject- ով ՝ կցելով C# սցենար, որը կոչվում է նաև ArduinoReceive: Այս սցենարը այն վայրն է, որտեղ մենք կավելացնենք բոլոր ծածկագրերը, որոնք կարգավորում են Arduino- ի հետ հաղորդակցությունը:

Գոյություն ունի գրադարան, որը պետք է հասանելի լինի ձեր համակարգչի սերիական նավահանգիստների հետ հաղորդակցվելու համար: Պետք է ստեղծվի միասնություն, որը թույլ կտա օգտագործել որոշակի գրադարաններ: Գնացեք Խմբագրել-> ProjectSerring-> Նվագարկիչ և Api Compatibility Level- ի կողքին ՝ Configuration switch. NET 2.0 ենթաբաժին. NET 2.0-ին: Այժմ ավելացրեք հետևյալ ծածկագիրը սցենարի վերևում.

օգտագործելով System. IO. Ports;

Սա թույլ կտա մուտք գործել SerialPort դաս, որը կարող եք սահմանել որպես օբյեկտ ArduinoReceive դասին: Անձնական դարձրեք ՝ այլ սցենարի ցանկացած միջամտությունից խուսափելու համար:

մասնավոր SerialPort arduinoPort;

ArduinoPort օբյեկտը կարող է բացվել ՝ ընտրելով ճիշտ նավահանգիստը (օրինակ ՝ որ USB- ով է միացված Arduino- ն) և բաուդ արագությունը (այսինքն ՝ տեղեկատվության ուղարկման արագությունը): Եթե վստահ չեք, որ Arduino- ն որ պորտին է միացված, կարող եք դա իմանալ կամ սարքի կառավարիչում, կամ բացելով Arduino IDE- ն: Baud փոխարժեքի դեպքում սարքի մեծ մասի կանխադրված արժեքը 9600 է, պարզապես համոզվեք, որ այս արժեքը ունեք ձեր Arduino ծածկագրում և այն պետք է աշխատի:

Այժմ ծածկագիրը պետք է ունենա այս տեսքը.

օգտագործելով System. Collections;

օգտագործելով System. Collections. Generic; օգտագործելով UnityEngine; օգտագործելով System. IO. Ports; հանրային դաս ArduinoReceive: MonoBehaviour {մասնավոր 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 ծածկագրին `մուտքային հրահանգը ճիշտ վերլուծելու համար:

մասնավոր դատարկություն WriteToArduino (լարային հաղորդագրություն)

{հաղորդագրություն = հաղորդագրություն + "\ r / n"; arduinoPort. Write (հաղորդագրություն); arduinoPort. BaseStream. Fush (); }

Այս գործառույթը կարող է կանչվել Update loop- ում:

անվավեր թարմացում ()

{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 գործառույթով: Ընթերցումը ներառված է try-catch բլոկում, եթե ընթերցման ժամանակը սպառվում է, փոփոխականները մնում են անվավեր, իսկ OnArduinoInfoFail գործառույթը կոչվում է OnArduinoInfoReceive- ի փոխարեն:

Հաջորդը մենք սահմանում ենք OnArduinoInfoFail և OnArduinoInfoReceive գործառույթները: Այս ուսանելիի համար մենք արդյունքները տպում ենք վահանակում, բայց դուք կարող եք արդյունքները պահել ձեր նախագծի համար անհրաժեշտ փոփոխականների մեջ:

մասնավոր դատարկ OnArduinoInfoFail ()

{Debug. Log («Ընթերցումը ձախողվեց»); } private void OnArduinoInfoReceived (լարերի պտույտ, լարերի արագություն) {Debug. Log ("Readin Successfull"); Debug. Log ("Առաջին արժեքը." + Պտույտ); Debug. Log («Երկրորդ արժեք.» + Արագություն); }

Վերջին քայլը պետք է սկսել և դադարեցնել այն թեմաները, որոնք արժեքները կպահանջեն Arduino- ից: Մենք պետք է ապահովենք, որ վերջին շարանը կատարվի իր վերջին առաջադրանքով ՝ նորը սկսելուց առաջ: Հակառակ դեպքում, Arduino- ին կարող են միանգամից մի քանի անգամ դիմել, ինչը կարող է շփոթել Arduino/Unity- ին և անկանխատեսելի արդյունքներ տալ:

մասնավոր թեմա activeThread = null;

void Update () {if (activeThread == null ||! activeThread. IsAlive) {activeThread = նոր թեմա (AsynchronousReadFromArduino); activeThread. Start (); }}

Եթե համեմատեք ծածկագրի կատարումը այն բանի հետ, որը մենք գրել ենք 5 -րդ բաժնում, կատարումը պետք է զգալիորեն բարելավվի:

մասնավոր դատարկ OnArduinoInfoFail ()

{Debug. Log («Ընթերցումը ձախողվեց»); }

Քայլ 5: Որտե՞ղ է հաջորդը:

Որտե՞ղ Հաջորդ
Որտե՞ղ Հաջորդ

Մենք պատրաստել ենք դեմո, որը կարող եք ներբեռնել մեր Github- ում (https://github.com/AlexandreDoucet/InfinityBike), ներբեռնել կոդը և խաղը և անցնել մեր ուղու վրայով: Ամեն ինչ պատրաստված է արագ մարզման համար, և մենք հույս ունենք, որ այն կարող է ձեզ համտեսել այն, ինչ կարող եք կառուցել, եթե օգտագործեք այն, ինչ մենք ձեզ սովորեցրել ենք այս ուսանելի:

Վարկեր

Projectրագրի մասնակիցներ

Ալեքսանդր Դոսեթ (_Doucet_)

Մաքսիմ Բոդրո (MxBoud)

Արտաքին ռեսուրսներ [The Unity խաղային շարժիչ] (https://unity3d.com)

Այս նախագիծը սկսվեց այն բանից հետո, երբ կարդացինք Ալան uուկկոնիի «Ինչպես միացնել Arduino- ն միասնության հետ» ձեռնարկը (https://www.alanzucconi.com/2015/10/07/how-to-int…)

Arduino- ի խնդրանքը լուծվում է SerialCommand գրադարանի միջոցով (https://github.com/kroimon/Arduino-SerialCommand)

Խորհուրդ ենք տալիս: