Color to Sound - Wie man einen Farbsensor über I2C ausliest
über
Von Annika Schlechter (Deutschland) und Volker Ziemann (Schweden)
Wie kann ein sehbeeinträchtigter Mensch morgens die farblich passende Kleidung auswählen? Die Idee hinter diesem Projekt ist, dass die Farbinformation in ein Tonsignal umwandelt wird, dessen Frequenz die Farbe und dessen Dauer die Helligkeit widerspiegelt.
Bild 1 zeigt den Schaltplan eines Prototyps. Auf einem Steckboard sind ein Piezo-Summer und ein ams-Farbsensor TCS34725 auf einem kleinen Breakout-Board zusammen mit einem Arduino Nano montiert.
Ein solcher Prototyp wurde im Rahmen des Kurses „From Sensor to Report“ an der Universität Uppsala entwickelt, in dem grundlegende Fähigkeiten zur Datenerfassung einschließlich der Anbindung von Sensoren und Mikrocontrollern an die Außenwelt vermittelt werden. Und weil man nichts lernt, wenn man vorgefertigten Bibliotheken zur Sensoranbindung verwendet, programmieren wir die Grundfunktionen zum Auslesen der Sensoren selbst. Außerdem befindet sich die Logik zur Zuordnung der Töne zu den Farben zunächst in einem Python-Skript auf einem Laptop und nicht auf dem Mikrocontroller. Die Kommunikation zwischen PC und Mikrocontroller erfolgt über eine serielle Schnittstelle. Wir haben ein Kommunikationsprotokoll entwickelt, um die Sensorwerte vom Nano zum PC zu senden; in die andere Richtung gehen Befehle, um den Summer mit der richtigen Frequenz zu aktivieren. Später haben wir die Funktionalität jedoch so erweitert, dass ein Stand-alone-Betrieb auf dem Nano möglich ist. Dennoch handelt es sich hier nicht um ein „serienreifes“ System, sondern um einen Prototyp, der die Grundfunktionalität zeigt und zum weiteren Experimentieren einlädt.
Bevor wir mit dem Zusammenbau der Komponenten beginnen, müssen wir das Arduino-Entwicklungssystem (IDE) installieren, um Programme für den Nano entwickeln zu können. Die IDE ist für alle gängigen Betriebssysteme verfügbar. Bitte beachten Sie die für Ihr System relevanten Hinweise. Wenn Sie bisher noch nicht mit dem Arduino gearbeitet haben, folgen Sie bitte [4], um sich mit der Arduino-IDE vertraut zu machen. Als zweite Voraussetzung müssen wir Python installieren, das ebenfalls für alle Systeme verfügbar ist. Die Binärdateien für Windows und MAC OS finden Sie unter [5] und nehezu alle Linux-Distributionen haben entsprechende Pakete in ihren Repositories. Auch hier gilt: Folgen Sie den Anweisungen für Ihr System. Aber genug der Vorrede, fangen wir an!
Der Farbsensor
Das Herzstück dieses Projekts ist der Farbsensor TCS34725, der aus einem 3x4-Fotodioden-Array besteht (Bild 2).
Farbsensitive Filter, die vor den Dioden angebracht sind, machen sie empfindlich für rotes, grünes und blaues Licht. Darüber hinaus liefert eine klare Diode ohne Filter die Information über die Helligkeit. Das analoge Signal der Dioden wird durch Analog-Digital-Wandler auf dem Chip in eine digitale Form umgewandelt und in Registern gespeichert. Diese Farb-/Helligkeitsinformationen werden schließlich über eine I2C-Schnittstelle zur Verfügung gestellt, die mit einem Mikrocontroller verbunden wird. Für die Kommunikation werden nur zwei Drähte benötigt, einer für das Taktsignal (SCL) und einer für die Daten (SDA). Der Farbsensor wird dann durch das Schreiben und Lesen der Register auf dem Sensor-IC gesteuert, aber dazu später mehr, wenn wir die Software beschreiben.
Auf dem Breakout-Board befinden sich außer dem winzigen Farbsensor ein 3V3-Spannungsregler samt Pegelwandler für den I2C-Bus sowie eine vom Controller schaltbare weiße LED.
Die Hardware ist auf einem lötfreien Breadboard aufgebaut (Bild 3), ziemlich genau nach Bild 1 mit dem Nano auf der linken und dem Farbsensor-Breakout TCS34725 auf der rechten Seite.
Nano und Breakout-Board sind über schwarze und rote Drähte mit Masse und der 5-V-Schiene verbunden, während der I2C-Bus über den grünen Draht (Daten SDA an A4) und den gelben Draht (Takt SCL an A5) verläuft. Der Nano schaltet über den blauen Draht vom digitalen Ausgangspin D2 zum mit LED beschrifteten Pin die besagte weiße LED auf dem Breakout-Board. Der Summer ist mit Pin D8 des Nano verbunden. Der Taster, der über den braunen Draht Pin D3 mit Masse verbindet, löst eine A/D-Wandlung aus, wenn der Nano im Standalone-Modus betrieben wird, wie dies weiter unten besprochen wird.
Die Schaltung wird durch einen Arduino-Sketch zum Leben erweckt, der die wire.h-Bibliothek nutzt, die Basisfunktionen zur Kommunikation über die I2C-Leitungen bereitstellt. In unserem Sketch werden die beiden Funktionen I2Cread() und I2Cwrite() verwendet, die die gesamte Kommunikation mit dem Sensor kapseln.
I2Cread() dient zum Auslesen eines Sensorwertes oder Parameters, der in den Registern gespeichert ist. Als Parameter erhält die Funktion die Adresse des Sensors auf dem I2C-Bus (hier 0x29), und die Registeradresse (es hat eine Weile gedauert, bis wir herausgefunden haben, dass zu letzterer immer 0x80 addiert werden muss). Die Funktion gibt den Inhalt des Registers zurück.
Die Funktion I2Cwrite() wird verwendet, um Befehle vom Controller an den Sensor zu senden, zum Beispiel, um Konfigurationswerte zu setzen. Diese Funktion erhält die Sensor- und Registeradressen und zusätzlich den neuen Wert, der in dieses Register geschrieben werden soll. Von dieser Funktion wird kein Wert (void) zurückgegeben.
Die Anwendung
Kehren wir nun zu unserem Sketch zurück. In der Funktion setup() initialisieren wir die serielle Kommunikation, die grundlegende I2C-Funktionalität und den Sensor (über die Funktion color_begin()). Innerhalb der Funktion loop(), die unendlich oft ausgeführt wird, prüfen wir zunächst, ob ein Befehl vom PC auf der seriellen Leitung angekommen ist. Wenn das der Fall ist, lesen wir die Registerinhalte des Sensors aus, und zwar für alle drei Farben. Für jede Farbe werden zwei 8-Bit-Register ausgelesen und die empfangenen Bytes zu einem 16-Bit-Wort zusammengesetzt - entsprechend der Anleitung aus dem Datenblatt. Dies ist im folgenden Codeschnipsel für die rote Farbe dargestellt:
b3=I2Cread(TCS34725,0x16); // raw data, red
b4=I2Cread(TCS34725,0x17);
red=b4*256+b3;
Hier enthält b3 das niederwertige und b4 das höherwertige Byte, das wir mit 256 multiplizieren und zu b3 addieren, um die 16-Bit-Variable red zu erhalten. Die anderen Farben werden ähnlich behandelt, nur die Registeradressen sind andere.
Zusätzlich verwenden wir die von der ungefilterten Diode gemeldete Helligkeit und speichern sie in der Variablen clea, die die Dauer d des Tons bestimmt. Ist der Wert von clea kleiner als 1000, wird ein 0,5 s langer Ton ausgegeben, ist er größer, verwenden wir 1,5 s.
Nun lesen wir den empfangenen Befehl und kopieren das Ergebnis in ein Zeichenarray namens line, so dass wir mit der Standard-C-Funktion strstr() herausfinden können, welcher Befehl gesendet wurde. Der folgende Codeschnipsel zeigt dies:
Serial.readStringUntil('\n').toCharArray(line,30);
if (strstr(line,"color?")==line) {
Serial.print(clea); Serial.print(" ");
Serial.print(red); Serial.print(" ");
Serial.print(green); Serial.print(" ");
Serial.println(blue);
} else if (strstr(line,"tone_red")==line) {
tone(buzz, 262, d);
...
Wir sehen, dass der Befehl color? den Nano veranlasst, die Werte der vier Signale clea, red, green und blue über die serielle Leitung zurückzusenden. Wird tone_red empfangen, wird der eingebaute tone()-Befehl verwendet, um den Piezo-Summer zu aktivieren - in diesem Fall mit der Frequenz, die der roten Farbe zugeordnet ist. Es folgen mehrere gleich aufgebaute strstr()-Blöcke, die die entsprechenden Aktionen auslösen.
Beachten Sie, dass wir ein einfaches Protokoll verwenden, das auf dem Hin- und Herschicken von Zeichenketten basiert. Eine Anfrage aus Richtung des Laptops wird mit einem Fragezeichen abgeschlossen, zum Beispiel color?, und der Nano antwortet, indem er die Werte zurückschickt. Eine Anweisung basiert auf dem einfachen Senden des Befehls, zum Beispiel tone_red, wodurch der Summer für die Dauer d mit 262 Hz ertönt. Die Kommunikation ahmt ein wenig die SCPI-Befehlssprache nach, die von modernen Oszilloskopen und anderen Test- und Messgeräten unterstützt wird. Dies macht die Anbindung an externe Programme, die den Zugriff auf die serielle Leitung unterstützen, sehr einfach: Python, Octave, Matlab und Labview unterstützen dies.
Das PC-Programm
Wir haben Python 3 auf dem Laptop verwendet, um mit dem Nano zu kommunizieren. Der sehr einfache Code ist in Listing 1 dargestellt.
Listing 1: Python-Skript für die Kommunikation zwischen Laptop und Arduino Nano
Nach dem Importieren der Unterstützung für die serielle Kommunikation und der grundlegenden Timing-Funktionalität öffnen wir den seriellen Port zum Nano mit der passenden Baudrate. Wir geben dem Betriebssystem 3 s Zeit, um die Verbindung herzustellen und senden dann den Befehl color?.
Beachten Sie, dass Python 3 Zeichenketten als Unicode kodiert, während der Nano reine ASCII-Zeichenketten erwartet. Wir müssen also dem Befehl color? den Buchstaben „b“ voranstellen, um die Zeichenkette als reine ASCII-Daten zu senden. Nach einer weiteren kurzen Wartezeit erhalten wir die Antwort des Nano in Form der Variablen reply, die die Werte der vier Farben enthält. Mit der Methode .split() rufen wir die Werte einzeln ab und ordnen sie mnemotechnischen Namen wie red oder intensity zu.
Nachdem wir die Werte zur Verfügung haben, können wir die Logik implementieren, die die Töne den Farben zuzuordnet. Dazu haben wir in einigen Experimenten mit farbigen Papierbögen einem hellen, mittleren und dunklen Ton für jede der drei Grundfarben eine gute Zuordnung gefunden und den Sensor kalibriert. Wir haben die jeweiligen Farbwerte in einem festen Abstand wiederholt gemessen und diese Informationen verwendet, um die Konstanten in dem oben gezeigten Python-Code festzulegen. Zum Beispiel wird der Befehl tone_red an den Nano gesendet, wenn der Rotanteil, normiert auf die Intensität, größer als 0,6 ist. Als nächstes wird die Grünintensität getestet und tone_green gesendet, wenn der Schwellwert überschritten wird. Schließlich wird der Wert der Blaukomponente getestet. Wenn auch das nicht ausreicht, wird no_color an den Nano gesendet, was ihn veranlasst, den entsprechenden Ton austzugeben. Sicherlich ist etwas Experimentieren mit den Konstanten erforderlich, um das System an die Garderobe anzupassen.
Standalone-Version
Die Standalone-Version des Codes ist auf der Website dieses Artikels verfügbar. Sie lehnt sich eng an das obige Beispiel an, mit dem Unterschied, dass der Nano nun nicht mehr auf einen Befehl auf der seriellen Leitung wartet, sondern auf das Drücken der Taste, bevor er den Sensor ausliest und den entsprechenden Ton ausgibt. Außerdem wird die Farbinformation direkt auf dem Nano verarbeitet, wie im folgenden Schnipsel gezeigt:
if (red/clea > 0.6) {
tone(buzz, 262, d);
} else if (green/clea > 0.3) {
...
Wenn es wünschenswert ist, die Kleidung mit der eingebauten LED auf dem Breakout-Board zu beleuchten, können wir sie mit digitalWrite(led,HIGH) einschalten, kurz bevor wir die Register aus dem TCS34725 lesen, und sie danach wieder ausschalten.
In einem dritten Schritt können wir das System portabel machen, indem wir einen nackten ATmega328, geflasht mit einem Arduino-Bootloader, an den Sensor anschließen. Das System wird von einer Batterie mit Strom versorgt, solange ein Knopf gedrückt wird, startet es und wandelt kontinuierlich Farbe in Ton um, bis der Knopf losgelassen wird, um die Batterie abzutrennen. Diese Software ist ebenfalls auf der Webseite des Artikels verfügbar. Der Bau des Systems wird als Übung den interessierten Lesern überlassen.
Im Kurs Sensor to Report war der Farbsensor recht beliebt. Eine Studentin, die die Farbe des Himmels über einen längeren Zeitraum überwachen wollte, um die Daten später zu analysieren, verwendete im Wesentlichen den gleichen Aufbau, wobei der Nano über die serielle Leitung mit einem Host-Computer kommunizierte. Sie verwendete ein Python-Skript auf einem Raspberry Pi, um die Daten in einer MySQL-Datenbank zu speichern, die ebenfalls auf dem Pi läuft, und nutzte später Octave, um Plots der Farben zu erstellen, die über etwa eine Woche aufgezeichnet wurden. Die Plots wurden kurz vor Weihnachten aufgenommen und machten uns schmerzlich bewusst, wie kurz die Tage in Uppsala im hohen Norden werden können. Weitere Projekte zur Datenerfassung, die demselben Geist folgen, sind in [8] beschrieben.
Über die Autoren
Volker Ziemanns Interesse an der Elektronik wurde von Elektor geweckt, etwa Mitte der 1970er Jahre, zur Zeit des 40-W-Edwin-Verstärkers. Er wurde aber durch sein Physikstudium abgelenkt und arbeitete seitdem mit Teilchenbeschleunigern - SLAC in den USA, CERN in Genf und jetzt in Uppsala, Schweden. Da Elektronik natürlich eine wichtige Rolle für die Steuerung und Datenerfassung in Beschleunigern spielt, war sein frühes Interesse während seiner gesamten Karriere nützlich. Er lehrt jetzt an der Universität Uppsala und hat drei Bücher verfasst, eines davon über Datenerfassung mit Arduino-Boards und dem Raspberry Pi.
Annika Schlechter studiert mit dem Ziel eines MSc in Physik an der Universität Heidelberg. Im Moment setzt sie ihr Studium im Rahmen ihrer Bachelorarbeit am dortigen Deutschen Krebsforschungsinstitut fort. Dieses Projekt begann während eines Erasmus-Semesters an der Universität von Uppsala, wo sie Volkers Vorlesung „Sensor to Report“ besuchte.
Haben Sie Fragen oder Kommentare?
Haben Sie technische Fragen zu diesem Artikel? Bitte senden Sie eine E-Mail an die Redaktion unter redaktion@elektor.de.
Übersetzung: Rolf Gerstendorf
Diskussion (0 Kommentare)