Ein Theremin mit Ultraschall

Lektion
Downloads

In einer früheren Lektion hast du eine Art Drehorgel mit einem Poti gebaut. Jetzt gehst du einen Schritt weiter: Du spielst dein Instrument, indem du deine Hand vor dem Sensor vor und zurück bewegst. So bestimmst du wie von Geisterhand die Höhe der Töne, die dein Piezo erzeugt.

Wenn du dein Theremin lieber mit dem Lichtsensor aus deinem Starter Kit bedienen möchtest – am Ende dieser Lektion erfährst du, wie das geht.

Werfen wir zunächst einen Blick auf den Aufbau. Einen Piezo und den HC-SR04 hast du ja bereits schon einmal mit dem Arduino verbunden. Baue dein Theremin nun wie folgt auf dem Breadboard auf:

Aufbau Arduino Theremin

Sobald du fertig bist, kann es gleich mit dem Sketch weitergehen.

Die benötigten Konstanten und Variablen

Für dein Theremin benötigst du eine ganze Reihe von Konstanten und Variablen. Zunächst die drei Konstanten für die Pins, an denen dein Ultraschallsensor und der Piezo angeschlossen sind.

const int trigger = 7;
const int echo = 6;
const int piezo = 10;

Dann benötigst du noch zwei Variablen für die Entfernungen, die dein HC-SR04 misst. In der ersten Variablen distance speicherst du fortlaufend das aktuelle Messergebnis. Die zweite distanceHigh benötigst du, um zu Beginn des Sketchs die maximale Distanz deiner Hand zum Sensor abzuspeichern – dazu gleich mehr.

int distance = 0;
int distanceHigh = 0;

Fehlt noch eine Variable für die Note, die dein Piezo spielt. Wie bei der Drehorgel mit dem Poti unterscheiden sich die Frequenzwerte (Tonhöhen) von den Werten, die dein Ultraschallsensor misst. Deshalb kommt später auch wieder die Funktion map() zum Einsatz. Doch zunächst setzt du die Variabel auf Null:

int note = 0;

Die Setup-Funktion

Hier definierst du zunächst wieder den jeweiligen pinMode der Pins Echo und Trig deines Sensors:

pinMode(trigger, OUTPUT);
pinMode(echo, INPUT);

Anschließend folgt ein While-Loop mit dem Zweck, deinen Sensor zu kalibrieren. Du misst in den ersten drei Sekunden nach dem Programmstart die maximale Entfernung deiner Hand zum Sensor.

Hierfür verwendest du die Funktion millis(), die die Anzahl der seit dem Programmstart vergangenen Millisekunden zurückgibt. Solange (while) noch keine 3000 Millisekunden – also drei Sekunden – vergangen sind, misst dein Sensor immer wieder die Entfernung und speichert sie in der Variablen distance:

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

Doch das reicht noch nicht, sondern du möchtest auch die maximale Entfernung in der Variablen distanceHigh speichern, um dein „Spielfeld“ zu begrenzen. Das machst du mit einer bedingten Abfrage nach jeder Messung.

Immer, wenn die gerade gemessene Entfernung distance die maximale Entfernung distanceHigh überschreitet, wird diese auf den Wert von distance aktualisiert.

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

Wie gesagt, der While-Loop wird nur in den ersten drei Sekunden nach dem Programmstart ausgeführt. Sobald diese Zeit verstrichen ist, geht es sofort weiter – mit der Musik. 🙂

Im Loop spielt die Musik

Auch der Loop beginnt jedes Mal mit der Messung der Entfernung deiner Hand. Anschließend speicherst du diese Entfernung in der Variablen distance.

digitalWrite(trigger, HIGH);
delay(10);
digitalWrite(trigger, LOW);

distance = pulseIn(echo, HIGH);

Diese Entfernung kann natürlich immer noch die von dir kalibrierte maximale Entfernung überschreiten – was sie aber nicht soll. Deshalb prüfst du als nächstes, ob distance über distanceHigh liegt. Ist das der Fall, limitierst du den gemessenen Wert auf die maximale Entfernung:

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

Alles, was jetzt noch fehlt, sind Töne. Hierfür benötigst du wieder die Funktion map(). Du nimmst hier die Entfernung distance, deren Wertebereich du auf 50 bis distanceHigh begrenzt. Den Frequenzbereich deiner Töne legst auf 50 bis 3000 Hz. fest. Den in der Funktion „gemappten“ Wert weist du der Variablen note zu.

note = map(distance, 50, distanceHigh, 50, 3000);
tone(piezo, note);

delay(10);

Anschließend spielst du die gefundene Note mit tone() und schließt den Loop mit einem ganz kurzen Delay ab.

Und das war es! Lade den Sketch aus den Downloads dieser Lektion auf deinen Arduino, kalibriere deinen Sensor und leg mit deiner Karriere am Theremin los! 🙂

Den Lichtsensor verwenden

Du kannst statt des Ultraschall- auch deinen Lichtsensor (auch Fotowiderstand) verwenden, um das Theremin zu bedienen. Allerdings möchten wir dir hier nicht den vollständigen Lösungsweg an die Hand geben. 😉 Stattdessen erfährst du im Folgenden, wie du den Lichtsensor generell am Arduino anschließt und seine Messwerte ausliest.

Schließe deinen Lichtsensor zunächst wie folgt an deinem Arduino an:

Wie du siehst, benötigst du einen 10kΩ Widerstand, den du zwischen Sensor und GND anbringst. Neben 5V benötigst du noch eine Verbindung zu einem Analog-Pin an deinem Arduino – in unserem Fall der Pin A0.

Um die Helligkeit zu messen, benötigst du nur ein wenig Code.

const int lightSensorPin = A0;
int light;

void setup() {
  Serial.begin(9600);
}

void loop() {
  light = analogRead(lightSensorPin);
  Serial.println(light);
  delay(50);
}

Öffne nun deinen Seriellen Monitor und prüfe, welche Werte dort erscheinen. Um den Wertebereich des Sensor zu testen, halte eine Lampe direkt über den Sensor – das ist dein Maximalwert, den du im Sketch für das Theremin benötigst. Der Minimalwert sollte bei absoluter Dunkelheit gegen Null gehen, dürfte aber weitaus höher sein, wenn du deine Hand über den Sensor hältst.

Jetzt bist du dran. Bestimmt kannst du den Sketch des Theremins so anpassen, dass er mit dem Lichtsensor funktioniert! 🙂 Welche Projekte könntest du noch mit dem Lichtsensor bauen? Später im Kurs lernst du viel über das Internet of Things und Smart Homes. Vielleicht hast du hierfür ein spannende Idee?