I²C & Bit-Shifting

English version.

In letzter Zeit wurde ich häufiger über I²C, beziehungsweise dem damit oft einhergehenden Bit-Shifting gefragt. Konkret meine ich damit den Code der OLED-Lib und dem des Wii-Nunchuk. Beide Geräte unterstützen den I2C-Bus, welcher Thema dieses Eintrages ist. Als Antwort habe ich meistens eine kurze Erklärung, sowie den Verweis auf den Wikipedia-Eintrag zu I²C gegeben. Hier will ich aber etwas genauer darauf eingehen, wie man I²C und Bit-Shifting tatsächlich auf mehreren Controllern nutzt.

setup

(Sorry für das schlechte Bild, hatte im Moment nur meine Handykamera)

Entwickelt wurde der BUS in den 80ern von Phillips. Der genaue Name lautet Inter-Integrated Circuits Bus (IIC), woraus schnell die Abkürzung I²C (i squared c) wurde. Oftmals liest man auch die Abkürzung TWI, diese steht für Two-Wire-Interface. Die Grundzüge sind:

  • Jedes Gerät hat seine eigene 7-bit Adresse. Dies bedeutet es können bis zu 2^7=128 Geräte angeschlossen werden.
  • Eine genaue Taktgeschwindigkeit, um die Daten senden/empfangen zu können.
  • Zwei Leiter, SDA, welcher den Takt vorgibt, und SCL, die Datenleitung.
  • Einen Master, welcher den Takt vorgibt und den Bus administriert.
  • Mehrere Slaves, welche dem Master unterliegen.

Es kann auch mehrere Master geben, Zugriff auf den BUS hat aber immer nur einer, weshalb man sich bei der Verwendung mehrerer Master etwas überlegen muss, damit jeder darauf zugreifen kann – Stichwort: Multi-Master.

Der elektrische Aufbau

Für dieses Beispiel nutze ich die folgenden Bauteile:

Stk. Komponente Ausführung Beschreibung
1 Arduino UNO Master
2 Arduino Nano Slave
2 Widerstand 1kΩ I2C Pull-up
2 Widerstand 220Ω Vorwiderstand LED
1 Widerstand 10kΩ Taster Pull-down
1 Potentiometer 10kΩ
1 Taster

Der folgende Schaltplan zeigt, wie der Aufbau aussehen soll. Wichtig ist, dass man hier nur das Arduino UNO mit Spannung über den USB-Port, den VIN-Pin oder den 7-12V-Anschluss versorgt. Die beiden Nanos dürfen mit keiner externen Quelle versorgt werden. Der Grund ist, dass man mit diesem Aufbau die Schutzmaßnahmen, sowie die automatische Wahl der Versorgung der Boards umgeht. Des weiteren sollte man in diesem Aufbau an keinem der Boards zu viele zusätzliche Geräte anschließen, da alles über den +5V-Pin des UNOs versorgt wird. Der Aufbau ist für dieses Beispiel konzipiert.

shematic

Wer mehrere Geräte an die Powerline (+5V) anschließen will, muss eine zusätzliche 5V-Versorgung verbauen, welche genung Strom für alle Geräte liefert und außerdem in jedem Fall einen stabilen Output hat. In diesem Fall darf man auch das UNO nicht mehr extern mit Spannung versorgen. Will man das UNO (in diesem Fall den Master) dennoch mit einem USB-Gerät kommunizieren lassen, so muss man auf einen externen FTDI-Adapter zurückgreifen, wobei man ihn dann nur mit RX, TX & GND des Masters verbinden darf. Die Logik des Aufbaus folgt dann dem folgenden Schaltplan:

shematic_2

Die beiden Pull-up Widerstände werden gebraucht, weil der BUS LOW-active ist. Das bedeutet, dass die Daten nicht durch eine 1, sondern durch eine 0 dargestellt sind (ähnlich zu einem Bar-Code, wo die weißen Balken die Daten repräsentieren). Die meisten erhältlichen I2C-Geräte haben die Widerstände bereits verbaut, weshalb man sich darum keine Gedanken mehr machen muss.

Der Code

Wie immer findet man das Programm auf GitHub.

Dort findet man drei Verzeichnisse: Master, Slave_Reader und Slave_Writer. Die Idee meines Beispiels ist, dass der Master Daten vom Slave_Reader anfordert und diese dann dem Slave_Writer zur Verfügung stellt. Diese Daten sind der digitale Wert eines Taster und der analoge Wert eines Potentiometers. Der Ablauf sieht wie folgt aus:

  • Der Master stellt einen Request an den Slave_Reader.
  • Der Slave_Reader bekommt diesen, nimmt die Daten auf (digitalRead() & analogRead()), konvertiert diese und schickt sie dem Master.
  • Der Master konvertiert die Daten und schickt sie an den seriellen Monitor, damit man sie am PC lesen kann.
  • Als nächsten Schritt schickt der Master die unkonvertierten Daten an den Slave_Writer.
  • Dieser erhält die Daten, konvertiert sie und bringt zwei LEDs entsprechend zum leuchten.

Mit dem Wort „Konvertierung“ meine ich Bit-Shifting. Doch was ist das?

Bits & Bytes

Um zu vertstehen, warum wir Bit-Shifting benötigen, muss man wissen, dass der I²C-Bus maximal ein Byte größe Nachrichten versenden kann. Man kann zwar mehrere 1-byte-Nachrichten hintereinander schicken, doch eben nur nacheinander. Ein Byte ist acht Bits lang, und ein Bit repräsentiert den kleinsten möglichen Zustand auf einem Rechner (sei es nun ein Mikrocontroller oder PC).

Als binäre Zahl dargestellt ist ein Bit also entweder eine Null oder eine Eins. Als Variable auf dem Mikrocontroller wird ein Bit als bool-Variable dargestellt (1-0, true-false, HIGH-LOW). Ein Byte ist wie bereits bekannt eine Kette aus 8 Bits, die daraus resultierende höchste Zahl ist 255. Wem das Konzept der binären Zahlen fremd ist: Es folgt ein kurzes Beispiel:

Die Zahl 0 als Byte dargestellt wäre eine einfache 8-stellige Kette aus Nullen: 00000000. Sind alle Stellen mit Einsern belegt, so ergibt sich die Zahl 255, oder eben 11111111. Die Zahlen dazwischen ergeben sich über die Summe aus 1 & 0 mit der folgenden Logik:

2^7=128 2^6=64 2^5=32 2^4=16 2^3=8 2^2=4 2^1=2 2^0=1 Summe
0 0 0 0 0 1 1 1 7
1 0 1 0 1 0 1 0 170
1 1 1 1 0 0 0 0 240

Nun lässt sich auch erkennen, warum es binäre Zahlen heißt; das Produkt resultiert immer aus der Potenz mit Basis 2. Des weiteren ist das Bit rechts immer das mit dem niedrigsten Stellenwert (least-significant-bit lsb) und das Bit links mit dem höchsten (most-significant-bit msb). Auf diese Weise können alle Zahlen dargestellt werden, man benötigt lediglich genug Bits. Daher stammt unter anderem die Namensgebung des 64-Bit-Betriebssystems. Mit solch einem Prozessor können 64 Bits (8 Bytes) gleichzeitig berechnet werden. Als Zahl betrachtet sind das 2^64=18446744073709551616 mögliche Zustände.

Generell bedeutet das „B“ in msb und lsb jedoch Byte und nicht Bit.

Auf dem AVR-Controller, welcher auf dem Arduino verbaut ist, ist eine Integer-Variable 2 Bytes groß. Das muss man wissen, denn auf anderen Maschinen (PCs, etc.) ist ein Integer 4 Bytes groß. Man kann also folgendes festhalten:

byte a = 255;           // Von 0 bis 255, 1 Byte: 2^8=256
int b = 32767;          // Von -32767 bis 32767, 2 Bytes (1 Vorzeichenbit): 2^15=32768
unsigned int c = 65535; // Von 0 bis 65535, 2 Bytes: 2^16=65536
/*  
   Das erste (linke) Bit ist im Regelfall immer das
   Vorzeichen-Bit. Durch das Keyword 'unsigned' kann 
   dieses als Datenbit genutzt werden.
*/

Jetzt sieht man auch die Problematik: Mit dem I²C-Bus kann man wie bereits erwähnt nur 1-Byte lange Nachrichten senden. Einen Integer zu senden funktioniert nicht so einfach, wie man es gerne hätte, denn er ist einfach zu lang. Das führt uns zum eigentlichen Thema:

Bit-Shifting

Der Grundgedanke um das Problem zu lösen ist: Teile den 2-Byte großen Integer am Slave in zwei 1 Byte große Pakete auf, schicke diese nacheinader und setze sie am Master wieder zusammen. Klingt einfach, ist es auch.

Hierfür stellt uns der C++ Standard auch die nötigen Werkzeuge zur Verfügung. Wir brauchen die folgenden Operatoren:

<< Nach links shiften
>> Nach rechts shiften
& Bitweises UND
| Bitweises ODER

Zum besseren Verständnis folgt eine kurze Erklärung der Funktion der Operatoren.

Nach links shiften
110010011 << 2 = 001001100
110010011 << 4 = 100110000
110010011 << 6 = 011000000
/* 
   Die Bits werden um die nach dem '<<'-Operator angegeben Zahl
   nach links verschoben. Am rechten Ende werden Nullen angehängt.
*/
Nach rechts shiften
110010011 >> 2 = 001100100
110010011 >> 4 = 000011001
110010011 >> 6 = 000000110
/* 
   Die Bits werden um die nach dem '>>'-Operator angegeben Zahl
   nach rechts verschoben. Am linken Ende werden Nullen angehängt.
*/
Bitweises UND
1100 & 1010 = 1000
1111 & 0000 = 0000
1111 & 1010 = 1010
/* 
   Das bitweise UND gibt nur dann eine Eins, wenn zwei Einsen addiert werden.
   In jedem anderen Fall ist das Ergebnis Null.
*/
Bitweises ODER
1100 | 1010 = 1110
1111 | 0000 = 1111
1111 | 1010 = 1111
/* 
   Das bitweise ODER gibt nur dann eine Null, wenn beide Bits Null sind.
   In jedem anderen Fall ist das Ergebnis eine Eins.
*/

Mit diesem Wissen erklärt sich auch, was im Programm des Slave_Reader passiert. Dort findet man die folgenden Zeilen:

byte msb = (integerValue >> 8) & 0xFF;
byte lsb = (integerValue) & 0xFF;

Das most-significant-byte ist das linke der beiden. Ich rücke also den Integer bitweise um 8 Stellen nach rechts, wodurch die nun linken 8 Bits Nullen sind. Weil man nun trotz allem noch 16 Bits hat UNDe ich bitweise mit 0xFF (binär: 11111111). Auf diese Weise fallen die ersten 8 Bits weg. Im nächsten Schritt widme ich mich dem least-significant-byte – dem rechten Byte. Hier reicht es, einfach die linken 8 Bits zu löschen. Dies erledigt man wieder mit dem bitweisen UND von 0xFF.

Dem ’schöneren‘ Aussehen des Programms wegen schreibe ich die zu sendenden Bytes in ein Byte-Array. Man muss darauf achten, dass dieses Array am Master als auch am Slave die gleichen Daten an den gleichen Indizes hat. Also Integer_A an Stelle 0 & 1, Integer_B an Stelle 2 & 3, usw. Beim tatsächlichen Senden der Daten mit Wire.write(); steht die Zahl für die Größe des Arrays.

byte buffer[3] = {0};
buffer[0] = digitalValue; // Boolsche Variable, benötigt nur 1 Bit Platz
buffer[1] = (analogValue >> 8) & 0xFF; // analogValue ist ein Integer
buffer[2] = (analogValue) & 0xFF;
Wire.write(buffer, 3);

Betrachtet man nun den Code vom Master, so findet man die Zeile

Wire.requestFrom(slaveReader, 3);

, welche die Funktion requestHandler() am Slave_Reader triggert. Die Zahl 3 steht wieder für die Größe des Pakets in Bytes. Der Master fordert also den Slave auf, ihm Daten zu senden. Hat der Slave das getan, so werden die Daten mit den folgenden Zeilen gelesen.

while(Wire.available())
    for (int i = 0; i < 3; i++)
        buffer[i] = Wire.read();

Nun muss man lediglich die zwei Bytes des Integers wieder zusammenfügen. Dies erledigt man kurz und bündig in einer Zeile:

analogValue = (buffer[1] << 8) | buffer[2];

Was passiert hier? Das most-significant-byte befindet sich im Array an der Stelle 1, das lsb an Stelle 2. Deshalb schiebe ich das msb um 8 Stellen nach rechts, erschaffe dadurch eine 16-Bit Binärzahl in der sich an den rechten 8 Stellen lauter Nullen befinden. Diese überschreibe ich mit dem bitweisen ODER mit dem lsb. É voilà, der Integer ist wieder ganz.

Nachdem der Integer am seriellen Monitor ausgegeben wurde gehen wir noch etwas weiter und senden das Array an den Slave_Writer. Durch die drei Zeilen


Wire.beginTransmission(slaveWriter);
Wire.write(buffer, 3);
Wire.endTransmission();
    

im Programm des Masters wird die Verbindung zum Slave hergestellt, es wird das Paket gesendet, und die Verbindung wird getrennt. Die Funktion receiveHandler() im Sourcecode des Slave_Writers wird daduch getriggert und beginnt die Daten zu lesen. Über das gleiche Bit-Shift-Verfahren wie im Master wird der Integer wieder hergestellt. Letztendlich werden die beiden LEDs entsprechend angesteuert.

Die Variable slaveWriter beinhaltet lediglich die hexadezimale Zahl 0x02, welche in Dezimalschreibweise für 2 steht. Kurz: Der Slave_Reader hat die Adresse 0x01 = 1, der Slave_Writer die Adresse 0x02 = 2. Die Adressen können frei gewählt werden.

Letzte Worte

Geräte, welche an dem I²C Bus angeschlossen sind müssen immer mit Spannung versorgt sein. Ein deaktiviertes Gerät sollte deshalb auch nicht am Bus angeschlossen sein. Der Grund ist, dass das Gerät dann Spannung aus den beiden Busleitungen bezieht. Das Resultat ist ein blockierter Bus oder ein defektes Gerät.

Ich habe versucht, alles relevante zu beschreiben, was man wissen muss, um Daten mit dem I²C Bus zu senden. Falls dennoch Fragen offen sind: Ein Kommentar oder die Doku.

Arduino & Nunchuk

English version.

Eines meiner Projekte benötigt einen Joystick und 2 Buttons als Eingabemöglichkeit. Das ganze selbst zu bauen wäre nicht das Problem, doch als ich hörte, dass der Wii Nunchuk mit I2C arbeitet konnte ich gar nicht anders, als ihn für meine Zwecke zu nutzen.

Setup_Bokeh.jpg

In diesem Beitrag zeige ich, wie man die Daten vom Controller via I2C auslesen kann. Diese Daten werden dann auf einem Display und mit 6 LEDs dargestellt.

Der elektrische Aufbau

Für dieses Tutorial benötigt man die folgenden Bauteile

  • 1 Arduino UNO/Nano
  • 1 Wii Nunchuk
  • 1 0.96″ I2C Display
  • 6 LEDs
  • 6 220Ω Widerstände für die LEDs

Neben dem Steckbrett gibt’s auch noch den Schaltplan, da es wegen der LED-Anordnung recht eng geworden ist.

Wii_Nunchuk_Schaltplan

Wii_Nunchuk_Steckplatine

In Real sieht der Setup dann etwa so aus:

Setup

Achtung! Die Versorgungsspannung des Nunchuks beträgt 3.3V. Er darf auf keinen Fall an die 5V Leitung angeschlossen werden, da dies ihn sonst beschädigen würde! Er hat zudem einen Logic Level Shifter integriert, was die Nutzung der I2C-Pins ohne weitere Maßnahmen erlaubt.

Die meisten I2C-Displays dieser Größe arbeiten mit 5V. Mehr zu dem Display und dessen Verwendung kann man hier nachlesen. Wem das Lesen zu viel ist, der kann sich hier die nötige Programmbibliothek für den Display herunterladen und in das Standard-Verzeichnis für Arduino-libs (../Arduino/libraries/) kopieren.

Der Code

Wie immer: GitHub.

Im Hauptverzeichnis auf GitHub findet man 3 *.ino-Dateien. Wer die Standard-Arduino-IDE nutzt, der muss lediglich das Hauptfile – Wii_Nunchuk.ino – öffnen. Die beiden anderen Dateien werden automatisch in neue Tabs geladen. Wenn alle Dateien offen sind folgt hier die Erklärung der Funktionen:

  • setup. Pins festlegen, Controller initialisieren, controllerspezifische Kalibrierung festlegen (dazu später mehr), Display initialisieren.
  • loop. Daten vom Nunchuk anfordern, diese dann auf ein „hübsches“ Outputformat für den Display bringen und ausgeben. Zum Schluss noch die LEDs passend zum Signal ansteuern.
  • printFormNum. Damit die Zahlen rechtsgebunden am Display erscheinen wird der auszugebende String an die Länge der Zahl angepasst.
  • sendDataToNunchuk. Hier wird mit Hilfe der Wire.h-Library ein Datensatz an den Nunchuk gesendet. Für mehr Info über die I2C-Kommunikation: http://playground.arduino.cc/Learning/I2C.
  • initNunchuk. Zu Beginn muss der Nunchuk initialisert werden, wobei festgelegt wird aus welchem Register des Nunchuks wie ausgelesen wird.
  • getNunchukData. Hier passiert das Spannende. Zuerst schickt man dem Controller einen Request für die ersten 6 Register (0x00, 0x01, …). Hinter diesen Registern verbergen sich die Postionsdaten des Joysticks und der Buttons als Zahlenwert. Hat der Controller den Request erhalten, so schickt er an das Arduino die jeweiligen Daten zurück. Die map-Funktion wird hier als controllerspezifische Kalibrierung eingesetzt.

Ist das Programm auf das Arduino geladen, so kann man bei Benützung des Nunchuks die Daten, welche von ihm empfangen werden vom Display ablesen. Zusätzlich ändert sich die Helligkeit der LEDs passend zur Eingabe.

Display_Close.JPG

Was ist nun die ominöse Kalibrierung? Die Daten, welche der Controller an den Arduino schickt sind nicht weiter verarbeitet, sie sind also Rohdaten. Nun kann es passieren, dass man den Joystick ganz nach links drückt, der Zahlenwert der X-Koordinate dennoch nicht Null ist. Um das zu ändern muss man zunächst im Setup alle die Min/Max-Values zurücksetzen auf:

nunchuk.MinX = 0;
nunchuk.MaxX = 255;
nunchuk.MinY = 0;
nunchuk.MaxY = 255;

Nun lädt man das Programm erneut auf das Arduino und notiert sich die angezeigten Werte der äußersten Position des Joysticks:

  • MinX ist jener Wert, wenn der Joystick ganz nach links gedrückt wird (zB: 29).
  • MaxX: Wert, wenn Joystick ganz nach rechts gedrückt wird (zB 228).
  • MinY: Wert, wenn Joystick nach unten gedrückt wird (zB 33).
  • MaxY: Wert, wenn Joystick nach oben gedrückt wird (zB 222).

Diese Werte trägt man dann in die Kalibrier-Variablen ein.

nunchuk.MinX = 29;
nunchuk.MaxX = 228;
nunchuk.MinY = 33;
nunchuk.MaxY = 222;

Nun ist das Programm für diesen einen Controller ausgelegt.

Das war’s, bei Fragen ist ein Kommentar immer erwünscht!

.

 

16×2 I2C-Display on Raspberry Pi

English version.

Wer einen kleinen Display am Raspberry benötigt, der ist hier richtig! Mit wenig Aufwand und ein paar wenigen Bauteilen kann man einen I2C-Display am Raspberry Pi nutzen.

Das Raspberry vorbereiten

Als erstes muss alles aktuell sein, weshalb man im Terminal den Befehl

sudo apt-get update

eingeben muss. Um auf dem Raspberry Pi auch wirklich den I2C-Bus nutzen zu können, muss man diesen zuerst aktivieren. Der erste Schritt ist es im Terminal den Befehl

sudo raspi-config

einzugeben. Daraufhin erscheint die Setup-Utility, in welcher man den Menüpunkt 8 Advanced Options auswählen muss.

001

Im nächsten Fenster muss man A7 I2C auswählen, und alle kommenden Fenster mit Yes oder OK bestätigen. Mit Finish kehrt man zurück zum Terminal.

002

Im zweiten Schritt muss das Module File um zwei Einträge erweitert werden. Dies wird erledigt, indem man zunächst

sudo nano /etc/modules

ausführt und dann am Schluss der Datei die beiden Einträge

i2c-bcm2708
i2c-dev

hinzufügt. Mit STRG+X, Yes und Enter speichert man die Datei und schließt sie.

003

Um den I2C-Bus mit Python nutzen zu können benötigt man python-smbus und die i2c-tools. Beides hohlt man sich durch den Terminal-command

sudo apt-get install -y python-smbus i2c-tools

Danach muss man das Raspberry neu starten, sodass der I2C-Bus wirksam wird. Dies kann über die grafische Oberfläche oder im Terminal geschehen:

sudo reboot

Der Aufbau

Die paar wenigen Bauteile sind:

  • Raspberry Pi 2
  • 16×2 I2C-Display
  • Logic Level Shifter

Der Logic-Level-Shifter wird benötigt, da das Raspberry mit dem logischen Level von 3.3V arbeitet, die meisten Displays jedoch mit 5V arbeiten. Solche Level Shifter gibt es bereits um unter einen Euro auf eBay zu haben. Bei diesem Preis lohnt sich das selbst machen nur noch aus Interesse daran.

Level_Shifter

Die Verdrahtung ist wie im Bild unten ersichtlich nach der folgenden Tabelle durchgeführt.

  • Level Shifter – Raspberry Pi
    • GND – GND (Pin 6)
    • HV – 5V (Pin 2)
    • LV – 3V3 (Pin 1)
    • LV1 – SDA (Pin 3)
    • LV2 – SCL (Pin 5)
  • Level Shifter – I2C Display
    • GND – GND
    • HV – Vcc
    • HV1 – SDA
    • HV2 – SCL

Untitled Sketch_Steckplatine

Der fertige Setup sieht dann in etwa so aus:

Setup

Das Display ist ein normales HD44780-Display, welches einen I2C-Rucksack bekommen hat. Diese „Rucksäcke“ gibt es einzeln, oder bereits mit dem Display verlötet.

Display

Der Code

Das Programm befindet sich auf GitHub und kann auch direkt von dort auf das Raspberry geladen werden.

Die beiden Python-files (16x2_I2C_Display.py & lcd.py) müssen in das selbe Verzeichnis auf dem Raspberry kopiert werden, da das erste File das zweite aufruft.

16x2_I2C_Display.py

Dieses Programm zeigt die IP-Addresse des Pi auf dem Display an. Dabei importiert es die Funktionen der Datei lcd.py.

Im Main ist die Herangehensweise gezeigt. Man muss den Display zuerst initialisieren, danach kann man ihm Text zum „Drucken“ schicken oder aber auch die Hintergrundbeleuchtung an- oder abschalten.

lcd.initialize()
lcd.printString("TEXT", lcd.LINE_1)
lcd.noBacklight()
lcd.Backlight()

lcd.py

Hier passiert das Wichtige – die Kommunikation mit dem Display. Diese funktioniert ähnlich wie mit einem Arduino (siehe hier). Deshalb lassen sich die Befehle des Displays auch genauso bequem senden. In der sendByte()-Funktion lässt sich erkennen, dass ich immer wieder BACKLIGHT mitsende. Das muss so sein, weil der Display ansonsten die Hintergrundbeleuchtung abdreht, und so seinen Sinn & Zweck verliert.

Über den smbus (hier als i2c deklariert) werden die nötigen Daten gesendet. Dabei wird immer die Addresse, gefolgt von den Daten gesendet. In der sendByte()-Funktion werden diese als Abfolge der Datenblöcke (Typ, Daten, Beleuchtung) gesendet. Hier wird das Delay benötigt, da der Display die Daten ansonsten nicht korrekt erhält.

Das lcd.py kann man nun (genau so wie es ist) für andere Projekte nutzen. Einfach in das jeweilige Python script mit import lcd einfügen. Allerdings muss es sich im selben Verzeichnis befinden.

Anmerkung: Man kann auch einen 20×4 Display verwenden, dazu muss man im lcd.py File einfach nur die Zeile 15 verändern (16 -> 20) und Line_3, Line_4 nutzen im printString-Befehl nutzen.

Nachbereitung

Ich möchte die IP-Adresse für 15 Sekunden anzeigen lassen, sobald der Raspberry hochgefahren ist. Hierfür muss man das Script nach dem Start ausführen lassen.

Zuerst habe ich beide Dateien in das Verzeichnis /home/pi/Autostart/ verschoben und die Datei 16x2_I2C_Display.py umbenannt in showIP.py.

Danach muss man das Terminal öffnen und folgenden Befehl eingeben:

sudo nano /etc/rc.local

Anschließend muss man den Pfad und die zu öffnende Datei angeben, in meinem Fall ist dies

/bin/sleep 15 && cd /home/pi/Autostart/ && sudo python showIP.py &
exit 0

sleep 15 bewirkt, dass das Script erst 15 Sekunden nach dem Hochfahren ausgeführt wird. Nach einigem Testen hat sich gezeigt, dass das Pi etwa 15 braucht, um eine IP Adresse abzurufen. & am Ende der Zeile bedeutet, dass das Script im Hintergrund ausgeführt wird. Das exit 0 am Ende wird von rc.local benötigt, es beendet das Script. Wenn ihr also noch andere Scripts beim Systemstart ausführen wollt, stellt sicher, dass exit 0 auch wirklich in der letzten Zeile steht.

004

Mit STRG+O speichert man das File, und mit STRG+X schließt man es. Beim nächsten Neustart sollte man dann ein ähnliches Bild wie das folgende sehen können.

IP.jpg

Bei Fragen ist ein Kommentar immer erwünscht!

 

Catalex SD & SoftSPI

English version.

In einem früheren Beitrag hatte ich erwähnt, dass ich Daten eines Sensors auf einer SD Karte speichern wollte, dies aber nicht möglich war, da das Catalex SD Card Modul den SPI Bus blockierte, mit dem auch ein anderes benötigtes Modul verbunden war.

Nach etwas Arbeit und trouble shooting läuft es nun. Für alle, die das selbe Problem haben (dass das Catalex Modul nicht mit anderen SPI-Geräten verwendbar ist) habe ich hier die Lösung!

Vorweg meine Idee: Ich möchte zwei Arduinos verwenden, das eine dient als Sender, das andere als Empfänger von Daten. Diese Daten nehmen ich am Sender mit Hilfe von Temperatursensoren auf und schicke sie mit dem NRF24L01+ Wireless-Modul an den Empfänger. Dieser nimmt sie mit dem gleichen Modul auf und zeigt sie an einem Display an. Zusätzlich werden sie noch auf dem SD Card Modul von Catalex gespeichert.

Catlex

Der Grund für diesen Aufwand ist, dass das SD Kartenmodul von Catalex (v1.0) den SPI-Bus blockiert, da es das SN74LVC125A-Modul als Level-Shifter nutzt. Leider wurden die nötigen Pins, um anderen Geräten die Kommunikation auf dem BUS zu ermöglichen, auf Ground gelötet. Deshalb blockiert das SD-Karten-Modul den BUS. Die einzige Lösung es trotzdem mit anderen SPI-Geräten zu nutzen ist es mit einer Softwarelösung auf andere Pins zu setzen. So erzeugt man quasi 2 SPI-Bus-Systeme auf einem Arduino.

Der elektrische Aufbau

Die Temperatursensoren und den Display habe ich beide hier vorgestellt. Die Details zum NRF24-Modul sind hier zu finden und der Inhalt zum SD Card Modul soll in diesem Beitrag folgen.

Der Aufbau benötigt neben den Modulen auch ein paar andere Komponenten.

  • Sender
    • 1 Arduino Uno/Nano
    • 1 NRF24L01+ Wireless Modul
    • 2 DS18B20 OneWire Temperatursensoren
    • 1 4.7kΩ Widerstand für den Datenbus
  • Empfänger
    • 1 Arduino Uno/Nano
    • 1 NRF24L01+ Wireless Modul
    • 1 SD Card Reader Modul (Catalex v1.0)
    • 1 I2C Display (16×2)
Der Sender

Transmitter_Shematic

Transmitter

* den Button einfach ignorieren!

Der Empfänger

Receiver_Shematic

Receiver

Der Code

Das Programm befindet sich natürlich auf GitHub.

Doch bevor man das Programm auf das Arduino laden kann benötigt man ein paar Programmbibliotheken, damit die Module auch richtig funktionieren. Alle nötigen Libs findet man auf GitHub im Verzeichnis ‚Libraries‘.

Das Catalex SD Card Modul wird an den SoftSPI-Bus angeschlossen. Dies ist nichts anderes als eine Imitation des Hardware-SPI-Bus, nur eben von der Software verwaltet. Hierzu muss man die SdFat-Bibliothek etwas editieren, genauer das ‚SdFatConfig‘-File.

Zu editierender Inhalt: Zeile 81, #define SD_SPI_CONFIGURATION 3 (Standard 1).

Ich habe dies bereits getan, sodass man nur mehr alle Bibliotheken des Ordners auf GitHub in das Standardverzeichnis von Arduino kopieren muss.

Transmitter.ino

Der Transmitter nimmt in definierten Zeitintervallen die Messwerte der Sensoren auf und sendet sie über das RF24 an den Empfänger. Für mehr Informationen verweise ich auf die oben genannten Beiträge.

Receiver.ino

Die Daten werden vom RF24 empfangen und auf dem Display dargestellt. Um sie dann auf der SD Karte zu speichern muss man das Textfile auf der Karte wie folgt aufrufen:

file.open("Temp.txt", O_WRITE | O_CREAT | O_AT_END);

Das erste Attribut gibt den Dateinamen an. Das zweite steht für die Art des Zugriff. In diesem Fall passieren 3 Dinge:

  • O_WRITE: Es wird auf die Karte geschrieben und nicht gelesen.
  • O_CREAT: Existiert keine Datei namens ‚Temp.txt‘ wird eine leere erzeugt.
  • O_AT_END: Es wird am Ende der Datei weiter geschrieben. Andernfalls würde man alle Daten in der Datei überschreiben.

Zu Beginn der Datei muss man zusätzlich noch definieren, wo man den SoftSPI-Bus verwenden will. Ab Zeile 55 wird dies erledigt.

const uint8_t SOFT_MISO_PIN = 4;
const uint8_t SOFT_MOSI_PIN = 5;
const uint8_t SOFT_SCK_PIN = 6;
const uint8_t SD_CHIP_SELECT_PIN = 7;

Im großen und ganzen war es das. Es ist, wie man sieht, nicht besonders schwer alles unter einen Hut zu bringen, doch bis man alles nötige zusammen hat dauert es schon etwas. Ich hoffe mal das hilft all‘ jenen die das gleiche Problem haben wie ich.

Vielleicht noch eine kleine Anmerkung zum Schluss. Da das SD Modul nun am SoftSPI-Bus hängt kann man den „normalen“ SPI-Bus wieder ganz normal und ohne Einschränkungen nutzen. Die Verwendung beschränkt sich nicht auf SD+RF24, sondern man kann jede Kombination nutzen, etwa SD+RFID.

Bei Fragen ist ein Kommentar immer erwünscht!

Water Drop (Pro)

English version.

Nachdem ich mit Water Drop (Advanced) gute Erfolge im Bereich der Wassertropfenfotografie verbuchen konnte, war es an der Zeit ein neues Projekt zu starten und die Water Drop Reihe etwas zu erweitern. Und so startet hier das neue und bessere Water Drop (Pro).

.

drop_0.JPG

.

Was ist nun der Unterschied zu den beiden Vorgängern, außer das einfallslose Pro hinter dem noch einfallsloserem Water Drop? Nun zum einen nutze ich hier zum ersten Mal Elektromagnetventile, welche über den Mikrocontroller gesteuert werden. Zum anderen arbeitet der Controller nun mit einer Host-Software zusammen, die vorerst nur unter Windows OS läuft. Zusätzlich unterstützt die Software alle gängigen Canon EOS DSLR Modelle, wodurch sich die Einstellung des Fokus, der Blende, der Filmempfindlichkeit sowie der Verschlusszeit vereinfachen soll – man braucht seine Kamera nun nicht mehr anzufassen, um Änderungen vorzunehmen.

Der Umfang der steuerbaren Ventile beläuft sich derzeit auf drei Stück. Zusätzlich arbeite ich noch an ballistischen Ad-Ons, doch bis diese lauffähig sind wird es noch etwas dauern.

Das Projekt ist doch sehr umfangreich, dennoch will ich versuchen, es für alle vollständig nachvollziehbar zu machen, sodass sich jeder, der Tropfen fotografieren will, daran erfreuen kann. Der Aufbau der elektronischen Schaltung benötigt neben Zeit und etwas Geschick beim Löten (falls man sich für die Verwendung einer Platine entschließt) auch etwas mehr an fotografischer Ausrüstung. Doch zu allem später mehr !

Da ich in diesem Blogpost nicht alles unterbringe, was ich unterbringen will, findet man hier alles weitere. In dem Zip-File (so nenne ich es im weiteren Verlauf) sind nicht nur die neuesten Versionen der Software für Host und Controller zu finden, sondern auch die Fertigungspläne für elektrischen und mechanischen Aufbau und ein kleiner Guide für das gesamte Package.

Vorerst möchte ich ein paar Tricks verraten, wie man das Wasser behandeln kann, sodass es sich besser ablichten lässt.

Das Wasser

Wer meinen Beitrag zu Water Drop (Advanced) gelesen hat, dem mögen die folgenden Zeilen vielleicht bekannt sein, denn es hat sich nicht viel geändert.

Die Tropfflüssigkeit, welche von der Düse auf das Wasser trifft, behandle ich auf zwei verschiedene Arten, je nach gewünschtem Ergebnis:

  • Reines Wasser – ergibt starke Spritzer
  • Wasser-Guarkernmehl-Mischung – ergibt gebundenere Formen.

Abgesehen von der Variante filtere ich das Wasser vor jeder Fotosession, um so wenig Verunreinigungen wie möglich im Bild erkennen zu können (der Raum sollte auch sauber sein, da sich ansonsten Staub aus der Umgebung auf der Wasseroberfläche sammeln kann). Als Filter nutze ich einen Sieb, in das ich ein Stück Küchenpapier oder ein Taschentuch lege. Kaffeefilter sind ebenso gut zu verwenden.

Filter.jpg

Die Guarkernmehl-Mischung (etwa ein Teelöffel) bereite ich mit etwa 5cl Weingeist zu. Nach dem Umrühren gibt man das Gemisch in einen sauberen Behälter mit 2 Litern warmen Wasser. Danach muss 15 Minuten stark umgerührt werden, sodass sich das Guarkernmehl im Wasser lösen kann. Dieses Gemisch lasse ich dann abgedeckt ein paar Stunden so stehen.

Guarkern

Die Dichte des Beckenwassers behandle ich nicht. Ich filtriere lediglich reines Leitungswasser, und achte darauf, dass das Becken sauber ist. Als Becken nutze ich alles Mögliche, von Trinkgläsern bis hin zu Pfannen. Je nach Bildausschnitt sollte das Becken bis zum Rand gefüllt werden, sodass man den “Horizont” nicht mehr erkennen kann. Hinter das Becken kann man verschiedenfarbige Platten stellen, um so eine tolle Farbgebung der Szene zu erreichen.

Zuletzt habe ich auch mit destilliertem Wasser experimentiert. Die Ergebnisse auf den Bildern sind identisch mit jenen des normalen Wassers. Ich nutze es lediglich, um das Ventil und die Schläuche zu schonen (Kalkansammlungen). Wer mit höher viskosen Flüssigkeiten seine Bilder macht, der sollte den Aufbau nach der Arbeit auf jeden Fall mit destillieren (oder normalen) Wasser spülen.

Da alles zum Thema Wasser gesagt wurde, kommen wir nun zum nächsten Schritt.

Der mechanische Aufbau

Wie bereits erwähnt unterstützt der Controller bis zu 3 Elektromagnetventile, welche die Wassertropfen erzeugen. Aus finanziellen Mitteln zeige ich die Konstruktion nur mit einem Ventil, doch die Installation der beiden anderen Ventile funktioniert in jeder Hinsicht gleich. Sowohl die Software, als auch die Hardware unterstützen alle drei Ventile – Plug & Play.

Der Rahmen

Als Rahmen nutze ich ein selbst gebautes Gestell, welches so gebaut ist, dass man es einfach zerlegen und platzsparend verstauen kann, denn nicht jeder ist mit viel Platz gesegnet.

Die kompletten Daten, sowie die Pläne für die Fertigung sind unter dem oben genannten Link – ZIP-File – zu finden.

Frame_001.jpg

Das Gestell hat eine Höhe von etwa ein-ein-halb Metern, sodass man es auch auf einen Beistelltisch stellen kann, um nicht immer am Boden sitzen zu müssen. Die Breite ist so gewählt, dass man ein Backblech darunter legen kann, das als Spritzschutz für die Umgebung dient.

Die Montage ist einfach. Die beiden seitlichen Bretter werden mit Flügelschrauben an den horizontalen Staffeln befestigt. In den Staffeln sind Einschraubmuttern eingeschraubt, welche die Verbindung zwischen Holz und Schraube herstellen.

So kann man das Gestell schnell zusammenbauen und wieder zerlegen.

Der Ventilkopf

Hierauf sitzen die Ventile, deshalb habe ich hier bei der Fertigung besonders auf hohe Genauigkeit geachtet. Die Ventile befinden sich alle auf der selben Höhe und lassen sich in ihrer Entfernung zueinander über Langlöcher verstellen. Das Ventil präsentiere ich etwas später im Beitrag.

Frame_003

.

Frame_004

Vom Controller ausgehend lasse ich ein 6-poliges Kabel zum Ventilkopf laufen, welches dort dann in einem Verteiler endet. An diesem können die Ventile separat angeschlossen werden.

Der Wassertank

Eine Ebene höher befindet sich der Wassertank. Jedes Ventil hat seinen eigenen Wassertank, welcher nach dem Mariotteschen Prinzip gebaut wurde. So bleibt der Druck des Wassers auf das Ventil konstant und erlaubt eine immer gleich bleibende Austrittsgeschwindigkeit. Das ist in der Berechnung der Fallzeit in der Software äußerst wichtig!

Frame_005.jpg

Das Prinzip der Flasche ist im Grunde recht einfach. Läuft Wasser unten aus, so erzeugt das schwindende Volumen des Wassers einen niedrigeren Druck der Luft oberhalb. Ist der Druck der Umgebung groß genug, das er sowohl jenen der Flüssigkeit und der Luft in der Flasche überwinden kann, so wird Luft von außen angesaugt. Dies hat die Folge, das der Druck am unteren Ende des Röhrchens immer der konstante Umgebungsdruck ist (solange der Wasserspiegel nicht unter die Öffnung des Röhrchens fällt).

Mariottesche_Bottle_Concept

Das Gehäuse

Das Gehäuse beinhaltet die Platine, auf welcher das Arduino Nano sitzt. Die nötigen Unterlagen für die Fertigung der Platine sind ebenfalls im oben genannten Zip-File zu finden, die Details zum Schaltplan folgen etwas später in diesem Post.

Switchbox_Front

An der Front des Gehäuses findet man einen Display, der den jeweiligen Status anzeigt, den Hauptschalter, einen Reset-Button und drei Buttons, welche die jeweiligen Ventile kurz öffnen. Dies soll die Einrichtung des Fokus der Kamera erleichtern.

Switchbox_Back

Auf der Rückseite sind die Anschlüsse untergebracht. Das System wird über die Spannungsbuchse (links unten) mit 12 VDC versorgt und benötigt mindestens 2 A Strom. Darüber erkennt man die Klinkenbuchse für die Kamera.

ACHTUNG! Die Versorgungsbuchse muss passend zum Netzteil verlötet werden! Wie die Beschaltung am Netzteil ist, findet man am Gerät selbst, diese sieht in etwa so aus:

Connection

Hier erkennt man, dass der Plus-Pin innen liegt, also muss man auch bei der Buchse an den innen liegenden Pin das Kabel für die +12V anlöten.

Neben der Versorgungsbuchse findet man die 4-polige Buchse für das USB-Kabel, über welches der PC mit dem Controller kommuniziert. Die Buchse ist deshalb keine Standard-USB-Buchse, weil ich diese 4-polige „Mikrofonbuchse“ und den passenden Stecker gesamt günstiger erworben habe, als eine USB-Buchse alleine … naja ..

Die beiden anderen Buchsen sind für die Steuerung der Ventile und für den Sensor zuständig. Zur Zeit wird noch kein Sensor in der Software unterstützt, doch das Interface hierfür ist bereits gegeben.

Alle nötigen Bauteile, sowie die Pläne für das Gehäuse sind ebenfalls im Zip-File unter „Mechanical Engineering“ zu finden.

Wem das nötige Werkzeug fehlt, um die Bleche entsprechend bearbeiten zu können, der kann diese durch Kunststoffplatten ersetzen. Diese lassen sich recht passabel mit einer Laubsäge bearbeiten.

Der elektrische Aufbau

Zu Beginn eine kleine Anmerkung: Ich nutze auch bei diesem Projekt wieder einen kleinen Display, dieser dient allerdings nur der Visualisierung der Zustände (Verbunden, Prozess arbeitet, offene Ventile, etc.). Wer darauf verzichten will, der kann auch auf den Display verzichten.

Ich habe folgende Komponenten verbaut:

Die Verdrahtung zeige ich als Steckbrett-Aufbau und als Schaltplan, da es auf dem Steckbrett recht eng geworden ist, und so die Übersicht etwas gelitten hat. Zusätzlich habe ich die Leiterplatte für das Projekt auf meinem Webserver (Zip-File) zur Verfügung gestellt. Darin findet man auch eine Bauteilliste und eine Bauanleitung für die Platine.

Zu den beiden folgenden Bildern muss ich anmerken, dass das System mit 12V gespeist wird, und nicht mit 9V, wie hier dargestellt. Außerdem sind die Ventile hier als Schubbolzen dargestellt. Die Funktion ist aber die selbe.

.

Water_Drop_Pro_Breadboard

.

Water_Drop_Pro_Circuit

.

Hinweis: Wer bereits ein Arduino Uno besitzt, und dieses auch verwenden mag, der hat hier ein leichtes spiel. Da sich im Nano v3.0 und im Uno Rev3 der selbe Prozessor befindet, und auch die Pinbelegung ident ist, kann man das Nano einfach gegen das Uno austauschen, ohne dabei die Pins ändern zu müssen.

Nun erkläre ich die einzelnen Komponenten im Detail.

Komponente Camera

Der Kameraanschluss ist ein einfacher 3.5mm Stereo-Klinkenstecker. Viele Kameras und Blitze unterstützen ein Auslösen mit einem solchen Stecker. Um einen solchen zu bauen, braucht man folgende Komponenten:

  • 3.5mm Stereo-Klinkenstecker
  • 2.5mm zu 3.5mm Adatperkabel
  • 3.5mm Stereo-Kabel (Male-Male)

Audio_Jack_Real_Image

Die Verdrahtung zwischen Optokoppler und Klinkenstecker muss so ausgeführt sein, dass das Gehäuse (SLEEVE) des Steckers mit dem Emitter des Kopplers verbunden ist. Der Kollektor des Optokopplers muss mit dem Left-Pin des Steckers verbunden werden, da dieser für das Auslösen der Kamera zuständig ist. Mit Right-Pin kann man den Autofokus betätigen.

Audio_Jack_Shematic

Pin 1 des Optokopplers ist die Anode (+) und Pin 2 ist die Kathode (-). Wenn sich nun jemand fragt, warum ich hierfür einen Optokoppler verwende: Keeps you from frying your stuff!

Das Arduino gibt durch den digitalWrite()-Befehl 5V am entsprechenden Pin aus. Diese 5V könnten an der Kamera Schäden verursachen, deshalb muss man etwas zur Sicherheit zwischenschalten. Diese Sicherheit ist der Optokoppler, er ist von der Funktion her vergleichbar mit einem Relais, jedoch ist die Schaltzeit wesentlich kürzer – also perfekt für solche Anwendungen! Wer sich unsicher ist, wo sich die Kontakte des Optokopplers befinden: Datenblatt!

Mehr dazu findet man hier.

Komponente Elektromagnetventil

Die Elektromagnetventile habe ich bei diesem Shop erworben (Spannung 12 V, Leistung 5 W). Zusätzlich habe ich mir noch 2 Schlauchtüllen (Schlauchgröße 6 mm) dazu bestellt, um das Ganze abzurunden.

Valve_G1_8.jpg

Das Magnetventil arbeitet mit einer Gleichspannung von 12V, das Arduino jedoch mit 5V. Aus diesem Grund braucht man eine Transistorschaltung, um mit dem Arduino das Ventil öffnen und schließen zu können.

Ein Transistor ist im Grunde ein Schalter, welcher elektronisch geöffnet und geschlossen wird. Wer mehr darüber wissen mag -> Transistorschaltung.

Transistor_Circuit.jpg

Der Ground (-) muss vom Signalgeber und vom Ventil der selbe sein, damit die Schaltung funktionieren kann. Ich habe zusätzlich die 12V direkt an den Vin-Pin des Arduinos gehängt, so wird dieses auch gleich von dem Netzteil versorgt.

Die Gleichrichterdiode 1N4001 dient als Schutz für die Bauteile, da es durchaus vorkommen kann, dass es wegen der Spule im Ventil zu einem Rückschlag kommen kann.

Das Ventil hat eine Leistung von 5 Watt und benötigt 12 VDC Spannung. Mit dem Zusammenhang P = U * I ergibt sich für den Strom 0,41667 Ampere. Um 3 Ventile gleichzeitig zu nutzen, und das Arduino Nano/Uno mit ausreichend Strom zu versorgen (max. 200mA in Summe an den Ausgängen) rate ich zu einem 2A Netzteil. Ich habe mir ein kleines Netzteil aus China zugelegt, welches bis zu 8 Ampere liefern kann. Die Schaltung benötigt natürlich nie so viel Strom, doch das Netzteil war außerordentlich günstig (6,50 €, kostenloser Versand).

Die Schaltung kann nun nicht mehr mit einem USB-Akku-Pack genutzt werden, wie es zum Beispiel bei Water Drop (Advanced) zum Einsatz kommt, da diese Akkus-Packs nur 5V liefern. Eine ausreichend starke 12V Batterie würde hier funktionieren, doch ich nutze lieber das Netz, da das Projekt ohnehin nicht portabel sein muss.

Komponente Display (optional)

Display_Real_Image

Bei dem Display handelt es sich um einen 0,96″ OLED Display, welcher mit dem BUS-System I²C angesteuert wird. Das Arduino Nano unterstützt dies, indem man die Library Wire.h implementiert. Dann sind allerdings die beiden Pins A4 & A5 für eben diese Übertragung reserviert und können nicht mehr für andere Zwecke verwendet werden. Wichtig ist hier, dass die Verbindung des Displays mit dem Arduino folgendermaßen ausgeführt wird:

  • SDA ⇒ A4
  • SCL ⇒ A5
  • VCC ⇒ 5V
  • GND ⇒ Ground

Um auch tatsächlich etwas auf dem Display anzeigen zu können bedarf es einer eigenen Programmbibliothek. Ich habe für diesen Zweck eine einfache Bibliothek erstellt. Die Erklärung und Verwendung findet man hier. Die Beschreibung des Codes findet man etwas weiter unten im Beitrag!

Die Platine

Um alles sauber abzuschließen habe ich eine Leiterplatte entworfen, auf welcher alle Komponenten sitzen. Die Kabel von den Buttons, dem Display, der Steckerbuchsen, etc … werden einfach über Terminal-Blocks mit der PCB verbunden. Das Bild unten zeigt die Platine, geroutet in Fritzing. Die Datei findet ihr natürlich auch im oben genannten Package.

Water_Drop_Pro_Finale_Without_Copper_Fill.jpg

.

Raw_Circuit_Board

Für die Platine benötigt man zumindest halb-schlechte Fähigkeiten im Löten. Das Arduino und der Optokoppler sitzen beide auf für diese passende Sockel, um sie einfach austauschbar zu machen. Alle Bauteile findet man natürlich im ZIP-File.

Fertig bestückt ist die Platine bereit für das Verlöten.

Circuit_Board

Beim Einsetzen des Optokopplers sollte man besonders auf den Punkt dessen Gehäuse achten, dieser muss sich dort befinden, so sich im Fritzing-File (Skizze oben) der Stern (*) befindet. Oder anders gesagt: Der Punkt definiert die Position der Anode des ersten Optokoppler im Gehäuse.

Optocoupler_Detail

Die Platine selbst habe ich hier bestellt. Das Preis-Leistungsverhältnis ist unschlagbar (unter 20€ für die Platine + Versand nach Österreich). Es reicht völlig, einfach nur das PDF zu senden, und folgendes anzugeben:

  • Die 4 äußeren Bohrungen: D3.2mm
  • Alle anderen Bohrungen: D1.0mm

Der Code

Eines vorweg: Das Programm wurde in Sublime Text 3 ( Stino ) mit der Arduino IDE 1.6.6 geschrieben.

Sowohl das Programm für den Mikrocontroller, als auch das Programm für den PC sind auf GitHub zu finden. Wer auf Nummer sicher gehen will, kann sich natürlich das Programm durchlesen/durchdenken, bevor es ausgeführt wird.

Wem den Weg über GitHub zu Steinig ist, der findet im ZIP-File ebenfalls beide Programme und eine ausführliche Beschreibung für jedes.

Der Mikrocontroller

Wie bereits oben erwähnt, nutze ich das Arduino Nano v3.0 und habe das Programm auch mehrfach auf diesem getestet. Natürlich kann man auch das Arduino UNO nutzen, da beide Boards den gleichen Prozessor (ATmega328) nutzen.

Arduino_Nano.jpg

Wer neu ist, und sich nicht sicher im Umgang mit dem Arduino ist, der kann sich hier einmal einlesen. Für alle, die schon vertraut mit der Umgebung sind: Einfach auf den Controller hochladen & fertig. Das Programm ist in mehrere Files gesplittet. Um alles auf einmal zu öffnen öffnet ihr nur die Water_Drop_Pro.ino Datei. Die Arduino-Software lädt dann automatisch alle im Verzeichnis befindlichen Dateien automatisch nach.

Ich erstelle gelegentlich Updates für das Programm, um eventuelle Bugs zu fixen, oder einfach um Funktionen einfacher zu machen. Daher sollte man öfter mal auf Github vorbei schauen – aus Selbsterfahrung weis ich: macht man im Allgemeinen nicht.

Der Host

Oben habe ich schon darauf verwiesen, das die Host-Software nur unter Windows läuft. Wie kann man das nur machen? Meine Ausrede ist, dass ich keine Lust hatte, ein GUI mit Pyhon oder Java zu schreiben. Ich habe den einfachen Aufbau von Visual Studio C# genutzt, um den grafischen Aspekt der Software schnell und einfach zu erstellen.

Host_Software_Mask

Das Nachfolgerprojekt soll dann aber Plattformübergreifend sein, bis dahin dauert es aber noch (eventuell, dass es Sommer 2016 beginnt).

Wer dennoch das Programm unter Mac nutzen will, der bekommt hier ein paar Möglichkeiten gezeigt. Leider kann ich aufgrund des Fehlens eines Macs nicht sagen, ob die Software dann auch tatsächlich reibungsfrei läuft.

Die Software unterstützt zudem alle Canon EOS DSLR Kameras. Dies hat den großen Vorteil, das man die Kamera für das Setzen der Einstellungen nicht mehr berühren muss und so unter Umständen den Bildausschnitt kaputt macht. Nikon, Sony, Pentax oder ähnliche Kameras unterstützt die Software nicht, da ich zur Zeit noch an einer neueren Version arbeite, welche alle anderen gängigen Marken unterstützt. Wer keine Canon hat muss sich leider vorerst ohne dieses Feature zufrieden geben.

Live_View

Ein besonderes Plus ist der Live-View, mit dem man den Fokuspunkt exakt einstellen kann.

Host & Controller

Hier mal eine einfache Anleitung für den Vorgang:

  • Anschließen des Arduino (mit bereits geladenem Code) an den PC.
  • Starten der Software am PC und auswählen des COM-Ports mit anschließendem Verbinden.
  • Warten, bis beide Geräte verbunden sind.
  • Done. Jetzt können die Ventile mit dem PC gesteuert werden.
Auf der linken Seite in der Software muss man beim ersten Mal benutzen die Höhe zwischen Ventilauslass und Wasseroberfläche einstellen. Danach wird automatisch die nötige Zeit berechnet, die der Tropfen vom Auslass bis zum Wasser braucht. Diese Dauer ist zudem jene für die Kamera, ist sie abgelaufen, dann löst die Kamera aus.
Host_Software_Mask_Height
.
Die Startzeiten für die Ventile sind an Punkt 0 gebunden. Dies bedeutet, dass eine Startzeit für das Ventil kürzer sein muss, als die Zeit für die Kamera, ansonsten würde ja das Ventil erst öffnen, nachdem die Kamera ausgelöst hat – das ist nicht Zweckdienlich!
.
Um die Verbindung zu trennen sollte man immer auf den Button „Disconnect“ klicken. Dies hat zwar was von „USB-Stick sicher entfernen„, doch es gibt am Arduino Nano/UNO keine Möglichkeit zu erkennen, ob ein Gerät verbunden ist oder nicht. So muss man ihm immer brav den Trennen-Befehl senden, sodass das nächste mal Koppeln gut geht.
Oder man drückt den Reset-Knopf – brute force!
.
Alles Weitere findet man im ZIP-File.
.

Die Vorgehensweise

Nun verrate ich noch ein paar Tricks, wie ich meine Bilder mache. Zuerst möchte ich aber auf meine Ausrüstung eingehen.

  • Canon EOS 650D Spiegelreflexkamera
  • Canon 100mm f/2.8 Macro Objektiv
  • Cullmann Stativ (mit Wechselplatte)
  • Yongnuo 560 III Blitz (kein TTL)
  • Yongnuo RF-602/C Funkauslöser (Entfesselter Blitz)
Das ist meiner Meinung nach die „Mindestausstattung“. Mir ist klar, dass das alles viel Geld kostet, ich habe es mir schließlich selbst über Jahre hinweg zusammengespart. Wer ein ähnliches Sortiment zu Hause hat, der ist gut gewappnet!
.
Equipment.JPG
 .
Zusätzlich empfehle ich noch einen Makroschlitten. Das vereinfacht das feine Positionieren enorm, da man mit dem Festbrennweitenobjektiv doch sehr eingeschränkt ist.
.
Ein sehr gutes Resümee zum Blitz gibt es hier.
.
Zu Beginn jedes Shootings sollte man das Ventil so lange offen lassen, bis Wasser unten austritt. Wenn man es dann schließt ist sicher gestellt, dass beim nächsten Öffnen sofort ein Tropfen austritt.
.
Zum Schluss jedes Shootings sollte man das Ventil unbedingt säubern, um die Lebensdauer so hoch wie möglich zu halten.
 .
Der Fokus
 .
Die beste und zugleich einfachste Methode den Fokus der Kamera einzustellen ist, einen Stab oder ein ähnliches Ding dort hinzulegen, wo später der Tropfen im Bild sein soll. Um sicherzustellen, dass der Tropfen auch tatsächlich dort landet wo man will, habe ich an die Front der Steuerbox die Buttons für die drei Ventile gesetzt. So kann man gezielt nur einen Tropfen fallen lassen. Diesen lasse ich dann auf ein einen Holzstab fallen, an dessen Mitte eine Markierung ist.
..
Setup_02
.
Im Anschluss muss man nur noch die markierte Stelle des Stabes fokussieren. Dies kann man entweder über den LiveView der Kamera oder über die Host-Software erledigen.
.
Focus_01.JPG
.
 Focus_02.JPG
 .
Die Position
 .
Eine perfekte Position für die Kamera und den Blitz gibt es nicht. Jede Session wird anders laufen, jede Veränderung der Viskosität der Tropfflüssigkeit bewirkt andere Tropfen und jede Positionsänderung des Blitzes sorgt für eine andere Stimmung. Eines kann ich allerdings bestimmt sagen: Den Blitz nicht auf der Kamera montieren. Irgendwie wirkt das Bild dann nicht.
.
Setup_01
.
 
Die Wassertropfenfotografie ist zu Beginn eher try & error, bis man ein Gespür für die Vorgänge entwickelt und immer mehr probiert. Nur nicht entmutigen lassen!
 .
Der Vorgang
 .
Hier ist eigentlich alles straight forward. Einfach den Host mit dem Controller verbinden, die Zeiten für die Ventile einstellen, die Auslöseverzögerung festlegen und auf Start drücken. Falls die Aufnahme nicht so wird wie gewünscht, einfach an die Zeitdauer einzelner Punkte anpassen, bis alles sitzt.
Bei immer gleichen Parametern sollten auch immer gleiche Tropfen entstehen. Bedingt durch die Flüssigkeit kommt es allerdings recht oft vor, dass ich an unterschiedlichen Tagen auch unterschiedliche Tropfen bekomme (trotz gleicher Settings in der Software). Hin und wieder passieren auch während eines Shootings random Dinge, doch das ist eher die Ausnahme. Ich denke, das liegt vielleicht an lokalen Dichteunterschieden oder sich ändernden Adhäsionskräften zwischen Düse und Fluid. Sicher kann ich das jedoch nicht sagen.

Das Ergebnis

Zum Schluss gibt’s noch ein paar Bilder, die ich mit dem System gemacht habe.

Ich hoffe ich habe nichts ausgelassen, und alle Fragen auch beantwortet. Falls dennoch Fragen offen sind, oder jemand generell ein paar Gedanken zu meinem Projekt hat: Ein Kommentar ist immer erwünscht!

Get Temperature Via DS18B20

English version.

In einem früheren Eintrag habe ich das Stichwort Temperaturmessung erwähnt, jedoch nicht gezeigt, wie man dies auf dem Arduino bewerkstelligt. Das möchte ich jetzt nachholen.

Das Modul

Hierfür nutze ich das günstige und sehr einfach zu verwendende Thermometer DS18B20. Dieses nutzt den One-Wire-Datenbus um so mit anderen Geräten kommunizieren zu können. Der große Vorteil daran ist, dass die Daten eines, aber auch mehrerer Sensoren über nur eine Datenleitung gesendet werden. Daher auch der Name.

Sensor.jpg

Zusätzlich stelle ich hier gleich einen LC-Display vor, welcher mir I2C angesteuert werden kann. Normale 2-zeilige LCD’s (HD44780) verbrauchen sehr viele Pins am Arduino. Bei größeren Projekten kann dies ein Ausschlusskriterium sein. Deshalb nutze ich gerne die sparsamere Version der Datenübertragung – I2C.

Der Schaltplan

One-Wire bezieht sich nur auf die Datenübertragung. Zusätzlich benötigen die Sensoren noch Masse (GND) und optional eine Versorgung (Vcc). Ich sage bewusst optional, da die Datenleitung zugleich auch als Versorgungsleitung genutzt werden kann. In diesem Fall legt man dann auch den Vcc-Pin auf Ground. Ja: Vcc auf GND.

In meinem Fall verbinde ich jedoch Vcc mit +5V, denn das Kabel ist vorhanden und es stört auch nicht weiter. Die meisten Module, welche 1-Wire einsetzen arbeiten auch mit 3,3V als Versorgung. Diese können dann auch am Raspberry Pi verwendet werden.

DS18B20

Für das folgende Beispiel benötigt man eine Hand voll Bauteile:

  • Arduino UNO/Nano
  • 2 DS18B20 Thermometer
  • 1 4.7kΩ Widerstand für den Datenbus
  • Jumper-Wire

.

Temperature_OneWire_Steckplatine

Die Pinbelegung des Thermometers sieht dabei wie folgt aus:

ds18b20_pinout.jpg

Wer so wie ich ein wasserdichtes Gehäuse nutzt, der muss sich an den Farben des Kabels orientieren, um den Sensor richtig anzuschließen:

  • Pin 2: Gelb
  • +5V: Rot
  • Ground: Schwarz

 

Cables

.

Um alles zu fixieren gibt es hier noch den Schaltplan:

Temperature_OneWire_Schaltplan

Wie man erkennen kann, steck wirklich nicht viel hinter dem Aufbau. Es gibt sogar Sensoren mit integriertem Widerstand zu kaufen, diese sind jedoch unverhältnismäßig teuer.

Apropos Preis:  3,00€ für zwei Sensoren ist unschlagbar.

Liquid Crystal Display via I2C

Bei dem Display handelt es sich um das sehr weit verbreitete HD44780 Liquid Crystal Display. Ihm wird lediglich ein Rucksack-Modul verpasst, welches die I2C-Befehle in HD44780er-Befehle umwandelt.

Display.jpg

Das Display-Modul nutzt wie bereits erwähnt den I2C-Bus. Er wird genau wie der letzte von mir vorgestellte Display angeschlossen:

  • SDA: A4
  • SCL: A5
  • Vcc: +5V
  • GND: Ground

.

Backpack.jpg

Wer das Display nicht nutzen mag, der kann das Programm trotzdem auf das Arduino laden, denn die Temperatur wird nicht nur am LCD ausgegeben, sondern auch auf dem seriellen Monitor.

Das Programm

GitHub.

Im Verzeichnis auf GitHub findet man 5 Ordner. Die beiden namens Dallas Temperature und OneWire sind benötigte Programmbibliotheken für die Temperaturmessung. Das Verzeichnis namens LiquidCrystal_I2C beinhaltet die Bibliothek für den Display. Alle drei müssen in das Standard-Bibliotheken Verzeichnis von Arduino (../Arduino/Libraries/) kopiert werden. Ist dies erledigt, so kann man das erste Programm öffnen und auf das Arduino laden.

Temperature.ino

In Zeile 13 findet man die Definition, welche den Pin angibt, an dem die Datenleitung verbunden wird. In diesem Fall an Pin 2.

#define ONEWIRE_BUS 2

Um die Anzahl der angeschlossenen Sensoren herauszufinden nutze ich die Funktion

oneWire.search(Address))

So kann ich später zwischen allen verwendeten Sensoren automatisch umschalten lassen. Bis jetzt ist es mir noch nicht gelungen, automatisch herauszufinden, welcher Sensor welchen Index bekommt. Um es dennoch in Erfahrung zu bringen nehme ich einen Sensor in die Hand und warte, welcher Index die Temperatur ändert. Um überhaupt eine Temperatur auslesen zu können benötigt man zwei Funktionen:

oneWireSensors.requestTemperatures();
float Temp = oneWireSensors.getTempCByIndex(i);

Das Index der Funktion getTempCByIndex bezieht sich auf den Sensor. Sensor 1 hat Index 0, Sensor 2 hat Index 1, usw.

Im Großen und Ganze war es das. Die restlichen Zeilen im Programm sind dazu da, alle 2 Sekunden einen anderen Sensor am Display anzuzeigen, ohne dass das Programm gestoppt wird. Denn mit der delay(ms); Funktion wird das Programm angehalten. Nutzt man so wie ich einen Timer, kann man in der Zwischenzeit anderes erledigen, etwa Daten auf dem seriellen Monitor in kürzeren Zeitabständen ausgeben.

Temp.jpg

Vielleicht noch eine Kleinigkeit: Der Bus ist schon recht langsam. Es können je nach Anzahl der Sensoren bis zu wenige Sekunden vergehen, bis die Daten ausgelesen und verarbeitet sind.

Temperature_Scale.ino

Dieses Programm ist eine kleine Erweiterung des ersten um eine Skala. Es wird zwar nur mehr ein Sensor unterstützt, dessen Temperatur wird nun aber in Bezug auf die Grenzen des Sensors angezeigt.

Temp_Scala.jpg

Die Scala kann auch als Ladebalken oder Ähnliches genutzt werden. Dazu muss man nur die Funktion

void Scale (int Row, int Value, int Minimum_Value, int Maximum_Value)

einbinden und aufrufen. Row ist die Zeile auf dem Display, Value jener Wert, der dargestellt werden soll, und Min-& Max Value sind eben die Grenzen.

Will man also den Wert des Sensors in Zeile 2 innerhalb seines Einsatzgebietes darstellen (von -55°C bis +125°C), dann muss man die Funktion wie folgt aufrufen:

Scale(1, int(Temperature), -55, 125);

Das war es auch schon wieder. Ein Kommentar ist bei Fragen immer erwünscht!

 

 

 

 

Magnetometer Compass

English version.

Wer schon einmal mit dem Gedanken gespielt hat, einen kleinen Fahrroboter zu bauen, der wird sich sicherlich Gedanken über die Positionierung gemacht haben. Neben dem GPS benötigt man eine weitere Komponente, welche sicherlich genau so wichtig ist: dem Kompass. Man braucht ihn, damit der Roboter weis, in welche Richtung er gerade schaut. Ohne diesen müsste er sich nur mit dem GPS in eine beliebige Richtung bewegen, aus der man anschließend den Kurs bestimmen müsste.

Ich möchte in diesem Beitrag zeigen, wie man das mit einem HMC5883L-Modul einfach und schnell schaffen kann. Außerdem habe ich noch eine größere Erweiterungen parat, welche ich ebenfalls präsentieren werde. Hierfür benötigt man neben dem Kompass auch einen Schrittmotor (hier bereits gezeigt).

Das Modul

Bei dem Modul HMC5883L handelt es sich um ein preiswertes, baukleines Magnetometer, welches mit dem Mikrocontroller via I²C kommunizieren kann. Hierfür benötigt man die Wire.h Programmbibliothek, welche mit der Arduino IDE mit installiert wird. Dazu mehr bei der Code-Erklärung. Das Modul habe ich auf eBay um 1€ neu gekauft, sogar mit kostenlosen Versand!

Compass

Bei meinem Modul habe ich darauf geachtet, dass es einen Spannungsregler verbaut hat, sodass ich es in einem Bereich von 3.3V bis 5V betreiben kann. Laut Hersteller lässt sich eine Genauigkeit von 1 – 2 Grad Kurs errechnen.

Doch wie funktioniert das Modul? Wie bereits erwähnt, handelt es sich hierbei um ein Magnetometer. Dieses misst die Flussdichte des magnetischen Feldes der Erde. Hierfür werden dünne Nickel-Eisen Streifen als Widerstandselement verbaut. Legt man nun Spannung an und setzt diese Streifen einem Magnetfeld aus, so ändert sich der Brückenwiderstand. Man misst das Magnetfeld also als Spannungsänderung. Diese Elemente sind so aufgebaut, dass sich 3 verschiedene Achsen ergeben (x, y, z). Diese sind auch dementsprechend auf der Platine gekennzeichnet.

Axis

Das Modul verfügt über 3 Betriebsmodi. Continous-Mode, Single-Mode und Idle-Mode. Bei ersterem sendet das Modul durchgehend seine Daten. Beim Single-Mode sendet es nur einmal den Messwert und versetzt sich dann in den Idle-Mode. Dieser ist vergleichbar eines Energiesparzustandes. Das Modul eignet sich also auch perfekt für Anwendungen abseits dauerhaft verfügbarer Spannungsquellen.

Übrigens: Das Modul wird auch in manchen Handys, Tablets oder anderen mobilen Geräten verwendet.

Der Aufbau

Viel bedarf es nicht, lediglich dem Arduino (UNO oder Nano), dem Kompass einem Steckbrett, und (optional) einem kleinen I²C Display, welches ich hier bereits vorgestellt habe. Wer direkt die Programmbibliothek für das kleine OLED Display herunterladen möchte, der kann dies hier tun.

Compass+Display

Bei der Verdrahtung muss man sich an die Regeln des I²C-BUS halten. Dieses BUS-System nutzt lediglich 2 Datenleitungen, um Daten zu senden und zu empfangen. Insgesamt benötigt man jedoch 4 Kabel, denn die Geräte müssen mit Spannung versorgt werden (Vcc & GND).

Bei diesem Projekt lässt sich auch gleich der Vorteil des BUS-Sytsems erkennen. Ich habe zwei I²C-Module einfach miteinander verbunden. So kann man mit wenig Aufwand viele Geräte betreiben, ohne dabei wichtige Pins zu belegen.

Die Anschlüsse müssen wie folgt miteinander verbunden werden:

  • SDA ⇒ Arduino Pin A4
  • SCL ⇒ Arduino Pin A5
  • Vcc ⇒ Arduino +5V
  • GND ⇒ Arduino Ground
Sollte es dennoch etwaige Unstimmigkeiten geben, findet man hier die schematische Zeichnung sowie das Steckbrett.
,
Magnetometer_Compass_Schaltplan
,
Magnetometer_Compass_Steckplatine

Das Programm

Das Programm findet man auf GitHub.

Zuerst möchte ich die Datei Magnetometer_Compass.ino vorstellen, die Erweiterung folgt zum Schluss.

Die ersten paar Zeilen dienen der Festlegung der Adressen des Kompass-Modules. Wichtig ist vor allem die Hauptadresse des HMC5883. Diese ist einmalig, sodass man das Modul auch dann noch verbinden kann, wenn auch mehrere I²C Geräte angeschlossen sind.

#define HMC5883L_Address             0x1E
#define HMC5883L_Mode_Register       0x02
#define HMC5883L_Continuous_Mode     0x00
#define HMC5883L_Data_Output_Address 0x03

In der loop() wird der Winkel stetig zur Ausgabe gebracht. Dies habe ich über 2 „Timer“ gelöst, da ich den Bildschirm schneller aktualisieren will, als ich die Daten in den seriellen Monitor schreibe. Ist das Projekt in Betrieb, und hat man den seriellen Monitor gestartet, so sollte man folgenden Datenstrom erkennen.

Serial_Monitor

Das Arduino sendet also konsequent die magnetische Flussdichte aller 3 Hauptachsen, sowie den daraus errechneten Kurs.

In der Funktion readHMC5883L() werden lediglich die Messdaten des Moduls aufgerufen. Jede Achse hat 2 Register (LSB & MSB). Aus diesem Grund muss man auch insgesamt 6 Messwerte einlesen.

if(6 <= Wire.available())
{
    compass.X_Axis  = Wire.read() << 8 | Wire.read();
    compass.Z_Axis  = Wire.read() << 8 | Wire.read();
    compass.Y_Axis  = Wire.read() << 8 | Wire.read();
}

Kommen wir nun zur wichtigsten Funktion, der getAngle(). Natürlich müssen zuerst die Daten vom Sensor ausgelesen werden, doch dann beginnt der eigentliche Spaß an der Sache. Man muss sich überlegen, wie man aus der magnetischen Flussdichte den Kurs errechnen kann.

Heading

Aus der Grafik, welche die Erde darstellen soll, lässt sich erkennen, dass sich dies mit Hilfe des Arkustangens bewerkstelligen lässt. Erhält man beispielsweise als Datenwert für x=1 und für y=1.7235 (Wurzel aus 3), so erkennt man, dass der Arkustangens den Wert 1.0472 (PI / 3) zurückgibt.

float Angle = atan2(-compass.Y_Axis, compass.X_Axis);

Das Ergebnis erhält man in Radiant. Für eine sinnvolle Kursangabe benötigt man den Wert jedoch in Grad. Die Umrechnung ist hier sehr einfach, denn

GRAD = RADIANT * (180 / PI)

Und schon hat man den Kurs im Bereich von -180° bis 180° berechnet. Um das auf das etwas leserlichere Format von 0° bis 360° zu bringen, muss man den Winkel, sofern er kleiner als Null ist, einfach mit 360 addieren.

if (Angle < 0)
    Angle += 360;

Nun könnte man das Ergebnis auch dabei belassen, wenn es da nicht auch noch die Missweisung gäbe. Das Erdmagnetfeld verläuft nicht konstant von Süd- nach Nordpol. Es ändert seinen Winkel immer wieder etwas. Des weiteren liegen magnetischer Nordpol und geografischer Nordpol nicht übereinander. Aus diesem Grund existiert für jeden Ort auf der Welt eine Deklination. Man kann diese für seine aktuelle Position auf der folgenden Webseite herausfinden: http://magnetic-declination.com/

Deklination

Quelle: Wikipedia

Die Missweisung wird in Grad und Minuten angegeben. Um sie korrekt zum Winkel addieren zu können, muss man diese in Grad umrechnen. Die Grade können auch negativ sein (Ost = positiv, West = negativ) und müssen auch dementsprechend eingesetzt werden.. Dazu gibt es die folgende Formel:

(DEGREE + (MINUTES / 60)) / (180 / PI)

Zur besseren Übersicht habe ich die Grade und die Minuten als eigene Variable deklariert.

byte  Declination_Degree = +3;
byte  Declination_Minute = 57;
float Declination = (Declination_Degree + (Declination_Minute / 60)) / (180 / M_PI);
Angle += Declination;

Das wars. So einfach kann man sich selbst einen kleinen Kompass bauen!

Erweiterung

Hier möchte ich mit einem Schrittmotor eine Kompassnadel simulieren. Dazu habe ich die selbe selbst gebastelte Gradscheibe genutzt, wie ich sie im hier beschriebenen Tutorial bereits verwendet habe. Auch die Verdrahtung des Schrittmotors mit dem Arduino ist ident:

  • IN1 ⇒ Pin 2
  • IN2 ⇒ Pin 3
  • IN3 ⇒ Pin 4
  • IN4 ⇒ Pin 5

Es ist quasi nur eine Erweiterung des Schrittmotors um einen Kompass.

Compass+Stepper

Wenn alles zusammengebaut ist, sollte es so ähnlich aussehen. Das kleine Board ganz rechts auf dem Steckbrett ist ein MPU6050 Beschleunigungssensor. Diesen werde ich demnächst einmal näher beschreiben.

Das Programm besteht nun aus zwei kombinierten Programmen. Zum einen aus der Goto_Position.ino und zum anderen aus der Magnetometer_Compass.ino. Zusammen ist aus beiden das hier beschriebene File Magnetometer_Compass_With_Stepper.ino entstanden.

Ist das Programm auf das Arduino übertragen, so wartet dieses auf die momentane Position des Schrittmotors in Grad (0° – 360°), denn das Arduino kann ja nicht wissen, wo der Zeiger gerade steht. Erst wenn die Position via seriellen Monitor übertragen wurde, beginnt das Arduino den Zeiger auf die vom Kompass ermittelte Position zu drehen.

Das war’s. Einfach eine kleine Spielerei!