Maschinen kommunizieren Teil 1
Mit etlicher Verspätung kommt nun heute endlich das Tutorial zur seriellen Kommunikation. Serielle Kommunikation bedeutet, dass die Daten hintereinander in Form von Strompulsen über eine Leitung geschickt werden (im Gegensatz zur parallelen Kommunikation wo Daten gleichzeitig über mehrere Leitungen geschickt werden).Im Mikrokontroller-Bereich ist die serielle Kommunikation traditionell die am häufigsten verwendete Methode, da sie vergleichsweise simpel und billig zu realisieren ist.
Für unseren Physical-Kurs sind 3 Szenarien besonders interessant:
- Kommunikation von Arduino zu PC
- Kommunikation von PC zu Arduino
- Kommunikation von Arduinos untereinander oder mit anderen Schaltkreisen
Aufgrund der unterschiedlichen Anforderungen beim 3. Punkt, die den Rahmen dieses Beitrags leider sprengen würden, beschränken wir uns hier auf die ersten beiden Möglichkeiten.
Um überhaupt mit der seriellen Schnittstelle arbeiten zu können, brauchen wir auch erstmal eine Software die uns den Zugriff darauf gestattet. Hier funktioniert zum Beispiel PureData oder Processing sehr gut, für Flash brauch man dagegen eine Zusatzsoftware namens “SerialProxy”. Aufgrund der großen Nähe zu Arduino und der Einfachheit halber, wird in diesem Tutorial zunächst nur auf die Kommunikation zwischen Arduino und Processing eingegangen. Die grundlegenden Prinzipien sind aber überall gleich.
EINFACH, ABER INEFFIZIENT
Die einfachste Möglichkeit Daten zwischen Arduino und Processing hin und her zu schicken ist, sie in Form von Strings, also Zeichenketten zu versenden. Beide Programmierumgebungen bieten einfache Funktionen um Strings über die serielle Schnittstelle zu senden und zu empfangen.
Allerdings ist diese Methode nicht die effizienteste, wenn zum Beispiel Messwerte von Sensoren übertragen werden sollen. Beispiel: Der Sensorwert “206″ wird, wenn als String gesendet, zerlegt und hintereinander als “2″ … “0″ … “6″ gesendet. Der gleiche Sensorwert könnte, wenn als Zahl übertragen, mit nur einem Paket (bzw. Byte) geschickt werden.
Wenn ihr besonders viele Daten hin und her schicken wollt, oder es bei der Übertragung auf wenige Millisekunden ankommt, dann solltet ihr versuchen die Übertragung zu optimieren und auf solche Feinheiten achten. Bis dahin machen wir es uns jedoch einfach - hier der erste Arduino-Code:
/*
* AnalogInput
* by DojoDave <http://www.0j0.org>
* angepasst von Marcus <http://physical-computing.de>
* Dieser Code liest die Messwerte von einem Potentiometer
* und sendet sie über die serielle Schnittstelle als String
*
*/
int potPin = 5; // Der Pin an den das Poti angeschlossen ist
int value = 0; // Zwischenspeicher für die Werte
void setup() {
Serial.begin(9600); // Starte die serielle Verbindung mit 9600 baud
}
void loop() {
value = analogRead(potPin) / 4; // Wert vom Poti auslesen und auf 0..255 runter brechen
Serial.println(value); // Sende Wert 0...255 als STRING inklusive Zeilenumbruch
delay(20); // Kurze Pause, um Zeit für die Übertragung zu lassen
}
WAS MUSS MAN GENERELL BEACHTEN
In dem Quellcode oben sind 3 Punkte besonders wichtig für die Serielle Kommunikation. Da hätten wir zunächst Serial.begin(9600); in der setup-Methode, die dem Programm mitteilt, dass wir diese Technik verwenden wollen und - GANZ WICHTIG - die Übertragungsgeschwindigkeit festlegt.
Sender und Empfänger müssen immer auf die gleiche Geschwindigkeit eingestellt sein, da ihr sonst nur Datensalat erhaltet.
Die Funktionen Serial.print() oder Serial.println() senden dann die Daten über den Port, wobei Serial.println() standardmäßig nur Strings verschickt. Ganz wichtig ist auch, dass das Kürzel “ln” in der Funktio für “line” (also Zeile) steht und beim Aufruf der Funktion automatisch ein Zeilenumbruch mitgesendet wird. Das Zeichen sehen wir im Computeralltag eigentlich nie, trotzdem werden dafür 2 BYTE EXTRA übertragen, die wir anschließend beim Auslesen der Daten in Processing mitbedenken müssen.
Zu guter letzt ist das delay(20); nach dem Senden nicht unwichtig. Da der Controller auf dem Arduino Daten viel schneller erzeugen kann, als sie gesendet werden können und damit kein Paket verloren geht, machen wir so eine kurze Pause.
DIE GEGENSTELLE: DATEN EMPFANGEN MIT PROCESSING
Hier noch ein kurzes Stück Quelltext mit dem man die vom Arduino übertragenen Daten in Processing auslesen kann.
/* * AnalogDemo * von Marcus <http://physical-computing.de> * Dieser Code empfängt Daten von der seriellen Schnittstelle */ import processing.serial.*; // Wichtig, damit Processing überhaupt mit dem seriellen Port arbeitet int potentiometer = 0; // Variable in der wir den Wert erfassen int linefeed = 10; // Enter-Tase = Linefeed = ASCII-Code 10 int ret = 13; // 2. Zeichen für Zeilenwechsel Serial port; // Variable für die serielle Schnittstelle void setup () { size(200,200); port = new Serial(this, Serial.list()[0], 9600); // Für Mac-User // port = new Serial(this, Serial.list()[Serial.list().length-1], 9600); // Für PC-User } void draw() { if(port.available() > 0) { // Überprüft, ob Daten empfangen wurden String data = port.readStringUntil(linefeed); // Liest eine Zeile bis zum Zeilenumbruch potentiometer = int(data); // Konvertiert den String in eine Zahl } println(potentiometer); // Daten zur Kontrolle ausgeben fill(potentiometer); // Helligkeit des Applets entsprechend der empfangenen Daten rect(0,0,200,200); }
Wie man Daten von Processing an Arduino schickt, besprechen wir in Teil 2 dieses Tutorials (in Kürze).