Samstag, 3. November 2012

(Teil 1) Netzwerkverbindung zwischen Windows Phone 7 und Netduino Plus

WP7_und_Netduino_01
Netduino Plus und Windows Phone 7 Mobiltelefon

Eigentlich hatte ich vor, schon früher einen neuen Post zu schreiben. Aber wie so oft fehlt mir leider die Zeit. Und da ich versuche, weniger Kaffee zu trinken, werden meine Abende auch immer kürzer.

Heute zeige ich ein einfaches und kurzes Beispiel, wie man mit dem Windows Phone 7 und dem Netduino eine Netzwerkverbindung herstellen kann. Der Quellcode ist wieder auf das Wesentliche gekürzt, um möglichst nur die Funktionsweise von notwendigen Klassen zu zeigen.
Das Ziel des Beispiel wird sein, einen Servo anzusteuern. Am besten fangen wir mit der Anwendung auf dem Windows Phone 7 an. Hierzu benötigen wir einen “Slider” um einen Stellwert zum Netduino übermitteln zu können sowie zwei “Textboxen” um später die Zieladresse und den Port zu bestimmen. Zuletzt einen Button, um die Verbindung herzustellen. Mit “Textblock” können Status und der eingestellte Wert angezeigt werden. (Eine fertige Beispiel-Solution habe ich am Ende des Posts eingefügt)

image
So könnte die Anwendung auf der App aussehen.


Nun zum interessanten Teil der App. Um eine Netzwerkverbindung herzustellen, legen wir eine neue Klasse an.

   1: /// <summary>
   2: /// Stellt eine Netzwerkverbindung her
   3: /// </summary>
   4: public class NetworkRemote
   5: {
   6:     /// <summary>
   7:     /// Mit Hilfe der Socket Klasse 
   8:     /// richten wir den Client für diese Anwendung ein.
   9:     /// </summary>
  10:     private Socket _Socket = null;
  11:     /// <summary>
  12:     /// Wie lange auf die Antwort vom Server gewartet wird (in Milisekunden)
  13:     /// </summary>
  14:     private int _Timeout = 5000;
  15:     /// <summary>
  16:     /// Die Thread Klasse wird verwendet, damit die Oberfläche der Anwendung
  17:     /// nicht anhält, wenn z.B. gesendet wird.
  18:     /// </summary>
  19:     private Thread _ThreadSend;
  20:     /// <summary>
  21:     /// Wird verwendet, um die Rückantwort zum Thread zu ermöglichen.
  22:     /// </summary>
  23:     private ManualResetEvent _ClientDone = new ManualResetEvent(false);
  24:  
  25:     /// <summary>
  26:     /// Stellt zu der Host Adresse und Port Nummer eine TCP Verbindung her
  27:     /// </summary>
  28:     /// <param name="hostAddress"></param>
  29:     /// <param name="port"></param>
  30:     /// <returns></returns>
  31:     public string Connect(string hostAddress, int port)
  32:     {
  33:         // Rückanwort, ob nun die Verbindung hergestellt werden konnte.
  34:         string result = string.Empty;
  35:  
  36:         // Ziel Adresse und Port festlegen.
  37:         DnsEndPoint dnsEndPoint = new DnsEndPoint(hostAddress, port);
  38:  
  39:         // Die Socket Klasse initialisieren
  40:         _Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  41:  
  42:         // Asynchrone Socket Event
  43:         SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
  44:  
  45:         // Endpunkt an Event übergeben.
  46:         socketEventArg.RemoteEndPoint = dnsEndPoint;
  47:  
  48:         // Event zuweisen
  49:         socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
  50:         {
  51:             // Ruft das Ergebnis der Anfrage
  52:             result = e.SocketError.ToString();
  53:  
  54:             // Signal, dass der Antrag vollständig ist
  55:             _ClientDone.Set();
  56:         });
  57:  
  58:         // Legt den Zustand des Ereignisses auf nicht signalisiert, so der Thread blockiert ist.
  59:         _ClientDone.Reset();
  60:  
  61:         // Verbindung herstellen, die asynchron verläuft
  62:         _Socket.ConnectAsync(socketEventArg);
  63:  
  64:         // Blockiert den Thread in Millisekunden.
  65:         _ClientDone.WaitOne(_Timeout);
  66:  
  67:         return result;
  68:     }
  69:     /// <summary>
  70:     /// Daten senden, nachdem eine Verbindung hergestellt wurde.
  71:     /// Das Senden wird in einem Thread ausgeführt
  72:     /// </summary>
  73:     /// <param name="data">Eingabe der Daten</param>
  74:     /// <returns>Ergbnis der gesendeten Daten</returns>
  75:     public void Send(byte[] data)
  76:     {
  77:         // Nur einen neuen Thread starten, wenn dieser nicht aktiv ist.
  78:         if (_ThreadSend == null || !_ThreadSend.IsAlive)
  79:         {
  80:             _ThreadSend = new Thread(new ParameterizedThreadStart(SendInThread));
  81:             _ThreadSend.Start(data);
  82:         }
  83:     }
  84:     /// <summary>
  85:     /// Der Vorgang sollte in einem Thread ausgeführt werden. Das verhindert,
  86:     /// dass die Oberfläche stehenbleibt
  87:     /// </summary>
  88:     /// <param name="obj"></param>
  89:     private void SendInThread(object obj)
  90:     {
  91:         // Status Meldung hinterlegen.
  92:         string response = "Operation Timeout";
  93:  
  94:         // Asynchrone Socket Event
  95:         SocketAsyncEventArgs socketEvent = new SocketAsyncEventArgs();
  96:  
  97:         // Endpunkt an Event übergeben.
  98:         socketEvent.RemoteEndPoint = _Socket.RemoteEndPoint;
  99:  
 100:         // Zuordnung auf Null setzen 
 101:         socketEvent.UserToken = null;
 102:  
 103:         // Event zuweisen
 104:         socketEvent.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
 105:         {
 106:             response = e.SocketError.ToString();
 107:             _ClientDone.Set();
 108:         });
 109:  
 110:         // Übergabe der zu sendenden Daten.
 111:         socketEvent.SetBuffer((byte[])obj, 0, ((byte[])obj).Length);
 112:  
 113:         // Legt den Status des Ereignisses für Kein Signal, verursacht Thread Blockade
 114:         _ClientDone.Reset();
 115:  
 116:         // Stellt eine asynchrone Sendungsantwort ausserhalb des Socket
 117:         _Socket.SendToAsync(socketEvent);
 118:  
 119:         // Blockiert den Thread in Millisekunden.
 120:         _ClientDone.WaitOne(_Timeout); 
 121:  
 122:         // Event senden.
 123:         MessageEvent(response);
 124:     }
 125:     /// <summary>
 126:     /// schließt die Socket Verbindung
 127:     /// </summary>
 128:     public void Close()
 129:     {
 130:         if (_Socket != null)
 131:         {
 132:             _Socket.Close();
 133:         }
 134:     }
 135:     /// <summary>
 136:     /// Ruft ab, ob der Thread für Senden noch aktiv ist
 137:     /// </summary>
 138:     public bool IsSending
 139:     {
 140:         get
 141:         {
 142:             if (_ThreadSend.ThreadState == ThreadState.Running)
 143:             {
 144:                 return true;
 145:             }
 146:  
 147:             return false;
 148:         }
 149:     }
 150:     /// <summary>
 151:     /// Ruft ab, ob die Netzwerkverbindung besteht.
 152:     /// </summary>
 153:     public bool IsConnected
 154:     {
 155:         get
 156:         {
 157:             try
 158:             {
 159:                 return _Socket.Connected;
 160:             }
 161:             catch
 162:             {
 163:                 return false;
 164:             }
 165:         }
 166:     }
 167:  
 168:     public delegate void NetwokrMessageHandler(object sender, NetworkMessageEventArgs e);
 169:     public event NetwokrMessageHandler NetworkMessage;
 170:     /// <summary>
 171:     /// Event auslösen; durch Ausführen der Methode
 172:     /// wird an die obere Klasse ein Ereignis gesendet, 
 173:     /// um z.B. einen Status wiederzugeben.
 174:     /// </summary>
 175:     /// <param name="message"></param>
 176:     public virtual void MessageEvent(string message)
 177:     {
 178:         if (NetworkMessage != null)
 179:         {
 180:             NetworkMessage(this, new NetworkMessageEventArgs(message));
 181:         }
 182:     }
 183: }



Für Rückmeldungen wie Status, wird ein Event Objekt benötigt, damit ich als Anwender weiss, ob die Verbindung erfolgreich war.


   1: public class NetworkMessageEventArgs
   2: {
   3:     public string Message { get; private set; }
   4:  
   5:     public NetworkMessageEventArgs(string message)
   6:     {
   7:         Message = message;
   8:     }
   9: }


Für das Beispiel ist eigentlich ein Protokoll noch zu viel, soll jedoch zeigen, das für die Übertragung weitere Werte hinzugefügt werden könnten.




   1: /// <summary>
   2: /// Ein Objekt das als Protokol für die Übertragung verwendet wird.
   3: /// Der Inhalt kann beliebig erweitert werden. 
   4: /// Im Beispiel wird zunächst ein Wert übermittelt.
   5: /// </summary>
   6: public struct NetworkProtocolRemote
   7: {
   8:     /// <summary>
   9:     /// Die Variable zum festlegen des Stellwertes.
  10:     /// </summary>
  11:     private int _ServoValue;
  12:     /// <summary>
  13:     /// Initialisiert das Protokol mit Variabeln.
  14:     /// </summary>
  15:     /// <param name="servoValue"></param>
  16:     public NetworkProtocolRemote(int servoValue)
  17:     {
  18:         _ServoValue = servoValue;
  19:     }
  20:     /// <summary>
  21:     /// Empfangenes Byte Array wird eingelesen und befüllt die Variablen.
  22:     /// </summary>
  23:     /// <param name="receive"></param>
  24:     public NetworkProtocolRemote(byte[] receive)
  25:     {
  26:         _ServoValue = 90;
  27:  
  28:         string protocol = Encoding.UTF8.GetString(receive, 0, receive.Length);
  29:         SetProperties(protocol);
  30:     }
  31:     /// <summary>
  32:     /// Der Inhalt des Empfangenen Protokols wird in die Variablen festlegt.
  33:     /// </summary>
  34:     /// <param name="protocol"></param>
  35:     private void SetProperties(string protocol)
  36:     {
  37:         // Das Protokol kann um weitere Variablen erweitert werden,
  38:         // daher habe ich hier eine Schleife eingesetzt, 
  39:         // um die Variablen festzulegen.
  40:  
  41:         foreach (string item in protocol.Split(';'))
  42:         {
  43:             string[] sa = item.Split(':');
  44:  
  45:             switch (sa[0])
  46:             {
  47:                 case ("ServoValue"):
  48:                     {
  49:                         _ServoValue = Convert.ToInt16(sa[1]);
  50:                         break;
  51:                     }
  52:                 default:
  53:                     {
  54:                         break;
  55:                     }
  56:             }
  57:         }
  58:     }
  59:     /// <summary>
  60:     /// Gibt den Inhalt des Objektes als Byte Array zurück
  61:     /// </summary>
  62:     /// <returns></returns>
  63:     public byte[] GetRemoteToByte()
  64:     {
  65:         string content = string.Empty;
  66:  
  67:         content += "ServoValue:" + _ServoValue + ";";
  68:  
  69:         return Encoding.UTF8.GetBytes(content);
  70:     }
  71:     /// <summary>
  72:     /// Ruft den Wert des Servos ab oder legt diesen fest.
  73:     /// </summary>
  74:     public int ServoValue
  75:     {
  76:         set { _ServoValue = value; }
  77:         get { return _ServoValue; }
  78:     }
  79: }

Das Wesentliche zeigt die Klasse im ersten Code Schnipsel (natürlich lässt sich dies noch kürzer schreiben, aber ich wollte nicht zu viel auslassen).

Im zweiten Teil des Posts geht es mit dem Netduino weiter.
Zweiter Teil

Die fertige Windows Phone 7 App Solution für Visual Studio 2010:
WP7 App Solution - Download

Eine Windows Desktop Anwendung zum testen:
Desktop Test Anwendung - Download

Montag, 10. September 2012

Immer wieder neue Erkenntnisse

image
Netduino mit meinem aktuellen Shield
Zugegeben, habe ich mich vielleicht etwas übernommen, als ich geglaubt habe, dass ich das in wenigen Monaten schaffe würde, eine brauchbare Lösung zu programmieren, ohne an die praktischen Schwierigkeiten zu denken.
Wer kennt es nicht, dass der PC mehr Arbeitsspeicher braucht für mehrere oder besonders speicherlastige Programme. Nun, mein Programmcode für den Controller zur Steuerung über Netzwerk und das Auswerten der Sensoren erfordert mehr Speicher als das, was im Netduino Plus steckt. Mit den 42KB Arbeitsspeicher scheine ich wohl derzeitig nicht auszukommen und so muss ich wohl einen anderen Weg finden, etwas kompakter zu programmieren.
image
Die Nummer 16 hinter Hauptroutine, bedeutet, dass der Thread angehalten ist. Der Thread wird gebraucht, um die Regler anzusteuern.
Wie wirkt es sich derzeitig aus? Sobald das Ende des Arbeitsspeichers erreicht ist, kommt es zu einem Ausnahmefehler in der Methode. Da ich jeden Thread mit einer eigenen Fehlerbehandlung bearbeitet habe, steigt nur der eine oder andere Thread aus, oder wird nicht gestartet. Also da ist noch einiges zu tun, jedoch muss ich leider mein Projekt zum Teil einschränken, da ich mit meiner Freundin kurz vor einem Umzug stehe. Also dann…

Mittwoch, 29. August 2012

Vorerst mein letzter Sensor für mein Projekt Quadrocopter

Quadrocopter_39
Der Sensor GY-52
Es hat wieder einige Wochen gedauert, bis meine Bestellung aus China kam. Dafür hat es sich gelohnt, einige zig Euros zu sparen. Und wie schon gesagt, ich habe Zeit.
Zunächst sehe ich zu, dass ich die Daten einlesen kann, und wie immer in C und C# werde ich Beispiele dazu posten.

Nachtrag:
Nachdem ich auch die Dokumentation zu dem Sensor gefunden habe, musste ich feststellen, dass es nicht gerade so einfach wird, die Daten auszulesen. Derzeitig bekomme ich zwar eine Verbindung, jedoch keine Daten.
Bis ich mit der Doku durch bin, werde ich erstmal weiter an der Windows Phone 7 App und dem Programmcode für den Controller arbeiten.

Montag, 20. August 2012

Wie schließe ich ein Brushless Motor an

image
Brushless am Arduino zum testen.
Vielleicht für den einen oder anderen Interessant, wie eigentlich ein Brushless Motor angeschlossen wird. Für die Versorgung sind zwei Zuleitung an den Regler, die jeweils mit Rot und Schwarz farblich zu erkennen sind. Andernfalls sind am Regler die Pol Richtung gekennzeichnet. Zum Bürstenlosen Motoren führen jedoch 3 Leitungen ab. In meinem Beispiel sind die Leitungen blau, andernfalls sind die Leitungen am Regler ebenfalls Kennzeichnet. Der Motor selbst hat wiederum gelb, rot und schwarz.
image
Links zusehen, die Plus und Minus Kennzeichnung. Rechts die Kennzeichen A, B und C.
Den ersten Blauen, bzw. hier Kennzeichen B, verbinde ich mit Schwarz. Im folgendem Bild ist der gelbe Leitung an Kennzeichen A und Rot an Kennzeichen C verbunden. Nun dürfte nach Anschluss sich der Motor beim durchsteuern gegen den Uhrzeigersinn drehen.
image
Motor dreht sich Linksrum (gegen den Uhrzeigersinn)
Schließe ich den  gelben an C und den roten an A, dreht sich der Motor im Uhrzeigersinn.
image
Motor dreht sich Rechtsrum (in Uhrzeigersinn)
In welche Drehrichtung der Motor Dreht, hängt im Grunde vom Propeller ab und den Motor kann man praktisch nicht falsch anschließen, so das dieser beschädigt wird. Vorausgesetzt ist, dass alle drei Leitungen verbunden sind, um ein Drehstromkreis zu erzeugen, der den Motor zum drehen bewegt.

Montag, 13. August 2012

Netduino Sensor & Controller Shield für den Quadrocopter

Quadrocopter_38
Servo Test am neuen Neduino Shield

Irgendwann kommt die Zeit, dass man sich von Altem trennen muss. Besonders dann, wenn man einen Prototypen Shield hat, der aus zusammengesteckten Leiterbahnen besteht und dadurch viele Fehlerquellen haben kann. Zudem musste ich über eine weitere Schaltung das PWM Signal verstärken. So baumelte noch bis vor kurzem eine weitere Platine mit 4 Pegelwandlern am Shield. Eine wackelige Angelegenheit kann ich euch nur sagen...
Quadrocopter_34
Prototypen Shield mit zusätzlichen Pegelwandler

Am letzten Donnerstag kamen endlich die bestellten Arduino/Netduino Platinen aus China. Die Verarbeitung ist vernünftig und das Geld wert. Ich habe hier 4€ pro Stück bezahlt, zusätzlich Porto und Versand. Hier ist es sinnvoll gleich ein paar mehr zu bestellen. Den richtigen Pegelwandler habe ich erst aussuchen müssen. Ich habe zwei verschiedene bestellt, zum probieren. Entschieden habe ich mich für den 74HCT125N. Der Pegelwandler soll später das Pulssignal bzw. PWM von 3,3V auf 5V anheben. Zwar geht es auch mit 3,3V, aber ich habe öfters keine Reaktion beim Steuern der Servos oder Regler gehabt. Erst mit dem selbstgebastelten Pegelwandler war das Signal stabil.
Elektronik_02
Links ist der 74HCT125N und rechts der 74HCT245N

Ich überlegte zunächst, wie ich meine Sensoren anordne und wo ich später den Pegelwandler mit den Anschlüssen positioniere. Hinzu kam noch ein Anschluss für den Lithium Polymer Akkumulator, der den Mikrocontroller mit Strom versorgt. Später soll auch die Kapazität gemessen werden, sobald ich damit ein paar Versuche durchgeführt habe. Am Ende habe ich dann für mein Netduino folgende Bauteile verwendet:
Quadrocopter_35a
- Arduino Platine
- Buchsenleisten
- Stiftleisten
- einen Pegelwandler (74HCT125N)
- Buchse für einen 3S LiPo Akku
- Gelbe 3mm LED mit 20mcd Leuchtkraft
- 150Ohm Widerstand
- Druckknopf.

Zusätzlich kamen natürlich auch Kabel und Überbrückungstücke hinzu, um den richtigen Schaltkreis herzustellen. Nachdem ich mit dem Löten fertig war, musste ich noch das Lötfett entfernen. Das ging am besten mit heiß Wasser und Seife (mit anschließendem ausreichenden Trocknen, versteht sich).
Quadrocopter_36
Mein fertiges Netduino Shield, (oder fast fertig)

Das was nicht so schön ist habe ich auf der Unterseite verlötet.
Quadrocopter_37
Gelb sind die Signalleitungen. Rot für anliegende Spannung, wie z.B. +5V.

Nun kurz zur Erklärung der Funktionsweise des Shields:
  • Die LED soll später die Aktivität des Controllers wiedergeben.
  • Auf den Buchsen wird der Beschleunigungssensor gesteckt, um die Lage des Quadrocopter zu stabilisieren.
  • Auf die vier 3-Pin Anschlüsse kommen jeweils die Regler für die Brushless Motoren. Das PWM Signal wird zuvor mit dem Pegelwandler von 3,3V auf 5V angehoben.
  • Die weisse Buchse ist der Anschluss für einen 3S LiPo Akku, um den Netduino mit Strom zu versorgen.
Das sind noch nicht alle Funktionen, die ich für dieses Shield geplant habe. Wenn ich mit den Tests soweit durch bin, kann ich sicher ohne weiteres die Platine mit den erforderlichen Bauteilen ergänzen.
Geplant sind noch:
  • Magnetsensor
  • Gyroskop
  • Akkukapazitätsmessung
  • Anschluss für ein Display

Freitag, 3. August 2012

Den HMC5883L 3 Achsen Magnet Sensor auslesen

Arduino_HMC5883L_01
Der Sensor am Arduino Nano 3.0

Zuerst habe ich gedacht, dass der Sensor nicht funktioniert, bis ich den Beispielcode angepasst habe. In der Wiki zu diesem Sensor ist leider noch ein veralteter Code zu einer frühen Version vom Arduino Compiler. Nach einem Hinweis stellte sich heraus, dass sich die Bibliothek vom Arduino 1.0 gegenüber seiner älteren Version geändert hat. Im Quellcode der Datei HMC5883L.cpp war es notwendig, den Eintrag “#include <WProgram.h>” in “#include <Arduino.h>” abzuändern und die Einträge “wire.send” in “wire.write”. Anschließend ließ sich der Code auf den Arduino Nano 3.0 beschreiben und daraufhin auch erfolgreich auslesen.

image
Ausgabe der Daten, die vom Sensor gemessen werden.

Aus den drei Achsenwerten kann dann über das Gauß-Verfahren der Nordpol gemessen werden. Jetzt fehlt mir noch eine Portierung auf den Netduino.

Arduino_HMC5883L_02
Einfache Verkabelung des Sensors

Ich denke, das dürfte die Sache erleichtern, wenn ich zu den Beispielen auch ein Schaltbild bzw. wie in diesem Bild hier zeige, wie die Komponenten miteinander verbunden werden.

image
Die Fritzing Software in der Steckplatinen Ansicht.

Die Software “Fritzing” ist hier sehr gut geeignet. Sie ist zwar noch im Beta Status, kann jedoch schon sehr viel. Am besten sieht man sich das Youtube Vorstellungsvideo an. Es lohnt sich, dort rein zuschauen.

Ameisen Simulation und andere Dinge

Wer lange sich schon mit C# beschäftig, hat sicherlich schon mal was von AntMe gelesen oder gehört. Diese Idee hatte ich aufgegriffen und mi...