Wenn man mit dem Arduino Daten an den PC schicken möchte, um diese dort zu visualisieren oder zu speichern, dann bietet sich die Programmiersprache Processing dafür an. Processing basiert auf Java, arbeitet aber mit einer stark vereinfachten Syntax. Processing richtet sich – ähnlich wie das Arduino-System – besonders an Leute, die mit wenig Einstiegshürden und ohne allzu tiefe Programmierkenntnisse eigene Projekte realisieren möchten.

In diesem Tutorial sind zwei einfache Pushbuttons mit dem Arduino verbunden. Der Arduino liest den Zustand der Drucknöpfe aus und schickt mit einem simplen Kommunikationsprotokoll den aktuellen Status an den PC. PC-seitig wird die serielle Schnittstelle ausgelesen und die übertragenen Daten werden grafisch dargestellt.

Zuerst das Video:

Und hier die notwendige Schaltung (am besten im Video anschauen):

schaltung-arduino-processing

Dann brauchen wir noch einige Zeilen Programmcode für den Arduino und für Processing.

Der Arduino-Sketch:

//Arduino Sketch
// Button 1 kommt an Pin 2, Button 2 an Pin 10
const int buttonPin1 = 2;
const int buttonPin2 = 10;
 
// Zum Zwischenspeichern der Button-Zustände
int buttonState1 = 0;
int buttonState2 = 0;
 
// Enthält den String, der an den PC geschickt wird
String data;
 
// Serielle Schnittstelle einrichten, pinModes setzen
void setup() {
  Serial.begin(9600);
  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);
}
 
 
void loop() {
  // Beise Buttons auslesen
  buttonState1 = digitalRead(buttonPin1);
  buttonState2 = digitalRead(buttonPin2);  
  // und in einen einfachen String zusammenbauen
  data = normalizeData(buttonState1, buttonState2);
  // dieser String (z.B. S10E+Zeilwenwechsel) wird dann seriell ausgegeben.
  Serial.println(data);
  // Um die serielle Ausgabe zu beobachten, einfach nach dem Programmstart den seriellen Monitor in der Arduino Umgebung starten
  delay(20);
}
 
// normalizeData fügt die Werte der beiden Buttons zusammen und ergänzt den String um ein eindeutiges Start- und Endezeichen
String normalizeData(int b1, int b2) {
 
  String B1string = String(b1);
  String B2string = String(b2);
 
  // Erzeugt Werte wie S00E, S10E, S01E, S11E
  String ret = String("S") + B1string + B2string + String("E");
  return ret;
}

Der Sketch für Processing ist nur wenige Zeilen länger. Einfach in ein neues Processing-Programmfenster kopieren und mit Sketch->Run ausführen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//Processing Sketch
// Serielle Bibliothek einbinden
import processing.serial.*;
 
// Objekt zur Überwachung eines seriellen Ports erzeugen
Serial myPort;
 
// String für empfangene Daten
String portStream;
 
// Zustände der beiden Buttons
int B1in = 0;
int B2in = 0;
 
// setup() wird einmal zu Beginn dea Programms ausgeführt
void setup() {
  // Ausgabefenster und Vorder-/Hintergrundfarben definieren
  size(380,200);
  // Wenn nur ein Wert angegeben wird, wird dieser für alle 3 Farben verwendet, d.h. 255 entspricht RGB(255,255,255)
  background(255);
  stroke(160);
  fill(50);
  // Hier muss der Index des Arduino-Ports ausgewählt werden. Notfalls ausprobieren.
  String portName = Serial.list()[2];
  // myPort initialisieren, Übertragungsrate wie bei Arduino Sketch einstellen
  myPort = new Serial(this, portName, 9600);
  // Ankommende Zeichen am Port werden solange gebuffert, bis das angebene Zeichen empfangen wird.
  // Damit ist ein Datenblock vollständig übertragen. \n ist das 2. Zeichen eines Zeilenwechsels (\r\n)
  myPort.bufferUntil('\n');
}
 
// Wie loop() beim Arduino wird draw() immer wieder aufgerufen, solange das Programm ausgeführt wird.
void draw() {
  // Steht was in portStream? (d.h. wurde ein vollständiger Datenblock übertragen)
  if(portStream != null) {
    // Entspricht der Datenblock dem Format "SxxE\r\n"? Wenn ja, dann weiter
    if (portStream.length() == 6 && portStream.charAt(0) == 'S' && portStream.charAt(3) == 'E') {
      // 2. und 3. Zeichen auslesen
      B1in = int(portStream.substring(1,2));   // z.B. bei "S10E" = 1
      B2in = int(portStream.substring(2,3));   // z.B. bei "S10E" = 0
 
      // Wenn Button1 gedrückt dann Farbe grün einstellen, sonst rot
      if (B1in == 1) {
        fill(0,255,0);
      }
      else {
        fill(255,0,0);
      }      
      // und mit der Füllfarbe ein Quadrat zeichen
      rect(20,20,160,160);
 
      // Wenn Button2 gedrückt dann Farbe grün einstellen, sonst rot
      if (B2in == 1) {
        fill(0,255,0);
      }
      else {
        fill(255,0,0);
      }     
      // und noch ein Quadrat für Button 2 
      rect(200,20,160,160);
    }
  }
 
}
 
// serialEvent wird aufgerufen, wenn das weiter oben über bufferUntil definierte Zeichen empfangen wird.
// Dann wird der Inhalt des seriellen Buffers in portStream geschrieben.
void serialEvent(Serial myPort) {
  portStream = myPort.readString();
}

Wenn der Arduino läuft und im Processing-Sketch die richtige serielle Schnittstelle angegeben wurde, dann sollte jetzt ein Fenster mit zwei roten Quadraten erscheinen. Sobald einer der Pushbuttons an der Arduino-Schaltung gedrückt wird, färbt sich das zugehörige Quadrat grün.

Falls zwar ein kleines Programmfenster erscheint, aber nichts angezeigt wird, dann werden keine Daten empfangen. Bitte überprüft zuerst mit dem seriellen Monitor, ob der Sketch am Arduino auch wirklich korrekt funktioniert. Wenn das der Fall ist, dann ist im Processing in dieser Zeile

  String portName = Serial.list()[2];

statt der 2 ein anderer Index notwendig. Entweder so lange herumprobieren (beginnend bei 0), bis nach dem Programmstart die beiden roten Quadrate erscheinen oder folgenden Processing Sketch als neue Datei anlegen:

1
2
3
4
//Processing Sketch
import processing.serial.*;
Serial myPort;       
println(Serial.list());

Nach dem Start des Programms werden in der Processing-Console (der schwarze Bereich am unteren Fensterrand) nacheinander die gefundenen seriellen Schnittstelleen ausgewählt. Dort jene suchen, die im Arduino-System unter Tools->Serieller Port ausgewählt ist und den Index – beginnend bei 0 – als Listenposition eintragen. Dann sollte alles funktionieren.

Aufbauend auf diesem Projekt sind viele weitere Anwendungsfälle möglich. Viele Arduino-Projekte beschäftigen sich ja mit dem Sammeln von Sensordaten (Helligkeit, Luftfeuchtigkeit etc.), diese können mit einem ähnlichen Verfahren zum PC geschickt und dort als Diagramm angezeigt oder zur späteren Auswertung zwischengespeichert werden.

Ich freue mich über Fragen und Kommentare.

 

6 thoughts on “Arduino und Processing – Datenübertragung leicht gemacht

  • 6. Dezember 2014 um 23:43
    Permalink

    Danke für das gut erklärte Tutorial. :-)

    Antworten
  • 9. Juli 2015 um 18:16
    Permalink

    Tolles Video und Codes zu Arduino und Processing.
    Ich habe viel gelernt.

    Schöne Grüße aus der Pfalz in Rheinland-Pfalz!!!

    Robert

    Antworten
  • 25. November 2015 um 14:30
    Permalink

    Hallo,

    Wir haben ein Projekt und wissen leider nicht weiter.

    Es geht darum 2 Arduinos über RX TX zu verbinden.

    Der eine soll Werte über I2c messen, zB Temperatur, und der andere soll sie empfangen und auf einem Display anzeigen :)

    Das messen und anzeigen am gleichen Arduino funktioniert super…

    Nur wie das mit der Überrragung und Anzeige an einem 2. Arduino funktioniert…da rätzeln wir seit Wochen.

    Ich hoffe sie können uns weiterhelfen :)

    Danke im Voraus

    Antworten
  • 13. April 2016 um 10:50
    Permalink

    Arduino-UNO-Editor kopiert, bekomme jedoch beim Verifizieren die Fehlermeldung bei „void serialEvent(Serial myPort) {“ immer „variable or field ´serialEvent´ declared void“. Diese Fehlermeldung erhalte ich auch bei anderen Processing-Sketchen in denen „serialEvent“ geschrieben steht. Die Datenübertragung Deines ersten Sketches, bei dem „B1“ und „B2“ in den seriellen Monitor geschrieben wird und bei dem kein „seriellesEvent“ steht, funktioniert jedoch einwandfrei.

    Hoffentlich kannst Du mir helfen.

    MfG Siegfried

    Antworten
  • 28. Januar 2017 um 10:58
    Permalink

    Guten Tag
    Ich bin noch absoluter Anfänger in Processing und bin mich gerade am einarbeiten. Das obige Beispiel hat mir sehr gefallen!
    Ich habe versucht, es so abzuändern, dass folgendes geschieht:
    Wenn ich den Knopf drücke, dann soll ein Punkt gezeichnet werden. Wenn ich den Knopf noch einmal drücke, so soll ein weiterer Punkt rechts davon gezeichnet werden usw.

    Der Sketch schaut bei mir so aus:

    //Processing Sketch
    // Serielle Bibliothek einbinden
    import processing.serial.*;

    // Objekt zur Überwachung eines seriellen Ports erzeugen
    Serial myPort;

    // String für empfangene Daten
    String portStream;

    // Zustände der beiden Buttons
    int B1in = 0;
    int i = 0;

    // setup() wird einmal zu Beginn dea Programms ausgeführt
    void setup() {
    // Sets the screen to be 640 pixels wide and 360 pixels high
    size(640, 360);

    // Set the background to black and turn off the fill color
    background(0);
    noFill();

    // Hier muss der Index des Arduino-Ports ausgewählt werden. Notfalls ausprobieren.
    String portName = Serial.list()[1];
    // myPort initialisieren, Übertragungsrate wie bei Arduino Sketch einstellen
    myPort = new Serial(this, portName, 9600);
    // Ankommende Zeichen am Port werden solange gebuffert, bis das angebene Zeichen empfangen wird.
    // Damit ist ein Datenblock vollständig übertragen. \n ist das 2. Zeichen eines Zeilenwechsels (\r\n)
    myPort.bufferUntil(‚\n‘);
    }

    // Wie loop() beim Arduino wird draw() immer wieder aufgerufen, solange das Programm ausgeführt wird.
    void draw() {
    // Steht was in portStream? (d.h. wurde ein vollständiger Datenblock übertragen)
    if (portStream != null) {
    // Entspricht der Datenblock dem Format „SxE\r\n“? Wenn ja, dann weiter
    if (portStream.length() == 5 && portStream.charAt(0) == ‚S‘ && portStream.charAt(2) == ‚E‘) {
    // 2. und 3. Zeichen auslesen
    B1in = int(portStream.substring(1, 2)); // z.B. bei „S1E“ = 1
    // Wenn Button1 gedrückt dann Farbe grün einstellen, sonst rot
    if (B1in == 1) {
    // The two parameters of the point() method each specify coordinates.
    // The first parameter is the x-coordinate and the second is the Y
    stroke(255);
    point(width * i, height * 0.5);
    i += 0.1;
    }
    if (i == 1) {
    i = 0;
    }
    }
    }
    }

    // serialEvent wird aufgerufen, wenn das weiter oben über bufferUntil definierte Zeichen empfangen wird.
    // Dann wird der Inhalt des seriellen Buffers in portStream geschrieben.
    void serialEvent(Serial myPort) {
    portStream = myPort.readString();
    }

    Das Ziel ist es eigentlich, mit meinem Arduino Sensor-Werte auszulesen und in Abhängigkeit der Zeit darzustellen. Z.B. den Verlauf der Temperatur während einer bestimmten Messdauer aufzuzeichnen.
    Leider stehe ich gerade etwas an und bin froh, wenn Sie mir hier weiterhelfen könnten.
    Vielen Dank!

    Antworten

Schreibe einen Kommentar zu Tungee Lucien Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Time limit is exhausted. Please reload the CAPTCHA.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.