การแสดงดนตรีสดเนี่ย มันเป็นอะไรที่พิเศษสุดๆ แต่ว่าจะจัดกันได้ก็ต้องมีคนเล่นใช่มะ? ปัญหาก็คือคนมันไม่ว่างตลอดเวลาไง! บางทีพี่ก็เล่นโชว์เองคนเดียว กีตาร์กับเสียงร้อง แต่เพลงมันก็ต้องมีเครื่องดนตรีอื่นๆ ด้วย เช่น กลอง ซึ่งเครื่องพวกนี้มันจะดังก็ต่อเมื่อมีคนตีเท่านั้นแหละ
ปัญหานี้แก้ได้ง่ายๆ ด้วยการเปิดแบคกิ้งแทร็กแล้วเล่นทับไป แต่แบบนั้นมันก็ไม่ใช่ "สด" 100% แล้วไงล่ะ
พี่เลยตัดสินใจกำจัดปัจจัยมนุษย์ออกไปซะเลย แล้วสร้าง... หุ่นยนต์ตีกลอง! ไอเดียคือทำของที่พกพาได้ เคลื่อนไหวได้ สร้างเสียงจังหวะต่างๆ ได้โดยไม่ใช้เสียงอัดสำเร็จรูป (samples) สามารถสั่งให้เล่นหรือหยุดได้ และที่สำคัญ เสียงมันต้องดังพอใช้กับวงดนตรีได้
แนวคิดหลัก
อย่างแรกเลย ต้องมากำหนดก่อนว่าชุดกลองของเราจะมีองค์ประกอบอะไรบ้าง ตามหลักช่วงความถี่เสียง (frequency range) ชุดกลองมาตรฐานมักประกอบด้วยสามส่วนหลัก: กลองใหญ่ (Kick - ช่วงต่ำ), กลองสแนร์ (Snare - ช่วงกลาง), และ ฉาบฮายแฮต (Hi-hat - ช่วงสูง) หลังจากทดลองอยู่สองสามสัปดาห์ พี่ก็เลือกวิธีสร้างเสียงพวกนี้แบบนี้:
Kick/เสียงต่ำ: ใช้ไพโซ (Piezo) 2 ตัว ปิดด้วยฟองน้ำชิ้นเล็กๆ แล้วใช้ไม้ที่ติดหัวยางนิ่มๆ ควบคุมด้วยเซอร์โวมาตี
Snare/เสียงกลาง: ใช้กระป๋อง Pringles (กินหมดแล้วนะ!) ติดแผ่นดีบุกสี่เหลี่ยมเล็กๆ เพื่อให้เกิดเสียงก้อง (resonation) แล้วใช้ไม้ติดหัวยางควบคุมด้วยเซอร์โวมาตี เสียงจะถูกจับด้วยไมโครโฟนแบบอิเล็กเตร็ต (Electret Microphone)
Hi-hat/เสียงสูง: ใช้วงจรสร้างเสียงไวท์นอยส์ (White Noise) แบบทรานซิสเตอร์ ควบคุมเปิด-ปิดตรงๆ ด้วย Arduino เลย
ระบบทั้งหมดจะถูกควบคุมจังหวะโดยบอร์ด Arduino จากนั้นสัญญาณเสียงที่ได้จะถูกขยายให้อยู่ในระดับเครื่องดนตรีด้วยวงจรแอมป์ง่ายๆ วงจรละตัว
กลองใหญ่ (Kick Drum)
หลักการคือใช้ประโยชน์จากเสียงความถี่ต่ำที่เกิดขึ้นเมื่อเราแตะหรือตีไพโซโดยตรงด้วยวัตถุที่นิ่มๆ งานของเราคือ 1) ทำให้ระบบตีไพโซทำงานอัตโนมัติ และ 2) ขยายสัญญาณเสียงจากไพโซ
อย่างที่บอกไป ใช้ไม้ควบคุมด้วยเซอร์โวมาตีไพโซสองตัวที่วางอยู่ปลายสองด้านของช่วงการเคลื่อนที่ของเซอร์โว (จะได้ใช้ประโยชน์เต็มที่) เพื่อลดเสียงความถี่สูงที่ไม่ต้องการ ไพโซถูกปิดด้วยฟองน้ำและไม้มีหัวยางนิ่ม

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

สัญญาณเสียงจากไพโซจะถูกขยายด้วยวงจรในภาพด้านบน ใช้ไฟเลี้ยง 5v - 7v จากเรกูเลเตอร์ ซึ่งรับไฟจากแหล่งจ่ายหลัก (อย่าไปเอาไฟจากบอร์ด Arduino) ทำไมน่ะเหรอ? แม้ว่าวงจรแอมป์จะทำงานกับไฟ 5v จาก Arduino ได้ แต่การแยกสัญญาณอนาล็อก (เสียง) ออกจากวงจรดิจิตอลให้มากที่สุด จะช่วยลดสัญญาณรบกวน (noise) จากดิจิตอลที่ปนเข้ามาในสัญญาณเสียงสุดท้ายได้
บอกตรงๆ พี่ก็ไม่ได้เรียนอิเล็กทรอนิกส์มาโดยตรง (หรือจะเรียกว่าไม่ได้เรียนเลย 555) และก็เจอปัญหากับ noise ตัวนี้อยู่เหมือนกัน จริงๆ แล้ว noise ในงานเกี่ยวกับเสียงมันกำจัดให้หมดเกลี้ยงได้ยากมาก แต่พี่พบว่าการกรองไฟที่เรกูเลเตอร์ การแยกสัญญาณอนาล็อก/ดิจิตอล และการป้องกันไฟฟ้าที่ดีของโปรเจค ช่วยลด noise ลงมาได้ในระดับที่ยอมรับได้
กลองสแนร์ (Snare)
เสียงนี้เลียนแบบยากโคตรๆ ตอนนี้พี่ก็ยังไม่ค่อยปลื้มกับเสียงที่ได้อยู่ดี ในการจับเสียง พี่เลือกใช้ไมโครโฟนแบบอิเล็กเตร็ต เพราะมันไวมากกว่า และธรรมชาติของเสียงสแนร์ที่พิเศษก็ต้องการความไวนี้
เหมือนกับระบบ Kick เลย ต้องมีส่วนกลไกและส่วนเสียง ภาพด้านล่างคือแบบที่พี่ออกแบบไว้ ใช่แล้ว! พี่ใช้กระป๋อง Pringles คว่ำลง มันเป็นรูปทรงที่เพอร์เฟกต์ ให้เสียงที่ดีที่สุดที่พี่หาได้ และที่สำคัญ มันฝรั่งข้างในก็อร่อยมาก 555


เหมือนเดิม! หามุมของเซอร์โวตอนพักและตอนตีให้ได้ โดยการไปงัด Tutorial เรื่องโพเทนชิโอมิเตอร์กับเซอร์โวมาลองเล่น แล้วใช้ Serial.print(); อ่านค่าออกมา

สัญญาณเสียงจากไมโครโฟนจะถูกขยายด้วยวงจรแอมป์แบบเดียวกับของ Kick แต่ปรับนิดหน่อยเพื่อจ่ายไฟให้ไมโครโฟน และไม่ต้องใช้ตัวกรองความถี่ต่ำ (low-pass filter) แบบใน Kick
ฉาบฮายแฮต (HiHat)
เสียงนี้พี่ใช้วิธีคนละแบบเลย ใช้วงจรสร้างไวท์นอยส์ (White Noise) แบบทรานซิสเตอร์ และติด LED ไว้เป็นตัวบอกสถานะ Arduino จะเป็นคนสั่งเปิดวงจรนี้เมื่อต้องการ
ไวท์นอยส์คือสัญญาณสุ่มที่มีความเข้มเท่ากันทุกความถี่ พูดง่ายๆ ก็เหมือนแสงสีขาวที่มีสีทุกสีผสมกัน ไวท์นอยส์ก็มีทุกความถี่ผสมกัน เสียงมันจะเหมือนคลื่นวิทยุที่จับสัญญาณไม่ได้ (เสียงซ่าๆ) เสียงนี้ใช้กันบ่อยในดนตรีอิเล็กทรอนิกส์และการสังเคราะห์เสียง เคยอ่านมาว่าแม้แต่เสียงสแนร์และฉาบในยุค 80s ก็ใช้หลักการนี้สร้างกัน

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

เรายังต้องการวิธีเลือกจังหวะกลอง (drumbeat) ที่จะเล่น และสั่งเริ่ม/หยุดเล่น สำหรับบทความนี้ เราจะใช้ปุ่มกด (tact button) และสวิตช์ธรรมดา อย่างละตัว (ต่อกับขา 2 และ 3 ของ Arduino ตามภาพด้านบน)

ฐานสำหรับส่วนอะคูสติกของหุ่นยนต์
แกนหลักฮาร์ดแวร์ของ DrumCube Robot Drummer นี้จัดว่าเข้าถึงได้ไม่ยากนัก วัยรุ่นต้องเตรียมของพวกนี้ไปจัด:
- Arduino Uno/Nano: สมองกลางสำหรับควบคุมจังหวะเวลา, การเคลื่อนที่ของเซอร์โว, และกระตุ้นวงจร Hi-hat
- SG90 Micro Servos (x2 หรือ x4): พวกนี้คือตัวให้การเคลื่อนไหวแม่นยำเพื่อตีองค์ประกอบ Kick กับ Snare สำหรับ Snare การใช้เซอร์โวสองตัว (ตามที่เห็นในแบบกลไก) จะทำให้ตีสลับได้เร็วขึ้น
- ไม้ไอติมหรือข้อต่ออลูมิเนียม: เอามาใช้เป็น "ไม้ตีกลอง" ติดกับแขนเซอร์โวเพื่อตีเป้าหมาย
- วัตถุกลองจากกระดาษแข็ง: ของใกล้ตัวเช่นกระป๋อง Pringles สำหรับ Snare ให้ตัวเรโซแนนซ์ ส่วน Kick ใช้ Piezo Element ติดบนพื้นผิว
อธิบายโค้ด I - การปรับเทียบเวลาเซอร์โว
ทีนี้ เนื่องจากโปรเจคนี้เป็นเครื่องดนตรี มันต้องสร้างเสียงให้ตรงจังหวะ ดังนั้น ก่อนที่เราจะเริ่มเขียนโค้ดจังหวะและฟังก์ชันต่างๆ โดยเฉพาะสำหรับ Kick กับ Snare เราต้องโปรแกรมการเคลื่อนที่ของเซอร์โวให้เริ่มต้นก่อนถึงจังหวะที่ต้องดังเป็นมิลลิวินาที เพื่อชดเชยเวลาที่ไม้ตีใช้จากตำแหน่งพักไปถึงจุดตี และทำให้ไม้ตีกระทบเป้าหมายพอดีเวลา
เพื่อแก้ปัญหานี้ พี่ได้ประยุกต์ระบบวัดเวลาง่ายๆ มาวัดว่าแต่ละเซอร์โวใช้เวลาเท่าไหร่จากตำแหน่งพักไปถึงจุดตีเป้าหมายพอดี พี่ติดฟอยล์อลูมิเนียมบนไม้ตีและจุดที่มันตี แล้วต่อคลิปจระเข้กับฟอยล์ สร้างการเชื่อมต่อที่ Arduino วัดได้เฉพาะตอนไม้ตีโดนเป้าหืน จากนั้นก็เขียนโค้ดง่ายๆ ที่ทำสองอย่าง: หนึ่ง สั่งให้ไม้ตีเซอร์โวตีเป้าหมายซ้ำๆ จากมุมพักไปมุมตี และสอง พิมพ์เวลาที่ส่งคำสั่งไปเซอร์โว กับเวลาที่ไม้ตีทำให้วงจรเชื่อมต่อ (ตีโดน) ลบค่าทั้งสองออกจากกัน เราก็จะได้เวลาที่ไม้ตีใช้สร้างเสียง ตั้งแต่พักจนถึงตี

หลังจากทำซ้ำหลายๆ รอบ น้องจะได้ตัวเลขที่ใกล้เคียงกันมาเพียบ จากนั้นก็หาค่าเฉลี่ย เราก็จะได้เวลาที่ต้องส่งคำสั่งล่วงหน้า (anticipation time) สำหรับแต่ละเซอร์โวที่ใช้การได้เลย
สู้กับปัญหาเรโซแนนซ์ของ Micro-Servo
เมื่อเซอร์โวเคลื่อนที่และหยุดกระทันหัน มันอาจจะสั่นหรือ "ริง" ทำให้เกิดเสียงกลไกที่ไม่ต้องการและอาจส่งผลต่อจังหวะเวลาได้ วิธีบรรเทามีดังนี้:
- การหน่วงเชิงกล (Mechanical Damping): ใช้ยางรองหรือโฟมในการติดตั้งเซอร์โว การติดวัสดุอ่อนนุ่มชิ้นเล็กๆ (เช่นฟองน้ำบน Piezo) ที่ปลายไม้ตีก็ช่วยลดแรงสั่นสะเทือนจากการกระทบได้
- จัดการความเร็ว (Velocity Management): แทนที่จะใช้ไลบรารีมาตรฐาน
Servo.hที่ขับเซอร์โวด้วยความเร็วสูงสุด ลองใช้ไลบรารีอย่างVarSpeedServo.hดู มันช่วยให้เราตั้งโปรไฟล์การเร่งและลดความเร็วที่ช้าลงและนุ่มนวลขึ้นสำหรับการเคลื่อนที่ของเซอร์โวได้ ซึ่งจะลดแรงกระแทกเชิงกลและเรโซแนนซ์ ทำให้ทำงานเงียบขึ้นและอาจได้แรงตีที่สม่ำเสมอกว่า
อธิบายโค้ด II - การผสมกลอง (Drum Combinations)
ทีนี้ เราจะกำหนดรหัสตัวเลขสำหรับทุกๆ การผสมกันของ Kick, Snare และ Hi-hat ในหนึ่งจังหวะ พี่กำหนดเลขคี่แรกๆ ให้กับองค์ประกอบทั้งสามของชุดกลองเรา:
Kick\tSnare\tHiHat
1\t3\t5
จากนั้น ถ้าเราต้องการเล่นมากกว่าหนึ่งองค์ประกอบพร้อมกัน ก็แค่บวกเลขของแต่ละองค์ประกอบเข้าไป Kick กับ Snare ก็จะเป็น 4, Kick กับ HiHat เป็น 6, ไปเรื่อยๆ เลขศูนย์คือการเงียบ ตอนนี้เรามีตัวเลขสำหรับทุกการผสมองค์ประกอบกลองที่เป็นไปได้แล้ว และเราสามารถเก็บมันไว้ในตัวแปรได้ (ตัวแปร 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
อธิบายโค้ด III - วัฏจักร Semiquaver (ตีให้ตรงเวลา)
ตอนนี้เรารู้แล้วว่าจำเป็นต้องส่งคำสั่งล่วงหน้าให้เซอร์โว Kick และ Snare แต่เราก็ต้องเล่น Hi-hat ให้ตรงเวลาด้วย ซึ่งเป็นวงจรที่ทำงานเกือบจะทันที
เพื่อจัดการกับปัญหานี้ ซึ่งอาจเริ่มมึนได้ พี่เลยตัดสินใจสร้างระบบ Checkpoint ขึ้นมาในทุกๆ Semiquaver (หรือโน้ตที่ 16) ของทุกๆ ห้องดนตรี พี่เลือกโน้ตที่ 16 เพราะใน Tempo ของจังหวะทั่วไปส่วนใหญ่ โน้ต 1 ใน 16 จะยาวประมาณ 100 ถึง 150 มิลลิวินาที ซึ่งก็คือความเร็วที่เซอร์โวตัวที่ช้าที่สุด (ในกรณีของพี่) สามารถเคลื่อนที่จากพักไปตี หรือกลับกันได้ เราสามารถเปลี่ยนความเร็วของ Tempo ได้ง่ายๆ โดยเปลี่ยนจำนวนมิลลิวินาทีที่กำหนดให้กับตัวแปร timeTotalCycle

ดังที่แสดงในไดอะแกรม เมื่อเริ่มต้นสิ่งที่เรียกว่า Semiquaver-cycle เราจะส่งคำสั่งให้เซอร์โว Snare กลับไปที่ตำแหน่งพัก เผื่อว่ามันถูกสั่งให้ตีในวัฏจักรก่อนหน้า และที่จุดนี้ เราก็เริ่มนับมิลลิวินาทีที่ตั้งไว้สำหรับระยะเวลาของ Semiquaver cycle ทั้งหมด
หลังจากนั้น Arduino จะเริ่มตรวจสอบว่าเวลาที่เหลือก่อนวัฏจักรจะจบ เท่ากับเวลาที่แต่ละเซอร์โวต้องการเพื่อสร้างเสียงหรือไม่ แนวคิดคือการตรวจจับจุดในเวลาที่เราต้องส่งคำสั่งตี เพื่อให้ทุกเซอร์โวเคลื่อนที่ไปถึงและตีเป้าหมาย (และสร้างเสียง) พอดีที่จุดสิ้นสุดของวัฏจักรพอดี ดังนั้นแต่ละองค์ประกอบจะต้องเริ่มเคลื่อนที่ที่ Checkpoint ต่างๆ กันในวัฏจักร ขึ้นอยู่กับว่าเซอร์โวและกลไกของมันเร็วแค่ไหน ส่วนวงจร White noise ของ Hi-hat นั้น สามารถเปิดตอนสุดท้ายของวัฏจักรพอดี หรือก่อนหน้านั้นไม่กี่มิลลิวินาที (แนะนำ 20) การปิดมันจะถูกสั่งในวัฏจักรถัดไปที่ Checkpoint ที่เรากำหนด เวลาที่เราตั้งหลังจากเริ่มวัฏจักรจะเป็นระยะเวลาที่เสียง Hi-hat ดัง (พี่ตั้งไว้ที่ 30 ถึง 40 มิลลิวินาที แต่นั่นขึ้นอยู่กับน้องเลย)
ทุกครั้งที่ถึง Checkpoint เหล่านี้ Arduino จะตรวจสอบว่าองค์ประกอบที่ตรงกันนั้นถูกตั้งใจให้ทำงานหรือไม่ โดยการเปรียบเทียบกับเลขผสมกลองที่เก็บไว้ในตัวแปร 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
ทำไมต้องใช้ไม้ตีและเซอร์โวสองชุดในกลไก Snare?
ถ้าน้องคิดดูดีๆ ถ้าใช้เซอร์โวแค่ตัวเดียว และสมมติว่าเวลาจากพักไปตีของมันคือ 100 มิลลิวินาที เวลาสั้นที่สุดที่ Semiquaver cycle ของเราจะเป็นได้คือ 200 มิลลิวินาที (100 เพื่อให้กลับจากตีมาพัก แล้วอีก 100 จากพักไปตี) 200 มิลลิวินาทีต่อโน้ต 1 ใน 16 เท่ากับ Tempo ประมาณ 75 bpm ซึ่งช้ามากและจำกัดในแง่ของจังหวะที่เป็นไปได้