In diesem Projekt lernst du, wie du ein einfaches Arduino Theremin mit einem Piezo-Summer und dem Ultraschall-Sensor HC-SR04 baust. Aber nicht nur das – damit auch ungeübte Musiker ihre Freunde begeistern können, spielt dieses Theremin nur Töne in der beliebten A-Moll Pentatonik. 🙂

Aktivieren Sie JavaScript um das Video zu sehen.
https://www.youtube.com/watch?v=7yfY3ije11s

Für dieses Projekt benötigst du:

*Amazon Affiliate Links – Wenn du dort bestellst, erhalten wir eine kleine Provision.

Der Aufbau des Arduino Theremins

Du musst nur zwei Bauteile auf deinem Breadboard montieren und mit deinem Arduino verbinden: Den Piezo-Summer und den Ultraschall-Sensor. Ersteren verbindest du mit dem Digitalpin 3 und mit Erde. Beim Ultraschall-Sensor verbindest du zunächst VCC mit Plus und GND mit Erde. Anschließend verbindest du den Ausgang TRIG mit dem Digitalpin 5 und ECHO mit dem Digitalpin 4 an deinem Arduino.

Arduino Theremin
Screenshot: Tinkercad

So funktioniert dein Theremin

Dieses Projekt funktioniert eigentlich ganz simpel: Der Ultraschall-Sensor HC-SR04 misst die Entfernung zu einem Objekt, z.B. zu deiner Hand. Diese Entfernung rechnest du in Tonhöhen um, die du über den Piezo-Summer ausgibst.

Da hier natürlich alle möglichen Entfernungen in einem bestimmten Bereich möglich sind, gibt es auch alle möglichen Töne – auch welche, die in klassischen Tonleitern nicht vorkommen. Deshalb sucht sich der folgende Sketch immer den nächsttieferen Ton in der A-Moll Pentatonik heraus. So spielst du kinderleicht ansprechende Melodien!

Der passende Sketch für Musiker

Zunächst legst du ein paar Variablen fest, die du später mit Leben füllst:

//Arduino Pins für den Ultraschall-Sensor
int trigger = 5;
int echo = 4;
int distance = 0;

//Variablen für die Bestimmung der Reichweite
int distanceLow = 0;
int distanceHigh = 0;

//Variable für die zu spielende Note
int note = 0;

Danach folgt ein Array, in dem die Töne der A-Moll Pentatonik stecken – genauer gesagt, welche Frequenzen (in Hertz) du mit deinem Piezo-Summer ausgibst. Das sind immer wieder die Töne A – C – D – E – G in verschiedenen Oktaven.

int pentatonicAMinor[] = {
  147, 165, 196, 220, 262, 294, 330, 392, 440,
  523, 587, 659, 784, 880, 1047, 1175, 1319, 1568,
  1760, 2093, 2349
};

Auf Github findest du eine mehr oder weniger vollständige Liste aller Töne und ihrer Frequenzen.

Die Setup-Funktion

Hier startest du zunächst den Seriellen Monitor und legst die PinModes für die Pins des Ultraschall-Sensors fest. Dann kommt der erste interessante Teil des Sketchs: Dein Sensor hat eine theoretische Reichweite von 2cm bis 4m –die Reichweite, in der du spielst, wird aber vermutlich geringer sein.

Deshalb kalibrierst du den Sensor in den ersten fünf Sekunden nach dem Start. Das heißt, du bestimmst, wie nah und wie weit weg deine Hand vom Sensor sein wird. Hierfür bewegst du deine Hand vor dem Sensor immer wieder vor und zurück. Die kleinste und die größte Entfernung speicherst du dann in die Variablen distanceLow und distanceHigh. Diese benötigst du später wieder.

void setup() {
  Serial.begin (9600);
  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);

  while (millis() < 5000) {

    //Der Sensor misst die Entfernung
    digitalWrite(trigger, HIGH);
    digitalWrite(trigger, LOW);
    distance = pulseIn(echo, HIGH);
    Serial.println(distance);

    //Kleinste und größte Entfernung speichern
    if (distance > distanceHigh) {
      distanceHigh = distance;
    }
    if (distance < distanceLow) {
      distanceLow = distance;
    }
  }
}

Hinweis: Um genau zu sein, misst der HC-SR04 nicht direkt die Entfernung, sondern nur wie lange ein ausgesendetes Ultraschall-Signal benötigt, um von einem Hindernis (deine Hand) wieder im Sensor einzutreffen. In diesem Tutorial erfährst du, wie du die Entfernung in cm messen kannst.

Der Loop

Hier spielt die Musik. Im Loop lässt du deinen Ultraschall-Sensor immer wieder die Entfernung zu deiner Hand messen. Je nachdem wie weit sie von ihm entfernt ist, erklingt ein anderer Ton. Zentral ist hierbei folgende Funktion:

note = map(distance, distanceLow, distanceHigh, 147, 2349);

Mithilfe der Funktion map() kannst du eine Zahl aus einem Bereich einem anderen Bereich zuordnen. In diesem Projekt „mapst“ du die aktuelle Entfernung deiner Hand (distance) auf eine bestimmte Tonfrequenz.

Hierfür sind zwei Bereiche notwendig: Die aktuelle Entfernung deiner Hand liegt im Bereich der minimalen (distanceLow) und maximalen (distanceHigh) Entfernung deiner Hand, die du in der Kalibrierung zu Beginn festgelegt hast. Der zweite Bereich wird vom tiefsten Ton (147 Hertz) und dem höchsten Ton (2349 Hertz) deiner Pentatonik im Array pentatonicAMinor[] begrenzt.

Die Entfernung deiner Hand wird also einer Zahl zwischen 147 und 2349 zugeordnet und in der Variablen note gespeichert.

In der Arduino-Referenz erfährst du mehr über die Funktion map().

Den richtigen Ton treffen

Bis jetzt hast du nur einen Frequenzbereich, in der die Note liegt. Dein Arduino Theremin soll aber keine ungenauen Zwischentöne spielen, sondern nur Noten der A-Moll Pentatonik. Hierfür benötigst du einen Loop und ein paar Abfragen:

  for (byte i = 0; i <= 20; i++) {

    if (note == pentatonicAMinor[i]) {
      tone(3, note);
    }
    else if (note > pentatonicAMinor[i] && note < pentatonicAMinor[i + 1]) {
      while (note != pentatonicAMinor[i]) {
        note -= 1;
      }
      tone(3, note);
    }
    else if (note > pentatonicAMinor[20]) {
      while (note != pentatonicAMinor[20]) {
        note -= 1;
      }
      tone(3, note);
    }
  }

Im For-Loop fragst du für jede Note des Arrays pentatonicAMinor[] ab, ob du deine Hand schon in der richtigen Entfernung und die Note somit genau getroffen hast. In diesem Fall spielst du sie über die Funktion tone() mit deinem Piezo-Summer ab.

Falls nicht fragst du im ersten else if, ob dein gespielter Ton zwischen zwei Noten steckt. Wenn das so ist, reduzierst du die Frequenz in einem While-Loop, bis sie den korrekten, nächsttieferen Ton erreicht hat.

Zu kompliziert? Ein Beispiel: Deine Hand hat eine Entfernung zum Sensor, die du mithilfe der Funktion map() auf eine Frequenz von 200 Hertz umgerechnet hast. Das ist aber keine Note der A-Moll Pentatonik, sondern liegt irgendwo zwischen einem G und einem Gis. Der nächsttiefere, richtige Ton ist laut deinem Array ein G mit 196 Hertz. Im While-Loop reduzierst du also die Variable note solange um 1, bis sie diese Frequenz erreicht hat.

Im letzten else if fängst du Töne ab, die über dem letzten Eintrag in deinem Array liegen und reduzierst sie auf die Frequenz dieses letzten Eintrags: hier 2349 Hertz.

Und das war’s! Schalte dein Arduino Theremin ein, kalibriere es und lass die Fetzen fliegen. 🙂

Hier nun der gesamte Sketch:

/*
   Arduino Theremin with A minor pentatonic scale
   pollux labs, 2020
   All rights reserved.
*/

const int trigger = 5;
const int echo = 4;

const int piezo = 10;

int distance = 0;
int distanceHigh = 0;

int lengthOfScale = 0;

int note = 0;

//A Minor pentatonic scale
int scale[] = {
  147, 165, 196, 220, 262, 294, 330, 392, 440,
  523, 587, 659, 784, 880, 1047, 1175, 1319, 1568,
  1760, 2093, 2349
};

//C Major scale
//int scale[] = {
//  131, 147, 165, 175, 196, 220, 247, 262, 294,
//  330, 349, 392, 440, 494, 523, 587, 659, 698,
//  784, 880, 988, 1047
//};


void setup() {
  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);

  while (millis() < 5000) {
    digitalWrite(trigger, HIGH);
    digitalWrite(trigger, LOW);
    distance = pulseIn(echo, HIGH);

    if (distance > distanceHigh) {
      distanceHigh = distance;
    }
  }

  for (byte i = 0; i < (sizeof(scale) / sizeof(scale[0])); i++) {
    lengthOfScale += 1;
  }
}

void loop() {
  digitalWrite(trigger, HIGH);
  digitalWrite(trigger, LOW);

  distance = pulseIn(echo, HIGH);

  note = map(distance, 250, distanceHigh, scale[0], scale[lengthOfScale - 1]);

  for (byte j = 0; j < (lengthOfScale); j++) {

    if (note == scale[j]) {
      tone(piezo, note);
      break;
    }
    else if (note > scale[j] && note < scale[j + 1]) {
      note = scale[j];
      tone(piezo, note);
      break;
    }
  }
  delay(30);
}