โปรเจกต์ DrumCube หุ่นยนต์ Robot Drummer ที่ใช้ Arduino
หุ่นยนต์ Robot Drummer ที่พัฒนาด้วย Arduino ทำงานโดยใช้ transistor noise-generator ร่วมกับชุดของ servos ที่ใช้ตี can และ piezos หนึ่งคู่
หุ่นยนต์ Robot Drummer ที่พัฒนาด้วย Arduino ทำงานโดยใช้ transistor noise-generator ร่วมกับชุดของ servos ที่ใช้ตี can และ piezos หนึ่งคู่
▶ กดเพื่อดูวิดีโอสาธิตโปรเจกต์
การแสดงดนตรีสดเป็นสิ่งที่พิเศษมากเสมอ แต่ในการสร้างสรรค์มันขึ้นมา คุณจำเป็นต้องใช้คน และคนก็ไม่ได้ว่างอยู่ตลอดเวลา ในบางครั้งผมก็ออกไปแสดงดนตรีโดยมีแค่กีตาร์และเสียงร้องของผม แต่โดยทั่วไปแล้วดนตรีมักจะมีเครื่องดนตรีอื่นๆ อีกหลายชิ้น เช่น เครื่องเคาะ (percussion) และเครื่องดนตรีเหล่านี้มักจะส่งเสียงได้ก็ต่อเมื่อมีคนเล่นเท่านั้น ปัญหานี้อาจแก้ได้ด้วยการใช้เสียงที่บันทึกไว้แล้วเปิดคลอไป แต่นั่นก็ดูจะขัดกับแนวคิดของการแสดง "สด" ไปสักหน่อย
ดังนั้น ผมจึงตัดสินใจตัดปัจจัยเรื่องคนออกไปให้หมด แล้วสร้างหุ่นยนต์มือกลองขึ้นมา... ไอเดียคือการสร้างบางอย่างที่พกพาสะดวก สามารถเคลื่อนที่และเล่นเสียงในจังหวะต่างๆ ได้โดยไม่ต้องใช้ samples หรือเสียงที่บันทึกไว้ สามารถสั่งเล่นหรือหยุดได้ตามต้องการ และเสียงของมันสามารถขยายออกลำโพงเพื่อใช้ในการแสดงสดหรือเล่นร่วมกับวงดนตรีได้
อันดับแรก จำเป็นต้องกำหนดก่อนว่าส่วนประกอบของชุดกลองจะมีอะไรบ้าง ตามตรรกะของช่วงความถี่ (frequency range) ชุดกลองมาตรฐานมักจะประกอบด้วยองค์ประกอบพื้นฐาน 3 อย่าง คือ kick (ย่านความถี่ต่ำ), snare (ย่านความถี่กลาง) และ hi-hat (ย่านความถี่สูง) หลังจากทดลองอยู่สองสามสัปดาห์ ผมตัดสินใจจำลองเสียงเหล่านี้ด้วยการจัดเตรียมดังนี้:
Kick/LowRange: ใช้ piezo 2 ตัว หุ้มด้วยฟองน้ำชิ้นเล็กๆ ซึ่งจะถูกตีโดยไม้ที่ควบคุมด้วย servo และมีปลายสายเป็นยางนุ่มๆ
Snare/MidRange: ใช้กระป๋อง Pringles พร้อมกับแผ่นดีบุกสี่เหลี่ยมเล็กๆ เพื่อให้เกิดการกังวาน ซึ่งจะถูกตีด้วยไม้ที่ควบคุมด้วย servo ที่มีปลายยางเช่นกัน จากนั้นเสียงจะถูกจับด้วย electret microphone
HiHat/HighRange: ใช้ชุดวงจร white noise generator แบบใช้ transistor ซึ่งควบคุมโดยตรงจาก Arduino
ระบบทั้งหมดที่กล่าวมาข้างต้นจะถูกกำหนดจังหวะเวลาโดย Board Arduino และสัญญาณเสียงที่สร้างขึ้นจะถูกขยายให้เป็นสัญญาณระดับเครื่องดนตรี (instrument level) ด้วยวงจรขยายเสียง (amplifier) ง่ายๆ สามชุดสำหรับแต่ละส่วน
ส่วนนี้ทำงานโดยใช้ประโยชน์จากเสียงความถี่ต่ำที่เกิดขึ้นเมื่อ piezo pickup ถูกสัมผัสโดยตรงหรือถูกตีด้วยวัตถุนุ่มๆ เพื่อให้สิ่งนี้ทำงานได้ ขั้นแรกเราต้องทำให้การตี piezo เป็นระบบอัตโนมัติ และขั้นที่สอง เราต้องขยายสัญญาณเสียงที่สร้างจาก piezo นั้น
ตามที่ผมได้กล่าวไปแล้ว ผมใช้ไม้ที่ควบคุมด้วย servo เพื่อตี piezo สองตัวที่วางอยู่ปลายแต่ละด้านของระยะการเคลื่อนที่ของ servo (เพื่อให้ใช้การเคลื่อนที่ได้คุ้มค่าที่สุด) และเพื่อช่วยลดเสียงความถี่สูง piezo จะถูกหุ้มด้วยฟองน้ำและปลายไม้จะมีหัวยางนุ่มๆ

ในจุดนี้ สิ่งสำคัญคือต้องกำหนดมุมที่ servo จะอยู่เมื่อมันตีที่ปลายแต่ละด้านของระยะการเคลื่อนที่ ข้อมูลนี้จะจำเป็นในภายหลัง และสามารถหาได้ง่ายๆ โดยใช้ Code Arduino พื้นฐาน (เหมือนที่อธิบายไว้ที่นี่) และคำสั่ง Serial.print();

สัญญาณเสียงจาก piezo จะถูกขยายโดยวงจรที่อธิบายไว้ในรูปภาพด้านบน โดยใช้ไฟเลี้ยง 5v - 7v จาก voltage regulator ซึ่งรับไฟมาจากแหล่งจ่ายไฟหลัก (ไม่ใช่ Board Arduino) เรื่องนี้สำคัญมาก เพราะแม้ว่าตัว amplifier เองจะสามารถทำงานด้วยไฟ 5v จาก Arduino ได้ แต่มันจะดีกว่าถ้าเราแยกสัญญาณเสียงแบบ analog ออกจากวงจร digital ให้มากที่สุด เพื่อหลีกเลี่ยงสัญญาณรบกวน digital (digital noise) ไม่ให้เข้าไปปะปนในสัญญาณเสียงสุดท้าย
ขอย้ำอีกครั้งว่าผมไม่มีการศึกษาด้านอิเล็กทรอนิกส์อย่างเป็นทางการ (ไม่มีเลยด้วยซ้ำ 555) และผมประสบปัญหาอย่างมากกับเรื่องหลังนี้ สัญญาณรบกวน (noise) นั้นแทบจะเป็นไปไม่ได้เลยที่จะกำจัดให้หมดสิ้นในงานด้านเสียง แต่ผมพบว่าการกรองสัญญาณใน voltage regulator (รวมถึงการแยกส่วน analog และ digital ออกจากกัน และการทำ electrical shielding ของโปรเจกต์อย่างเหมาะสม) ช่วยลด noise ให้อยู่ในระดับที่ยอมรับได้
นี่เป็นเสียงที่จำลองได้ยากมาก แม้แต่ตอนนี้ผมก็ยังไม่พอใจกับเสียงที่ทำได้เต็มร้อยนัก ในการรับเสียงนี้ ผมตัดสินใจใช้ electret microphone เนื่องจากมักจะมีความไว (sensitive) สูงกว่า และธรรมชาติของเสียง snare ที่มีเอกลักษณ์ทำให้จำเป็นต้องใช้อุปกรณ์นี้
เช่นเดียวกับระบบ kick เราต้องการทั้งส่วนกลไกและส่วนเสียง ผมได้แนบภาพวาดของระบบกลไกที่ผมออกแบบไว้ ใช่ครับ ผมใช้กระป๋อง Pringles วางกลับหัว เพราะมันมีรูปร่างที่สมบูรณ์แบบ ให้เสียงที่ดีที่สุดเท่าที่ผมจะหาได้ และมันฝรั่งทอดก็อร่อยมากด้วย


เช่นเดียวกับที่ทำกับ kick เราต้องหามุมที่แต่ละ servo จะอยู่เมื่ออยู่ในตำแหน่งพักและตำแหน่งตี อีกครั้งที่การลองปรับแก้ด้วย Tutorial Potentiometer+Servo จะทำให้เราได้ข้อมูลนั้นมา

สัญญาณเสียงจาก electret จะถูกขยายโดยวงจรเดียวกันกับที่ใช้ใน amplifier ของ kick แม้ว่าในกรณีนี้จะมีการดัดแปลงเล็กน้อยเพื่อจ่ายไฟให้กับ electret microphone และไม่มี low-pass filter เหมือนที่ใช้ใน kick
ผมใช้วิธีที่แตกต่างออกไปสำหรับเสียงนี้ โดยใช้วงจร white noise generator แบบใช้ transistor และมีไฟ led แสดงสถานะ ซึ่งจะถูกเปิดใช้งานโดย Arduino เมื่อต้องการ white noise คือสัญญาณสุ่มที่มีความเข้มเท่ากันในแต่ละช่วงความถี่ พูดง่ายๆ ก็คือ เช่นเดียวกับแสงสีขาวที่มีทุกสีรวมอยู่ white noise ก็มีความถี่ทั้งหมดรวมอยู่ด้วย และมันฟังดูเหมือนสถานีวิทยุที่ไม่มีสัญญาณ (เสียงซ่า) นี่คือ noise ที่มักใช้ในดนตรีอิเล็กทรอนิกส์และการสังเคราะห์เสียง ผมเคยอ่านมาว่ามันถูกใช้เพื่อสร้างเสียงคลาสสิกของ snare และ cymbal ในยุค 80 ด้วยซ้ำ

ตามที่ไดอะแกรมแสดง หลังจากสร้าง noise ขึ้นมาแล้ว มันจะผ่าน high-pass filter เพื่อกำจัดความถี่ที่ไม่ต้องการและเน้นความรู้สึกของฉาบกลอง (cymbal)
วงจร white noise generator ต้องการแรงดันไฟ 12v หรือสูงกว่าเพื่อทำงาน ซึ่งได้มาจาก step up voltage elevator ที่รับไฟโดยตรงจาก Pins ของ Arduino นี่เป็นกรณีเดียวที่ระบบเสียงเชื่อมต่อโดยตรงกับ Arduino เพราะ noise จะต้องถูกสร้างขึ้นในเวลาที่กำหนดเท่านั้น และ noise ดูเหมือนจะไม่เป็นปัญหาในวงจรที่ทำหน้าที่สร้าง noise อยู่แล้ว คุณไม่สามารถทำให้สีขาวมันขาวไปกว่าเดิมได้จริงไหม?
หลังจากสร้างเสียงชุดกลองทั้งสามเสียงแล้ว แต่ละสัญญาณจะผ่าน potentiometer และวงจร passive mixer พื้นฐาน ซึ่งจะผสมเป็นสัญญาณเสียงสุดท้าย

เรายังต้องการวิธีเลือกจังหวะกลองที่จะเล่น รวมถึงเวลาที่จะเริ่มและเลิกเล่น สำหรับ Tutorial นี้ เราจะใช้ tact button และ switch ธรรมดาสำหรับแต่ละหน้าที่ตามลำดับ (เชื่อมต่อกับ Pins ของ Arduino หมายเลข 2 และ 3 ตามที่รูปด้านบนแสดง)

เนื่องจากโปรเจกต์นี้เป็นเครื่องดนตรี มันจึงต้องสร้างเสียงให้ถูกจังหวะเวลา ดังนั้นก่อนที่เราจะเริ่มเขียน Code สำหรับจังหวะและฟังก์ชันต่างๆ โดยเฉพาะในกรณีของ kick และ snare เราต้องโปรแกรมการเคลื่อนที่ของ servo ให้เริ่มก่อนที่จะถึงคิวการเกิดเสียงไม่กี่มิลลิวินาที เพื่อชดเชยเวลาที่ไม้ต้องใช้ในการเคลื่อนที่จากตำแหน่งพักไปยังตำแหน่งตี และทำให้ไม้ตีเป้าหมายได้ทันเวลาพอดี
เพื่อแก้ปัญหานี้ ผมได้คิดค้นระบบง่ายๆ เพื่อวัดเวลาที่ servo แต่ละตัวใช้ในการเคลื่อนที่จากตำแหน่งพักไปยังจุดที่ตีเป้าหมายพอดี ผมหุ้มไม้ตีและพื้นที่ที่ถูกตีด้วยฟอยล์อลูมิเนียม แล้วติด alligator clips เข้ากับฟอยล์ ทำให้เกิดการเชื่อมต่อที่ Arduino สามารถวัดได้เฉพาะเมื่อไม้ตีเป้าหมายเท่านั้น จากนั้นผมก็เขียน Code สั้นๆ ซึ่งทำสองอย่าง: อย่างแรก ให้ไม้ servo ตีเป้าหมายซ้ำๆ โดยเคลื่อนที่จากมุมพักไปยังมุมตี และอย่างที่สอง ให้พิมพ์เวลาที่ส่งคำสั่ง servo ออกมา และเวลาที่ไม้ตีปิดวงจรกับเป้าหมาย การลบค่าทั้งสองนี้จะทำให้เราได้เวลาที่ไม้ใช้ในการสร้างเสียง ตั้งแต่เริ่มพักจนถึงตอนตี

หลังจากทำแบบนี้หลายๆ ครั้ง คุณจะได้ตัวเลขที่ใกล้เคียงกันจำนวนมาก ซึ่งคุณสามารถนำมาหาค่าเฉลี่ย และจะได้เวลาที่ต้องสั่งการล่วงหน้า (anticipation time) ที่ใช้งานได้จริงสำหรับ servo ทุกตัว
ตอนนี้เราจะกำหนดรหัสตัวเลขสำหรับการผสมผสานของ kick, snare และ hihat ในหนึ่งจังหวะ เรากำหนดเลขคี่ตัวแรกๆ ให้กับแต่ละองค์ประกอบของชุดกลองทั้งสาม:
Kick\tSnare\tHiHat
1\t3\t5
และถ้าเราต้องการเล่นมากกว่าหนึ่งอย่างพร้อมกัน เราก็แค่บวกเลขของแต่ละส่วนเข้าด้วยกัน เช่น kick และ snare จะเป็น 4, kick และ HiHat จะเป็น 6 และอื่นๆ ส่วนศูนย์ (zero) คือความเงียบ ตอนนี้เรามีตัวเลขสำหรับทุกการผสมผสานของกลองที่เป็นไปได้แล้ว และเราสามารถเก็บมันไว้ใน Variable (Variable cycleNumber)
5 HiHat\t\tx \t-\tx\tx
3 Snare\t\t-\tx\tx\tx
1 Kick\t\tx\tx\t-\tx
_________________________________________
COMBINATION:\t6\t4\t8\t9
ตอนนี้เรารู้แล้วว่าจำเป็นต้องส่งคำสั่งล่วงหน้าสำหรับ servo ของ kick และ snare แต่เรายังต้องเล่น hi-hat ให้ตรงเวลาด้วย ซึ่งเป็นวงจรที่ทำงานได้แทบจะทันที
เพื่อจัดการกับปัญหานี้ที่อาจจะสับสนได้ในภายหลัง ผมตัดสินใจสร้างระบบจุดตรวจสอบ (checkpoints) ภายในทุกๆ รอบของ semiquaver (หรือตัวโน้ตเขบ็ตสองชั้น) ของแต่ละห้องเพลง ผมเลือกโน้ตเขบ็ตสองชั้นเพราะใน Tempo ของจังหวะทั่วไป โน้ตเขบ็ตสองชั้นจะมีความยาวประมาณ 100 ถึง 150 มิลลิวินาที ซึ่งเป็นความเร็วที่ servo ตัวที่ช้าที่สุด (ในกรณีของผม) สามารถเคลื่อนที่จากจุดพักไปยังจุดตีได้พอดี เราสามารถเปลี่ยนความเร็วของ Tempo ได้ง่ายๆ โดยการเปลี่ยนจำนวนมิลลิวินาทีที่กำหนดให้กับ Variable timeTotalCycle ที่นี่ คือตารางที่มีประโยชน์เกี่ยวกับความสัมพันธ์ของ Tempo, ตัวโน้ต และมิลลิวินาที ถ้าเราพยายามเล่นอะไรที่เร็วขึ้น และลดเวลาทั้งหมดของรอบให้ต่ำกว่าเวลาที่ servo ตัวที่ช้าที่สุดใช้ในการเคลื่อนที่ servo นั้นอาจจะไม่สามารถเคลื่อนที่ถึงตำแหน่งตีได้ และจะไม่มีเสียงเกิดขึ้น ไดอะแกรมที่ผมโพสต์ไว้จะช่วยอธิบายเรื่องนี้ได้ดีขึ้น

ตามที่แสดงในไดอะแกรม เมื่อเริ่มต้นสิ่งที่ผมเรียกว่า semiquaver-cycle เราจะส่งคำสั่งเพื่อเลื่อน servo ของ snare กลับไปที่ตำแหน่งพัก ในกรณีที่พวกมันถูกสั่งให้ตีในรอบก่อนหน้า นอกจากนี้ ณ จุดนี้ เราจะเริ่มนับมิลลิวินาทีที่ถูกตั้งค่าไว้สำหรับระยะเวลาของทั้งรอบ semiquaver
หลังจากนั้น Arduino จะเริ่มตรวจสอบว่าเวลาที่เหลือของรอบนั้นเท่ากับเวลาที่ servo แต่ละตัวต้องใช้ในการสร้างเสียงหรือไม่ แนวคิดคือการตรวจจับจุดของเวลาที่เราต้องส่งคำสั่งตี เพื่อให้ servo ทุกตัวไปถึงและตีเป้าหมาย (และสร้างเสียง) ที่จุดสิ้นสุดของรอบพอดี ดังนั้นแต่ละส่วนจะต้องเริ่มเคลื่อนที่ใน checkpoints ที่ต่างกันในรอบจังหวะ ขึ้นอยู่กับว่า servo และกลไกของมันเร็วแค่ไหน ในทางกลับกัน วงจร white noise ของ hi-hat สามารถเปิดได้เลยที่จุดสิ้นสุดของรอบ หรือก่อนหน้านั้นไม่กี่มิลลิวินาที (แนะนำ 20 มิลลิวินาที) การสั่งปิดจะทำในรอบถัดไปใน checkpoint ที่คุณกำหนดเอง ความยาวของเสียง hi-hat จะขึ้นอยู่กับว่าคุณตั้งค่าให้ปิดช้าแค่ไหนหลังจากเริ่มรอบ (ผมตั้งไว้ระหว่าง 30 ถึง 40 มิลลิวินาที แต่ก็แล้วแต่คุณเลย)
ทุกครั้งที่ถึง checkpoints เหล่านี้ Arduino จะตรวจสอบว่าส่วนประกอบนั้นๆ ถูกสั่งให้ทำงานหรือไม่ โดยเปรียบเทียบกับตัวเลขผสมผสานกลองที่เก็บไว้ใน Variable cycleNumber (ระบบรหัสตัวเลขที่อธิบายไว้ก่อนหน้านี้) ตัวอย่างเช่น ถ้าถึง checkpoint ของ snare และรหัสของ snare คือ 3 คำสั่งตีจะถูกส่งก็ต่อเมื่อรหัสการผสมผสานกลองมีเลข 3, 4 (3+1), 8 (3+5) หรือ 9 (3+1+5)
5 HiHat\t\tx \t-\tx\tx
3 Snare\t\t-\tx\tx\tx
1 Kick\t\tx\tx\t-\tx
_________________________________________
COMBINATION:\t6\t4\t8\t9
ทำไมต้องใช้ไม้และ servo สองชุดในกลไกของ snare?
ลองคิดดูครับ ถ้าใช้ servo ตัวเดียว และสมมติว่าเวลาจากพักไปตีคือ 100 มิลลิวินาที เวลาที่สั้นที่สุดที่รอบ semiquaver ของเราจะยาวได้คือ 200 มิลลิวินาที (100 เพื่อเลื่อนกลับ และอีก 100 เพื่อตี) 200 มิลลิวินาทีสำหรับโน้ตเขบ็ตสองชั้นแต่ละตัวจะเท่ากับ Tempo ประมาณ 75 bpm (“Dream On” ของ Aerosmith) ซึ่งค่อนข้างช้าและจำกัดในแง่ของจังหวะที่เล่นได้
การใช้ไม้และ servo แยกกันสองชุดแล้วสลับกันใช้ โดยให้ตัวหนึ่งเลื่อนกลับจากตำแหน่งตีมาที่พักในเวลา 100 มิลลิวินาที ในขณะที่อีกตัวเริ่มตีในเวลาเดียวกัน จะช่วยลดเวลารอบ semiquaver ขั้นต่ำจากประมาณ 200 เหลือ 100 มิลลิวินาทีโดยประมาณ (“Call Me” ของ Blondie) ซึ่งเร็วกว่ามาก กล่าวอีกนัยหนึ่งคือ เวลาของ servo ตัวที่ช้าที่สุด ก็คือเวลาขั้นต่ำที่รอบ semiquaver จะเป็นไปได้นั่นเอง
ตอนนี้เรามีวิธีกำหนดเสียงที่แน่นอนที่ต้องการสร้าง และทำให้มันเกิดขึ้นพร้อมกันได้เป๊ะๆ แล้ว เราแค่ต้องเล่นรอบโน้ตเขบ็ตสองชั้น 16 รอบต่อกัน โดยมีการผสมผสานกลองที่ต้องการในแต่ละรอบ เราก็จะได้หนึ่งห้องเพลง (bar) เราแค่เล่นห้องเพลงนั้นซ้ำไปเรื่อยๆ ตามต้องการ และเท่านี้เราก็ได้จังหวะกลองสำหรับเล่นดนตรีแล้ว
ด้วย Code ง่ายๆ เราเก็บลำดับ 16 semiquaver ของเราไว้ใน array และทำให้ Arduino วิ่งผ่านลำดับนั้นซ้ำไปซ้ำมา จังหวะกลองแบบต่างๆ สามารถเก็บและเล่นได้โดยการตั้งค่า array ของตัวเลข 16 ตัวที่ต่างกัน ตามที่แสดงในไดอะแกรมนี้:
5 HiHat\t\tx-x-x-x-x-x-x-x-
3 Snare\t\t----x-------x---
1 Kick\t\tx-------x-------
ARRAY:\t\t6050805060508050
5 HiHat\t\tx-x-x-x-x-x-x-x-
3 Snare\t\t----x-------x---
1 Kick\t\tx--x--x--xx---x-
ARRAY:\t\t6051806051608060
ในการสลับระหว่าง array เหล่านี้ เราจะใช้ tact switch button ที่เชื่อมต่อกับ Pins 3 ครับ
สนับสนุนเพื่อรับ Source Code หรือแอปพลิเคชันสำหรับโปรเจกต์นี้
ประเมิน Project
เอาฟอร์มยาวออกจากท้ายหน้า Project แล้ว เหลือเป็นปุ่มให้กดไปกรอกหน้าเดียว ตัวใหญ่ เว้นบรรทัดเยอะ อ่านง่ายกว่า
รีวิวจากคนใช้งานจริง
ถ้าเคยสั่งงาน เคยอ่านหน้านี้แล้วได้ประโยชน์ หรือมีข้อเสนอแนะ ฝากรีวิวไว้ได้เลย
ยังไม่มีรีวิวบนหน้านี้ ถ้าเคยใช้งานหรือมีข้อเสนอแนะ เขียนเป็นคนแรกได้เลย