Mittwoch, 21. Juli 2010

Präsentation

Zunächst einmal: Wir haben einen überarbeiteten Prototypen (um das blöde XBee-Shield einzusparen, und um einen Taster statt Drehknopf zu verwenden, wie es auch im fertigen Element geschehen soll:
Das reale Version wird ja etwas kleiner, die Gehäuse sollen dann beispielsweise wie folgt aussehen:
Für den Fussballfan:

Die Edelversion in Mahagoni:
Und die Nerd-Version :-)
Jedenfalls haben wir jetzt unsere Abschlusspräsentation fertig, die Miniplatine ist auch gefräst und wartet auf den Bootloader (wenn wir den Mikrokontroller nicht schon bei Auflöten gegrillt haben :-)

Dienstag, 20. Juli 2010

Software

Da sich unser Projekt so langsam dem Ende nähert, dachte ich, ich schreibe nochmal was zu der aktuellsten Version der von uns genutzten Software.

Da unser Prototyp mit Ubisense arbeitet, wir aber auch an Orten, an denen es keine Ubisense-Sensoren gibt, arbeiten und testen wollten, haben wir in Processing ein kleines Programm geschrieben, dass den Ubisense-Server simuliert. Darin lassen sich die Positionen von unserem Test-Arduino und drei Freunden beliebig im Raum verschieben. Die Positionen werden dann in Nachrichten verpackt, die denen des Ubisense-Servers am Lehrstuhl entsprechen und per UDP an denselben Port gesendet.

An diesem Port lauscht dann unser zweites Processing-Programm, dass die Nachrichten wie in früheren Posts auf diesem Blog beschrieben interpretiert und über die serielle Schnittstelle per XBee an den Arduino weiterleitet.

Da wir inzwischen die Positionen von drei Freunden senden, mussten wir bei der Übertragung dafür sorgen, dass der Arduino die verschiedenen Datenpakete unterscheiden kann. Dazu senden wir für jede Positionsangabe (z.B. Friend2, X-Position) zwei Bytes. Zuerst eines, das dem Arduino mitteilt, welche Position nun übermittelt wird und danach die Position selbst.

Die weitere Interpretation der Daten geschieht dann auf dem Arduino:
Während eines Durchlaufs des Loops wird zunächst eine Funktion "getPositions()" aufgerufen, die den Buffer der seriellen Schnittstelle prüft und eventuell dort zwischengespeicherte Nachrichten einliest. Nach dem Aufruf dieser Funktion haben wir also schon einmal die Positionsdaten.
Als nächstes wird der Kompass ausgelesen. Dazu ist eine Kommunikation per I²C-Bus notwendig, für die es dankenswerterweise die Library "wire" für den Arduino gibt. Damit ist die Abfrage dann kein größeres Problem - Es reicht, dem Kompass den Befehl zukommen zu lassen, dass man gerne die aktuellen Daten hätte und dann auf den Empfang zu warten.
Nachdem die Kompassdaten dann erfasst wurden, geht es daran, aus den Positionsdaten und der Ausrichtung des FriendLocators die Richtung zu bestimmen, in der sich der aktuell ausgewählte Freund befindet. Dazu berechnen wir zunächst mithilfe der avr lib-c den Arkustangens der sich aus der eigenen und der Position des aktuell ausgewählten Freundes ergibt. Den erhaltenen Wert im Bogenmaß rechnen wir dann in Grad um und subtrahieren den vom Kompass erhaltenen Winkel.
Jetzt lässt sich ohne Probleme der so erhaltene Winkel einer LED auf dem Shield des Prototypen zuordnen. Zunächst wird aber nur gespeichert, welche LED später angeschaltet werden soll. Bevor die LED dann tatsächlich angeschaltet wird, berechnen wir noch die Distanz zwischen der eigenen Position und derjenigen des ausgewählten Freundes. Die Distanz beeinflußt die Frequenz, in der die LED blinkt: Je näher man dem ausgewählten Freund kommt, desto schneller blinkt die LED.

Der Code für die besprochenen Programme liegt frei in meiner Dropbox:
Ubisense-Simulation (Processing)
UDP-Client (Processing)
Arduino-Code

Mittwoch, 14. Juli 2010

Miniaturisieren...

Da unser Protyp noch ein wenig groß geraten ist, um ihn bequem am Handgelenk tragen zu können, gibt's jetzt den Entwurf zu einem entsprechend kleineren Modul, in dem auf eine Volumen von ca. 35,6*25,4*8 mm (Innenmass) alle Notwendigen Bestandteile integriert sind.
Den Aufbau zeigt folgende Skizze:
Dies sind im einzelnen ein Atmega-Microcontroller mit den Anzeige-Leds und einem Taster auf der oberen Platineseite. Da ein Drehschalter, Poti oder ähnliches recht groß und aufgrund dem verdrehenden Gehäuse auch stör- und verschmutzungsanfällig ist, sind wir doch zu einem Taster mit drei AnzeigeLeds für die Funktion übergegangen (also 3 Funktionen für den Normalbenutzer und 8 für den Informatiker :-). Indem über der Platine eine dünne, und damit flexible Oberfläche als obere Abdeckung verwendet wird, kann damit die ganze Fläche zum Drücken des Tasters verwendet werden. Glücklicherweise bietet der Atmega in der SMD-Variante zwei weitere Ausgabepins, sonst wäre die Anzeige etwas kompliziert geworden. Als Taktgeber dient hier ein 8MHz-Resonator, da kleiner und mit integrierten Kondensatoren im Vergleich zum Quartz (wobei der Atmega auch einen integrierten 8MHz Quartz hat, aber so kann man ihn auch durch einen anderen ersetzen, falls es mal einen entsprechenden 16MHz Resonator gibt.

Auf der Unterseite der Platine ist dann ein GPS-Modul (basierend auf dem Aufbau des Micro-Mini von Sparkfun.
und ein Kompass (HMC 6352, da für unsere Zwecke ein einfacher 2D-Kompass reicht) untergebracht.

Darunter liegt dann die Batterie, wobei auf der Unterseite der Platine und der Oberseite des darunter liegenden XBee-Moduls die entsprechenden Kontaktflächen aufgebracht sind. Die Batterie kann dann durch eine seitliche Öffnung (Einschub) ausgetauscht werden.
Die Platinenober- und Unterseite wird damit später wie folgt aussehen:
Eine Möglichkeit, das darumherumliegende Gehäuse zu erstellen ist damit abgesehen vom 3d-Drucker ein Schichtmodell mit dem Lasercutter aus 2mm dicken Platten (Holz, Plexiglas, etc) in 4 "Rahmenschichten", wobei an den mittleren beiden (oder einer davon) die Befestigungen für das Armband sind, und die über die verschiedenen Inneformen die einzelnen Elektronikelemente tragen. Als obere und untere Abdeckung dient dann eine entsprechend dünne Deckfläche (lasergraviertes Furnierholz, bedruckte Transparentfolie). Die Innenabmessungen sind im Folgenden skizziert:
Der Mikrokontroller soll dann später über insgesamt 3 serielle Schnittstellen mit den einzelnen Modulen kommunizieren:
An der "normalen" seriellen Schnittstelle hängt das XBee-Modul, an den AnalogPins 4 und 5 über das I2C Protokoll der Digitalkompass und (noch viel später mal :-) an den durch den SMD-Atmega gegebenen weiteren Pins 20m und 21 das GPS-Modul, das mittels der TinyGPS und der NewSoftSerial-Bibliothek mit dem Atmega kommuniziert.

Donnerstag, 8. Juli 2010

Victory!

Die Xbees sind wieder aus ihrem Schlaf (an dem wir wohl nicht ganz unschuldig waren) erwacht. "Was war denn nun das Problem?" werdet ihr fragen. Nun, ich gebe euch einen Tipp: Die API-Function Sets sind nichts, was man auf das Modem schreiben möchte, ohne zu wissen, was API ist (wir haben das natürlich trotzdem gemacht). Mit den normalen AT-Kommandos gibt sich das XBee dann nämlich scheinbar nicht mehr ab. 

Dann gibts auch keine Kommunikation mehr und überhaupt ist alles, als wäre das XBee gar nicht mehr da. In dem Falle hilft das Setzen des links hervorgehobenen Hakens enorm weiter. 

Nicht, dass dann alles wieder ohne Probleme funktionieren würde (auslesen und schreiben der Firmware klappte trotzdem nur nach x > 5 Versuchen), aber es besteht dann zumindest wieder die Möglichkeit, alles zum laufen zu bringen. 

Eine weitere Erkenntnis: Der Reset-Button auf dem Arduino-Shield bewirkt scheinbar keinen Reset des XBee-Moduls, sondern nur des Arduinos. Wenn X-CTU also nach einem Reset des XBee-Moduls fragt, dann muss ein Stück Draht zwischen dem RST- und dem GND-Pin des XBees her. Das erleichtert einiges.

Inzwischen befinden sich beide XBees wieder sicher im AT-Modus und funken glücklich miteinander um die Wette.


Mittwoch, 7. Juli 2010

UbiSense-Probleme und ihre Lösung

Für unseren Prototyp haben wir uns vorerst für die Ortung via UbiSense entschlossen. Da der UbiSense-Server am Lehrstuhl schon fertig aufbereitete Positionsdaten im XML-Format versendet, gibt es in diesem Fall nämlich angenehm wenige Störfaktoren auf unserer Seite. Das einzige Problem ist es nun, an die Daten heranzukommen.

Die Kommunikation läuft folgendermaßen ab:
1) Zunächst muss man ein UbiSense-Endgerät beim Server auf seine IP-Addresse registrieren, damit man die Daten überhaupt erst einmal zugesendet bekommt.
2) Danach fängt der Server an, UDP-Pakete mit den XML-Daten auf einem bestimmten Port zu senden. Diese müssen empfangen und interpretiert werden.

Der erste Punkt ist relativ schnell in Processing geschrieben, wenn man die mitgelieferte Network-Library nutzt:

import processing.net.*;

Client ctrlMsg;
String ubisenseId = "020-000-024-100";

void setup()
{
    size(200,200);
    ctrlMsg = new Client(this, "137.226.56.44", 3501);
    ctrlMsg.write("register " + ubisenseId + " " + ctrlMsg.ip());
}


Nun gilt es allerdings, Daten auf dem UDP-Port zu empfangen und zu parsen. Der Empfang war das erste Problem. Zunächst mal wunderten wir uns, dass wir die Daten zwar im Terminal anschauen konnten, es uns aber nicht möglich war, mit Processing an die Daten zu kommen. Wie wir später herausgefunden haben, spricht Processing von Hause aus kein UDP und konnte damit auch nichts mit den eintreffenden Paketen anfangen.
Zum Glück gibt es eine Library, die grundlegende UDP-Funktionalitäten zur Verfügung stellt. Also schon einmal ein Problem weniger. Als nächstes müssen die XML-Daten geparsed werden. Natürlich könnte man jetzt eine Library fürs Parsen von XML-Daten hernehmen oder gar selbst implementieren, aber weil die zu parsenden Daten ja doch relativ speziell sind, haben wir uns nun doch für reguläre Ausdrücke entschieden (es ist einfach unglaublich viel einfacher). Das ganze (Empfang von Daten und Parsen) sieht in Processing dann so aus:

import hypermedia.net.*;

UDP udp;
String[] posData = new String[4];

void setup()
{
    udp = new UDP(this, 3501);
    udp.listen(true);
}

void receive(byte[] data)
{
    String inputString = new String(data);  
    String[] id = match(inputString, "id=\"([^\"]*)\"");
    String[] posX = match(inputString, "posX=\"([^\"]*)\"");
    String[] posY = match(inputString, "posY=\"([^\"]*)\"");
    String[] posZ = match(inputString, "posZ=\"([^\"]*)\"");
    posData[0] = id[1];
    posData[1] = posX[1];
    posData[2] = posY[1];
    posData[3] = posZ[1];
}



In posData stehen nun also die aktuellen Positionsdaten.

Der nächste Schritt ist jetzt, den ganzen Kram auch am UbiSense-Server zu testen. Es funktioniert zwar mit einem Testprogramm, dass ähnliche Botschaften auf einen UDP-Port sendet, aber man weiß ja nie.

Ein weiteres Ziel: Die XBee-Module dazu bewegen, wieder mit uns zu sprechen. Wenn sie sich dazu dann mal entschließen sollten, können wir die restliche Kommunikation fertig machen. Im Grunde muss der Arduino ja jetzt nur noch per XBee alle paar Sekunden die aktuelle Position anfragen und von Processing zugeschickt bekommen. Dazu aber dann später mehr, jetzt naht das Halbfinale und ich habe keine Lust mehr, noch länger vorm Rechner zu sitzen ;)

Es wird Ernst...

Nach ein wenig probieren und googeln, nachdem das nichts wurde (Eine Woche im Labor ersetzt den Tag in der Bücherei, oder wie ging der Spruch noch mal...): Die 2.4 Ghz Frequenz ist gar nicht so leicht abschirmbar, und Richtfunkantennen zu groß, mit der Funkpeilung wird also nichts.
Die Peilung per Magicmap kann anscheinend auch nur Räume unterscheiden, ist damit auch nicht verwendbar.
Im Rennen bleibt damit vor allem das GPS-System, vor allem, da wir nur Richtungsanzeigen brauchen und damit der Positionsoffset bei Sucher und zu Suchendem grösstenteils gleich ist. Nachteilig dabei ist, das dann auch ein Digitalkompass verwendet werden muss (gleiches gilt für die UbiSense-Lösung, die wir zum Ausprobieren verwenden), so das die Anzeige per (magnetisch bewegtem) Pfeil wegfällt - zumindest dürfte das sonst den Magnetkompass ein wenig verwirren.
Damit bleibt fürs erste die Anzeige mittels LED-Kreis. Ein erster Prototyp zum Testen:
Später kann das Poti als recht klobiges Bauelement auf die Rückseite verlegt werden und die gesamte Elektronik gegenüber dem Armband verdreht werden, so das ein einfaches Austauschen der Hülle möglich ist. Ausserdem kann ein noch freier Analogeingang mit der Hülle verbunden werden, so das zwei Armbänder miteinander kommunizieren können, um z.B. einen anderen Freund einzuspeichern.

Bisher sieht der Versuchsaufbau also so aus: Über das UbiSense-Modul kann der entsprechende Server die Position des Armbandes bestimmen und sendet dieses über xBees an alle Teilnehmer. Diese können dann aus ihrer und der Position der zu findenen Person die Richtung bestimmen, in der sie ist, welche dann mit den Kompassdaten zum Anzeigesignal verarbeitet werden und damit die entsprechende LED aufleuchtet. Die zu findenen Ob- und Subjekte können dabei über ein Poti ausgewählt werden. Eine Stellung dient dabei später zum Einspeichern neuer Freunde und eine weitere nutzt den LED-Ring als Uhr.

Insgesamt wird der Aufbau allerdings aufgrund des zu verwendenen GPS-Moduls (bzw. UbiSense-Moduls), eines Digitalkompasses und schliesslich des xBee-Moduls recht teuer und auch verhältnismässig groß.

Eine einfache Alternative wäre dann einfach nur ein xBee-Modul in Kombination mit dem Arduino zu verwenden, und das Arband als Leuchtring zu gestalten. In diesem Fall sendet man einfach nur die Frage "wo seid ihr" und die Armbänder der angesprochenen leuchten auf (und vibrieren im Idealfall). Die Positionssuche geschieht dann optisch, indem die Angesprochenen dann mit ihren leuchtenden Armbändern winken oder örtlich durch laufen zu einem vereinbarten Treffpunkt :-).
Um das xBee-Modul und den Arduino dann wenigstens etwas zu fordern, kann man dann natürlich auch wieder Einfachbotschaften senden oder hübsche graphische Effekt (Farbwechsel etc) machen. Ausserdem könnte das ganze zusammensteckbar aus Anzeigemodulen aufgebaut werden (bastel dir dein Wunscharmband :-)
So sieht das zwar noch hübsch hässlich aus, aber man kann das ja noch optimieren: Das Band wird ja maximal so breit wie das xBee Modul als breitestes Bauelement. damit ist noch über und unter der LED-Matrix zur Anzeige des "anrufenden" Namens noch platz für hintergrundbeleuchtete Schnörkel, die sich dann über das ganze Armband als Rahmen hinziehen. Abgesehen vom xBee kann sich das Band dann auch verjüngen und kleiner Symbole für Fixbotschaften enthalten, die dann durch Taster (das Potis zu klobig sind) ausgewählt werden.