Breadboard ultrasonic theremin build with ESP32-C3 SuperMini, HC-SR04 ultrasonic sensor, and buzzer, hand hovering over sensor

ผู้เริ่มต้น

สร้างอุลตร้าโซนิกเทเรมิน

เซ็นเซอร์

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

รวมชิ้นส่วนจริง 3 รายการ

ราคารวมชุดนี้: 1,050.00 ฿

ยังไม่รวมส่วนลดคำสั่งซื้อที่คุณอาจได้รับตอนชำระเงิน

สิ่งที่คุณต้องใช้

เป้าหมายของโปรเจกต์

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

คอนโทรลเลอร์ทำอะไร

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

เซ็นเซอร์อัลตราโซนิกทำอะไร

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

ตัวส่งเสียงกริ่งทำอะไร

ตัวส่งเสียงกริ่งจะเล่นความถี่ใดๆ ที่คอนโทรลเลอร์ส่งมา และนั่นคือเครื่องดนตรีทั้งหมด: ไม่มีสาย ไม่มีคีย์ เพียงแค่โทนเสียงที่ติดตามตำแหน่งมือแบบเรียลไทม์

แนวคิดซอฟต์แวร์และไลบรารี

หัวใจสำคัญของโปรเจกต์นี้คือฟังก์ชันการแมปแบบเดี่ยว: รับค่าการอ่านระยะห่างภายในช่วงที่เลือก เช่น 5 ถึง 40 เซนติเมตร และปรับขนาดเป็นเส้นตรงไปยังช่วงระดับเสียง เช่น 200 ถึง 2000 Hz ส่วนที่เหลือเป็นเพียงการอ่านเซ็นเซอร์และเรียกใช้ฟังก์ชันนั้นในวงวน

การทดสอบและการแก้ไขปัญหา

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

การอัปเกรดเสริม

เพิ่มเซ็นเซอร์อัลตราโซนิกตัวที่สองเพื่อควบคุมระดับเสียงแทนระดับเสียงใกล้เคียงกับพฤติกรรมเทอร์มินจริง มือข้างหนึ่งสำหรับระดับเสียง อีกข้างหนึ่งสำหรับระดับเสียง

การเดินสาย

  • HC-SR04 VCC → ESP32-C3 5V
  • HC-SR04 GND → ESP32-C3 GND
  • HC-SR04 TRIG → ESP32-C3 GPIO2 (เอาต์พุต)
  • HC-SR04 ECHO → 1kΩ/2kΩ voltage divider → ESP32-C3 GPIO3 (อินพุต)
  • Buzzer signal → ESP32-C3 GPIO4
  • Buzzer GND → ESP32-C3 GND

สำคัญ: ตัวส่งเสียงกริ่ง "แอคทีฟ" แท้จริงมีออสซิลเลเตอร์ภายในของตัวเองและสามารถเปิดหรือปิดได้อย่างเต็มที่ด้วย `digitalWrite` — ไม่สามารถเล่นระดับเสียงที่เปลี่ยนแปลงได้ ดังนั้นจึงไม่สามารถใช้เป็นเทอร์มินได้ โค้ดนี้ขับเคลื่อนระดับเสียงด้วยไฟฟ้าผ่าน `ledcWriteTone` ซึ่งต้องใช้ตัวส่งเสียงกริ่งแบบพาสซีฟหรือองค์ประกอบเพียโซแบบเปลือยในช่องนั้นแทนที่จะเป็นตัวส่งเสียงกริ่งแบบแอคทีฟที่มีโทนเสียงคงที่ ช่วงระยะห่างถูกจำกัดไว้ที่ 2–40 ซม. ในตัวอย่างนี้ ขยาย `MAX_DISTANCE_CM` สำหรับพื้นที่เล่นที่ใหญ่ขึ้น

แผนภาพการต่อสาย

VCC → 5V GND TRIG → GPIO2 ECHO GPIO3 signal → GPIO4 GND ESP32-C3 HC-SR04 1kΩ/2kΩ voltage divider Buzzer

โค้ดเริ่มต้น

#include <Arduino.h>

// --- Pin definitions: adjust to match your ESP32-C3 SuperMini board if different ---
#define TRIG_PIN    2
#define ECHO_PIN    3   // through a 1k/2k voltage divider - HC-SR04 ECHO is 5V logic
#define BUZZER_PIN  4   // PASSIVE buzzer / piezo required - see note above

#define PWM_CHANNEL 0
#define PWM_RES_BITS 8

const int MIN_DISTANCE_CM = 2;
const int MAX_DISTANCE_CM = 40;
const int MIN_FREQ_HZ = 200;
const int MAX_FREQ_HZ = 2000;

long readDistanceCM() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  long duration = pulseIn(ECHO_PIN, HIGH, 25000);
  if (duration == 0) return -1;
  return duration * 0.0343 / 2;
}

void setup() {
  Serial.begin(115200);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);

  ledcSetup(PWM_CHANNEL, MIN_FREQ_HZ, PWM_RES_BITS);
  ledcAttachPin(BUZZER_PIN, PWM_CHANNEL);
}

void loop() {
  long distance = readDistanceCM();

  if (distance > 0) {
    long clamped = constrain(distance, MIN_DISTANCE_CM, MAX_DISTANCE_CM);
    // closer hand = higher pitch
    int freq = map(clamped, MIN_DISTANCE_CM, MAX_DISTANCE_CM, MAX_FREQ_HZ, MIN_FREQ_HZ);
    ledcWriteTone(PWM_CHANNEL, freq);
  } else {
    ledcWriteTone(PWM_CHANNEL, 0); // out of range - silence
  }

  delay(30);
}

ไม่แน่ใจขั้นตอนไหน? ถามเรา