Der Starter Kit umfasst folgende Module
Zusätzlich steht noch das Grove Interfacemodule zur Verfügung. Dieses Modul bietet 6 Grove Sockel und kommt mit einem Anschlusskabel. Leider ist der Sockel auf dem Modul falsch eingebaut, so dass man das Anschlusskabel verdrehen muss, damit man es mit dem netduino Go! board verbinden kann. Unschön aber funktionsfähig.
Die einzelnen Module sehen auf den ersten Blick sehr gut gefertigt aus, das netduino Go! board und die shield base werden mit Gummifüssen geliefert. Alles ist darauf ausgelegt, auf der netduino Go! Grundplatte mit Distanzbolzen montiert zu werden. Für den Review muss meine Arbeitsplatte genügen …
Als IDE wird für den netduino Go! Microsoft Visual C# verwendet. Dazu wurde Microsoft Visual C# 2010 Express installiert. Die Installation dauert etwa eine Stunde, da zu dem Originaldownload noch ein ServicePack (SP1) und diverse Patches geladen werden. Die Installation läuft übrigens problemlos neben einer Visual Basic 2010 Express Installation. Als nächstes muss der MicroFRamework SDK geladen werden. Als letztes wird noch der Netduino SDK geladen. Dabei mus die für die PC-CPU/Windows Architektur passende Version geladen werden. Bei dem verwendeten PC war dies die 64 bit Version. Konfguration des Systems:
Nachdem die Software installiert ist, sollte man vor dem ersten Start den netduino Go! an einen USB Port anschliessen. Wenn das board erkannt wird, war die Treiberinstalltion erfolgreich. Bei dem Testsystem gab es keine Probleme bei der Installation.
Nach dem Start von Visual C# 2010 hat man die Möglichkeit ein Projekt für das Micro Framework zu erstellen. Man wählt sinnvollerweise “Netduino Go! Application”.
Als erstes Projekt soll ein Programm geschrieben werden, welches dem Blink Beispiel vom Arduino entspricht. Dazu muss die Bibliothek für das RGB LED Modul geladen werden. Dazu wählt man in Visual C# unter “Projekt→Verweis hinzufügen…” im Tab “Durchsuchen” das Installationsverzeichnis der Netduino SDK Installation und selektiert im Unterverzeichnis Assemblies\V4.2 die Datei NetduinoGo.RgbLed an. Da auch die anderen Module getestet werden sollen, kann man hier gleich auch die DLL für Potentiometer und Button anwählen. Die eingefügten DDLs erscheinen im Projektmappen-Explorer unter “Verweise”. Das erste Programm sieht dann folgendermassen aus:
using System; using System.Threading; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using SecretLabs.NETMF.Hardware.NetduinoGo; namespace NetduinoGoApplication1 { public class Program { public static void Main() { // the RGB LED module is connected to socket #2 NetduinoGo.RgbLed rgbLed = new NetduinoGo.RgbLed(GoSockets.Socket2); while (true) { rgbLed.SetColor(255, 0, 0); // turn the LED to red Thread.Sleep(250); // sleep for 250ms rgbLed.SetColor(0, 255, 0); // turn the LED to green Thread.Sleep(250); // sleep for 250ms rgbLed.SetColor(0, 0, 255); // turn the LED to blue Thread.Sleep(250); // sleep for 250ms } } } }
Um den Code zu testen, muss man noch verifizieren, dass das Board angesprochen wird. Dazu prüft man in den Projekteigenschaften im .NET Framework die Transporteigenschaft auf USB gesetzt ist:
Danach kann man das Programm ausführen. Man beachte dabei, dass bei Fehlern, erst die Programmausführung gestoppt werden muss, bevor man sich der Korrektur widmen kann. Es ist anscheinend normal, dass vor der Ausführung das Board gebootet wird. Der Emulator funktioniert nicht, da die entsprechenden Dateien dafür nicht mit dem SDK geliefert werden.
Als nächstes wird das Potentiometer eingelesen. Dieses liefert einen Wert zwischen 0.000 und 0.99904, also effektiv 0 - 1. Damit soll der Grünbereich der LED durchgestimmt werden. Die LED ist wie im ersten Beispiel an Socket 2 angeschlossen und das Potentiometer ist an Socket 1 angeschlossen. Das Debug.Print Statement ist optional und liefert im Debug Ausgebefenster den gelesenen Potentiometerwert.
using System; using System.Threading; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using SecretLabs.NETMF.Hardware.NetduinoGo; namespace NetduinoGoApplication1 { public class Program { public static void Main() { // the RGB LED module is connected to socket #2 - modify to reflect your setup NetduinoGo.RgbLed rgbLed = new NetduinoGo.RgbLed(GoSockets.Socket2); // the Potentiometer module is connected to socket #1 - modify to reflect your setup NetduinoGo.Potentiometer pot = new NetduinoGo.Potentiometer(GoSockets.Socket1); while (true) { Debug.Print("value: " + pot.GetValue().ToString()); rgbLed.SetColor(0, (byte)(255*pot.GetValue()), 0); Thread.Sleep(50); } } } }
Mit dem Potentiometer sollte nun die Helligkeit der grün leuctenden LED zu steuern sein.
Als dritter Schritt wird nun noch das Button Modul eingebunden. Dieses ist mit Socket 3 verbunden und wird etwas umständlicher ausgelesen, da eine Statusänderung des Buttons ein Ereignis ist, für das man eine Routine schreiben muss. Hierbei hilft einem Visual Sudio gewaltig, welches die passenden Codeelemente automatisch generiert. Für das Beispiel soll mit dem Button der LED Kanal durchgeschaltet werden. Dazu wird eine Variable LedStatus eingeführt, die jeder Druck auf den Button zyklisch durckschaltet. Angenehm ist hier, dass die Entprellung des Buttons von der Bibliothek schon vorgenommen wird. Der Code selbst stimmt dann den LED Kanal des jeweiligen Status durch:
using System; using System.Threading; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using SecretLabs.NETMF.Hardware.NetduinoGo; namespace NetduinoGoApplication1 { public class Program { public static int LedSelect = 0; public static void Main() { // the RGB LED module is connected to socket #2 - modify to reflect your setup NetduinoGo.RgbLed rgbLed = new NetduinoGo.RgbLed(GoSockets.Socket2); // the Potentiometer module is connected to socket #1 - modify to reflect your setup NetduinoGo.Potentiometer pot = new NetduinoGo.Potentiometer(GoSockets.Socket1); // the Button module is connected to socket #3 - modify to reflect your setup NetduinoGo.Button button = new NetduinoGo.Button(GoSockets.Socket3); button.ButtonPressed += new NetduinoGo.Button.ButtonEventHandler(button_ButtonPressed); while (true) { switch (Program.LedSelect) { case 0: rgbLed.SetColor((byte)(255 * pot.GetValue()),0, 0); break; case 1: rgbLed.SetColor(0, (byte)(255 * pot.GetValue()), 0); break; case 2: rgbLed.SetColor(0, 0, (byte)(255 * pot.GetValue())); break; } Thread.Sleep(50); } } static void button_ButtonPressed(object sender, bool buttonState) { Program.LedSelect++; if (Program.LedSelect > 2) Program.LedSelect = 0; } } }
Damit wäre das Grundprinzip der Modulsteuerung gezeigt. Man merkt deutlich bei der Programmierung die Ausgereiftheit der Visual Studio IDE gegenüber der Arduino IDE, die einem viel Programmierarbeit abnimmt. Man muss nur aufpassen, dass man die C-Dilekte C++ (Arduino) und C#(Netduino) nicht durcheinander bringt…
Als nächsten Schritt gilt es, das Arduino Shield Base zu verstehen. Dazu sei angemerkt, dass das Shield Base selbst einen eigenen Netduino besitzt, der über den netduino Go! angesteuert wird. Für die Ansteuerung der Shield Base ist zu Beachten, dass die Shield Base in der vorliegenden Beta Version einen der beiden Go!bus Kanäle für sich beansprucht. Der netduino Go! hat zwei Go!bus Kanäle: der erste Kanal spricht die Socket 1-4 an, der zweite Kanal die Socket 5-8. Bei der finalen Version der Shield Base soll diese Einschränkung entfallen. Für die weitere Betrachtung ist daher die Shield Base auf Socket 5 gesteckt und Socket 6-8 sind leer.
Der sich direkt anbietende test ist das erste Arduino Beispiel mit einer blinkenden LED auf pin 13. Dies ist mit dem Netduino Go! shield base mit folgendem Code realisierbar:
using System; using System.Threading; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using SecretLabs.NETMF.Hardware.NetduinoGo; namespace NetduinoGoShieldAppBlink { public class Program { public static NetduinoGo.ShieldBase sb = new NetduinoGo.ShieldBase((GoBus.GoSocket)5); public static OutputPort Pin13; public static void Main() { // define OutputPort assigned to digital pin 13, start with LOW Pin13 = new OutputPort(Program.sb.Pins.GPIO_PIN_D13, false); while (true) { Pin13.Write(!Pin13.Read()); Thread.Sleep(1000); } } } }
Als nächsten Test für das Ansprechen der Pins und eines Shields bietet sich ein passives Shield an, welches keine komplexere Ansteuerung und Initialisierung erfordert. Das 4×4 keypad (ohne das optionale LCD) ist solch ein Shield. Verwendet wurde das IBridge shield von IteadStudio. Die Ansteuerung wurde dem Beispielsketch für den Arduino entnommen. Die Keynummer entspricht dabei der Numerierung der Shielddokumentation, also Key-1 oben links, Key-4 oben rechts, wobei die Fassung des LCD oben ist, also der Pin A5 des Shields unten links. Der Code sieht folgendermassen aus:
using System; using System.Threading; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using SecretLabs.NETMF.Hardware.NetduinoGo; namespace NetduinoGoApplication1 { public class Program { public static NetduinoGo.ShieldBase sb = new NetduinoGo.ShieldBase((GoBus.GoSocket)5); // define column and row pins public static OutputPort CP0, CP1, CP2, CP3; public static InputPort RP0, RP1, RP2, RP3; public static OutputPort B13; public static void Main() { int key; // pin map for ITeadStudio IBridge 4x4 shield // - other shields may(will) differ! CP0 = new OutputPort(Program.sb.Pins.GPIO_PIN_D4, false); CP1 = new OutputPort(Program.sb.Pins.GPIO_PIN_D5, false); CP2 = new OutputPort(Program.sb.Pins.GPIO_PIN_D6, false); CP3 = new OutputPort(Program.sb.Pins.GPIO_PIN_D7, false); RP0 = new InputPort(Program.sb.Pins.GPIO_PIN_D3, true, Port.ResistorMode.PullDown); RP1 = new InputPort(Program.sb.Pins.GPIO_PIN_D2, true, Port.ResistorMode.PullDown); RP2 = new InputPort(Program.sb.Pins.GPIO_PIN_A4, true, Port.ResistorMode.PullDown); RP3 = new InputPort(Program.sb.Pins.GPIO_PIN_A5, true, Port.ResistorMode.PullDown); while (true) { key = readKey(); if (key != -1) { Debug.Print("==>Key pressed : " + key.ToString()); } } } public static int readKey() { int kwait = 5; Boolean r0, r1, r2, r3; // scan column 0 CP0.Write(true); CP1.Write(false); CP2.Write(false); CP3.Write(false); Thread.Sleep(kwait); r0 = RP0.Read(); r1 = RP1.Read(); r2 = RP2.Read(); r3 = RP3.Read(); if ( r0 && !r1 && !r2 && !r3) return (13); if (!r0 && r1 && !r2 && !r3) return (9); if (!r0 && !r1 && r2 && !r3) return (5); if (!r0 && !r1 && !r2 && r3) return (1); // scan column 1 CP0.Write(false); CP1.Write(true); CP2.Write(false); CP3.Write(false); Thread.Sleep(kwait); r0 = RP0.Read(); r1 = RP1.Read(); r2 = RP2.Read(); r3 = RP3.Read(); if (r0 && !r1 && !r2 && !r3) return (14); if (!r0 && r1 && !r2 && !r3) return (10); if (!r0 && !r1 && r2 && !r3) return (6); if (!r0 && !r1 && !r2 && r3) return (2); // scan column 2 CP0.Write(false); CP1.Write(false); CP2.Write(true); CP3.Write(false); Thread.Sleep(kwait); r0 = RP0.Read(); r1 = RP1.Read(); r2 = RP2.Read(); r3 = RP3.Read(); if (r0 && !r1 && !r2 && !r3) return (15); if (!r0 && r1 && !r2 && !r3) return (11); if (!r0 && !r1 && r2 && !r3) return (7); if (!r0 && !r1 && !r2 && r3) return (3); // scan column 3 CP0.Write(false); CP1.Write(false); CP2.Write(false); CP3.Write(true); Thread.Sleep(kwait); r0 = RP0.Read(); r1 = RP1.Read(); r2 = RP2.Read(); r3 = RP3.Read(); if (r0 && !r1 && !r2 && !r3) return (16); if (!r0 && r1 && !r2 && !r3) return (12); if (!r0 && !r1 && r2 && !r3) return (8); if (!r0 && !r1 && !r2 && r3) return (4); return -1; } } }
Der Vollständigkeit halber seien hier einige Details zu den Ports erklärt: Eine Umdefinition eines OutputPorts in einen InputPort ist nicht möglich. Die Parameter sind:
CP3 = new OutputPort(Program.sb.Pins.GPIO_PIN_D7, false);
Das erste Argument ist der pin der ShieldBase, das zweite Argument den initialen Zustand.
RP0 = new InputPort(Program.sb.Pins.GPIO_PIN_D3, true, Port.ResistorMode.PullDown);
Das erste Argument ist der pin der ShieldBase, das zweite Argument die Aktivierung des GlichFilters (angeblich ein Debouncing, konnte aber nicht beobachtet werden), das dritte Argument definiert den Defaultzustand mit den Optionen PullUp, PullDown und Disabled. Das Programm liefert die entsprechenden Keys, jedoch konnte ich beobachten, dass Keys hin und wieder verschluckt wurden. Dieses Verhalten reagierte sehr empfindlich auf den Wert des Delays (kwait) nach der Spalteninitialisierung. Bei Werten unter 5 ms wurden die Keys fast nicht erkannt. Darüber wurde die Verzögerung spürbar, so dass der Key schon recht lange gedrückt werden muss, bis das Shield ihn sieht. Ich habe alle Permutationen der Parameter durchgespielt und die Variante oben ist die beste. Anscheinend geht bei der Kommunikation mit dem ShieldBase sehr viel Zeit verloren, so dass die ShieldBase-Pins nur zögerlich angesprochen werden. Für eine Shieldansteuerung, wie man die für ein LCD oder gar ein TFT braucht, völlig unbrauchbar.
Die .net netmf toolbox führt matrix keypads als unterstützte Module. Diese Software Bilbiothek ist noch in der Entwicklung. Eine Beschreibung der Installation gibt es so gut wie nicht. Die Toolbox kann installiert werden, wenn man sich sklavisch an die Schritte aus der Anleitung “How to use the class” hält. Leider findet man dan am Ende heraus, dass diese Class für den Netduino geschrieben ist und für den Netduino Go! keinen Wert hat.
Die Netduino Go Umgebung ist wohl erst sinnvoll verwendbar, wenn der pre-Alpha-Zustand der Software überwunden ist. Bis dahin wird das Modul wohl in den Schrank wandern. Schliesslich gibt es mit dem Arduino eine funktionierende Alternative.
Eigentlich hatte ich vor, zumindest das 16×2 LCD Shield von DFrobot zum Laufen zu bringen. Die Erfahrung mit dem IBridge Shield lässt aber die Vermutung zu, dass das korrekte Timing mit der ShieldBase noch unerreichbar ist. Daher wurde dieser Versuch aufgegeben.
Dier Shield Base ist im derzeitgen pre-Alpha-Zustand kaum dazu geeignet, komplexe Arduino Shields zu betreiben. Eine Unterstützung für diese Shield Base, die über das einfache Ansprechen der Pins hinaus geht, ist praktisch nicht vorhanden. Wahrscheinlich ist es besser, auf eine finale Version der Base zu warten und darauf zu hoffen, dass es dann auch eine Unterstützung für diese an sich sinnvole Idee geben wird. Da auf der ShieldBase angeblich ein eigener Netduino werkelt, muss man warten, bis man diesem Netduino direkt Code laden kann. Beim derzeitigen Zustand der Entwicklung wohl erst in ferner Zukunft.
Generell ist die Unterstützung des netduino Go! sehr dürftig und es war sehr aufwändig, die Information für die obigen simplen Beispiele zusammen zu tragen. Fast alle Hinweise im Internet sind rudimentär und unvollständig. Diese Platform ist eben “bleeding edge” und noch sehr neu.
Ist am im Arduino Umfeld gewohnt, in den entsprechenden Foren recht schnell Antworten zu Posts zu finden, blieb eine Anfrage im Netduino Forum 16 Tage unbeantwortet. Noch niocht einmal die Entwickler hatten es nötig, sich die einfache Frage nach einem bekannten Shield, welches auf der ShieldBase läuft, zu beantworten.
Wenn man bedenkt, dass man mit dem Netduino ohne das zu Arduino fast doppelt so teure LCD Display gerade mal eine RGB LED, ein Poti und ein Button ansteuern kann, so wird schnell klar, dass es hier sinnvoller ist, auf den nächsten Evolutionsschritt zu warten. Wem der Arduino zu langsam ist, dem sei ein chipKit Modul angeraten oder der eigentliche Netduino.