6Mit Processing eine Arduino-Lampe ins Netz bringen

In diesem Kapitel werden wir sehen, wie wir eine funktionierende Anwendung zusammenstellen, die das in den vorangegangenen Kapiteln Erlernte nutzt. Dieses Kapitel soll dir zeigen, wie jedes einzelne Beispiel als Baustein für ein komplexes Projekt verwendet werden kann.

Hier kommt der Möchtegern-Designer in mir zum Vorschein. Wir werden die 21.-Jahrhundert-Version einer klassischen Lampe meines bevorzugten italienischen Designers Joe Colombo anfertigen. Das Objekt, das wir bauen werden, ist von einer Lampe namens Aton aus dem Jahr 1964 inspiriert.

– Massimo

Wie du in Abb. 6–1 siehst, ist die Lampe eine einfache Kugel, die auf einem Fuß mit einem großen Loch sitzt, das verhindert, dass die Kugel auf deinen Tisch herunterrollt. Dieses Design erlaubt dir, die Lampe in verschiedene Richtungen auszurichten.

In Bezug auf die Funktionalität wollen wir ein Gerät bauen, das sich mit dem Internet verbindet, die aktuelle Artikelliste des Make-Blogs (http://blog.makezine.com) abruft und zählt, wie oft die Wörter »Peace«, »Love« und »Arduino« erwähnt werden. Mit diesen Werten erzeugen wir eine Farbe und stellen sie auf der Lampe dar. Die Lampe selbst hat einen Taster, den wir zum Ein- und Ausschalten verwenden können, und einen Lichtsensor für die automatische Aktivierung.

image

Abb. 6–1Die fertige Lampe

Planung

Schauen wir uns an, was wir erreichen wollen und welche Dinge wir dafür brauchen. Zuerst benötigen wir Arduino, um eine Verbindung zum Internet herstellen zu können. Da das Arduino-Board nur einen USB-Port hat, können wir es nicht direkt mit einem Internetanschluss verbinden, sodass wir uns überlegen müssen, wie wir die beiden überbrücken. Normalerweise führen Leute eine Anwendung auf einem Computer aus, der sich mit dem Internet verbindet, die Daten verarbeitet und Arduino etwas einfache, gefilterte Information zusendet.

Der Arduino ist ein simpler Computer mit kleinem Speicher; er kann große Dateien nicht einfach verarbeiten, und wenn wir eine Verbindung mit einem RSS-Feed herstellen, erhalten wir eine sehr ausführliche XML-Datei, die erheblich mehr RAM erfordern würde. Andererseits hat dein Laptop- oder Desktop-Computer viel mehr RAM und ist für diese Art von Arbeit weit besser geeignet, sodass wir zum Vereinfachen der XML einen Proxy implementieren, indem wir die Programmiersprache für die Ausführung auf deinem Computer verwenden.

Processing

Arduino basiert auf Processing. Wir lieben diese Sprache und verwenden sie, um Anfängern das Programmieren beizubringen und um schönen Code zu schreiben. Processing und der Arduino bilden ein perfektes Team. Ein weiterer Vorteil ist, dass Processing quelloffen ist und auf allen wichtigen Plattformen läuft (macOS, Linux und Windows). Es kann auch eigenständige Anwendungen erzeugen, die auf diesen Plattformen laufen. Darüber hinaus gibt es eine lebhafte und hilfsbereite Processing-Community, und du findest Tausende vorgefertigter Beispielprogramme.

Hol dir Processing (engl. für »Verarbeitung«) von https://processing.org/download.

Der Proxy erledigt die folgende Arbeit für uns: Er lädt den RSS-Feed von http://makezine.com herunter und extrahiert alle Wörter aus der sich ergebenden XML-Datei. Dann, beim Durchgehen aller Wörter, zählt er die Anzahl der im Text auftauchenden Wörter »Peace«, »Love« und »Arduino«. Mit diesen drei Zahlen berechnen wir einen Farbwert und schicken ihn an Arduino. Der Arduino-Code sendet wiederum die vom Sensor gemessene Lichtmenge an den Computer, die dann vom Processing-Code auf dem Computermonitor angezeigt wird.

Auf der Hardwareseite kombinieren wir das Drucktastschalter-Beispiel, das Lichtsensor-Beispiel, die PWM-LED-Steuerung (mit 3 multipliziert!) und die serielle Kommunikation. Schau, ob du jede dieser Schaltungen identifizieren kannst, während du sie in »Zusammenbau der Schaltung« auf Seite 93 baust. So werden normalerweise Projekte durchgeführt.

Da es sich bei Arduino um ein einfaches Gerät handelt, müssen wir auch die Farbe auf eine einfache Art und Weise festlegen. Wir verwenden die standardisierte Form, in der Farben in HTML angegeben werden: # gefolgt von sechs hexadezimalen Zeichen.

Hexadezimale Zahlen sind praktisch, da jede 8-Bit-Zahl in genau zwei Zeichen gespeichert wird; bei Dezimalzahlen variiert dies von ein bis drei Zeichen. Die Berechenbarkeit macht zudem den Code einfacher: Wir warten, bis wir ein # sehen, und dann lesen wir die folgenden sechs Zeichen in einen Puffer ein (eine als vorübergehender Wartebereich für Daten verwendete Variable). Abschließend wandeln wir jede Gruppe aus zwei Zeichen in ein Byte um, das die Helligkeit einer der drei LEDs repräsentiert.

Programmieren

Die zwei auszuführenden Sketche: der Processing-Sketch und der Arduino-Sketch. Beispiel 6–1 ist der Code für den Processing-Sketch. Du kannst ihn auch über den Link für die Beispielcodes von der Katalogseite der englischen Originalausgabe des Buches herunterladen (https://makezine.com/go/arduino-4e-github/).

Beispiel 6–1Arduino-Netzwerk-Lampe

Teile des Codes sind von einem Blog-Beitrag von Tod E. Kurt inspiriert (http://todbot.com).

import processing.serial.*;

import java.net.*;

import java.io.*;

import java.util.*;

String feed = "http://makezine.com/feed/";

int interval = 5 * 60 * 1000; // retrieve feed every five minutes;

int lastTime; // the last time we fetched the content

int love = 0;

int peace = 0;

int arduino = 0;

int light = 0; // light level measured by the lamp

Serial port;

color c;

String cs;

String buffer = ""; // Accumulates characters coming from Arduino

PFont font;

void setup() {

size(640, 480);

frameRate(10); // we don't need fast updates

font = createFont("Helvetica", 24);

fill(255);

textFont(font, 32);

// IMPORTANT NOTE:

// The first serial port retrieved by Serial.list()

// should be your Arduino. If not, uncomment the next

// line by deleting the // before it, and re-run the

// sketch to see a list of serial ports. Then, change

// the 0 in between [ and ] to the number of the port

// that your Arduino is connected to.

//println(Serial.list());

String arduinoPort = Serial.list()[0];

port = new Serial(this, arduinoPort, 9600); // connect to Arduino

lastTime = millis();

fetchData();

}

void draw() {

background( c );

int n = (lastTime + interval - millis())/1000;

// Build a colour based on the 3 values

c = color(peace, love, arduino);

cs = "#" + hex(c, 6); // Prepare a string to be sent to Arduino

text("Arduino Networked Lamp", 10, 40);

text("Reading feed:", 10, 100);

text(feed, 10, 140);

text("Next update in "+ n + " seconds", 10, 450);

text("peace", 10, 200);

text(" " + peace, 130, 200);

rect(200, 172, peace, 28);

text("love ", 10, 240);

text(" " + love, 130, 240);

rect(200, 212, love, 28);

text("arduino ", 10, 280);

text(" " + arduino, 130, 280);

rect(200, 252, arduino, 28);

// write the colour string to the screen

text("sending", 10, 340);

text(cs, 200, 340);

text("light level", 10, 380);

rect(200, 352, light/10.23, 28); // this turns 1023 into 100

if (n <= 0) {

fetchData();

lastTime = millis();

}

port.write(cs); // send data to Arduino

if (port.available() > 0) { // check if there is data waiting

int inByte = port.read(); // read one byte

if (inByte != 10) { // if byte is not newline

buffer = buffer + char(inByte); // just add it to the buffer

} else {

// newline reached, let's process the data

if (buffer.length() > 1) { // make sure there is enough data

// chop off the last character, it's a carriage return

// (a carriage return is the character at the end of a

// line of text)

buffer = buffer.substring(0, buffer.length() -1);

// turn the buffer from string into an integer number

light = int(buffer);

// clean the buffer for the next read cycle

buffer = "";

// We're likely falling behind in taking readings

// from Arduino. So let's clear the backlog of

// incoming sensor readings so the next reading is

// up-to-date.

port.clear();

}

}

}

}

void fetchData() {

// we use these strings to parse the feed

String data;

String chunk;

// zero the counters

love = 0;

peace = 0;

arduino = 0;

try {

URL url = new URL(feed); // An object to represent the URL

// prepare a connection

URLConnection conn = url.openConnection();

conn.connect(); // now connect to the Website

// this is a bit of virtual plumbing as we connect

// the data coming from the connection to a buffered

// reader that reads the data one line at a time.

BufferedReader in = new

BufferedReader(new InputStreamReader(conn.getInput

Stream()));

// read each line from the feed

while ( (data = in.readLine()) != null) {

StringTokenizer st =

new StringTokenizer(data, "\"<>,.()[] ");// break it down

while (st.hasMoreTokens ()) {

// each chunk of data is made lowercase

chunk= st.nextToken().toLowerCase() ;

if (chunk.indexOf("love") >= 0 ) // found "love"?

love++; // increment love by 1

if (chunk.indexOf("peace") >= 0) // found "peace"?

peace++; // increment peace by 1

if (chunk.indexOf("arduino") >= 0) // found "arduino"?

arduino++; // increment arduino by 1

}

}

// Set 64 to be the maximum number of references we care about.

if (peace > 64) peace = 64;

if (love > 64) love = 64;

if (arduino > 64) arduino = 64;

peace = peace * 4; // multiply by 4 so that the max is

255,

love = love * 4; // which comes in handy when building a

arduino = arduino * 4; // colour that is made of 4 bytes

(ARGB)

}

catch (Exception ex) { // If there was an error, stop the sketch

ex.printStackTrace(); System.out.

println("ERROR: "+ex.getMessage());

}

}

Eine Sache gilt es noch zu tun, bevor der Processing-Sketch korrekt abläuft: Du musst bestätigen, dass der Sketch den korrekten seriellen Port für die Kommunikation mit Arduino verwendet. Du musst warten, bis du die Arduino-Schaltung zusammengebaut und den Arduino-Sketch hochgeladen hast, bevor du das bestätigen kannst. Auf manchen Systemen läuft dieser Processing-Sketch ganz ordentlich. Wenn du allerdings keine Aktivität auf dem Arduino erkennst und keine Angabe vom Lichtsensor auf dem Bildschirm erscheint, suche nach dem Kommentar WICHTIGER HINWEIS im Processing-Sketch und folge den dortigen Anweisungen.

image

Wenn du unter MacOS arbeitest, ist die Wahrscheinlichkeit hoch, dass dein Arduino am letzten aufgelisteten seriellen Port ist. Wenn das der Fall ist, kannst du die 0 in Serial.list()[0] mit Serial.list().length -1 ersetzen. Das zieht von der Länge der Liste aller seriellen Ports einen ab; Bereichsindizes zählen ab Null, aber length nennt dir die Größe der Liste (ab Eins zählend), sodass du eins abziehen musst, um den tatsächlichen Index zu erhalten.

Beispiel 6–2 ist der Arduino-Sketch. Du kannst ihn auch über den Link für die Beispielcodes von der Katalogseite der englischen Originalausgabe des Buches herunterladen (https://makezine.com/go/arduino-4e-github/).

Beispiel 6–2Arduino-Netzwerk-Lampe (Arduino-Sketch)

const int SENSOR = 0;

const int R_LED = 9;

const int G_LED = 10;

const int B_LED = 11;

const int BUTTON = 12;

int val = 0; // variable to store the value coming from the sensor

int btn = LOW;

int old_btn = LOW;

int state = 0;

char buffer[7] ;

int pointer = 0;

byte inByte = 0;

byte r = 0;

byte g = 0;

byte b = 0;

void setup() {

Serial.begin(9600); // open the serial port

pinMode(BUTTON, INPUT);

}

void loop() {

val = analogRead(SENSOR); // read the value from the sensor

Serial.println(val); // print the value to

// the serial port

if (Serial.available() > 0) {

// read the incoming byte:

inByte = Serial.read();

// If the marker's found, next 6 characters are the colour

if (inByte == '#') {

while (pointer < 6) { // accumulate 6 chars

buffer[pointer] = Serial.read(); // store in the buffer

pointer++; // move the pointer forward by 1

}

// now we have the 3 numbers stored as hex numbers

// we need to decode them into 3 bytes r, g and b

r = hex2dec(buffer[1]) + hex2dec(buffer[0]) * 16;

g = hex2dec(buffer[3]) + hex2dec(buffer[2]) * 16;

b = hex2dec(buffer[5]) + hex2dec(buffer[4]) * 16;

pointer = 0; // reset the pointer so we can reuse the buffer

}

}

btn = digitalRead(BUTTON); // read input value and store it

// Check if there was a transition

if ((btn == HIGH) && (old_btn == LOW)){

state = 1 - state;

}

old_btn = btn; // val is now old, let's store it

if (state == 1) { // if the lamp is on

analogWrite(R_LED, r); // turn the leds on

analogWrite(G_LED, g); // at the colour

analogWrite(B_LED, b); // sent by the computer

} else {

analogWrite(R_LED, 0); // otherwise turn off

analogWrite(G_LED, 0);

analogWrite(B_LED, 0);

}

delay(100); // wait 100ms between each send

}

int hex2dec(byte c) { // converts one HEX character into a number

if (c >= '0' && c <= '9') {

return c - '0';

} else if (c >= 'A' && c <= 'F') {

return c - 'A' + 10;

}

}

Zusammenbau der Schaltung

Abb. 6–2 zeigt den Zusammenbau der Schaltung. Verwende genau wie bei der »Lichtsteuerung mit PWM« auf Seite 60 in Kapitel 5 einen 220-Ω-Widerstand (rot-rot-braun) für jede LED und genau wie bei »Analoge Eingabe« auf Seite 71 einen 10-kΩ-Widerstand mit dem Fotowiderstand.

Erinnere dich, dass LEDs wie bei der »Lichtsteuerung mit PWM« auf Seite 60 polarisiert sind: In dieser Schaltung muss die Anode (langer Leiter, positiv) auf die rechte Seite gehen, die Kathode (kurzer Leiter, negativ) nach links. Abb. 6–2 zeigt auch die abgeflachte Seite der LED, die die Kathode kennzeichnet.

Bau die Schaltung wie dargestellt, verwende eine rote, eine grüne und eine blaue LED. Als Nächstes lade die Sketche in Arduino und Processing. Lade den Arduino-Sketch in den Arduino hoch, dann führe den Processing-Sketch aus und probiere ihn aus (du musst den Taster drücken, damit sich die Lampe einschaltet). Wenn du irgendwelche Probleme hast, schau in Kapitel 11 nach.

Statt drei separate LEDs zu verwenden, kannst du eine einzelne RGB-LED einsetzen, die vier Leiter aufweist. Du schließt sie auf sehr ähnliche Weise wie die in Abb. 6–2 gezeigten LEDs an, mit einer Änderung: Statt dreier separater Anschlüsse am Masse-Pin des Arduino führt ein einzelner Leiter (gemeinsame Kathode genannt) zur Masse.

image

Abb. 6–2Die Schaltung für die Arduino-Netzwerk-Lampe

Adafruit verkauft eine RGB-LED mit vier Leitern für ein paar Euro: https://www.adafruit.com/product/159. Im Gegensatz zu einzelnen einfarbigen LEDs ist der längste Leiter bei dieser Art von RGB-LED jener, der zur Masse führt. Die drei kürzeren Leiter müssen an den Arduino-Pins 9, 10 und 11 angeschlossen werden (mit einem 220-Ω-Widerstand zwischen den Leitern und den Pins, genau wie bei den separaten roten, grünen und blauen LEDs).

Das im Vorwort erwähnte Set enthält ebenfalls eine RGB-LED.

image

Der Arduino-Sketch ist für den Betrieb mit einer RGB-LED mit gemeinsamer Kathode ausgelegt (bei der der lange Anschlussdraht mit Masse verbunden wird). Wenn du eine falsche Ausgabe erhältst, hast du möglicherweise eine RGB-LED mit gemeinsamer Anode. Wenn das der Fall ist, ändere den Code an den Stellen, wo du die Intensität der LED einstellst, wie dargestellt (du kehrst die Werte im Grunde genommen um; wo du 0 verwendet hattest, nutzt du jetzt 255):

if (state == 1) { // wenn die Lampe an ist

analogWrite(R_LED, 255 - r); // schalte die LEDs

analogWrite(G_LED, 255 - g); // in der vom Computer

analogWrite(B_LED, 255 - b); // gesendeten Farbe ein

} else {

analogWrite(R_LED, 255); // andernfalls abschalten

analogWrite(G_LED, 255);

analogWrite(B_LED, 255);

}

Lass uns nun die Konstruktion abschließen, indem wir die Steckplatine in eine Glaskugel stecken. Der einfachste und billigste Weg ist hier der Kauf einer FADO-Tischleuchte von IKEA. Diese wird gegenwärtig für etwa 15 € angeboten.

So wird es zusammengebaut

Entpacke die Lampe und entferne das Kabel, das von unten her in die Lampe hineinführt. Du wirst sie nicht mehr an die Wandsteckdose anschließen.

Du kannst zum Befestigen des Arduino auf der Steckplatine ein Gummiband verwenden und dann die Steckplatine mit Heißleim an die Rückseite der Lampe kleben, wie in Abb. 6–1 dargestellt. Lass etwas Platz, damit du die LED einsetzen kannst, und klebe sie dann fest.

Löte längere Drähte an die RGB-LED und klebe diese dort fest, wo die Glühbirne saß. Verbinde die Drähte der LED mit der Steckplatine (an der Stelle, an der sie sich befanden, bevor du sie entfernt hast). Du kannst ein wenig Zeit sparen, indem du dir vergegenwärtigst, dass du nur eine Verbindung zur Masse benötigst, egal ob du die RGB-LED oder drei separate LEDs verwendest.

Such dir jetzt ein schönes Stück Holz mit einem Loch in der Mitte, das als Ständer für die Kugel dienen kann. Oder schneide den oberen Teil des Kartons, in dem die Lampe verpackt war, so zurecht, dass er eine Höhe von etwa 5 cm erhält. Dann schneide ein Loch mit zur Lampe passenden Durchmesser hinein. Verstärke die Innenseite des Kartons mit Heißleim an allen inneren Kanten, damit der Sockel stabiler wird.

Platziere die Kugel auf dem Ständer, führe das USB-Kabel oben aus der Lampe heraus und verbinde es mit dem Computer.

Starte deinen Processing-Code, drück den Ein/Aus-Taster und erlebe, wie die Lampe zum Leben erwacht. Lade deine Freunde ein und bring sie zum Staunen!

Versuche zur Übung, Code hinzuzufügen, der die Lampe einschaltet, wenn es im Zimmer dunkel wird. Weitere mögliche Verfeinerungen wären:

Denk dir verschiedene Dinge aus, experimentiere und habe Spaß!