Sonntag, 19. April 2015

Beleuchtung mit dem ATtiny 45

image

Zuerst habe ich darüber nachgedacht, was ich alles an Beleuchtung am Quadrocopter anschließen möchte und kam zu dem Entschluss Positionslichter anzubringen. Das macht dann besonders Sinn, wenn der Quadrocopter bereits 40 Meter entfernt ist. Für diesen Zweck eignen sich ultrahelle LEDs ab einer Lichtstärke von über 5000mcd. Für das Bunte sah ich die WS2812B auf Streifen für die Unterbodenbeleuchtung. Diese RGB LEDs sind nicht nur leuchtstark, sondern können über eine Leitung angesteuert werden.

image

Normalweise würde ich einen ATMega328 oder 168 verwenden, doch die bessere Wahl ist ein ATtiny. Der ATTiny45/85 z.B. hat insgesamt acht Pins. Zwei für die Stromversorgung, einen für Reset und der Rest kann frei programmiert werden.

image

Für das Vorhaben werden folgende Teile benötigt:

  • 1x ATTiny45
  • 2x Ultrahelle LEDs Grün (3mm, 6000mcd)
  • 2x Ultrahelle LEDs Rot (3mm, 5000mcd)
  • RGB LEDs WS2812B
  • 2x PNP Transistoren (es gehen auch 2x NPN, muss nur im Code umgedreht werden)
  • 2x 22µF Kondensatoren (63V, darf auch niedriger sein)
  • 1x 5V Spannungsregler (UTC LP2950G 5.0 QC4, 160mA)
  • 2x 75 Ohm Widerstand (100Ohm kamen in meiner Schaltung)
  • 2x 2,2kOhm Wiederstände
  • 1x Rasterplatine
  • ausreichend Schrumpfschläuche
  • und natürlich dürfen die Kabel nicht fehlen

[Bild von den Teilen]

Bevor das Ganze zusammengelötet wird, empfiehlt sich ein Test der Schaltung auf dem Breadboard. In meinem Fall war dies auch notwendig, da die Anzahl der angeschlossen LEDs mehr Strom benötigt hat. Der vorgegebene Spannungsregler kann bis zu 160mA durchlassen und reicht für die grünen und roten LEDs auch aus. Kommen nun die RGB LEDs hinzu, dann wird es knapp. Selbst wenn jetzt die vier LEDs ca. 120mA verbrauchen, bleiben nur 40mA übrig. Das reicht gerade mal für zwei weitere LEDs, in einer RGB LED sind aber drei. Abgesehen davon, dass der ATtiny für die Ansteuerung der WS2812B verwendet wird, kann dieser auch die Ansteuerung der Helligkeit regulieren und somit den Stromverbrauch reduzieren. Hierbei werden die einzelnen LEDs mit einem PWM Signal angesteuert. Kommen wir zur Grundschaltung.

image
Schaltbild vom Versuchs- und Testaufbau.

Kommen wir nun zu dem ATtiny. Um diesen zu beschreiben verwende ich einfach einen Arduino und einen eigenen, selbst gelöteten Shield. Alternativ kann dies auch auf einem Breadboard zusammengesteckt werden.

image

Ich empfehle, die Arduino Entwicklungsumgebung zu verwenden; dies erspart weitere Kosten für ein neues Board. Das setzt natürlich voraus, dass man bereits einen Arduino besitzt.

Nachteil ist, dass für die Verwendung eine weitere Komponente installiert werden muss.

Die Seite high-low tech erklärt, wie der Arduino als ISP Programmer für den ATtiny verwendet werden kann. Daher fasse ich kurz zusammen, was für die Installation wichtig ist.

Nun fehlt noch eine Sache. Für die Verwendung der WS2812B RGB LEDs wäre eine wenig mehr Code notwendig. Ich greife deshalb auf eine fertige Library zurück. Diese wird von Adafruit bereit gestellt auf GitHub.com/adafruit/Adafruit_NeoPixel. Die fertige Bibliothek kommt diesmal in den Ordner ../Arduino/libraries/Adafruit_Neopixel.

Jetzt kann der eigentliche Spaß losgehen. Der folgende Beispiel Code ist extra kurz gehalten und geht mehr auf die verwendete Inhalte ein.

// NeoPixel Bibliothek hinzufügen für die Ansteuerung der WS2812B LED Streifen
#include <Adafruit_NeoPixel.h>

// Instanz initialisieren
// Parameter Angaben:
// 1. Anzahl für verwendeter RGB LEDs
// 2. Auf welchen Pin soll verwendet werden.
// 3. Auswahl zwischen RGB, GRB oder BRG und verwendeter Takt 400KHz oder 800KHz

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(4, 2, NEO_GRB + NEO_KHZ800);

// Helligkeit einstellen. Kann von 0 bis Maximal 255 festgelegt werden.
// Bei Maximaler Ausleuchtung ist zu prüfen, ob die Maximale Stromabnahme erreicht wird.

int brightness = 100;

// Helligkeit bei verwendung der WS2812b, wenn sie weis auf blitzen sollen.
// Bei 210 wird die Maximale Stromabnahme überschritten.
// Darf nur kurz verwendet werden, ansonsten brennt der Spannungsregler durch.

int brightnessWhite = 210;

// Wird zum festlegen des Licht Einstellung verwendet.
// Damit die Einstellung funktioniert,
// muss an der Fernsteuerung einmal hin und her Geschaltet oder gedreht werden,
// um die längste Pulslänge zu ermitteln.

unsigned long maxPwmIn = 2;

void setup() {
  // Signal von der Fernsteuerung aufnehmen.
  pinMode(3, INPUT);
  // Positionslichter schalten
  pinMode(0, OUTPUT);
 
  // RGB LEDs Stribes starten
  pixels.begin();
  pixels.show();
}

void loop() {
 
  // Signal von der Fernsteuerung einlesen.
  // Für die Verwendung sollte ein Schalter genutzt werden.

  unsigned long pwmIn =  pulseIn(3, HIGH);
  // Wird zum Anlernen verwendet. Durch festlegen der maximalen Pulslänge
  // können zwei Zustände verwendet werden.

  if(pwmIn > maxPwmIn) { maxPwmIn = pwmIn; }
 
  // Wenn das Signal kürzer ist als der Maximalen Pulslänge.
  if(pwmIn < maxPwmIn - 100){
    // Positionslichter einschalten
    // (Bei verwendung von NPN Transisitor, kann die '255 -' weg)

    analogWrite(0, 255 - brightness); delay(100);
   // Ausschalten (Bei NPN, den Wert auf 0 setzen.)
   analogWrite(0, 255); delay(100);
   
    // RGB LED Streifen ansteuern.
    // Rot und Grün

    allRGB_LED_Off();
    pixels.setPixelColor(0, pixels.Color(brightness, 0, 0));
    pixels.setPixelColor(1, pixels.Color(0, brightness, 0));
    pixels.show();
    delay(100);
    allRGB_LED_Off();
    pixels.setPixelColor(2, pixels.Color(brightness, 0, 0));
    pixels.setPixelColor(3, pixels.Color(0, brightness, 0));
    pixels.show();
   delay(100);
  }
  else
  {
    // Positionslichter ausschalten
    // (Bei verwendung von NPN Transisitor, ist zum Ausschalten der Wert 0)

    analogWrite(0, 255);
   
   // RGB LED Streifen ansteuern.
    for(int i = 0; i < 4; i++)
    {
      // Alle aus.
      allRGB_LED_Off();
     
     // Mit der Aktuellen Iteration als Index verwenden,
      // um den entsprechende RGB LED zu überschreiben.

      pixels.setPixelColor(i, pixels.Color(brightnessWhite, brightnessWhite, brightnessWhite));
      pixels.show();
      delay(100);
    }
  }
}

// Stellt alle Werte zurück.
void allRGB_LED_Off()
{
  for(int i = 0; i < 4; i++)
  {
    pixels.setPixelColor(i, pixels.Color(0, 0, 0));
  }
}

Im folgendem Video wird gezeigt, wie dieses Code Beispiel aussieht. Daneben ist noch ein Netduino der ein PWM Signal abgibt und alle drei Sekunden wechselt zwischen 900 und 1100 Mikrosekunden Pulslänge, um das Umschalten zu simulieren.

Bei dem ATtiny45 wird man schnell feststellen, dass der Speicher sehr knapp ist. Wer mehr Lichtanimationen einsetzen möchte, sollte auf einen ATtiny85 wechseln. Und wer mehr Licht einsetzen und nicht unbedingt an Strom sparen will, wird einen größeren Spannungsregler benötigen.

 Referenzen

Sonntag, 22. März 2015

Stereoskopie mit Windows Phone und MonoGame

StereoscopicTest03

Inzwischen findet sich immer mehr Zubehör für das Smartphone, um etwas Ähnliches zu schaffen wie die Oculus Rift. Zum Thema habe ich vor ein einigen Tagen im AppStore fürs Windows Phone nach solchen Apps mit Stereoskopie Ausgabe erfolglos gesucht. Die Verbreitung ist offenbar Android und iOS vorbehalten. Kommen wir aber zu der Frage: wie schwer ist die Umsetzung einer Stereoskopie Wiedergabe?

Das Prinzip ist simpel. Der gezeigte Inhalt wird für das linke und das rechte Auge gerendert. Um den 3d Effekt zu erzielen, müssen, wie in der realen Welt, zwei Kameras eingesetzt werden, die zueinander leicht versetzt sind. Doch wie sieht das im Programmcode aus?

Tatsächlich wird das für dieses Beispiel mit wenigen Ergänzungen im Programmcode erreicht. Und am Ende werden Sie sich fragen, wieso das noch keiner für Windows Phone gemacht hat.

Bevor Sie starten, sollten Sie neben Visual Studio 2013 noch MonoGame installiert haben und dann können Sie mit einem neuen Projekt für Windows Phone 8.1 starten.

image

Mit dem neuen Projekt wird in der Vorlage bereits eine fertige Szene mit einem 3d Würfel vorgegeben. Daher gehe ich im Beispiel nur auf das Wesentliche ein, nämlich, welche Ergänzungen notwendig sind.

Öffnen Sie die Game1.cs und legen sie oben zusätzliche Member Variable an.

// Ausgabebereich
Viewport viewportDefault;
Viewport viewportLeft;
Viewport viewportRight;

// Renderbereich
Matrix matrixProjection;
Matrix matrixProjectionHalf;

// Kamera Position und Ausrichtung
Matrix matrixViewLeft;
Matrix matrixViewRight;

In der Methode ‘Initialize()’ wird die Kameraposition und Ausrichtung festgelegt. Zusätzlich wird der ViewPort zusammengestaucht und der Platz für zwei Bilder hergerichtet. Mit den zwei Variablen für die Projektion wird noch der Renderbereich festgelegt.

this.matrixViewLeft = Matrix.CreateLookAt(new Vector3(.3f, 1f, -4f), new Vector3(0, 0, 0), Vector3.Up);
this.matrixViewRight = Matrix.CreateLookAt(new Vector3(-0.3f, 1f, -4f), new Vector3(0, 0, 0), Vector3.Up);

this.viewportDefault = this.GraphicsDevice.Viewport;
this.viewportLeft = viewportDefault;
this.viewportRight = viewportDefault;
this.viewportLeft.Width = viewportLeft.Width / 2;
this.viewportRight.Width = viewportRight.Width / 2;
this.viewportRight.X = viewportLeft.Width;

this.matrixProjection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 4.0f / 3.0f, 1, 10000);
this.matrixProjectionHalf = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 2.0f / 3.0f, 1, 10000);

Zuletzt wird eine Änderung an der ‘Draw()’ Methode vorgenommen. Der zu rendernde Inhalt wird nun als eigene Methode mit dem Namen ‘DrawScene’ ausgelagert.

image

Damit dürfte Anschließend Ihre Methode so aussehen.

private void DrawScene(ref Matrix View, ref Matrix Projection, ref Matrix World)
{
    vertexBuffer.SetData(cube, 0, 8, SetDataOptions.Discard);
    indexBuffer.SetData(cubeIndices, 0, 36, SetDataOptions.Discard);

    GraphicsDevice device = basicEffect.GraphicsDevice;
    device.SetVertexBuffer(vertexBuffer);
    device.Indices = indexBuffer;

    basicEffect.View = View;
    basicEffect.Projection = Projection;
    basicEffect.World = World;
    foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
    {
        pass.Apply();
        device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 8, 0, 36);
    }
}

Die Matrix Variable für ‘View’ und ‘Projection’ werden ersetzt. Im folgenden Code werden Sie erkennen, wie nun das Splitting erreicht wird.

// Linke Seite
this.GraphicsDevice.Viewport = this.viewportLeft;
this.DrawScene(ref this.matrixViewLeft, ref this.matrixProjectionHalf, ref World);

// Rechte Seite
this.GraphicsDevice.Viewport = this.viewportRight;
this.DrawScene(ref this.matrixViewRight, ref this.matrixProjectionHalf, ref World);

Und schon ist das Beispiel fertig. Nach Drücken auf die F5 Taste und hochladen auf das Smartphone dürfte nun, wie im Bild zu sehen, dieses Ergebnis erscheinen:

Stereoscopic_01

Fehlt noch der Aufsatz, um die Stereoskopie zu erleben. Für wenig Geld bekommen Sie bei Online Händlern z.B. ein aus Pappe hergestelltes Gestell mit den entsprechenden Linsen. Achten Sie in diesem Fall darauf, welche Größe Ihr Smartphone hat.

DIY Google Karton_01 DIY Google Karton_02
DIY Google Karton_03

Was eigentlich noch fehlt, um die Sache im wahrsten Sinne des Wortes abzurunden, ist die fehlende Krümmung. Der 3D-Effekt wirkt ein wenig nach innen gezogen. Wer bereits die Oculus Rift oder Bilder davon gesehen hat, wird feststellen, dass die Renderbilder einen leichten Fischaugeneffekt haben. Was den Komfort angeht, naja, zum Experimentieren reicht die Lösung aus.

Quellen:

Suchbegriffe:

  • Virtual Reality
  • VR Handy 3d
  • Google Cardboard

Freitag, 16. Januar 2015

Arduino Control (Teil 4) – Potentiometer Wert am PC ausgeben

image

Der Arduino kann auch analoge Signale einlesen. Dieser Wert kann zwischen 0 und 1023 liegen. Für dieses Beispiel wird ein Potentiometer verwendet, der möglichst hochohmig sein sollte. In meinem Fall habe ich einen 470 Ohm Stellwiederstand verwendet. Empfohlen ist 1k Ohm.

image

Der Quellcode ähnelt dem Beispiel für den Button. Nur müssen hier für den Empfang zwei Bytes zu einem Wert zusammengesetzt werden. Das Stichwort ist hier Byte Shifting. Das erste Byte wird um acht Bits nach links verschoben, um die Bits von 9 bis 16 abzubilden. Das zweite Byte bleibt für die ersten acht Bits.

static void Main(string[] args)
{
   // Die Verwendete COM Verbindung
    // sollte der aus dem Arduino Programm entsprechen.
    SerialPort sp = new SerialPort("COM16", 115200);

    // Event zuweisen für den Empfang.
    sp.DataReceived += sp_DataReceived;

   // Verbindung öffnen.
    // Wenn das Programm gestartet ist,
    // sollte der Arduino bereits mit dem PC verbunden sein.
    sp.Open();

    while (true)
    {
       // Nur warten.
        Thread.Sleep(1000);
    }
}


// Wird ausgeführt, wenn Daten im Empfangspuffer vorhanden sind.
static void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    // SerialPort aus 'sender' casten.
    SerialPort sp = (SerialPort)sender;

    // Bytes einlesen vom Empfang und auf die Console wiedergeben.
    byte[] buffer = new byte[2];
    if (sp.Read(buffer, 0, 2) != 0)
    {
        Console.Clear();
        // Die zwei empfangenen Byte müssen wieder zusammengelegt werden,
        // um den Eigentlichen Wert wiederzugeben.
        Console.WriteLine("Received: {0}", (int)buffer[0] << 8 | buffer[1]);
    }
}

Der Input verwendet diesmal analogRead(), statt des digitalRead(). Unterscheidet sich der Wert zu dem zuletzt versendeten, dann soll der neue gemessene Wert gesendet werden. Der Wert kann bis zu 1023 betragen und passt nicht in ein Byte. Daher wird dieser in zwei Bytes aufgeteilt und anschließend versendet. Am Ende wird eine Verzögerung von 100 Millisekunden festgelegt, um zwischen den Sendungen eine Lücke zu erzeugen. Ansonsten kann nicht erkannt werden, welches das erste und das zweite Byte ist.

// Pin Nummer A0 vom Arduino
int pinPegel = A0;

// Enthält den letzten Button Zustand.
int lastValue = 0;

void setup()
{
  // Baudrate wie bei dem C# Programm
  Serial.begin(115200);
  pinMode(pinPegel, INPUT);
}

void loop()
{
  // Status am Pin abfragen
  int readValue = analogRead(pinPegel);
 
  // Nur Inhalt im If ausführen,
  // wenn der Status sich geändert hat.
  if(readValue != lastValue)
  {
   // Member Field überschreiben.
    lastValue = readValue;
  
   // Buffer vorbereiten und
   // den Wert in zwei bytes aufteilen.
    byte ba[2];
    ba[0] = (byte)((readValue >> 8) & 0xff);
    ba[1] = (byte)(readValue & 0xff);
   
    // Buffer Inhalt von zwei Bytes senden.
    Serial.write(ba, 2);
       
    // Ermöglicht das Erkennen vom 1. und 2. Byte
    // in dem zwischen den Sendungen eine Pause gesetzt wird.

    delay(100);
  }
}

Damit ist auch schon alles getan.

 

Quellcode zum Download

Dienstag, 13. Januar 2015

Arduino Control (Teil 3) – LED mit dem PC Dimmen

image

Nicht alles lässt sich immer sinnvoll mit Ein- und Ausschalten lösen. Möchte man eine LED dimmen, so sollte ein PWM Signal verwendet werden. Ein PWM verwendet einen Timer, um das Rechtecksignal abzubilden. Daher können nur sechs bestimmte Ausgänge am Arduino (D3, D5, D6, D9, D10, D11) verwendet werden. Die Pins sind daran zu erkennen, dass neben den Anschlüssen ein kleines Wellensymbol zu sehen ist (oder sie sind direkt mit PWM beschriftet).

image

Der Programm Code ist dem ersten Beispiel Ähnlich. Beim Senden jedoch, kann ein Wert von 0 bis 255 angegeben werden.

static void Main(string[] args)
{
    // Die Verwendete COM Verbindung
    // sollte der aus dem Arduino Programm entsprechen.
    SerialPort sp = new SerialPort("COM16", 115200);

    // Verbindung öffnen.
    // Wenn das Programm gestartet ist,
    // sollte der Arduino bereits mit dem PC verbunden sein.

    sp.Open();

    while (true)
    {
        Console.Write("Bitte geben sie einen Wert von 0 bis 255 ein und drücken sie anschließend die Enter Taste: ");

        // Abfrage eines Wertes.
        string readline = Console.ReadLine();

        // Zeichenkette in einen Integer Wert umwandeln.
        byte value = byte.Parse(readline);

       // Sendet den Wert.
        sp.Write(new byte[] { value }, 0, 1);
    }
}

Für den Empfang im Arduino wird diesmal für die LED Ansteuerung der Pin D3 verwendet. Und anstatt eines digitalWrite wird ein analogWrite verwendet.

// Pin 3 für die LED Beleuchtung
int pinPwmOut = 3;

void setup()
{
  // Baudrate wie bei dem C# Programm
  Serial.begin(115200);
 
  // Pin 3 für die LED
  pinMode(pinPwmOut, OUTPUT);
}

void loop()
{
  // Wenn neue Daten verfügbar sind.
  if(Serial.available() > 0)
  {
    // Liest den empfangen Byte Wert ein
    byte value = Serial.read();
   
    // Empfangener Byte Wert für das PWM Signal verwenden.
    analogWrite(pinPwmOut, value);
  }
}

Nach Eingabe eines Wertes von 0 bis 255 sollte die LED weniger oder heller leuchten. Durchschnittlich haben die LEDs eine Stromaufnahme von 20mA. Der Unterschied liegt in der Farbe, die unterschiedliche Spannungen für den Betrieb benötigen.

Farbe Spannung Berechneter Vorwiderstand Widerstand aus der E6 Reihe
Rot 1,6V 170 220 Ohm
Grün 2,1 145 150 Ohm
Blau 2,9 105 100 Ohm

Wenn die technischen Daten der verwendeten LED bekannt sind, dann kann der Widerstand mit der Formel R = U / I berechnet werden.

image

Das Schaltbild weist keine Besonderheiten auf, stelle dies jedoch zur Vollständigkeit mit in den Post ein.

image

Wie zu sehen ist, lässt sich dieses Beispiel schnell umsetzten.

 

Quellcode zum Downloaden

Dienstag, 6. Januar 2015

Arduino Control (Teil 2) – Button Status auf PC wiedergeben

image

Eine Eingabe vom PC zum Arduino zu bringen ist nicht sonderlich schwierig. Das Gleiche gilt auch bei der Umsetzung einer Tasteneingabe vom Arduino zum PC. Am Arduino wird diesmal eine kleine Schaltung mit einem Button zusammengesteckt.

Zusätzlich benötigt: Taster und 10k Ohm Wiederstand

image

Kommen wir zum Consolen Programm. Wie im vorherigen Post, werden die selben Verbindungsparameter verwendet.

Für den Empfang wird noch der hierfür erforderliche Event hinzugefügt. Sobald sich also Daten im Eingangspuffer befinden, wird der Inhalt der Event Methode ausgeführt.

In der Schleife wird diesmal nur ein 'Thread.Sleep' eingesetzt; das soll verhindern, dass die Anwendung zu viel der CPU Zeit beansprucht (und es nicht so wirkt, als wäre sie eingefroren).

static void Main(string[] args)
{
    // Die Verwendete COM Verbindung
    // sollte der aus dem Arduino Programm entsprechen.

    SerialPort sp = new SerialPort("COM16", 115200);

    // Event zuweisen für den Empfang.
    sp.DataReceived += sp_DataReceived;

   // Verbindung öffnen.
    // Wenn das Programm gestartet ist,
    // sollte der Arduino bereits mit dem PC verbunden sein.
    sp.Open();

    while (true)
    {
        // Nur warten.
        Thread.Sleep(1000);
    }
}

// Wird ausgeführt, wenn Daten im Empfangspuffer vorhanden sind.
static void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    // SerialPort aus 'sender' casten.
    SerialPort sp = (SerialPort)sender;

    // Byte einlesen vom Empfang und auf die Console wiedergeben.
    Console.WriteLine("Received: {0}", sp.ReadByte() == 0x01);
}

Der Code für den Arduino kann sich den letzten Zustand des Button "Drücken" merken. Damit wird nur gesendet, wenn sich der Zustand geändert hat. Für das Senden wird im Beispiel der selbe Hex Wert verwendet.

// Pin Nummer A0 vom Arduino
// an dem ein HIGH (gedrückt) oder
// LOW (nicht gedrückt) gelesen wird.

int pinButton = A0;

// Enthält den letzten Button Zustand.
boolean buttonState = false;

void setup()
{
  // Baudrate wie bei dem C# Programm
  Serial.begin(115200);
  pinMode(pinButton, INPUT);
}

void loop()
{
  // Status am Pin abfragen
  boolean readState = digitalRead(pinButton);
 
  // Nur Inhalt im If ausführen,
  // wenn der Status sich geändert hat.
  if(readState != buttonState)
  {
   // Member Field überschreiben.
    buttonState = readState;
  
    // Wenn 'true' sende 0x01 für ist gedrückt
    if(buttonState == true)
    {
      Serial.write(0x01);
    }
    else
    {
      Serial.write(0x00);
    }
  }
}

Das war schon auch wieder alles. Nun können mit dem Beispiel Eingaben vom Arduino auf dem PC wiedergegeben werden.

Quellcode zum Downloaden

Sonntag, 4. Januar 2015

Arduino Control (Teil 1) – LED ein und ausschalten

image

Diesmal gehen die folgenden Beispiele darauf ein, einen Arduino mit seinen Eigenschaften anzusteuern. Im Wesentlichen handelt dieser mehrteilige Blog Post davon, wie eine Eingabe vom PC zum Arduino kommt und auch wieder zurück.

Die Anforderung wird sein, dass mit der Enter Taste die rote LED auf dem Arduino ein oder ausgeschaltet wird. Für das erste Beispiel reicht daher ein Consolen Programm aus, um eine Eingabe aufzunehmen und einen Befehl entsprechend zu senden. Beide Programme müssen dieselbe Baudrate haben, die hier bei 115200 Baut liegt.

static void Main(string[] args)
{
    // Die Verwendete COM Verbindung
    // sollte der aus dem Arduino Programm entsprechen.
    SerialPort sp = new SerialPort("COM16", 115200);

    // Verbindung öffnen.
    // Wenn das Programm gestartet ist,
    // sollte der Arduino bereits mit dem PC verbunden sein.
    sp.Open();

    // Wird verwendet um den Zustand zu wechseln.
    bool changeState = true;

    // Der Eigentliche Steuerinhalt wird immer wieder ausgeführt.
    while (true)
    {
        // Programm hält an dieser Stelle,
        // bis die Enter Taste gedrückt wurde.

        Console.ReadLine();

        // Ist der Wechsel Status 'True'...
        if (changeState)
        {
            //... dann soll die LED eingeschaltet werden.
            sp.Write(new byte[] { 0x01 }, 0, 1);
        }
        else
        {
            //... dann soll die LED ausgeschaltet werden.
            sp.Write(new byte[] { 0x00 }, 0, 1);
        }

        // Wechselt den Zustand von True auf False oder umgekehrt.
        changeState = !changeState;
    }
}

Hinweis: Hier im Beispiel verwende ich COM16, der wahrscheinlich angepasst werden muss. Das könnte dann ggf. über dem Arduino Programm gesichtet werden.

image

Nun muss der Arduino die Sendung vom Programm verstehen. Momentan wird erwartet das Hex 0x01 oder Hex 0x00 empfangen wird.

void setup()
{
  
// Baudrate wie bei dem C# Programm
  Serial.begin(115200);

  // Pin 13 für die Rote LED
  pinMode(13, OUTPUT);
}

void loop()
{
  // Wenn neue Daten verfügbar sind.
  if(Serial.available() > 0)
  {
    // Wird am Serial 0x01 gelesen, wird an die
    // Methode digitalWrite ‘true’ übergeben.

    digitalWrite(13, Serial.read() == 0x01);
  }
}

Das war im Grunde schon alles. Wenn nun das C# Programm gestartet wird und der Arduino bereits angeschlossen ist, so kann dann mit der Enter Taste die Rote LED ein und ausgeschaltet werden.

Quellcode zum Downloaden

Dienstag, 14. Oktober 2014

Intervallaufnahme mit der Kamera ohne Interne Funktion

IntervallAufnahme01

Die Funktion für eine Intervallaufnahme ist simpel, daher ist es für mich unverständlich, warum nicht zumindest die Systemkameras von der Nikon 1 Serie in ihren Modellen diese Option anbieten. Nun gut, dies war kein Kaufkriterium, wäre aber schön gewesen. Ich selbst verwende die Nikon 1 J3 (die J1 hat die Intervallaufnahme), allerdings sollte mein Beispiel auch für andere Kameras funktionieren. Grundsätzlich geht es darum einen Servo auf den Auslöser zu drücken. Für diesen Zweck habe ich aus Aluminium Eckschienen eine Vorrichtung gebaut.

image

Wie schon am Bild zu erkennen ist, sollten zum Schutz die Alu Eckschienen nach der Verarbeitung abgerundet und ggf. mit Filzaufklebern beklebt werden.

Die Materialliste:

  • Alu Eckschienen ca. 20cm
  • Filzaufkleber
  • ein paar 3mm Schrauben und entsprechende Muttern
  • Mini Servo mit ca. 10 Ncm
  • Eine passende Schraube zur Kamera dass mit dem Stativ auch verschraubt werden kann. (siehe folgendes Bild)
image

Zum Ansteuern wird der Netduino mit einem passenden Shield zur Ansteuerung für einen Servo verwendet. Die geringe Belastung kann das Board verkraften. Bei Normalen und größeren Servos wird eine Externe Stromversorgung notwendig.

image

Der Aufwand des Programmcodes gestaltet sich übersichtlich. Zusehen ist, dass noch ein Analoger Wert eingelesen wird, worauf ich im nächsten Absatz zu sprechen komme.

public class Program
{
    // Für die Einstellung des Druckpunktes.
    private static SecretLabs.NETMF.Hardware.AnalogInput _Input;

    // Ansteuerung des Servos für den Auslöser.
    private static PWM _Servo;

    // Led Status wiedergeben.
    private static OutputPort _Status;

   // Einen Zähler.
    private static int _IntervallCounter = 0;

   // Nach wie viel Sekunden soll ausgelöst werden.
   private static int _IntervallEnd = 15;//30;

    public static void Main()
    {
        _Input = new SecretLabs.NETMF.Hardware.AnalogInput(Pins.GPIO_PIN_A0);
        _Servo = new PWM(Pins.GPIO_PIN_D5);
        _Status = new OutputPort(Pins.ONBOARD_LED, false);
           
        // 20ms für den Analog Servo.
        uint periode = 20000;

        // Mittelstellung bei 1,5ms
        _Servo.SetPulse(periode, 1500);

       while (true)
        {
           if (_IntervallCounter >= _IntervallEnd)
            {
                for (int i = 0; i < 3; i++)
                {
                    _Status.Write(true);
                    Thread.Sleep(100);
                    _Status.Write(false);
                    Thread.Sleep(100);
                }

                // Hinweis: bei Netduino 1 wird ein Wert gelesen von 0 bis 1023.
                //          Der Netduino 2 hingegen liest bis 4095.
                //uint duration = 1000 + (uint)_Input.Read();         // Ein kommentieren um den Servo
                //Debug.Print("Duration: " + duration.ToString());  // einzustellen am Pin A1.

                _Servo.SetPulse(periode, 1710); // 1710 ist eine Einstellung, an meiner Kamera
                Thread.Sleep(400);

               // Zähler Zurücksetzten.
                _IntervallCounter = 0;
            }
            else
            {
                // Aktivität zeigen
                _Status.Write(true);
                Thread.Sleep(100);
                _Status.Write(false);
               Thread.Sleep(900);

                _IntervallCounter++;
            }

           // Zurückstellen.
            _Servo.SetPulse(periode, 1500);
        }
    }
}

Das gleiche nochmal für den Arduino.

#include <Servo.h>
// Servo Kontrolle anlegen
Servo controlServo;
// Einstellung wie weit sich der Servo drehen darf
int pinAnalogIn = A0;
// Servo ansteuern
int pinServo = 5;
// LED Status
int pinLed = 13;
// Intervall Zähler
int intervall = 0;
// IntervallLänge in Sekunden
int intervallLength = 15; // 30;

void setup(){

  // Dient zu Einstellgunszwecke
  Serial.begin(9600);
  // Pins zuweisen
  pinMode(pinAnalogIn, INPUT);
  controlServo.attach(pinServo);
  pinMode(pinLed, OUTPUT);
}

void loop()
{
  if(intervall >= intervallLength)
  {
    for(int i = 0; i < 3; i++)
    {
      digitalWrite(pinLed, HIGH);
      delay(100);
      digitalWrite(pinLed, LOW);
      delay(100);
    }
   
   // Einkommentieren um die Reichweite des Servos einzustellen,
    // mit einem Potitometer am Pin A1.

    int result = 500; //analogRead(pinAnalogIn);
   
    controlServo.write(map(result, 0, 1023, 0, 179));
    delay(400);
   
    // Zähler zurück setzen
    intervall = 0;
  }
  else
  {
   digitalWrite(pinLed, HIGH);
   delay(100);
    digitalWrite(pinLed, LOW);
    delay(900);
    intervall++;
  }
 
  // Zurück stellen.
  controlServo.write(90);
}

Jetzt fehlt noch ein fester Wert für den Druckpunkt. Der Potentiometer wird an Pin A1 angeschlossen, die Spannungsversorgung muss beim Netduino mit 3,3V angelegt werden. Das Auslesen des Stellwertes erfolgt beim Netduino über Debug.Print() und wird über die Ausgabe angezeigt. Beim Arduino wird der Stellwert über dem Serial Monitor wiedergegeben. Je nach Belastung kann die Versorgung über USB instabil werden. Das zeigt sich dann, wenn der Servo beim Drücken des Auslösers leicht zittert. Später, mit einem 9V Akku oder Netzteil, sollten diese Schwierigkeiten nicht mehr auftauchen. Ansonsten muss der Servo einen eigenen Stromkreis erhalten, um zu verhindern, dass die Versorgung des Mikrocontrollers zu sehr schwankt und so zu einem Neustart des Programms führt.

image image
image image

Zu den Einstellungen der Kamera. Um ein schnelles Auslösen der Kamera zu ermöglichen, sollte auf den Kreativ Modus gewechselt werden. Die Blende, die Verschlusszeit und der Fokus sind am besten manuell festzulegen. Spätestens bei Nachtaufnahmen kommt man an diesen Einstellungen nicht vorbei. Achja, das Dateiformat JPG ist für die Ausgabe zu empfehlen. Mit dem NEF bzw. RAW ist das Bearbeiten im Video Schnittprogramm kaum machbar.

BeiNachtMitSternenhimmel_06

Tipp zur Nachtaufnahme: acht bis fünfzehn Sekunden für die Verschlusszeit bei maximal offener Blende reichen aus. Zu lange Belichtung führt dazu, dass die Sterne Streifen bilden, also praktisch gesehen wird die Erdrotation sichtbar. Die idealen Nächte mit Sternenhimmel sind in der Zeit um Neumond. Die besten Bedingungen sind Orte, die so dunkel sind, dass beim Hinabsehen die eigenen Füße nicht mehr zu sehen sind. Zwinkerndes Smiley

Nun noch ein paar Aufnahmen, die ich mit meiner Apparatur erstellt habe.

Zu guter Letzt auch noch der Quellcode zum Herunterladen.

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...