Montag, 19. August 2013

Kleiner Vergleich zwischen Netduino Plus 1 und Netduino Plus 2

NetduinoPlus1u2
Netduino Plus 1 (Links) und Netduino Plus 2 (rechts)

Seit kurzem zählt zu meinem Bastelsortiment der Netduino Plus 2, der mit mehr Takt deutlich schneller rechnet als der Netduino Plus 1. Die Investition hat sich gelohnt und bringt mein Projekt weiter voran.

Kommen wir zunächst zu den grundlegenden technischen Daten. Auch auf der Seite Netduino.com/Hardware/ zu finden.

  Netduino Plus 1 Netduino Plus 2
Speed 48 MHz 168 MHz
Code Storage 64 KB 384 KB
RAM 42 KB 100+ KB
GPIO 20 22
UART 2 4
PWM 4 6
SPI 1 1
I²C 1 1

Klar ist, dass der neue schneller sein muss, allerdings habe ich mich gefragt, wie viel mehr ich verarbeiten kann. Nun, mein Beispiel zeigt eine kleine Rechenaufgabe, in der die Zeit gestoppt wird und man nach 100 Durchläufen den Durchschnittswert erhält.

int counter = 0;
long average = 0;

while (true)
{
    Stopwatch.GetElapsedMicrosecounds();

    for (int i = 0; i < 100; i++)
    {
        float f = (float)System.Math.Pow(1234, 4321);

        double d = System.Math.Sqrt((double)f);

        Int64 i64 = (Int64)(d * f);
    }

    average = (average + Stopwatch.GetElapsedMicrosecounds()) / 2;

    if (counter > 99)
    {
        Debug.Print("Average Time: " + average.ToString() + " Microsecounds");
        counter = 0;
    }
    else
    {
        counter++;
    }
}

Der Programmablauf in der Main() Methode

Die Aufgabe ist eine eher nicht optimal ausgelegte Rechnung, was aber für den Testlauf absichtlich so gestaltet ist. Die Unterschiede bei der Zeitmessung können sich sehen lassen.

Netduino Plus 1 ca. 43182 bis 43232 Mikrosekunden
Netduino Plus 2 ca. 7902 bis 7927 Mikrosekunden

Bei weiteren Tests, die ich bereits durchgeführt habe, funktionierte z.B. die I²C Verbindung deutlich schneller. Mit dem Sensor MPU6050 las der NP+ zuvor nur die Sensor Daten in 3ms, jetzt kann ich noch einen künstlichen Horizont und 4 PIDs berechnen und der NP+2 benötigt für das Ganze gerade mal 2ms.

Ein paar Dinge haben sich geändert. Der I²C Bus liegt jetzt auf Pin 15 und 16, wenn man das so nennen kann. Also quergegenüber auf dem Board. Und wenn man UART 1 bzw. COM1 verwenden will, ist dieser ebenfalls dort. Somit fällt leider eine serielle Verbindung weg, was jedoch nicht weiter schlimm ist, da es 3 weitere davon gibt. Für die Netzwerk Buchse RJ45 ist nur noch eine LED als Status zusehen, was allerdings auch weiterhin ausreicht.

Die Beispiel Solution mit .NET Framework 4.2 für NP+ und NP+2 zum Downloaden.

Donnerstag, 1. August 2013

HMC5883L Sensor auslesen mit dem Netduino

Netduino_HMC5883L_2
HMC5883L Magnet Sensor auf dem Breadboard Shield und PullUp-Widerständen.

Was mit dem Arduino geht, geht auch mit Netduino. Auch hier konnte ich ein funktionales Beispiel für den 3 Achsen Magnet Sensor HMC5883L als Klasse schreiben.

public class HMC5883L
{
    /// Klasse für die I²C Verbindung
    private I2CDevice _i2CDevice;
    /// Die Variabeln zum Speichern der Ergebnisse nach der Messung.
    private byte[] _Data = new byte[6];
    /// Ruft die Achse X ab oder legt diese fest.
    public int AxisX { get; set; }
    /// Ruft die Achse Y ab oder legt diese fest.
    public int AxisY { get; set; }
    /// Ruft die Achse Z ab oder legt diese fest.
    public int AxisZ { get; set; }
    /// Der Konstruktor Initialisiert die Verbindung her und
    /// stellt den Sensor mit einer Standard Konfiguration ein.
    public HMC5883L()
    {
       // I²C Bus verbindung herstellen mit 100kHz
        _i2CDevice = new I2CDevice(new I2CDevice.Configuration(0x1E, 100));
        // Operating Mode (0x02):
        // Continuous-Measurement Mode (0x00)
        StatusMessage(Write(new byte[] { 0x02, 0x00 }));

        // Die Konfiguration besteht in zwei Abschnitten.
        // Der erste Byte bestimmt, wie viel Proben pro Messung vorgenommen
        // werden (Default = 1) sollen. In welcher Bit Rate an die Ausgänge
        // geschrieben wird (Default = 15Hz) und den Messmodus bestimmt
        // die Vorspannung (Default = Normal)
        // Standard Einstellungen, siehe Datenblatt für weitere Einstellungen.

        StatusMessage(Write(new byte[] { 0x00, 0x10 }));

        // Standard Skalierung, siehe ggf. Datenblatt
        // +- 1.3 Ga, 1090 Gain(LSb/Gauss)
        StatusMessage(Write(new byte[] { 0x01, 0x20 }));
    }
    /// Liest die Sensor Messungen ein und schreibt diese in die Properties
    public void ReadMagnetic()
    {
        // Sendet das Byte für die erste Achse
        Write(new byte[] { 0x03 });
        // Nur wenn das Einlesen erfolgreich war.
        _Data[0] = 0x03;
        if (Read(_Data) != 0)
        {
            AxisX = (_Data[0] << 8) | _Data[1];
            AxisY = (_Data[2] << 8) | _Data[3];
            AxisZ = (_Data[4] << 8) | _Data[5];
        }
        else
        {
            Debug.Print("Fehler beim lesen!");
        }
    }
    /// Sendet das Byte Array zum Modul
    private int Write(byte[] buffer)
    {
        I2CDevice.I2CTransaction[] transactions = new I2CDevice.I2CTransaction[]
        {
            I2CDevice.CreateWriteTransaction(buffer)
        };
        return _i2CDevice.Execute(transactions, 1000);
    }
    /// Liest mit den Byte Array die Daten vom Modul
    private int Read(byte[] buffer)
    {
        I2CDevice.I2CTransaction[] transactions = new I2CDevice.I2CTransaction[]
        {
            I2CDevice.CreateWriteTransaction(new byte[] { 0x03 }),
            I2CDevice.CreateReadTransaction(buffer)
        };
        return _i2CDevice.Execute(transactions, 1000);
    }
    /// Gibt mit dem Ergebnis den Status des Vorgangs
    /// über die Ausgabe(Output) in Visual Studio wieder.

    private void StatusMessage(int result)
    {
       if (result == 0)
        {
            Debug.Print("Status: Fehler beim Senden oder Empfangen");
        }
        else
        {
            Debug.Print("Status: OK");
        }
    }
}

Anschließend muss diese Klasse in der Program.cs instanziiert werden und eine Schleife, die fortlaufend die Messungen abfragt, eingetragen werden.

public static void Main()
{
    // Sensor Initialisieren
    HMC5883L sensor = new HMC5883L();

    while (true)
    {
        // Einlesen
        sensor.ReadMagnetic();
        // Ergebnisse ausgeben
        Debug.Print("Raw Measurement: X " + sensor.AxisX +
            "\tY" + sensor.AxisY +
            "\tZ" + sensor.AxisZ);

        // Kurz warten
        Thread.Sleep(100);
    }
}

Was die Schaltung angeht, ist diese identisch mit der für den  Arduino, allerdings mit einer Ausnahme.

Netduino_HMC5883L_Steckplatine
Netduino –> HMC5883L
3,3V      –> VCC
GND     –> GND
A4         –> SDA
A5         –> SCL

HINWEIS: Wenn beim Ausgeben nur 0 heraus kommt oder generell der Status nicht in Ordnung ist, dann kann es an fehlenden PullUp Widerständen liegen. Es gibt einige Module ohne diese, so wie bei mir.

Netduino_HMC5883L_FehlendePullUpResistor
2 Fehlende SMD Widerstände, die eigentlich die offene Schaltung schließen sollten.

Mit dem Ergänzen der zwei fehlenden 2,2kOhm Widerstände ist dies schnell angepasst.

Netduino_HMC5883L_Steckplatine_PullUp
Netduino <–> HMC5883L
3,3V      <–> VCC
GND     <–> GND
A4         <–> SDA
A5         <–> SCL

Netduino <–> Widerstand 2,2kOhm <–> HMC5883L
3,3V     <–> Widerstand <–> SDA
3,3V     <–> Widerstand <–> SCL

Am besten wenn man hier zwei SMD Widerstände verbaut oder gleich einen Sensor kauft, worauf man später nicht mehr achten muss. Zwinkerndes Smiley

Wie immer die Solution für .NET Micro Framework 4.2: Download

HMC5883L Sensor ohne (externe) Library auslesen mit dem Arduino

HMC5883L_auf_Breadboard
HMC5883 Magnet Sensor auf dem Breadboard Shield.

Letztes Jahr habe ich bereits darüber geschrieben, allerdings keinen Code dazu gepostet. Ich habe nur beschrieben, was mit der Library verändert werden musste, damit diese funktioniert. Diesmal hatte ich Zeit, um mich etwas näher damit zu befassen und konnte nun endlich ein funktionales Beispiel schreiben. Um den Code fürs erste übersichtlich zu halten, habe ich das Skalieren und das Berechnen nach Norden ausgelassen.

// Wird für die I²C Verbindung verwendet.
#include <Wire.h>
// Adresse des Sensors
#define sensor_address 0x1E
// Variabelen die für den Lese Vorgang benötigt werden
byte data[6];
int axisX;
int axisY;
int axisZ;
// Konfiguration der Seriellen Verbindung und Initialisierung des Sensors.
void setup()
{
  Serial.begin(9600);
  Serial.println("Init Sensor");
  // I²C Verbindung starten.
  Wire.begin();
  // Operating Mode (0x02):
  // Continuous-Measurement Mode (0x00)
  SetConfiguration(0x02, 0x00);
  // Standard Skalierung, siehe ggf. Datenblatt
  // +- 1.3 Ga, 1090 Gain(LSb/Gauss)
  SetConfiguration(0x01, 0x20);
}
// Hauptschleife
void loop()
{
  // Rohdaten abrufen
  ReadMagnetic();
  // Zeige Roh Messwerte
  Serial.print("Raw Measurement: X ");
  Serial.print(axisX, DEC);
  Serial.print("\tY ");
  Serial.print(axisY, DEC);
  Serial.print("\tZ ");
  Serial.println(axisZ, DEC);
}
// Liest die Messwerte aus dem Magnet Sensor
void ReadMagnetic()
{
  Wire.beginTransmission(sensor_address);
  Wire.write(0x03);
  Wire.endTransmission();
  // Die Array Größe, die hier zu erwarten ist sind 6 Bytes.
  Wire.requestFrom(sensor_address, 6);
  // Die einzelnen Bytes werden nun gelesen
  // und in das Byte Array geschrieben

  for(int i = 0; i < 6; i++)
  {
    data[i] = Wire.read();
  }
  // 2 Bytes bilden zusammen einen Wert von 0 bis 65536.
  // Durch Byte Shifting lassen sich die Bytes zu einem Integer Wert zusammen fügen.

  axisX = (data[0] << 8) | data[1];
  axisY = (data[2] << 8) | data[3];
  axisZ = (data[4] << 8) | data[5];
}
// Legt die Konfiguration fest, mit dem Einstellungs Byte und
// dem Byte für die Einstellungsbereich.
void SetConfiguration(byte reg, byte setting)
{
  Wire.beginTransmission(sensor_address);
  Wire.write(reg);
  Wire.write(setting);
  Wire.endTransmission();
  Wire.requestFrom(sensor_address, 1);
  byte result = Wire.read();
 
// Das Ergebnis aus dem Senden gibt einen Wert zurück. Ist der Wert 0,
  //
war das senden fehlerhaft.
  Serial.print("Status: ");
  if(result != 0)
  {
    Serial.println("OK");
  }
  else
  {
    Serial.println("Failur");
  }
}

Funktionaler Programmcode für das Einlesen der der Rohdaten.

Eigentlich hatte ich vor, noch die Himmelsrichtung zu bestimmen, allerdings habe ich eine Webseite gefunden, die das bereits sehr gut erklärt (Love Elektronics - HMC5883L Compass Tutorial with Arduino Library).

Zuletzt noch ein Schaltbild, mit dem Arduino.

Arduino_HMC5883L_2_Steckplatine
Arduino –> HMC5883L
3,3V      –> VCC
GND     –> GND
A4         –> SDA
A5         –> SCL

Gehäuseentwurf für Signalleuchten (Part 1)

RGB LEDs und LIPO Akkus sind bestellt. Weil ich bereits die Abmessungen habe, kann ich schon mal mit dem Gehäuseentwurf in Blender anfangen....