=====Dokumentation===== ====Einleitung==== Unser Ziel war es einen Roboter zu bauen, der in der Lage ist einem Nutzer die Grundlagen des Klavierspielens zu vermitteln. Dafür wählen wir den Ansatz "learning by doing". Durch Anzeigen einer virtuellen Tastatur in Processing, an der Tasten grün eingefärbt werden können, wird dem Nutzer angezeigt welche Taste gedrückt werden muss um ein vorher vom Nutzer ausgewähltes Stück zu spielen. Dem Nutzer wird durch ein rotes Aufleuchten des Hintergrundes eine Rückmeldung gegeben, falls seine Eingabe falsch war und erst der nächste Ton vorgegeben, wenn die korrekte Taste betätigt wurde. Das Drücken der Tasten bewirkt dabei auch die Ausgabe des entsprechenden Tons wie auf einem Klavier. Der Roboter bewertet die Performance des Nutzers am Ende mit einer Punktzahl zwischen 0 und 100. Außerdem ist eine Demonstration der Stücke möglich. ====Umsetzung==== ===Überblick über das Gesamtsystem===
{{ :projektesose18:soundprof:soundproflabel.png?nolink |Das Gesamtsystem}} Das Gesamtsystem
Unser Roboter besteht aus einer zusammenhängenden Baugruppe, die die Stromkreise der Taster und den Piezo mit seinem Stromkreis umfasst. Grob betrachtet mussten fünf Hauptaufgabenbereiche bearbeitet werden: Tonausgabe, Bereitstellen der Informationen, die für ein Stück kennzeichnend sind, Anzeigen des nächsten Tons, Rückmeldung, ob gespielter Ton richtig oder falsch war und Navigation/Bedienung. Wir haben uns bewusst dafür entschieden, die Ausgestaltung des Roboters zu einem klavierähnlichen Design zu streichen und das nur anzudeuten. Ebenso das Spielen von mehreren Tönen gleichzeitig. ==Tonausgabe== Wenn eine Taste gedrückt wird, soll der Ton erklingen, dem diese Taste auf einem herkömmlichen Klavier entspricht. Dabei wichtig ist auch, dass sobald keine Taste mehr gedrückt wird auch kein Ton gespielt wird. ==Bereitstellung der Informationen, die für das Vorgeben von Songs benötigt werden== Um feststellen zu können, ob ein Ton richtig oder falsch war und ein Stück vorzuspielen, muss der Roboter wissen in welcher Reihenfolge welche Töne gespielt werden sollen und wie lange sie gespielt werden sollen. Dafür haben wir eine Arduino-Library geschrieben, die es ermöglicht "Song" - Objekte zu erstellen, die diese Informationen in Form von Attributen gespeichert haben und die nötigen Methoden besitzen um sich selbst zu demonstrieren. ==Anzeigen des nächsten Tons== Um den nächsten Ton anzeigen zu können, muss zunächst eine blanke Tastatur in Processing angezeigt werden können, davon ausgehend kann dann die Farbe des Rechtecks, das die gefragte Taste repräsentiert geändert werden, um sie zu markieren. ==Rückmeldung, ob gespielter Ton richtig oder falsch war== Als Rückmeldung die möglichst intuitiv verstanden werden kann, haben wir uns überlegt für den Fall, dass der Ton richtig war einfach den nächsten Ton zu markieren ohne eine zusätzliche Ausgabe. Sollte der Ton falsch gewesen sein, wird der Hintergrund rot eingefärbt und die selbe Taste bleibt markiert. ==Bedienung/Navigation im Menü== Um den Roboter zu bedienen wird in Processing ein Menü angezeigt, welches die zur Auswahl stehenden Stücke enthält und das im jeweiligen Moment ausgewählte in einer anderen Farbe darstellt. Mit drei zusätzlichen Tastern kann man durch dieses Menü hindurch navigieren. Ein Taster wählt den nächsten Song aus, ein zweiter startet die Demo und ein weiterer Taster startet den Spielmodus.
{{:projektesose18:soundprof:screenshot_32_.png?700, nolink |Das Gesamtsystem}} Das Menü
===Tonausgabe=== Um zu überprüfen welcher Taster vom Nutzer gedrückt wurde und dann den entsprechenden Ton auszugeben existieren im loop if-Abfragen für jeden Taster nach folgendem Muster (jeder Note wird zu Beginn eine Frequenz zugeordnet): int speakerPin = 3; //Beispielhaft gewählt int g2 = 196; //Dem Ton g2 ist auf der üblichen Klaviertastatur die Frequenz 196 Hz zugeordnet if (digitalRead(2) == HIGH) { //Wenn der Stromkreis an Pin 2 geschlossen ist (also der entsprechende Taster gedrückt wurde) tone(speakerPin, g2); //soll der zuvor festgelegte Ton gespielt werden played = "g2"; } else { played = "null"; } if (played.equals("null")) { noTone(speakerPin); //Wenn kein Taster gedrückt wird, soll kein Ton gespielt werden (noTone beendet alle tone-Aufrufe auf dem übergegebenen Pin) } Der Aufruf der noTone-Funktion ist erforderlich, da wir das Spielen so gestalten wollten, dass es möglichst viel Ähnlichkeit mit klassischem Klavierspielen hat, der Ton muss also genau dann ertönen, wenn der Taster gedrückt wird und nicht für eine vorher festgelegte Dauer, wie es mit der tone-Funktion alleine möglich gewesen wäre. ===Die Arduino-Song-Library=== Da der Nutzer erst zur Laufzeit entscheidet welches Stück gespielt werden soll, haben wir uns für die Bereitstellung der songspezifischen Informationen überlegt, dass dies am sinnvollsten realisiert werden kann mittels einer Song-Klasse, die für jeden Song die Tonreihenfolge, Länge des Songs, Länge der Töne und das Tempo in Attributen speichert und Methoden zum Vorspielen des Songs bereitstellt. Dadurch sind diese Informationen unabhängig, flexibel und gekapselt, da sie für die Funktionalität des Haupt-Codes nicht relevant sind. Aus der Header-Datei der Klasse: class Song { public: Song(int laenge, String* notes, int* beats, int tempo); //Konstruktor void play(); //spielt den Song ab void playTone(int sound, int duration); //spielt genau spezifizierten Ton void playNote(String note, int duration); //spielt den Ton, der dem Notennamen entspricht int laenge; //Anzahl der Noten String* notes; //Tonhöhe int* beats; //Länge der Töne int tempo; //Geschwindigkeit des Liedes static const int speakerPin = 3; //Variable für den speakerPin }; ===Kommunikation zwischen Arduino und Processing=== Arduino und Processing kommunizieren ständig miteinander, dabei gibt es einmal das regelmäßige Verschicken der aktuell zu markierenden Taste sowie andere Nachrichten, deren Verschicken von Aktionen des Nutzers ausgelöst wird. Um zu gewährleisten, dass keine der Nachrichten verloren geht, weil der Serial Port gerade mit einer anderen Nachricht beschäftigt ist, haben wir ein wenig mit der Baud-Rate für die Kommunikation herumprobiert und durch Ausprobieren die beste Häufigkeit für das Verschicken der aktuellen Taste gefunden. Unsere ausgewählte Baud-Rate beträgt 1200 und die zu markierende Taste wird bei jedem 2000. Durchlauf des loops gesendet. Mit diesen Einstellungen konnten wir die besten Ergebnisse erzielen (nach unserem subjektiven Empfinden haben wir bewertet, wie schnell die Reaktionen des User-Interface zu sehen sind). Weiterhin haben wir uns dazu entschieden nur Daten eines Typs, des Datentyps String zu verschicken. Um in einer ersten if-Abfrage grob zu unterscheiden was dort versendet wurde, betrachten wir die Länge des erhaltenen Strings und erst dann den Inhalt des Strings. Die Noten werden mit den üblichen Bezeichnungen von g2 bis c5 gekennzeichnet, wenn der Name einer weißen Taste verschickt wurde hat der erhaltene String also eine Länge von 4, da immer noch ein "\n" mitgeschickt wird. Entsprechend ist der String 6 Zeichen lang, wenn der Name einer schwarzen Taste enthalten ist. Die anderen Möglichkeiten für den gesendeten String sind "correct", wenn die richtige Taste gedrückt wurde, "false", falls eine falsche Taste gedrückt wurde und "gameover", wenn das Ende des ausgewählten Stückes erreicht wurde, jeweils mit einem Zeilenumbruch angehängt. value = myPort.readStringUntil('\n'); if (value != null) { if (value.length() == 4) { val = value.substring(0, 2); //wenn der Name einer weißen Taste gesendet wurde } else if (value.length() == 6) { val = value.substring(0, 4); //wenn der Name einer schwarzen Taste gesendet wurde } else if (value.length() == 7) { wasRight = false; //wenn "false" gesendet wurde bg = wrong; } else if (value.length() == 9) { wasRight = true; //wenn "correct" gesendet wurde bg = norm; } else if (value.length() == 10) { //wenn gameover gesendet wurde gameMode = false; endScreen = true; } ===Die virtuelle Tastatur=== Die virtuelle Tastatur stellt das User Interface dar. Um die Processing-Datei möglichst übersichtlich zu gestalten haben wir die Tasten mittels zweier Klassen modelliert, eine Klasse "Key" welche eine (weiße) Taste darstellt sowie eine Klasse "BlackKey" welche eine schwarze Taste repräsentiert. Die BlackKey-Klasse erbt dabei von der Superklasse "Key". Dies ist aus mehreren Gründen vorteilhaft. Zum einen müssen dadurch nur die wenigen Attribute und Methoden überschrieben/neu geschrieben werden, die für weiße und schwarze Tasten unterschiedlich sind, zum anderen können nun in Variablen des Typs "Key" sowohl Instanzen der Klasse "Key" als auch der Klasse "BlackKey" gespeichert werden. Diese Tatsache haben wir ausgenutzt indem wir sämtliche Tasten-Objekte in einer Hash-Map gespeichert haben, die als Datentypen Key-Objekte speichert und diesen String-Schlüssel zuweist. Diese Schlüssel sind die Notennamen, wie sie für die Töne der Klaviertastatur genutzt werden. Die Tasten-Objekte werden erzeugt und dabei direkt der put-Methode der Hash-Map übergeben. Die Konstruktoren der beiden Klassen führen mittels Klassenattributen Buch wie viele schwarze bzw. weiße Tasten schon existieren und berechnen daraus die x-Position der neuen Taste, damit sie nahtlos an der Letzten anliegt. Die Tasten werden als einfache Rechtecke gezeichnet, die durch ihre Höhe, Breite, Farbe und ihre Position gekennzeichnet sind. Bei jedem Aufruf der draw-Methode in Processing werden zuerst die weißen Tasten gezeichnet, dann ermittelt welche Taste markiert werden muss, dann alle Markierungen entfernt und dann die neue Taste markiert. Erst danach werden die schwarzen Tasten gezeichnet, damit sie nicht von den benachbarten weißen Tasten überdeckt werden.
{{:projektesose18:soundprof:screenshot_31_.png?400 |Die virtuelle Tastatur}}Die virtuelle Tastatur
===Menü und Bewertung=== In sowohl dem Arduino als auch dem Processing Code existiert jeweils eine boolean-Variable, die angibt, ob sich der Nutzer noch im Menü Modus befindet oder schon im Spielmodus. Je nachdem ob true oder false wird im loop bzw. der draw()-Funktion unterschiedlicher Code ausgeführt, im Falle, dass sich der Nutzer noch im Menü befindet wird vom Arduino gezählt wie häufig der Taster gedrückt wurde, der für die Auswahl des Songs zuständig ist. Diese Anzahl wird an Processing gesendet, was immerzu alle Namen der verfügbaren Songs anzeigt, wobei der gerade ausgewählte in einer anderen Farbe angezeigt wird als die Restlichen. Im Arduino-Code wird zu Beginn eine Integer-Variable "score" deklariert, die für die Bewertung steht, und mit dem Wert 100 initialisiert. Für jeden Durchlauf des loops bei dem eine falsche Taste gedrückt ist wird eins davon abgezogen, sodass je mehr Punkte abgezogen werden, je länger ein falscher Ton gespielt wird. Wenn 0 erreicht wird, werden keine weiteren Punkte mehr abgezogen. Wenn der Nutzer ein Stück zu Ende gespielt hat, wird der Wert der score-Variable an Processing gesendet und während der Arduino ein 30 sekündiges Delay ablaufen lässt zeigt Processing einen Endbildschirm mit der erreichten Punktzahl. ----- ===Materialliste=== ^ Material ^ Anzahl ^ |Arduino Mega|1| |Steckplatine|3| |Taster|32| |Widerstände (1000 Ohm)|32| |Piezo-Lautsprecher|1|
Materialliste
===Pinbelegungstabelle=== ^Arduino-Pin ^ Funktion ^ |3|Piezo| |42|Taster zum Starten des Spielmodus| |44|Taster zum Abspielen der Demo| |46|Taster Auswählen des Songs| |2, 4-19, 22-32, 52, 53|Taster für Klaviertasten|
Pinbelegungstablle
{{:projektesose18:soundprof:klavier_steckplatine.png?nolink|}}Schaltplan
== Materialliste des Modells == ^ Material ^ Anzahl ^ |Arduino Nano|1| |Steckplatine|1| |Taster|5| |Widerstände (1000 Ohm)|5| |Piezo-Lautsprecher|1|
Materialliste des Modells
{{:projektesose18:soundprof:prototyp.jpg}} Klavierähnlicher kleinerer Prototyp
====Ergebnis und Diskussion===== Der Roboter ist in der Lage den Nutzer durch ein Menü zu führen, in welchem vier Stücke zur Auswahl stehen, die alle auch per Knopfdruck vorgespielt werden können. Es kann eines dieser vier Stücke zum Nachspielen ausgewählt werden und dann die virtuelle Tastatur angezeigt werden, die die zu drückende Taste grün markiert und rot aufleuchtet, wenn ein falscher Ton gespielt wurde. Auch die Tonausgabe und Vergabe einer Punktzahl am Ende funktionieren so wie geplant und der Roboter kehrt nach Beenden eines Stückes zurück in das Menü und der Ablauf beginnt von neuem. Jedoch konnten wir ein klavierähnliches Aussehen nur in einem kleinen Modell umsetzen und mussten uns für die große Ausführung mit den Tastern und einer Markierung von schwarzen und weißen Tasten durch eine angeklebte Leiste begnügen. Außerdem konnten wir keine unserer weiteren Ideen umsetzen, man könnte zum Beispiel noch den Piezo durch einen besseren Lautsprecher ersetzen und dann auch eine Lösung für das Spielen mehrerer Töne gleichzeitig erarbeiten. Auch hilfreich wäre die Möglichkeit MIDI-Files nutzen zu können um sich das manuelle Zusammenstellen der Stücke aus Tonreihenfolge und einzelnen Tonlängen zu sparen. Wir haben einen kleinen klavierähnlichen Prototypen mit einem Tonumfang von fünf Tönen gebaut (Abbildung 5). Dieser hat Tasten aus Holz, die dem klaviertypischen Layout nachempfunden sind und das Spielen auf dem SoundProf erleichtern sollen und mittels kleiner Scharniere an einer Art Wand aus Holz befestigt sind. Die Taster samt Kabeln und Widerständen befinden sich darunter, so dass durch Herunterdrücken einer der Holztasten der darunter liegende Taster heruntergedrückt wird. Diesen Aufbau könnte man noch vergrößern, so dass alle 30 Taster des SoundProfs sich darüber betätigen ließen (Version SoundProf 2.0). =====Gesamter Code===== {{:projektesose18:soundprof:soundprof_code.zip?linkonly}}