Ein und Aus (Linux-Magazin, Januar 2014)

Mit ein paar Zeilen selbstgeschriebener Firmware und einem simplen Perlskript schaltet ein Linux-Rechner mit eingestöpselten Arduino-Board und Relais elektrische Haushaltsgeräte ein und aus.

Jeden morgen um vier Uhr früh schaltet das Ubuntu-System in meinem Büro einen uralten Debian-PC in der Ecke mit 6 TB Plattenplatz an, um per rsync ein Backup wichtiger Daten zu ziehen. Dazu stellt es per X10-Protokoll über das Stromnetz den Strom am Backup-PC an, und dieser fährt sofort hoch, da in seinem BIOS die Option "After Power Loss" auf "On" gesetzt ist. Sobald der ssh-Server des gestarteten Debian-Systems antwortet, kann es losgehen. Nach dem Backup fährt der PC wieder herunter, und der steuernde Rechner entzieht ihm wieder den Strom.

Da X10 aber aus unerfindlichen Gründen in geschätzten 1% der Fälle versagt, und dann kein Backup erfolgt, habe ich die Steuerung neulich auf ein Arduino-Board mit Relais-Zusatz umgestellt. Über den USB-Port schickt der steuernde Rechner ein Kommando an den an einer seriellen Schnittstelle lauschenden Microcontroller, dessen Firmware die Spannung auf einem Ausgangspin ändert, der wiederum mit einem Pin auf einer Platine mit zwei Relais verbunden ist ([4]). Eines davon schaltet mit einem Klicken durch, der angeschlossene Stecker führt Netzspannung, und der eingesteckte elektrische Verbraucher fängt an zu laufen. Das verwendete Relais verträgt bis zu 5 Ampere bei 230V.

Abbildung 1: Die Schaltung mit Arduino, Leuchtdiode und Relayboard.

Abbildung 1 zeigt die mit einem sogenannten "Breadboard" aufgebaute simple Schaltung, die zu Testzwecken auch noch mittels einer Leuchtdiode anzeigt, ob ein bestimmter Ausgangspin des Arduino an oder aus ist.

Einfach programmierbar

Anders als industriell vertriebene Systeme erlaubt das Arduino-Board direkt die Programmierung des aufgesteckten Micro-Controllers über ein USB-Interface. Ein PC oder Mac schickt komplilierten C-ähnlichen Code rüber, den der Arduino speichert und diese "Firmware" dann bis zum St. Nimmerleinstag ablaufen lässt. Der USB-Port versorgt das Board nicht nur mit Signalen zum Steuern der Firmware, sondern liefert auch die notwendige elektrische Spannung zum Betrieb des Arduino-Boards, der Relais-Platine, sowie der beiden aufgelöteten Relais. Das Board benötigt also keine externe Spannungsquelle wie ein Netzteil oder eine Batterie. Bei einem Kalt-Boot fängt der Code sofort wieder an zu laufen, sobald der USB-Stecker wieder Spannung liefert.

Abbildung 2: Die Arduino-IDE lädt die Firmware in den Microcontroller.

Um nun die Pins des Arduino von einem PC aus an- und auszuschalten, muss auf dem Arduino ein Programm auf Befehle von der USB-Schnittstelle horchen und diese ausführen.

Stangenware oder Maßanzug?

Als Fertiglösung hätte statt einem selbstgeschriebenen Programm auch "Firmata" (http://firmata.org) herhalten können, eine freie generell verwendbare Firmware. Einmal auf den Arduino geladen, erwartet sie Kommandos über das USB-Interface nach dem Firmata-Protokoll, manipuliert auf Anfrage den Strom auf den Pins oder liest ihre Werte aus, und liefert Antworten zum anfragenden Host-Rechner zurück. Allerdings operiert das gekaufte Relais-Board von der Firma SainSmart ([4]) im Low-Active-Modus, das Relais schnappt also zu, falls die Spannung am Eingang abfällt, und lässt los, falls 5 Volt anliegen. Da Firmata die Ausgangs-Pins aber beim Hochfahren immer auf Low stellt, würde das jedes Mal nach dem Einstöpseln des USB-Steckers den elektrischen Verbraucher einschalten, bevor ein Programm die Kontrolle übernehmen könnte.

Listing 1: relay_on_off.ino

    01 /* Simple relay controlling firmware
    02  * Mike Schilli, 2013 (m@perlmeister.com)
    03  */
    04 
    05 void setup() {
    06   Serial.begin(9600);
    07   pinMode(11, OUTPUT);
    08   digitalWrite( 11, HIGH );
    09   pinMode(13, OUTPUT);
    10   digitalWrite( 13, LOW );
    11 }
    12 
    13 void loop() {
    14   while( Serial.available() > 0 ) {
    15     int val = Serial.read();
    16     Serial.print( val );
    17     if( val == '1' ) {
    18       digitalWrite( 11, LOW );
    19       digitalWrite( 13, HIGH );
    20     } else {
    21       digitalWrite( 11, HIGH );
    22       digitalWrite( 13, LOW );
    23     }
    24   }
    25 }

Der selbstgeschriebene Arduino-Sketch (so nennt die Arduino-Community Source-Code für die Firmware) in Listing 1 setzt deswegen die Ausgangsspannung am Pin 11 mit

  digitalWrite( 11, HIGH );

in der Funktion setup() sofort auf 5 Volt, sobald der Arduino hochfährt. Später, in der Hauptschleife loop(), prüft die Methode available() des Moduls Serial, ob Daten an der seriellen Schnittstelle des Arduino anliegen. Ist dies der Fall, liest Serial.read() ein anliegendes Byte aus und speichert es in der Variablen val ab. Hat der Host das Zeichen '1' geschickt (ASCII-Code 49), setzt die Firmware Pin 11 auf LOW, und die dort angeschlossene Relais-Platine zieht das Relais zu.

USB und Serial

Microcontroller hören traditionsgemäß auf Kommandos, die vom Host über eine serielle Schnittstelle ankommen. Allerdings bieten PCs seit vielen Jahren schon keine 9-Pin-Buchsen mehr an, sondern nur noch eine Reihe von USB-Steckplätzen. Das ist auch nicht weiter schlimm, denn USB und das serielle Interface sind zwar nicht kompatibel, lassen sich aber leicht mit Hilfe eines Chips ("USB-to-Serial Converter") ineinander umwandeln. Auf alten Arduino-Boards steckt deswegen noch ein extra Chip, der die USB-Signale in serielle Kommandos umwandelt, die der Microcontroller versteht. Der relativ neue Arduino Leonardo kommt erstmals mit einem Microcontroller daher, der von Haus aus USB versteht. Der Host schickt aber weiterhin serielle Signale.

Auf dem Breadboard in Abbildung 1 ist auf Pin 13 auch noch eine Leuchtdiode mit 220-Ohm-Widerstand angeschlossen, und da die Firmware Pin 13 entsprechend des eingegangenen Kommandos setzt (also invers zum Relais-Ausgangs-Pin), schaltet sich die LED an, wenn das Relais aktiv ist.

Abbildung 3: Das Relais-Board mit zwei Relais, die Geräte bis 5A bei 230V einschalten können.

Mit der in Java geschriebenen Arduino-IDE (erhältlich auf http://arduino.cc) kann der Entwickler die Firmware nun wie in Abbildung 2 gezeigt hochladen. Die IDE findet an ein Linux-System angeschlossene Arduinos normalerweise selbstständig, aber es ist zu beachten, dass ältere Arduino-Boards teilweise unterschiedliche Device-Schnittstellen verwenden. Die serielle Schnittstelle eines relativ aktuellen "Arduino Uno" Board ist auf dem Hostsystem so unter /dev/ttyACM0 zu erreichen, während ein schon etwas in die Jahre gekommener "Arduino Duemilanove" auf /dev/ttyUSB1 horcht. Die IDE unterstützt alle jemals herausgekommenen Boardversionen und der User kann das aktuell verwendete Board in einem Drop-Down-Menü auswählen.

Testen Quick and Dirty

Zum schnellen Testen der Firmware eignet sich der "Serial Monitor" im "Tools"-Menu der IDE, mit der der Entwickler Zeichen zum Arduino senden kann und die Antwort der Firmware im Textfenster darunter angezeigt bekommt.

Der Sketch in Listing 1 schickt jedes empfangene Zeichen mittels Serial.print() wieder an den Host zurück. Abbildung 3 zeigt, wie der Entwickler das Zeichen "1" an den Arduino gesendet hat und von der Firmware mittels Serial.print() den ASCII-Code "49" zurück erhält. Gleichzeitig schnappt das Relais zu und die Leuchtdiode springt an.

Abbildung 4: Auf der seriellen Konsole schickt der Host Kommandos zum Ein- und Ausschalten des Relais.

Was nun noch fehlt, ist ein Perl-Skript, das sich an der seriellen Schnittstelle am USB-Port andockt und dem Arduino Kommandos schickt. Listing 2 nimmt hierzu von der Kommandozeile entweder "on" oder "off" entgegen. Das über das serielle Interface zu übermittelnde Zeichen ist dementsprechend "1" oder "0", das Zeile 31 an den mit dem CPAN-Modul Device::SerialPort gebundenen Port schickt.

Um zu verifizieren, dass der Arduino das Kommando auch erhalten und den gewünschten Ausgangs-Pin gesetzt hat, liest das Skript anschließend in Zeile 35 mit read() die von der Firmware zurückgeschickten Daten. Kommt nichts an, geht das Skript mit redo in die nächste Runde und unternimmt einen weiteren Schreibversuch. Wie Abbildung 5 zeigt, kann dies einige Durchgänge in Anspruch nehmen, besonders wenn der Arduino gerade erst eingestöpselt wurde. Das Skript nutzt Log4perl im $DEBUG-Modus, wer es weniger geschwätzig mag, sollte Zeile 6 dahingehend modifizieren, dass der Log-Level $ERROR beträgt.

Listing 2: relay

    01 #!/usr/local/bin/perl -w
    02 use strict;
    03 use Device::SerialPort;
    04 use Pod::Usage;
    05 use Log::Log4perl qw(:easy);
    06 Log::Log4perl->easy_init($DEBUG);
    07 
    08 my( $cmd ) = @ARGV;
    09 
    10 if( !defined $cmd ) {
    11     pod2usage();
    12 } 
    13 
    14 my $byte;
    15 
    16 if( $cmd eq "on" ) {
    17     $byte = "1";
    18 } elsif( $cmd eq "off" ) {
    19     $byte = "0";
    20 } else {
    21     pod2usage();
    22 }
    23 
    24 my $dev = Device::SerialPort->new(
    25    "/dev/ttyACM0",
    26   1,
    27 );
    28 
    29 {
    30     DEBUG "Writing ...";
    31     $dev->write( $byte );
    32 
    33     DEBUG "Reading ...";
    34     my $bytes = 2;
    35     my( $count, $data ) = $dev->read( $bytes );
    36 
    37     DEBUG "Got $count bytes";
    38 
    39     if( $count != $bytes ) {
    40         sleep 1;
    41         redo;
    42     }
    43     DEBUG "Received: \"$data\"\n";
    44 }
    45 
    46 $dev->close();
    47 
    48 __END__
    49 
    50 =head1 NAME
    51 
    52     relay - Switch relay on and off
    53 
    54 =head1 SYNOPSIS
    55 
    56     relay on|off
    57 
    58 =head1 AUTHOR
    59 
    60 2013, Mike Schilli <m@perlmeister.com>

Abbildung 5: Nachdem vierten write-Kommando kommt die Antwort des Arduino zurück.

Vorsicht Netzspannung!

Da am Relais die vollen 230V Netzspannung anliegen, muss das Selbstbauprojekt in ein stabiles Gehäuse und die Niedervolt-Platine sauber von etwaigen herumbaumelnden Netzkabeln getrennt werden. Die Relaisplatine verfügt dankenswerterweise über eine Reihe von stabilen Schraubklemmen, um das spannungsführende Netzkabel mit dem Relais zu verbinden. Bei verpolungssicheren Steckern sollte man die Phasenleitung zu unterbrechen, und nicht etwa den Nulleiter. Wer sich nicht ganz sicher ist, oder nicht über ausreichende Erfahrung beim Arbeiten mit Netzspannung verfügt, sollte einen Fachmann hinzuziehen. Schiefgegangene Experimente mit voller Netzspannung können tödliche Folgen haben, und die Redaktion des Linux-Magazins appelliert an die Vernunft ihrer geschätzten Leser.

Abbildung 6: In ein Gehäuse vom Baumarkt eingebaut ...

Abbildung 7 zeigt die amerikanische Version des USB-Schalters, mit den in den USA üblichen Flachsteckern bei 110 Volt. Auch verwenden amerikanische Elektriker keine Lüsterklemmen zum Verbinden von Litzenkabeln, sondern schrauben pragmatisch farbige Hütchen mit innenliegendem Metallgewinde, sogenannte "Twist-on Wire Connectors" ([5]) auf.

Abbildung 7: ... ergibt sich ein "industrielles" Design des USB-Relais.

Das robuste Gehäuse vom Baumarkt in Abbildung 7 ist eigentlich für die wetterfeste Verdrahtung von Stromkabeln im Hausbereich gedacht, gibt dem Hobbyprojekt aber einen rustikal-industriellen Touch. Vielleicht kann der urbane Hipster das Design ja bald bei Manufaktum erwerben?

Die Zahl der Selbstbauprojekte mit Arduinos ist über die Jahre enorm angewachsen, und es hat sich ein erstaunliches Ökosystem aus Erfindern und Produktanbietern entwickelt. Wer technische Details zur Arduino-Programmierung sucht, dem bietet [3] ist eine ausgezeichnet fundierte und detaillierte Einführung.

Infos

[1]

Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2008/05/Perl

[2]

Installationsanleitung für Ubuntu: http://www.arduino.cc/playground/Linux/Ubuntu

[3]

"Exploring Arduino" Tools and Techniques for Engineering Wizardry, Jeremy Blum, Wiley (2013)

[4]

"SainSmart 2-Channel Relay Module", http://www.amazon.com/gp/product/B0057OC6D8

[5]

"Schraub- statt Lüsterklemmen", http://usarundbrief.com/62/p6.html

Michael Schilli

arbeitet als Software-Engineer bei Yahoo in Sunnyvale, Kalifornien. In seiner seit 1997 laufenden Kolumne forscht er jeden Monat nach praktischen Anwendungen der Skriptsprache Perl. Unter mschilli@perlmeister.com beantwortet er gerne Ihre Fragen.