Knöpfchenspiel 1 – Systemübersicht

Heute beschreibe ich das Knöpfchenspiel. Wie bereits im Podcast erzählt, ist das primäre Ziel das Spiel bis April fertig zu bekommen. Daher gibt es bereits einige fertige Komponenten.

Das originale Knöpfchenspiel steht meistens in Spielhallen und kann dort gegen Geldeinwurf gespielt werden. Dazu müssen die leuchtenden Knöpfe gedrückt werden. Jeder Knopfdruck gibt einen Punkt. Wenn ein nicht leuchtender Knopf gedrückt wird, wird ein Punkt abgezogen. Das sieht dann so aus:

Das von mir geplante System ist ähnlich aufgebaut. Nur dass die Spieler nicht gegenüber, sondern nebeneinander spielen und dass die Punkteanzahl an einem großen Fernseher dargestellt wird und nicht auf einer 7-Segementanzeige. Dazu wird das System in mehrere Submodule aufgeteilt.

  • System-Controller (Raspberry-Pi)
  • Bus-Interface (Differenzieller I²C Bus Treiber)
  • Knöpfchen-Controller (STM32F030)
  • Knöpfchen
  • LED-Band-Controller
  • Power Supply

System-Controller

Der Raspberry Pi übernimmt die Steuerung des Spiels und die Anzeige der Punkte am Bildschirm. Dazu wird das HDMI Interface in maximaler Auflösung (1920×1080) betrieben. Weiterhin hängt am Pi noch eine Webcam (USB) mit der die Spieler für die High-score Liste fotografiert werden.
Auf dem Raspberry steckt die DIIC Baugruppe. Das Bus-Interface Board
Bus-Interface

Bus-Interface

Um einen stabilen I2C Bus über alle Baugruppen zu bekommen, habe ich mich für einen Differenziellen Bustreiber entschieden. Dieser ist in der Lage die Eindraht-Signale der I2C Strecke auf zwei differenzielle Signale aufzuteilen. Diese sind wesentlich unempfindlicher gegenüber elektromagnetischer Störung. Das Bus-Interface Board besitzt die nötigen Stecker für den Knöpfchenspiel Bus, ein RJ45 Stecker, der über normale LAN-Kabel miteinander verbunden werden kann.

Knöpfchen

Das Knöpfchen ist ein 60mm durchmessender Plastik Druckknopf (Schließer), der von hinten beleuchtbar ist. Die Beleuchtung wird von einer weißen LED übernommen.

Knöpfchen Controller

Die 16 Knöpfchen sind an dem Knöpfchen-Controller angeschlossen. Der Controller ließt den Schaltzustand der Knöpfchen ein und vergleicht ihn mit den Lampen. Wenn die Lampe an war, wird der Punktestand um eins erhöht, wenn die Lampe aus war, wird der Punktestand reduziert, bis er bei 0 angekommen ist.
Auf dem Knöpfchen-Controller Board ist ein DC/DC Wandler, der die 12V Bus-Spannung auf 5V herab setzt. Die 5V werden dann mit einem linear Regler auf 3,3V für den Controller heruntergesetzt. Die Knöpfchen und Lampen in den Knöpfchen können mit 12V, 5V, oder 3,3V versorgt werden.
Der Controller besitzt ein I2C Slave-Interface, dass die Spielinformationen an den Spiel-Controller übertragen kann.

LED-Band-Controller

Um das Spiel von Außen attraktiver zu gestalten, habe ich vor eine LED-Leiste an der Kante anzubringen, ähnlich wie bei der oben gezeigten Variante. Dafür habe ich WS2812 LEDs als Leitungsband vorgesehen. Gesteuert werden die LEDs von einem eigenen Controller. Wahrscheinlich der Arduino Nano, den ich schon für die Bühnenkulisse verwendet habe. Den kann man über die USB -> UART Brücke auf dem Arduino vom Raspberry Pi ansprechen.
Für das System werden zwei AC/DC Netzteile eingesetzt. Ein 5V und ein 12V Netzteil. Das 5V Netzteil ist für die Versorgung des Raspberry Pis und LED-Band vorgesehen. Das 12V Netzteil übernimmt die Versorgung des Bus-Systems, Knöpfchen-Controller Boards und der Knöpfchen. Beide werden über den gleichen Kaltgeräte-Stecker angeschlossen und abgesichert.

ESP8266 – 2: Temperatur mit dem ESP8266 und DHT11

Das Hausautomationsteam in meiner Wohnung hat einen neuen Teamkollegen bekommen. Ein Tempertatur und Luftfeuchte Sensor. Der Sensor basiert auf einer kleinen Schaltung mit dem DHT11 Sensormodul und einem ESP-01 Board. Daran angeschlossen befinden sich zwei AA Akkus.

ESP-01 Modul mit DHT11 Sensor und 2 AA-Akkus

Die Software im ESP2866 wurde diesesmal nicht mit LUA und NodeMCU, sondern mit dem von ESP verfügbaren SDK erstellt. Ich habe dafür die Bibliothek für den DHT Sensor und den MQTT Client verwendet. Diese beiden Bibliotheken sind frei verfügbar und könne hier heruntergeladen werden.

Das System basiert immernoch auf einem MQTT Broker als zentraler Kommunikationshub. Die Sensoren besitzen alle eine eindutige Chip Indentifikationsnummer. Diese, kombiniert mit dem Systemnamen, bilden die Topics, auf denen die Sensoren Daten für das System bereit stellen. Eine Konfiguration des Sensors bei Inbetriebnahme ist auch in Arbeit. Dazu lauscht der Hauptknoten (Webserver, MQTT broker, Festplatte, usw.) auf WLAN Accesspoints die mit dem Namen ESP beginnen. Diese werden in einer bestimmten Liste angezeigt und können vom Hauptknoten angesprochen werden. Dabei verbindet sich der Knoten mit dem Sensor und überträgt die Daten, die für das eigentliche Netzwerk verwendet werden. Diese Kommunikation muss verschlüsselt stattfinden, daher wird auf die AES-Bibliothek des ESP2866 zurück gegriffen. Mit den Daten kann der Sensor sich dann am lokalen WLAN anmelden und seine Daten dem MQTT Broker zur Verfügung stellen.

Code für den Sensor gibt es hier. Eingestellt wird das ganze über die user_config.h
http://gist-it.appspot.com/github/DasBasti/esp8266/blob/master/Sensoren/Temperatur/dht112mqtt/include/user_config.h?footer=minimal&slice=10:46 Der Code wacht auf, verbindet sich mit dem MQTT Broker (Herbert) und sendet seine Messwerte. Danach begibt er sich wieder in den Tiefschlaf. Es sind sicherlich noch Optimierungen möglich, so ist es mit einem unmodifizierten ESP-01 Modul nicht möglich aus dem Tiefschlaf wieder aufzuwachen.

Werte in Openhab auf Herbert

Arduino Yún, Linux mit Arduino auf einem Board

Für unsere Projektarbeit haben wir entschieden, dass ein Linux fähiges Board und ein Arduino Mikrocontroller zum Einsatz kommen soll. Um das ganze möglichst klein zu halten haben wir den Arduino Yún ausgewählt. Der Yún hat neben den Funktionen, die auch ein Leonardo mitbringt zusätzlich einen voll funktionsfähigen Computer an Board, der mit einem speziellen openWRT Distribution läuft. Das Besondere ist, dass die beiden Geräte miteinander kommunizieren können und somit beide Geräte direkt miteinander verbunden sind. Auf der Linuxseite bietet die Linino Distribution einiges an Funktionalität, wie zum Beispiel eine REST-Full API um die Pins des Arduinos direkt anzusteuern. Eine weitere großartige Funktion wird in der Bridge Bibliothek zur Verfügung gestellt. Die Kommunikation zwischen Mikrocontroller und Programmen auf der Linuxseite.

SSH Konsole des Yún mit Erweiterung für die Kaffeemaschine

In unserem Falle wird der Mikrocontroller die Ansteuerung der Kaffeemaschine übernehmen und bestenfalls den SPI Bus abhören und die übertragenen Displaydaten in einen seriellen Bytestream umwandeln. Die Linuxseite wird die komplette Benutzerschnittstelle bereitstellen, also ein Webinterface mit dem die Kaffeemaschine gesteuert werden kann. Außerdem wird die Webseite den Inhalt des Displays darstellen. Wie die Daten von der Maschine in ein Bild gewandelt werden, habe ich letzte Woche schon beschrieben.

Diese Woche habe ich mich mit dem SPI Interface beschäftigt. Die Displaydaten werden über den SPI Bus vom Benutzerpanel an den Displaycontroller gesendet. Diese Daten können vom Arduino aufgezeichnet werden. Um klein anzufangen, habe ich verschiedene Ansätze ausprobiert. Die Grundvoraussetzung war, dass der Bustakt von 1 MHz eingehalten wird. Dann werden alle 0,1 Sekunden 541 Bytes übertragen. Der genaue Aufbau des Protokolls lässt sich relativ kurz beschreiben. Zuerst bekommt das Display den Wert 0x89 übertragen. In den Datenblättern, die etwas mit dem Display zu tun haben könnten habe ich diesen Befehl leider nicht finden können. Weiter geht es mit dem Byte 0xB4 was laut Datenblatt die Speicherseite 4 als Startadresse angibt. Darauf folgen 134 Bytes mit Bilddaten, bis dann 0xB5 (page 5) übertragen und die nächste Speicherseite ausgewählt wird. Nach weitern 134 Bytes folgt 0xB6 (page 6) und nach weiteren 134 Bytes folgt 0xB7 (page 7). Die abschließende Speicherseite und somit die letzte ‚Zeile‘ des Displays hört auch hier nach genau 134 Bytes auf. Da das Display auf dem Benutzerpanel auf dem Kopf stehend eingebaut ist, sind auch die Daten ‚gekippt‘ Eine einfache Spiegelung hilft das Bild wieder sichtbar zu machen.

Der Arduino Yún

Um mit dem SPI Bus zu arbeiten, ohne die Maschine dabei zu haben, habe ich die Daten eines Frames in ein Arduino-Sketch geladen. Dieser Arduino macht nichts als ein und dasselbe Bild immer und immer wieder alle 0,1 Sekunde über den SPI Bus zu übertragen. Die nächste Aufgabe ist jetzt, die Daten mit dem Yún zu empfangen und zu verarbeiten. Da ich bis jetzt nur einen funktionierende SPI Kommunikation mit Yún als Master und einem Nano als Client zum Laufen gebracht habe, kann ich noch nicht davon berichten, in wieweit sich die Idee mit der Bildgenerierung verwirklichen lässt.

Reverse Engineering einer Kaffeemaschine

Meine aktuelle Projektarbeit befasst sich mit dem Innenleben eines Kaffee Vollautomaten der Firma Severin, Genauer gesagt der KV8023 S2+. Ziel dieser Arbeit ist es die Kommunikation zwischen Bedienpanel und Kaffeemaschine zu analysieren und gegebenenfalls so zu manipulieren, dass die Maschine über einen Mikrocontroller ferngesteuert werden kann. Dazu habe ich die Maschine erst einmal geöffnet und zwei Flachbaugrupppen gefunden. Eine ist Netzteil, Netzspannung-Schaltung und Controller für die eigentliche Maschine, die andere ist ein Bedienpanel mit einem eigenen ATmega1284P an board. Das Flachbandkabel, mit dem beide Platinen verbunden sind deutet darauf hin, dass die Steuerung der Maschine über ein Bussystem gelöst ist. Wo die eigentliche Intelligenz steckt ist mit eines der ersten Punkte, die es herauszufinden gibt.
Geöffneter Vollautomat Controller des Bedienpanels

Nach einer genaueren Betrachtung des Panels habe ich die Verbindungen der Bauteile in einem Plan aufgestellt. Dieser Plan zeigt alle Steckverbinder, das Displayinterface und die, an den Controller angeschlossene Hardware (Taster, Drehencoder und LED). Eine Erweiterung des Verbindungskabels mittels eines Schneidklemmsteckers erzeugt den Zugriff auf den vermeindlichen Bus. Dieses Kabel ist verbunden mit dem SPI Interface des Controllers, mit dem Display (hier fehlt noch die Belegung der Kontakte).
Ein kurzer Test mit dem Logic Analyser zeigt, dass auf dem SPI Bus tatsächlich reger Betrieb herrscht. Nach einigen Kaffees habe ich jetzt mehrere Minuten Kommunikation mitgeschnitten und werde im nächsten Schritt versuchen die Telegramme auszuwerten und zuzuordnen.
Mitschnitt zweier Telegramme der Buskommunikation
Die Übertragung startet zyklisch alle 0,126 Sekunden, es werden 10 Byte über den Bus mit Enable Low (An) übermittelt. Auf diese Bytes gibt es eine Antwort auf der MISO Leitung. Darauf folgen 540 Bytes ohne Antwort, bei denen der Enable des Flachbandkabels konstant auf High (Aus) liegt. Es liegt nahe, dass es sich hierbei um Daten für das Display handelt, denn auch dorthin ist MOSI des Controllers verbunden. Mit einem Arduino und einem kleinen Sketch kann ich also nächste Woche die 10 Byte Telegramme abfangen und zur Auswertung aussortieren. Dadurch reduziert sich die Menge der Telegramme auf ein Minimum und die Entschlüsselung ebendieser wird hoffentlich leichter fallen.
Um eine Fernsteuerung durchzuführen, muss die Kommunikationsverbindung unterbrochen werden, da sonst das Bedienpanel in die automatisierten Telegramme zusätzliche Telegramme schicken würde. Gleichzeitig muss dem Bedienpanel die Antwort der Maschine vorgespielt werden, da sonst ein Fehler angezeigt wird. Wie sich die Anzeige des Displays manipulieren lässt habe ich mir noch nicht überlegt, da der Enable Eingang des Displays nicht nach Außen geführt wird.

Unit Tests für Mikrocontroller [Installation und Konfiguration für AVR]

Unit Tests sind im PC Bereich mittlerweile Standard. Allerdings ist es schwierig sie auch für Software im Bereich der Mikrocontroller zu verwenden. Die wenigen Ressourcen, die der Mikrocontroller zur Verfügung stellt sollten idealerweise für die Software verwendet werden, die später dann auf dem System laufen soll, denn alles andere wäre Geldverschwendung. Es gibt dennoch die Bemühungen mit so wenig Wasserkopf wie möglich Unit Tests auch auf Mikrocontrollern zu implementieren.
Ich habe das in meinen Projekten bisher so gelöst, dass ich zusätzlich zum normalen Programmcode Testfunktionen implementiert habe. Alles was nur zu Testzwecken im Code eingefügt wurde habe ich mit Präprozessor-Anweisungen eingekapselt, sodass sie bei einem Release Built nicht beachtet wurden. Dadurch habe ich während der Entwicklungszeit die Testfunktionen zur Verfügung und später im ‚fertigen‘ Projekt wurden die Testfunktionen nicht mehr übersetzt. Das führte neben kleinerem Programmcode auch zu schnellerer Abarbeitung von z.B. Interrupt Service Funktionen im fertigen Projekt. In dieser Artikelserie werde ich die Verwendung von µCUnit anhand des ASURO Projekts erklären.
Das µCUnit Framework liegt als Open Source Projekt auf GitHub und kann von dort als zip-Archiv heruntergeladen werden. Die verschiedenen Beispielprojekte für i386, avr und arm zeigen, wie das Framework verwendet werden kann.
Da jeder Mikrocontroller und jedes Projekt unterschiedlich sein kann, muss das Framework mit Macros angepasst werden. So muss zum Beispiel die Text Ausgabe so implementiert werden, dass Textzeichen über die Serielle Schnittstelle, Netzwerk, oder Dateien ausgegeben werden können. Sollte auf der Projektplattform die printf() Funktion zur Verfügung stehen, kann sie verwendet werden, aber gerade bei kleinen Controllern ist selten genügend Platz um diese Funktionen mit in dem Programmcode aufzunehmen. Es wird zusätzlich noch eine Funktion benötigt, um das System in einen sicheren Zustand zu setzten und es komplett herunter zu fahren. Jeder Ausgangspin der Hardware sollte in einen sicheren Zustand gesetzt werden, um zum Beispiel hohe Ströme durch den Controller zu verhindern. Die Beispieldateien System.c und System.h enthalten Code, der diese Funktionen beschreibt.

Die System.c für den AVR zeigt welche Funktionen vom Framework erwartet werden. Vor allem die Abwesenheit der printf() Funktion muss behoben werden. Da der ASURO schon eine schlanke Funktion zum Ausgeben von Zeichen besitzt, muss hier nur die Funktion zum Schreiben von Strings implementiert werden:

void System_WriteString(char * s) {
while(*s)
{
UARTbyte(*s);
s++;
}
}

Alle weitern Funktionen habe ich direkt aus der Beispieldatei übernommen.

Nachdem die Funktion implementiert ist, könne wir mit dem Aufbau eines Testcases beginnen. Dazu können wir uns an der mitgelieferten Testsuit.c orientieren. Eine Test Suite ist aufgebaut aus dem Haupt Test und den einzelnen Testcases. Der Haupttest initialisiert den Prozessor und führt die einzelnen Tests durch.
Hier wird auch die int main(void) implementiert; die Funktion, die als Hauptfunktion aufgerufen wird.
Das Beispiel zeigt und diese Funktion

int main(void)
{
UCUNIT_Init();
// [...]
Testsuite_RunTests();
UCUNIT_WriteSummary();
UCUNIT_Shutdown();

return 0;
}

Die Funktionen UCUINT_Init() und UCUNIT_Shutdown() sind in der System.c schon implementiert und tun zur Zeit nichts. Die Funktion Testsuite_RunTests() ruft die einzelnen Tests auf:

void Testsuite_RunTests(void)
{
Test_BasicChecksDemo();
Test_PointersDemo();
Test_ChecklistDemo();
Test_BitChecksDemo();
Test_CheckTracepointsDemo();
}

Es werden alle Tests in der Testsuite aufgerufen. Diese Herangehensweise erlaubt es die Tests einzelner Funktionesteile (Testcases) in verschiedene Hauptkategorien (Testsuits) zu unterteilen. Somit erhält man leichter einen Überblick über die einzelnen Funktionstests.
Schauen wir uns zunächst die einzelnen Testcases an. Der BasicCheckDemo() Test führt ein paar grundlegende arithmetische Operationen aus. Alle diese Tests sollten bestanden werden. Zu Beginn eines jeden Testcases werde die darin verwendeten Variablen deklaiert und eventuell initaialisiert. Der nächste Schritt ist den Testcases zu beginnen, mit Hilfe der Funktion

UCUNIT_TestcaseBegin("Name des Testcases");

Danach kommt dann eine eventuelle Generierung von Testdaten oder sonstige Funktionalität. Danach werden die Ergebnisse der Funktionen evaluiert. Hier sieht man die Verwendung der CheckIsEqual Funktion, die wie ihr Name schon sagt, zwei Werte miteinander vergleicht. Am Ende jedes Testcases wird die Funktion

UCUNIT_TestcaseEnd();

aufgerufen um den Testcase zu beenden und das Ergebnis zu speichern.
Weiter Testfunktionen werden in den anderen Testcases vorgestellt. Ich möchte an dieser Stelle noch einmal auf die Evaluierungsfunktion CheckIsBitSet eingehen, da hier direkt die Ausgangspins des Controllers getestet werden können.

PORTB = (PB1 << 1); 
UCUNIT_CheckIsBitSet(PORTB, 1); /* Pass */

Im der Nächstem Artikel betrachten wir dann die einzelnen Funktionen des ASURO und wie wir eine Testsuite für die einzelnen Hauptgruppen und Testcases für alle Unterfunktionen entwickeln.

GPIOs der Fonera

Heute habe ich ein wenig mit den GPIOs der Fonera gespielt. Um später das SoC der Fonera zum Steueren von anderen Hardwareprojekten zu verwenden, habe ich die vier am einfachsten zu erreichenden GPIO Kontakte mit einer Leitung verbunden. Dabei habe ich gleich noch die Kondensatoren nach Masse entfernt. Die bildeten mit dem Widerstand zusammen einen Tiefpass am Eingang und verhindern somit die Signalintegrität bei schnellen Schaltvorgängen.

Fonera mit LED an GPIO Ports

Die 8 IO Ports der Fonera sind teilweise schon von Hardware belegt, es bleiben jedoch fünf freie Ports übrig, die beliebig verwendet werden können. Vier dieser Kontakte sind auf den Steckplatz für SW1 geführt. Für die kleinen Experimente habe ich auch nur diese vier verbunden. Wenn komplexere Aufgaben gesteuert werden sollen, kann auch der serielle Port  der Fonera verwendet werden um mit einer Mikrocontroller Schaltung zu kommunizieren.

GPIO Description
0 TP3
1 pin 5 of SW1
2 WLAN LED
3 pin 1 of SW1
4 pin 2 of SW1
5 RESET (!)
6 RESET button
7 pin 6 of SW1

Zum Steuern der GPIOs kann das Kommandozeilentool gpioctl verwendet werden. Dieses ist standardmäßig bei der openWRT Installation mit installiert worden und kann zum Beispiel über die SSH Verbindung ausgeführt werden.


gpioctl dirout 3
gpioctl set 3

Dadurch wird der Port 3 als Ausgang definiert und eingeschaltet. Der erste Pin von SW1 ist jetzt auf +3,3V. Nachdem die Funktion der GPIOs funktioniert, wenden wir uns im nächsten Artikel der Software zu und schauen, wie die Fonera dazu gebracht werden kann als Gateway für eben diese Schaltung zu agieren.

Wifi Router als Client verwenden

Ich habe für ein zukünftiges Projekt vor, die Kommunikation über WLAN laufen zu lassen. Dazu benötige ich ein Modul, das mir WLAN so umsetzt, dass ich entweder verschiedene GPIOs steuern kann, oder Daten an einen einen UART Port weiter gibt. Ich habe in meiner Sammlung noch eine Fonera der ersten Generation, also ein Linuxboard mit WiFi, Ethernet, GPIOs und UART. Die Fonera muss zu diesem Unterfangen allerdings eine neue Firmware bekommen. Die einfachste Methode das zu tun ist, den Bootloader über das serielle Interface anzusprechen, wie das in diesem Artikel beschrieben ist.

Fonera ohne Gehäuse

Der nächste Schritt ist es die Konfiguration von OpenWRT zu ändern. Dazu können wir entweder eine Verbindung über SSH aufbauen, oder weiter in der seriellen Konsole bleiben. Als erstes benötigt man das wpa_supplicant Paket um zu verschlüsselten Netzwerken eine Verbindung aufbauen zu können, dass sich mit opkg installieren lassen.

opkg update
opkg install wpa-supplicant

 Der verfügbare Editor ist Vi und zu bearbeiten sind die Dateien /etc/config/network

config 'interface' 'loopback'
option 'ifname' 'lo'
option 'proto' 'static'
option 'ipaddr' '127.0.0.1'
option 'netmask' '255.0.0.0'

config 'interface' 'lan'
option 'proto' 'dhcp'

config 'interface' 'wan'
option 'ifname' ' '
option 'proto' 'none'

und /etc/config/wireless 

config 'wifi-device' 'wifi0'
option 'type' 'atheros'
option 'channel' 'auto'
option 'disabled' '0'

config 'wifi-iface'
option 'device' 'wifi0'
option 'network' 'lan'
option 'mode' 'sta'
option 'ssid' 'WLAN-SSID'
option 'encryption' 'psk2'
option 'key' 'WLANPASSWORT'

Nachdem die Dateien geändert wurden kann mit dem Befehl wifi up das Netzwerksystem gestartet werden. Zu beachten ist, das in dieser Konfiguration der Ethernet Port deaktiviert ist. Der nächste Schritt wird dann sein zu bestimmen, ob die GPIOs der Fonera ausreichen um die gewünschten Funktionen ausführen zu können.

Handy -> Bluetooth -> RGB-LED [Teil 1: Protokoll]

Die Vernetzung von Haushaltsgegenständen ist heutzutage nicht mehr weg zu denken. Das so genannte Internet der Dinge wird in den nächsten Jahren immer mehr Geräte miteinander vernetzen und untereinander kommunizieren lassen. Ein kleiner Teil davon wird die Wohnraumbeleuchtung sein. RGB-LEDs sind mittlerweile günstig auf dem Markt erhältlich und werden konventionelle Lampen ablösen. Dieser Artikel beschreibt Überlegungen für die Steuerung einer RGB-LED über ein serielles Protokoll.

Für dieses Projekt wird eine RGB-LED und der Mikrocontroller ATtiny2313A verwendet. Das Bluetooth Modul HC-05 bildet die Schnittstelle zwischen Beleuchtungseinheit und Steuerungssoftware auf Andorid Basis.

Um die Übertragung von Helligkeitswerten mit möglichst wenig Aufwand zu realisieren, wird ein Protokoll erstellt, dass aus einem 4 Byte großem Block besteht. Der Block beginnt mit einem Null Byte (0x00), darauf folgen die Helligkeitswerte für Rot, Grün und Blau. Das Nullbyte dient zur Synchronisation. Die sonstigen Bytes dienen zum Übertragen von Kommandos. Somit ist das Protokoll am Ende bei Bedarf erweiterbar, da erst nach der Synchronisation wieder mit den Farbwerten gerechnet wird.

Telegramm zur Steuerung der Lampe

Die Sonstigen Bytes können für Steuerbefehle verwendet werden. Um erneut eine Farbe zu übertragen muss das Byte 0x00 übertragen werden und danach die Bytes für Rot, Grün und Blau. So lässt sich zum Beispiel der Status der Lampe mit dem Code 0x01 abfragen, der aktuelle Batteriezustand mit 0x02 und so weiter. Die Befehle hier sind erst einmal nur als Beispiel gedacht, um die Grundfunktionen zu implementieren.

Steuerbefehle

Als nächstes wird der Aufbau der Hardware folgen.

[WIP] Ein neuer Versuch mit ASURO

Ich bearbeite für das Studium eine Projektarbeit für die Roboterplattform ASURO. Den Verlauf der Entwicklung werde ich hier dokumentieren. Ziel ist es ein Betriebssystem zu erstellen, dass die Werte der sechs Sensoren kontinuierlich ermittelt und sie für den Programmierer aufbereitet. Dazu gehört neben der reinen Speicherung der Messwerte eine, abhängig vom Sensor, kontinuierliche Verarbeitung. Deshalb habe ich mich in letzter Zeit intensiv mit der Wandlung von analogen Spannungen zu digitalen Werten beschäftigt; konkret mit der Wandlung von Spannungen eines IR-Transistors an einem ATmega8.
Der ADC des ATmega8 hat 6 Eingänge in der PDIP Konfiguration und zwei Ausleseverfahren. Einmal die einmalige Wandlung des aktuellen Wertes, und dann die kontinuierliche Wandlung. Dabei wird nach jeder vollständigen Konvertierung direkt eine neue angestoßen. Wenn ich kontinuierlich alle verfügbaren ADC Eingänge auslesen möchte, muss dazu eine interne Logik entwickelt werden, die die Messwerte und die Sensorauswahl steuert. Der normale Verlauf ist, dass der ADC Multiplexer (MUX) eingestellt wird, die Spannung gemessen und das Ergebnis als 10 bit Wert in einem 16 bit Register abgelegt wird. Wenn man aber so schnell wie möglich den Wert eines beliebigen Eingangs verwenden will, muss die Wandlung schon im Voraus durchgeführt und die Ergebnisse vorgehalten werden. Für diesen Fall sind 6 Eingangsgrößen zu bestimmen. Jede der Größen wird nacheinander gewandelt und soll in einem Array zur Verfügung stehen. Nach jeder Konvertierung des ADC wird eine Interrupt Service Routine (ISR) aufgerufen. Diese sorgt für die Verarbeitung des aktuell ermittelten Messwertes. Dabei ist darauf zu achten, dass der Wert, der im Register zur Verfügung steht, der ist, der vor zwei ISR Aufrufen beantragt wurde. Das kommt daher, dass Der MUX beim Aufruf der ISR umgeschaltet wird. Dann wird die noch laufende Konvertierung beendet bevor der neu eingestellte Eingang des MUX an den ADC weitergegeben wird. Dann wandelt der ADC den Wert und ruft die ISR nach Beendigung dessen auf. Jetzt liegt als Ergebnis im Register der Wert für den vor zwei Aufrufen geschalteten MUX Eingang. Dies muss bei der Verwendung der Daten unbedingt beachtet werden, denn sonst kann nicht garantiert werden, dass die Werte an der richtigen Stelle im Array landen. Dazu habe ich eine einfache Funktion geschrieben, die als inline direkt in der ISR eingefügt werden kann. V wird immer um eins erhöht und bei erreichen von max wieder auf 0 gesetzt.

static inline uint8_t cycleValue(uint8_t v, uint8_t max) {
if(v == max) v = 0;
else v++;
return v;
}

Im ASURO sind zwei Refelktionslichtschranken verbaut. Diese zeigen auf die Schwarz-Weißen Encoderscheiben am Getriebe der Räder. Für die Ermittlung der Drehtakte für die Räder wird so von den IR-Transistoren ein sinusförmiges Signal erzeugt. Dieses Signal ist einerseits einfach zu analysieren, andererseits stören Faktoren wie Streulicht, oder axiale Bewegungen der Zahnräder im Getriebe. Dieser Umstand wird mit einem Median-Filter umgangen. Dieser filtert alle Ausreißer in den Messwerten heraus und erzeugt dadurch eine ganz anschauliche Sinusform. Abbildung 1 zeigt den Verlauf von je 300 Messwerten der beiden Radsensoren vor und nach der Filterung.

Zwei sinusförmige Schwingungen, die mit einem Medianfilter geglättet wurden
Abb. 1 Sensorwerte Kanal 0 und 1 ohne und mit Medianfilter

Die Taktung der Radgeschwindigkeit geschieht einmal beim Übergang von hohem Messwert auf niedrigen und andersherum. Mit einem unteren und oberen Schwellwert, wie in Abbildung 2, rote Linie erhält man vier Zustände, die das Auswertesystem annehmen kann: Wert kleiner als die Maximumschwelle steigende Flanke, Wert kleiner als die Maximumsschwelle flanke fallend und des gleiche für die Minimalschwelle. Dabei bietet es sich an die Übergänge  in einem Zustandsautomaten zu berechnen.

Abb. 2 Grenzwert (rote Linie) und Markierungen für Ticks

Der Automat benötigt lediglich die Werte des ADC und kann dann dementsprechend zwischen den Zuständen durchschalten. Das Zählen der Schritte wird ebenfalls in dem Automaten erledigt. Es bietet sich an die Schritte in den unten markierten Zuständen zu zählen, aber es können natürlich auch die beiden anderen Zustände zum Zählen der Schritte verwendet werden.

extern inline void detectEdgeFlip() {
switch (edge) {
case RISING:
if(adc_median_value < threshold[MIN]){
edge = RISING_WAIT;
}
break;
case RISING_WAIT: // Hier kann ein Schritt gezählt werden
if(adc_median_value > threshold[MIN]){
edge = FALLING;
}
break;
case FALLING:
if(adc_median_value > threshold[MAX]){
edge = FALLING_WAIT;
}
break;
case FALLING_WAIT: // Hier kann ein schritt gezählt werden
if(adc_median_value < threshold[MAX]){
edge = RISING;
}
break;
}

Da die Sensoren auf dem Board des ASURO dem Umgebungslicht ausgesetzt sind, ist es wichtg, dass der Minimal- und Maximalwert ständig betrachtet wird und die Schaltgrenzen gegebenenfalls angepasst werden. Dazu werden die letzten 64 Messwerte für jeden Kanal abgespeichert und bei vollem Puffer der Minimal und Maximalwert gesucht.

Sehr wichtig ist es, dass die ISR nicht länger dauern darf als die Wandlung des ADC, denn sonst überholt der ADC die CPU und es kommt zur Blockade der Software, da nur noch die ISR verarbeitet werden kann. Die aktuelle ISR des ADC sieht sehr voll aus und ich werde demnächst die Laufzeitdauer messen. Eventuell müssen einige Funktionen ausgelagert und so sporadisch wie möglich aufgerufen werden.