สารบัญ:

Infinity Bike - วิดีโอเกมฝึกปั่นจักรยานในร่ม: 5 ขั้นตอน
Infinity Bike - วิดีโอเกมฝึกปั่นจักรยานในร่ม: 5 ขั้นตอน

วีดีโอ: Infinity Bike - วิดีโอเกมฝึกปั่นจักรยานในร่ม: 5 ขั้นตอน

วีดีโอ: Infinity Bike - วิดีโอเกมฝึกปั่นจักรยานในร่ม: 5 ขั้นตอน
วีดีโอ: ปั่นจักรยานให้ผ่านทั้ง 5 ด่าน | Obby But Your' on a Bike Roblox 2024, กันยายน
Anonim
Image
Image
วัสดุ
วัสดุ

ในช่วงฤดูหนาว วันที่อากาศหนาวเย็น และสภาพอากาศเลวร้าย ผู้ชื่นชอบการปั่นจักรยานมีทางเลือกเพียงไม่กี่ทางในการออกกำลังกายเพื่อเล่นกีฬาที่ชื่นชอบ เรากำลังมองหาวิธีที่จะทำให้การฝึกในร่มด้วยการตั้งค่าจักรยาน/ผู้ฝึกสอนให้สนุกสนานขึ้นเล็กน้อย แต่ผลิตภัณฑ์ส่วนใหญ่ที่มีจำหน่ายนั้นมีราคาแพงหรือใช้งานน่าเบื่อ นี่คือเหตุผลที่เราเริ่มพัฒนา Infinity Bike เป็นวิดีโอเกมฝึกอบรมโอเพ่นซอร์ส จักรยานอินฟินิตี้จะอ่านความเร็วและทิศทางจากจักรยานของคุณและนำเสนอระดับการโต้ตอบที่ครูฝึกจักรยานหาไม่ได้ง่ายๆ

เราใช้ประโยชน์จากความเรียบง่ายที่มีอยู่จากไมโครคอนโทรลเลอร์ Arduino และชิ้นส่วนที่พิมพ์ 3 มิติบางส่วนเพื่อรักษาความปลอดภัยเซ็นเซอร์ราคาไม่แพงให้กับจักรยานที่ติดตั้งบนเทรนเนอร์ ข้อมูลจะถูกส่งไปยังวิดีโอเกมที่สร้างด้วยเครื่องมือสร้างเกมยอดนิยมอย่าง Unity ในตอนท้ายของคำแนะนำนี้ คุณควรจะสามารถตั้งค่าเซ็นเซอร์ของคุณเองบนจักรยานยนต์และถ่ายโอนข้อมูลของเซ็นเซอร์ของคุณไปยัง Unity เรายังรวมแทร็กที่คุณสามารถขี่และทดสอบการตั้งค่าใหม่ของคุณ หากคุณสนใจที่จะมีส่วนร่วม คุณสามารถชำระเงิน GitHub ของเรา

ขั้นตอนที่ 1: วัสดุ

วัสดุ
วัสดุ

รายการวัสดุที่คุณต้องการอาจแตกต่างกันเล็กน้อย สำหรับ

ตัวอย่างเช่น ขนาดของจักรยานของคุณจะกำหนดความยาวของสายจัมเปอร์ที่คุณต้องการ แต่นี่คือส่วนหลักที่คุณต้องการ คุณอาจพบราคาที่ถูกกว่าสำหรับแต่ละชิ้นในเว็บไซต์เช่น AliExpress แต่การรอ 6 เดือนสำหรับการจัดส่งไม่ใช่ตัวเลือกเสมอไป ดังนั้นจึงใช้ชิ้นส่วนที่มีราคาแพงกว่าเล็กน้อยเพื่อให้การประเมินไม่เบ้

1 x Arduino นาโน ($ 22.00)

1 x มินิ เขียงหั่นขนม ($1.33/หน่วย)

ตัวต้านทาน 1 x 220 โอห์ม ($1.00/ชุด)

โพเทนชิออมิเตอร์ 1 x 10K ($ 1.80/หน่วย)

1 x เซ็นเซอร์ Hall ($0.96)

เข็มขัดเวลาเครื่องพิมพ์ 3D ขนาด 20 ซม. x 6 มม. ($3.33)

1 ชุด x สกรูและสลักเกลียว M3 ความยาวต่างๆ ($6.82)

1 x แม่เหล็กวัดความเร็วจักรยาน ($0.98)

เราติดตั้งวัสดุด้านบนด้วยชิ้นส่วนที่พิมพ์ 3 มิติ ไฟล์ที่เราใช้แสดงไว้ด้านล่างและจะมีหมายเลขกำกับแบบเดียวกับภาพที่ตอนต้นของหัวข้อนี้ ไฟล์ทั้งหมดสามารถพบได้ใน 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 ด้วยไลบรารี Serial Command ซึ่งใช้เพื่อจัดการคำขอจาก Unity โดยจับคู่สตริงคำขอกับฟังก์ชัน การตั้งค่าพื้นฐานสำหรับไลบรารีนี้สามารถทำได้ดังนี้

#include "SerialCommand.h"

SerialCommand sCmd; การตั้งค่าเป็นโมฆะ () { sCmd.addCommand ("TRIGG", TriggHanlder); Serial.begin(9600); } วงเป็นโมฆะ () { ในขณะที่ (Serial.available () > 0) { sCmd.readSerial(); } } โมฆะ TriggHandler () { /*อ่านและส่งเซ็นเซอร์ที่นี่*/ }

ฟังก์ชัน TriggHandler แนบมากับวัตถุ SCMd หากซีเรียลได้รับสตริงที่ตรงกับคำสั่งที่แนบมา (ในกรณีนี้คือ TRIGG) ฟังก์ชัน TriggHandler จะถูกดำเนินการ

เราใช้โพเทนชิออมิเตอร์ในการวัดทิศทางการบังคับเลี้ยวและเซ็นเซอร์ฮอลล์เพื่อวัดการหมุนรอบต่อนาทีของจักรยาน สามารถอ่านค่าจากโพเทนชิออมิเตอร์ได้อย่างง่ายดายโดยใช้ฟังก์ชันในตัวจาก Arduino ฟังก์ชัน TriggHandler สามารถพิมพ์ค่าไปยังซีเรียลได้โดยมีการเปลี่ยนแปลงดังต่อไปนี้

เป็นโมฆะ TriggHandler () {

/*การอ่านค่าของโพเทนชิออมิเตอร์*/ Serial.println(analogRead(ANALOGPIN)); }

เซ็นเซอร์ Hall มีการตั้งค่าอีกเล็กน้อยก่อนที่เราจะสามารถวัดผลที่เป็นประโยชน์ได้ ตรงกันข้ามกับโพเทนชิออมิเตอร์ ค่าทันทีของเซ็นเซอร์ฮอลล์ไม่มีประโยชน์มากนัก เนื่องจากพยายามวัดความเร็วของล้อ เวลาระหว่างทริกเกอร์จึงเป็นสิ่งที่สนใจ

ทุกฟังก์ชันที่ใช้ในโค้ด Arduino ต้องใช้เวลา และหากแม่เหล็กเข้าแถวกับเซ็นเซอร์ Hall ในเวลาที่ไม่ถูกต้อง การวัดอาจล่าช้าได้ดีที่สุดหรือข้ามไปอย่างแย่ที่สุด เห็นได้ชัดว่าสิ่งนี้ไม่ดีเพราะ Arduino สามารถรายงานความเร็วที่แตกต่างจากความเร็วจริงของล้อได้มาก

เพื่อหลีกเลี่ยงปัญหานี้ เราใช้คุณลักษณะของ Arduinos ที่เรียกว่าการขัดจังหวะการแนบ ซึ่งช่วยให้เราทริกเกอร์ฟังก์ชันเมื่อใดก็ตามที่พินดิจิทัลที่กำหนดไว้ถูกทริกเกอร์ด้วยสัญญาณที่เพิ่มขึ้น ฟังก์ชัน rpm_fun ติดอยู่กับอินเตอร์รัปต์ด้วยโค้ดบรรทัดเดียวที่เพิ่มลงในโค้ดการตั้งค่า

การตั้งค่าเป็นโมฆะ (){

sCmd.addCommand("TRIGG", TriggHanlder); แนบInterrupt(0, rpm_fun, RISING); Serial.begin(9600); } //ฟังก์ชัน rpm_fun ใช้ในการคำนวณความเร็วและถูกกำหนดเป็น; LastRevolTime แบบยาวที่ไม่ได้ลงนาม = 0; revolSpeed ยาวที่ไม่ได้ลงนาม = 0; เป็นโมฆะ rpm_fun () { revolTime แบบยาวที่ไม่ได้ลงนาม = มิลลิวินาที (); deltaTime แบบยาวที่ไม่ได้ลงนาม = revolTime - lastRevolTime; /*revolSpeed คือค่าที่ส่งไปยังโค้ด Arduino*/ revolSpeed = 20000 / deltaTime; LastRevolTime = เวลาหมุนรอบ; } TriggHandler สามารถส่งข้อมูลที่เหลือเมื่อได้รับการร้องขอ เป็นโมฆะ TriggHanlder () { /* กำลังอ่านค่าของโพเทนชิออมิเตอร์*/ Serial.println (analogRead (ANALOGPIN)); Serial.println(revolSpeed); }

ตอนนี้เรามีหน่วยการสร้างทั้งหมดที่สามารถใช้สร้างโค้ด Arduino ซึ่งจะถ่ายโอนข้อมูลผ่านซีเรียลไปยังเมื่อ Unity ร้องขอ หากคุณต้องการสำเนาโค้ดแบบเต็ม คุณสามารถดาวน์โหลดได้ที่ GitHub ของเรา หากต้องการทดสอบว่าโค้ดได้รับการตั้งค่าอย่างถูกต้องหรือไม่ คุณสามารถใช้จอภาพแบบอนุกรมเพื่อส่ง TRIGG ตรวจสอบให้แน่ใจว่าคุณตั้งค่าบรรทัดสิ้นสุดเป็น Carriage return ส่วนต่อไปจะเน้นว่าสคริปต์ Unity ของเราสามารถขอและรับข้อมูลจาก Arduino ได้อย่างไร

ขั้นตอนที่ 3: การรับและประมวลผลข้อมูล

การรับและประมวลผลข้อมูล
การรับและประมวลผลข้อมูล

Unity เป็นซอฟต์แวร์ที่ยอดเยี่ยมสำหรับมือสมัครเล่นฟรี

สนใจทำเกม; มันมาพร้อมกับฟังก์ชันจำนวนมากที่สามารถลดเวลาในการตั้งค่าบางอย่างได้จริง ๆ เช่น threading หรือการเขียนโปรแกรม GPU (AKA shading) โดยไม่จำกัดสิ่งที่สามารถทำได้ด้วยสคริปต์ C# สามารถใช้ไมโครคอนโทรลเลอร์ Unity และ Arduino ร่วมกันเพื่อสร้างประสบการณ์เชิงโต้ตอบที่ไม่เหมือนใครด้วยงบประมาณที่ค่อนข้างน้อย

จุดเน้นของคำแนะนำนี้คือช่วยตั้งค่าการสื่อสารระหว่าง Unity และ Arduino ดังนั้นเราจึงไม่ต้องเจาะลึกถึงคุณสมบัติส่วนใหญ่ที่มีใน Unity มากเกินไป มีบทช่วยสอนที่ยอดเยี่ยมมากมายสำหรับความสามัคคีและชุมชนที่น่าเหลือเชื่อที่สามารถอธิบายวิธีการทำงานของ Unity ได้ดีขึ้นมาก อย่างไรก็ตาม มีรางวัลพิเศษสำหรับผู้ที่พยายามทำงานผ่านคำแนะนำนี้ ซึ่งทำหน้าที่เป็นตัวแสดงเล็กๆ น้อยๆ เกี่ยวกับสิ่งที่สามารถทำได้ คุณสามารถดาวน์โหลดได้ที่ Github ความพยายามครั้งแรกของเราในการสร้างแทร็กด้วยฟิสิกส์ของจักรยานที่สมจริง

อันดับแรก มาดูขั้นตอนขั้นต่ำที่ต้องทำเพื่อสื่อสารกับ Arduino ผ่านซีเรียลกัน จะเห็นได้อย่างรวดเร็วว่ารหัสนี้ไม่เหมาะกับการเล่นเกม แต่เป็นการดีที่จะผ่านทุกขั้นตอนและเรียนรู้ว่าข้อจำกัดคืออะไร

ใน Unity ให้สร้างฉากใหม่ด้วย GameObject ว่างเดียวชื่อ ArduinoReceive ที่แนบสคริปต์ C# ชื่อ ArduinoReceive สคริปต์นี้เป็นที่ที่เราจะเพิ่มโค้ดทั้งหมดที่จัดการกับการสื่อสารกับ Arduino

มีห้องสมุดที่ต้องเข้าถึงก่อนที่เราจะสามารถสื่อสารกับพอร์ตอนุกรมของคอมพิวเตอร์ของคุณได้ ต้องตั้งค่า Unity เพื่ออนุญาตให้ใช้ไลบรารีบางตัว ไปที่ Edit->ProjectSerring->Player และถัดจากระดับความเข้ากันได้ของ Api ภายใต้การตั้งค่าสวิตช์. NET 2.0 Subset เป็น. NET 2.0 ตอนนี้เพิ่มรหัสต่อไปนี้ที่ด้านบนของสคริปต์

ใช้ System. IO. Ports;

สิ่งนี้จะช่วยให้คุณเข้าถึงคลาส SerialPort ซึ่งคุณสามารถกำหนดเป็นวัตถุสำหรับ ArduinoReceive Class ทำให้เป็นส่วนตัวเพื่อหลีกเลี่ยงการรบกวนจากสคริปต์อื่น

SerialPort arduinoPort ส่วนตัว;

วัตถุ arduinoPort สามารถเปิดได้โดยการเลือกพอร์ตที่ถูกต้อง (เช่น ที่ USB ที่ Arduino เชื่อมต่ออยู่) และอัตราบอด (เช่น ความเร็วในการส่งข้อมูล) หากคุณไม่แน่ใจว่า Arduino เสียบอยู่ในพอร์ตใด คุณสามารถค้นหาได้จากตัวจัดการอุปกรณ์หรือโดยการเปิด Arduino IDE สำหรับอัตราบอด ค่าเริ่มต้นบนอุปกรณ์ส่วนใหญ่คือ 9600 เพียงตรวจสอบให้แน่ใจว่าคุณมีค่านี้ในโค้ด Arduino ของคุณและควรใช้งานได้

ตอนนี้โค้ดควรมีลักษณะดังนี้

ใช้ System. Collections;

ใช้ System. Collections. Generic; ใช้ UnityEngine; ใช้ System. IO. Ports; ArduinoReceive คลาสสาธารณะ: MonoBehaviour { SerialPort arduinoPort ส่วนตัว; // ใช้สำหรับการเริ่มต้นเป็นโมฆะ Start () { arduinoPort = ใหม่ 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. Flush (); }

ฟังก์ชันนี้สามารถเรียกได้ใน 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 ("การอ่านล้มเหลว"); } โมฆะส่วนตัว OnArduinoInfoReceived (การหมุนสตริง ความเร็วสตริง) { Debug. Log ("Readin Sucessfull"); Debug. Log("ค่าแรก:" + การหมุน); Debug. Log("ค่าที่สอง:" + ความเร็ว); }

ขั้นตอนสุดท้ายคือการเริ่มและหยุดเธรดที่จะขอค่าจาก Arduino เราต้องตรวจสอบให้แน่ใจว่าเธรดสุดท้ายเสร็จสิ้นด้วยงานสุดท้ายก่อนที่จะเริ่มใหม่ มิฉะนั้น อาจส่งคำขอหลายรายการไปยัง Arduino ได้ในครั้งเดียว ซึ่งอาจทำให้ Arduino/Unity สับสนและให้ผลลัพธ์ที่คาดเดาไม่ได้

เธรดส่วนตัว activeThread = null;

โมฆะอัปเดต () { ถ้า (activeThread == null || !activeThread. IsAlive) { activeThread = เธรดใหม่ (AsynchronousReadFromArduino); activeThread. Start(); } }

หากคุณเปรียบเทียบประสิทธิภาพของโค้ดกับโค้ดที่เราเขียนไว้ในหัวข้อที่ 5 ประสิทธิภาพควรได้รับการปรับปรุงอย่างมาก

โมฆะส่วนตัว OnArduinoInfoFail()

{ Debug. Log ("การอ่านล้มเหลว"); }

ขั้นตอนที่ 5: ที่ไหนต่อไป?

ที่ไหนต่อไป?
ที่ไหนต่อไป?

เราได้เตรียมการสาธิตที่คุณสามารถดาวน์โหลดได้บน Github ของเรา (https://github.com/AlexandreDoucet/InfinityBike) ดาวน์โหลดโค้ดและเกมแล้วขี่ไปตามเส้นทางของเรา ทุกอย่างพร้อมสำหรับการออกกำลังกายอย่างรวดเร็วและเราหวังว่าสิ่งนี้จะทำให้คุณได้ลิ้มรสของสิ่งที่คุณสามารถสร้างได้หากคุณใช้สิ่งที่เราสอนคุณด้วยคำแนะนำนี้

เครดิต

ผู้ร่วมโครงการ

อเล็กซองเดร ดูเชต์ (_Doucet_)

Maxime Boudreau (MxBoud)

แหล่งข้อมูลภายนอก [เอ็นจิ้นเกม Unity](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)

แนะนำ: