Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

skript:kommunikation

Kommunikation zwischen Processing und Arduino

Eine detailliertere Anweisung mit verschiedenen Varianten (mit und ohne Bibliothek) gibt es an dieser Stelle im Wiki. Hier wird es um die einfache Kommunikation ohne Bibliotheken gehen. Wir werden die Position unseres Mauszeigers auf der Processing-Zeichenfläche an den Arduino schicken und damit eine LED oder einen Servo ansteuern.

1. Ein Zeichen von Processing an den Arduino schicken

Zuerst wollen wir Folgendes tun: wenn unser Mauszeiger sich in der oberen Hälfte der Zeichenfläche befindet, soll die eingebaute LED (LED_BUILTIN) angehen; ansonsten soll die LED sich ausschalten. Dies können wir mit Hilfe der seriellen Kommunikation realisieren, nur anstatt an den Seriellen Monitor von Processing (die Konsole unten) sollen die Zeichen an den Arduino geschickt werden. Wir modifizieren das Processing-Beipiel SimpleWrite (Libraries⇒Serial⇒SimpleWrite).

Wir müssen in unserem Processing-Programm angeben, an welchem Port wir mit dem Arduino kommunizieren wollen. Dies ist fast immer der letzte geöffnete Port:

  String portName = Serial.list()[Serial.list().length-1];
  // Alternativ den Portnamen direkt angeben: 
  // String portName = "/dev/ttyUSB0";
  myPort = new Serial(this, portName, 9600);

Dann können wir z.B. ein Zeichen über diesen Port an den Arduino schicken:

myPort.write('H');

Oder eine Zahl:

myPort.write(1);

Auf der Empfängerseite (Arduino) müssen wir dann dafür sorgen, dass der Datentyp richtig interpretiert wird.

Nun werden wir ein 'H' an den Arduino schicken, wenn der Mauszeiger sich in der oberen Hälfte der Zeichenfläche befindet, 'L' wenn er in der unteren Hälfte ist:

RegulateLed.pde
// Dieses Programm wird in Processing ausgeführt:
import processing.serial.Serial; // die Serial-Klasse nutzen
 
Serial myPort;  // der Port
 
void setup() 
{
  size(600, 400);
  String portName = Serial.list()[Serial.list().length-1]; // nimm den letzten
  myPort = new Serial(this, portName, 9600);
}
 
void draw() {
  if (mouseY < 200) { // Wenn Mauszeiger in der oberen Hälfte (y-Koordinate zwischen 0 und 200)
    myPort.write('H'); // schicke 'H'
  } else {
    myPort.write('L'); // sonst schicke 'L'
  }
  delay(100); // warte, bevor Daten wieder verschickt werden
}
RegulateLed.ino
// Dieses Programm wird auf dem Arduino ausgeführt:
void setup() {
  pinMode(LED_BUILTIN, OUTPUT); 
  Serial.begin(9600); 
  // Serielle Kommunikation mit 9600 bps -> diese Zahl muss mit der in Processing übereinstimmen!
}
 
void loop() {
  if (Serial.available()) { // Wenn Daten verfügbar,
    char val = Serial.read(); // lesen und in var ablegen
    if (val == 'H') { // Wenn 'H' geschickt,
      digitalWrite(LED_BUILTIN, HIGH); // LED an
    } else {
      digitalWrite(LED_BUILTIN, LOW); // sonst aus
    }
  }
}

2. Mehrere Informationen zusammen von Processing an den Arduino schicken

Im zweiten Beispiel werden wir mit dem Mauszeiger sowohl die LED als auch den Servo ansteuern. Bei der y-Koordinate bleibt es beim alten (s. das Beispiel oben). Für die Steuerung des Servos werden wir die x-Koordinate auf der Processing-Zeichenfläche nutzen: wenn der Mauszeiger ganz links ist (x=0), soll der Servo die Position 30° annehmen; wenn der Mauszeiger ganz rechts ist (x=600) die Position 150°; alle Werte dazwischen sollen dementsprechend berechnet werden. D.h. wir müssen zwei Informationen verschicken: die x- und y-Koordinate. Vorher fassen wir sie zusammen zu einem String. Wir müssen uns entscheiden, wie wir die einzelnen Informationen voneinander trennen. In diesem Beispiel werden wir die Winkelwerte von den LED-Status-Werten mit einem Semikolon (;) trennen und die Nachrichten mit einem Zeilenumbruch (\n). Unsere Nachrichten sehen z.B. so aus:

  • „90;1\n“ ⇒ Servowinkel 90°, LED an
  • „120;0\n“ ⇒ Servowindel 120°, LED aus usw.

Diesen String stellen wir dann so zusammen:

    int angle = round(mouseX / 600.0 * 120 + 30);  // den float-Wert aufrunden
    //120, weil 150 Grad - 30 Grad = 120 Grad (kleinster und höchster einstellbarer Winkel bei unseren Servos)
    myPort.write(angle + ";1\n");

Auf der Arduino-Seite empfangen wir einen String (eine Zeichenkette), welchen wir erstmal verarbeiten müssen. Der String wird zuerst zu einem char-Array umgewandelt. In diesem Array suchen wir dann, an welcher Position das Semikolon steht. Alles, was vor dem Semikolon ist, wandeln wir zu einer Zahl um und schicken diese an den Servo. Das Zeichen unmittelbar nach dem Semikolon wandeln wir ebenso zu einer Zahl um – sie bestimmt, ob die LED an- oder ausgeschaltet werden muss. Dabei nutzen wir die Funktionen String.toCharArray() und String.substring().

Die kompletten Programme sehen dann so aus:

RegulateServoAndLed.pde
// Dieses Programm wird in Processing ausgeführt:
import processing.serial.Serial; // die Serial-Klasse nutzen
Serial myPort;  // der Port
 
void setup() 
{
  size(600, 400);
  String portName = Serial.list()[Serial.list().length-1];
  myPort = new Serial(this, portName, 9600);
}
 
void draw() {
  int angle = round(mouseX / 600.0 * 120 + 30); // Servowinkel anhand der x-Koordinate berechnen
  if (mouseY < 200) { // wenn der Mauszeiger in der oberen Hälfte ist
    myPort.write(angle + ";1\n"); 
  } else { // wenn der Mauszeiger in der unteren Hälfte ist
    myPort.write(angle + ";0\n"); 
  }
  delay(100); // warte, bevor die nächste Nachricht verschickt wird
}
RegulateServoAndLed.ino
// Dieses Programm wird auf dem Arduino ausgeführt:
#include <Servo.h>
Servo motor;
int motorPin = 2;
 
void setup() {
  pinMode(LED_BUILTIN, OUTPUT); 
  Serial.begin(9600); // Soll die gleiche Geschwindigkeit sein wie im Processing-Programm
  motor.attach(motorPin);
}
 
void loop() {
  if (Serial.available()) { // Wenn Daten verfügbar,
    String message = Serial.readStringUntil('\n'); // Bis zum Zeilenumbruch lesen
    int semicolonIndex = message.indexOf(';'); // Position des Semikolons im String
    int angle = message.substring(0, semicolonIndex).toInt(); // Lese den Winkelwert aus
    int led = message.substring(semicolonIndex+1, semicolonIndex + 2).toInt(); // Lese den LED-Wert aus
    motor.write(angle); // Der Winkel muss vorher zum int umgewandelt werden
    digitalWrite(LED_BUILTIN, led); // Mach die LED an oder aus (1=HIGH, 0=LOW)
  }
}

3. Ausgabe auf der Konsole

Es wäre gut zu wissen, was für Daten eigentlich auf dem Arduino ankommen. Den Seriellen Monitor können wir leider nicht nutzen, denn der gleiche Port ist mit dem Empfangen von Daten beschäftigt. Stattdessen können wir die Daten an Processing schicken und diese dort auf der Konsole ausgeben. Auf der Arduino-Seite gibt es dafür den alten Befehl:

Serial.println("Diesen Text will ich ausgeben");

Auf der Processing-Seite fügt in der draw()-Methode den folgenden Code hinzu:

  while (myPort.available() > 0) { 
  // wiederhole das folgende, solange (while) es neue Daten (myPort.available() > 0)gibt.
    char inByte = myPort.readChar(); 
    // lese einen einzelnen Buchstaben von der Seriellen Schnittstelle
    print(inByte); // gib den gelesenen Buchstaben im Fenster unter dem Code aus.
  }
skript/kommunikation.txt · Zuletzt geändert: 2018/11/21 16:23 von d.golovko