Mittwoch, 5. April 2017

Umzug auf passende Plattform (Arduino Esplora Teil 2)


Nachdem ich viel probiert habe und dabei fast ein Spiel zusammen hatte (Nicht Pong, das ist zu einfach), entschied ich den Arduino Esplora zu bestellen. Normalerweise würde ich vom Breadboard umziehen und dann etwas selbst auf eine Platine mit den entsprechenden Komponenten zusammenlöten. Aber warum nicht eine fertige Plattform nutzen.

Etwas enttäuschend, fand ich die Suche im Internet, weil ich keine aufwendigen Spiele für den Arduino Esplora entdeckt habe. Damit will ich das nicht schlecht reden, aber etwas mehr hatte ich schon erwartet.

Der Umzug vom Breadboad auf den Arduino Esplora ist in wenigen Schritten erledigt. Als erstes werden die Adafruit Bibliotheken gegen die 'Esplora.h' und 'TFT.h' ausgetauscht. Die Beschreibung an welchen Pin vom TFT zum Arduino Uno (oder Nano) verbunden werden soll, sowie auch die Pin Variablen entfallen. Das Initialisieren der Pins sowie auch das TFT Display, wird durch ein 'EsploraTFT.begin()' ersetzt. Die Steuerrichtung wird durch den Joystick abgenommen, allerdings bleibt das Verhalten der Bewegungsgeschwindigkeit. Hinzu kommt noch, dass ein Offset benötigt wird. Bei analogen Eingängen kann es zu Abweichungen kommen die durch das Offset korrigiert werden können. Für diesen Zweck ist eine neue Methode hinzugekommen, mit der die Werte auf dem Display angezeigt werden können.


#include <SPI.h>
#include <TFT.h>
#include <Esplora.h>

// ruft die letzte Postion X ab. (Pixel Position)
int lastPosX = 5;
// ruft die letzte Postion Y ab. (Pixel Position)
int lastPosY = 5;

// mittelstellung des Joystick
int offsetX = -3;
int offsetY = 4;

void setup() {
  EsploraTFT.begin();
  EsploraTFT.background(0, 0, 0);
}

void loop() {

  // Eingänge einlesen
  int stickX = Esplora.readJoystickX() + (offsetX * -1);
  int stickY = Esplora.readJoystickY() + (offsetY * -1);

  boolean buttonLeft = false;
  boolean buttonRight = false;
  boolean buttonUp = false;
  boolean buttonDown = false;

  if(stickX > 3 || stickX < -3) {
    buttonLeft = stickX > 3;
    buttonRight = stickX < -3;
  }

  if(stickY > 3 || stickY < -3) {
    buttonUp = stickY < -3;
    buttonDown = stickY > 3;
  }

  // Werte ausgeben auf dem Bildschirm
  writeValue(10, 10, stickX, false);
  writeValue(10, 20, stickY, false);

  // Temporaer letzte Position merken
  int lastPosXtemp = lastPosX;
  int lastPosYtemp = lastPosY;

  // Abfragen zu den gesetzten joystick
  // Es kann nur in eine Richtung die Bedingung erfüllt werden.

  // Wenn nach links oder rechts gedrückt wird.
  if(buttonLeft && !buttonRight && lastPosX > 0) {
    // nach links und letzte Position Y ist groesser als '0'.
    lastPosX--;
  }
  else if(!buttonLeft && buttonRight && lastPosX < EsploraTFT.width()) {
    // nach rechts und letzte Position X ist kleiner als die TFT Pixel Breite.
    lastPosX++;
  }

  // wenn nach oben oder unten gedrückt wird.
  if(buttonUp && !buttonDown && lastPosY > 0) {
    // nach oben und letzte Position Y ist groesser als '0'.
    lastPosY--;
  }
  else if(!buttonUp && buttonDown && lastPosY < EsploraTFT.height()) {
    // nach unten und letzte Position X ist kleiner als die TFT Pixel hoehe.
    lastPosY++;
  }

  // Wenn sich X oder Y Position unterscheiden, dann den zu bewegenden Punkt neu zeichen.
  if(lastPosX != lastPosXtemp || lastPosY != lastPosYtemp) {
    // vorrigen punkt entfernen mit den temporaeren positionen.
    drawPoint(lastPosXtemp, lastPosYtemp, false);
    // neuen punkt zeichnen mit der neuen Position.
    drawPoint(lastPosX, lastPosY, true);
  }

  writeValue(10, 10, stickX, true);
  writeValue(10, 20, stickY, true);
}

void writeValue(int x, int y, int val, boolean clr) {
  if(clr) {
    EsploraTFT.stroke(0, 0, 0);
  }
  else {
    EsploraTFT.stroke(30, 200, 50);
  }
  String accResult = String(val);
  char valuePrint[5];
  accResult.toCharArray(valuePrint, 5);
  EsploraTFT.text(valuePrint, x, y);
}

// Einachen Punkt Zeichnen, der nicht ausgefuellt ist.
void drawPoint(int x, int y, boolean setColor) {

  // Schwarz Zeichnen.
  EsploraTFT.stroke(0, 0, 0);

  // Farbe festlegen
  if(setColor) {
    EsploraTFT.stroke(120, 100, 200);
  }

  EsploraTFT.circle(x, y, 2);
}


Sobald das Programm auf dem Esplora ist, sollte mit dem Lauf des Programms die Werte für X und Y des Joysticks zu sehen sein. Die angezeigten Wert zeigen die Abweichungen, die im Anschluss im Offset einzutragen sind.

Der Arduino Esplora ist eine schöne Plattform und kann wie jeder andere Arduino Programmiert und angesteuert werden. Das Potenzial an Möglichkeiten ist da. Abgesehen vom Joystick, Buttons und dem passenden TFT, sind noch weitere Sensoren und Aktoren auf der Plattform vorhanden. Falls diese nicht reichen sollten, dann können oben an die Stecker weitere Komponenten angeschlossen werden und Betrieben werden.

Einen wesentlichen Unterschied gibt es zwischen den Arduino Nano (den ich zuvor verwendet habe) und dem Arduino Esplora. Der SRAM vom ATMega32u4 ist um 512 Bytes größer 😃


Technische Daten
Microcontroller:   ATmega32u4
Flash Speicher:    32kb (4kb werden vom bootloader verwendet)
SRAM:                2,5 kb
EEPROM:           1 kb
Takt:                    16 MHz

Sensoren / Eingabemöglichkeiten: Analog X Y Joystick
                                                        4 Taster
                                                        Linear Potentiometer
                                                        Mikrofone
                                                        Lichtsensor
                                                        Drei Achsen Beschleunigungssensor

Aktor, Widergabe, Ausgabe:          Buzzer
                                                        RGB LED
                                                        TFT Display (gibt's wahlweise mit als Bundle)




Sonntag, 19. März 2017

Bewegter Punkt (Arduino und TFT Teil 1)


Eigentlich sollte das Display für die Wiedergabe der Messwerte meiner Wetterstation wieder geben. Aber zu diesen Zeitpunkt war nicht klar, welche Möglichkeiten eigentlich mit dem TFT und vor allem mit dem ATMega328 mit den 16MHz machbar sind. Nur blanke Werte sind für meine Anforderung zu wenig und daher galt zunächst herauszufinden, wie schnell sich die Inhalte auf dem Display aktualisiert werden können.

Das einfachste ist, man lässt einen Punkt von A nach B bewegen. Aber besser ist, wenn man die Bewegungsrichtung des Punktes selbst zur Laufzeit bestimmen kann. Daher wurden auf dem Breadboard, noch vier Taster an den Arduino Angeschlossen.












Das sieht etwas wirr aus und was vielleicht nicht gleich zu erkennen ist, dass an den Button jeweils ein 4,7 Kilo Ohm Pull-Down Widerstand gesetzt sind. Das ist erforderlich, damit die Kontakte an dem Arduino keinen Zufälligen Zustand einnehmen. Denn selbst hohe Luftfeuchtigkeit, kann zu unerwünschten Effekten führen.













Neben dem Initialisieren des Bildschirms, müssen auch die Eingänge definiert werden, die später die Steuerknöpfe abbilden. Pro Loop durchlauf, wird der Zustand eingelesen und die Bedingungen für die Bewegung abgefragt.


#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>

// Verkabelung / Pins
// SCLK => D13
// MOSI/DIN => D11
// CS => D10
// DC => D9
// RST => D8

// instanz anlegen zu dem verwendeten Bildschirm.
Adafruit_ST7735 tft = Adafruit_ST7735(10, 9, 8);

// Pins festlegen
// ruft die Pin Nummer ab, um die Helligkeit des Displays anzusteuern.
const int pinBrightness = 5;
// ruft die Pin Nummer ab, um den Status des linken Buttons abzufragen
const int pinButtonLeft = 6;
// ruft die Pin Nummer ab, um den Status des rechten Buttons abzufragen
const int pinButtonRight = 3;
// ruft die Pin Nummer ab, um den Status des oberen Buttons abzufragen
const int pinButtonUp = 2;
// ruft die Pin Nummer ab, um den Status des unteren Buttons abzufragen
const int pinButtonDown = 7;

// ruft die letzte Position X ab. (Pixel Position)
int lastPosX = 5;
// ruft die letzte Position Y ab. (Pixel Position)
int lastPosY = 5;

void setup() {

  // initialisiere Display
  tft.initR(INITR_BLACKTAB);

  // pin Eingänge festlegen
  pinMode(pinButtonLeft, INPUT);
  pinMode(pinButtonRight, INPUT);
  pinMode(pinButtonUp, INPUT);
  pinMode(pinButtonDown, INPUT);

  // pin für tft Helligkeit festlegen
  pinMode(pinBrightness, OUTPUT);
  // helligkeit auf maximal einstellen
  analogWrite(pinBrightness, 255);

  // Bildschirm Schwarzausfüllen und um 90 Grad drehen.
  tft.fillScreen(ST7735_BLACK);
  tft.setRotation(1);
}

void loop() {

  // Eingaenge einlesen
  boolean buttonLeft = digitalRead(pinButtonLeft);
  boolean buttonRight = digitalRead(pinButtonRight);
  boolean buttonUp = digitalRead(pinButtonUp);
  boolean buttonDown = digitalRead(pinButtonDown);

  // Temporaer letzte Position merken
  int lastPosXtemp = lastPosX;
  int lastPosYtemp = lastPosY;

  // Abfragen zu den gedrückten Buttons
  // Es kann nur in eine Richtung die Bedingung erfüllt werden.

  // Wenn nach links oder rechts gedrückt wird.
  if(buttonLeft && !buttonRight && lastPosX > 0) {
    // nach links und letzte Position Y ist groesser als '0'.
    lastPosX--;
  }
  else if(!buttonLeft && buttonRight && lastPosX < tft.width()) {
    // nach rechts und letzte Position X ist kleiner als die TFT Pixel Breite.
    lastPosX++;
  }

  // wenn nach oben oder unten gedrückt wird.
  if(buttonUp && !buttonDown && lastPosY > 0) {
    // nach oben und letzte Position Y ist groesser als '0'.
    lastPosY--;
  }
  else if(!buttonUp && buttonDown && lastPosY < tft.height()) {
    // nach unten und letzte Position X ist kleiner als die TFT Pixel Hoehe.
    lastPosY++;
  }

  // Wenn sich X oder Y Position unterscheiden, dann den zu bewegenden Punkt neu zeichnen.
  if(lastPosX != lastPosXtemp || lastPosY != lastPosYtemp) {
    // vorigen punkt entfernen mit den Temporaeren Positionen.
    drawPoint(lastPosXtemp, lastPosYtemp, false);
    // neuen punkt zeichnen mit der neuen Position.
    drawPoint(lastPosX, lastPosY, true);
  }
}

// Einfachen Punkt Zeichnen, der nicht ausgefuellt ist.
void drawPoint(int x, int y, boolean setColor) {

  int setupColor = ST7735_BLACK;
  // farbe festlegen
  if(setColor) {
    setupColor = ST7735_CYAN;
  }
  tft.drawCircle(x, y, 2, setupColor);
  delay(2);
}

Damit wäre der erste Schritt getan und ihr könnt nun auf dem Bildschirm einen Punkte bewegen. Das ist zwar nicht sonderlich spektakulär, aber dafür gibt es ein wenig nostalgisches Gefühl mit der grafischen Darstellung.

Wie bereits oben der Titel verrät, kommen mehre Zusammenhängende Posts. Hierbei werden die Anliegen und Anforderungen Möglichst einfach gelöst und sind nicht nach einer Ziel Architektur ausgelegt.

Sonntag, 6. November 2016

TFT Module und die richtige Bibliothek

Die Tage werden wieder kälter und ich sitze wieder länger Zuhause. Was gibt es besseres zu tun um einige Dinge heraus zu finden.

Bei meinen Versuchen mit dem TFT Modul traten Schwierigkeiten auf, wo ich oft nur wenig im Internet an „Lösungen“ (nicht) fand und zudem die Einträge schon relativ alt waren.

Was brauche wir für das Beispiel:
  • 1 x Arduino UNO
  • 6 x Kabel
  • 1 x Experimentierboard
  • 1 x 1.8“ TFT Modul, SPI 128x160


Bevor der erste Code geschrieben werden kann und auf den Arduino geladen wird, muss zunächst die Bibliothek eingebunden werden. In der Entwicklungsumgebung von Arduino sind bereits viele Bibliotheken vorhanden, sowie auch für das Display.



Wenn ihr beim kompilieren mehrere Fehler erhält, dann ist vielleicht die vorhandene Bibliothek die alte Version. Zumindest in meinem Fall und das führte dazu dass, sich der Quellcode nicht Kompilierern lies. Dieser Fehler trat mit der Arduino Version 1.6.8 auf, allerdings sei angemerkt, hat dieser Fehler nichts mit der Versionsnummer zu tun.

Falls neben der Bibliothek “Adafruit ST7735 Library” eine “Adafruit ST7735” vorhanden ist, dann sollte diese deinstalliert werden. Das gleiche gilt auch mit „Adafruit GFX Library“ und „Adafruit GFX“. Nur die, die am Ende des Namen „Library“ haben, müssen bestehen bleiben.

Das kann dann über dem Verzeichnis „../Dokumente/Arduino/libraries/ gelöscht werden. Sobald die aktuellere Bibliothek installiert ist, sollte der folgende „Hello World!“ Quellcode kompilierbar sein.

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>

// Verkabelung / Pins
// SCLK     => D13
// MOSI/DIN => D11
// CS       => D10
// DC       => D9
// RST      => D8

// Instanz anlegen zu dem verwendeten Bildschirm.
Adafruit_ST7735 tft = Adafruit_ST7735(10, 9, 8);

void setup() {

  // Initialisiert den Bildschirm
  // und legt die Spalten Adressierung fest.
  tft.initR(INITR_BLACKTAB);

  // Zusätzlichen Pin Ausgang festlegen
  // für die Beleuchtung
  pinMode(5, OUTPUT);

  // Bildschirm Beleuchtung einschalten.
  analogWrite(5, 255);
}

void loop() {

  // bildschirm zurück setzen,
  // bzw. es werden alle Pixel auf Schwarz umgestellt.
  tft.fillScreen(ST7735_BLACK);

  // Textgröße einstellen
  // Text ist mit einem Wert 2 doppelt so groß.
  tft.setTextSize(1);
  // Start Postion festlegen, von wo aus
  // der Text begonnen wird zu schreiben
  // x von links nach rechts
  // y von oben nach unten
  tft.setCursor(5,5); //x, y

  // farbe des Textes
  tft.setTextColor(ST7735_WHITE);
  // Ausgabe Text.
  tft.println("Hello World!");

  // fünf Sekunden warten
  delay(5000);
}

Für gewöhnlich kann die Verkabelung vorgenommen werden, wie bereits im Quellcode beschrieben ist. Dennoch zur Vollständigkeit darf das Bild dazu nicht fehlen.


Wenn das kompilieren klappt, dann sollte auf eurem Display „Hello World!“ leuchten.


Im Grunde ist der erste Schritt zur Verwendung des Display sehr leicht, dennoch können nicht gleich erkennbare Fehler auftreten. Zum Beispiel traten mit sehr günstigen Arduino Nano Klone ein Fehler mit der der Beleuchtung des Displays auf. So funktionierte das Display nicht an 3,3V sondern an 5V.
Wenn ihr andere Fehler und vielleicht auch Lösungen habt, schreibt mir einen Kommentar zu diesem Thema.

Sonntag, 17. Januar 2016

Arduino Control (Teil 5) - PWM Signal einlesen


Das Einlesen und Ausgeben des PWM Signals ist mit dem Beispiel für "Analoges Signal einlesen" vergleichbar. Daher gehe ich nochmal auf das Signal selbst ein.

Im Modellbau werden oft Analog Servos verwendet und nutzen zur Ansteuerung das PWM Signal. Die eingesetzte Frequenz liegt bei 50Hz. Bei Digital Servos wird ebenfalls ein PWM Signal verwendet, allerdings können diese mit einer deutlichen höheren Frequenz umgehen. Das bedeutet natürlich am Ende, dass in jeder Sekunde die Position des Servoarms mehrmals eingestellt wird. Also je höher die Frequenz, desto öfter pro Sekunde wird die Position festgelegt. Der Vorteil liegt auf der Hand: mit dem Digital Servo kann man wesentlich genauer arbeiten, hat aber entsprechend mehr Verbrauch. Hier muss man abwägen, ob sich für den geplanten Einsatz ein Digital Servo lohnt.

Zunächst zu dem PWM selbst sollte klar sein, wie  eigentlich das Signal aussieht. Im folgenden Bild ist zu sehen, dass eine Periodendauer aus einem HIGH und einem LOW Pegel besteht.
Mit der Pulslänge von 1ms bis 2ms wird das Steuersignal für den Ziel Steuereinheit bestimmt. Zum Beispiel bei einem Servo wäre dann bei 1ms Pulslänge der Winkel bei 0 Grad, bei 1,5ms bei 60 Grad und bei 2ms wäre die Ausrichtung  dann 120 Grad.
Im Modellbau ist der HIGH Level für gewöhnlich zwischen 4,8V und 6V. Wer einen Mikrocontroller mit einer Betriebsspannung von 3,3V verwendet, benötigt einen Pegelwandler. Hier reicht ein Wandler von 3,3V auf 5V aus. Natürlich können einige Servos wiederum mit der niedrigen Signalspannung umgehen. Dazu gehören z.B. Micro Servos.
Das HIGH Signal beinhaltet den Steuerwert und kann generell im RC Modellbau eine Pulslänge von 1 bis 2 Millisekunden betragen. Der LOW Zustand stellt die restliche Zeit der gesamten Periode. Zeitlich gesehen wird nichts mehr weiteres unternommen bis die nächste Periode beginnt. Bei 50Hz liegt die Periodendauer bei 20 Millisekunden, was bedeutet, dass 18 bis 19 Millisekunden kein neuer Steuerwert zugewiesen wird. Bei Digital Servos kann der LOW-Level-Zeitraum verkürzt werden. Als Beispiel könnte dann eine Periodendauer von 5 Millisekunden geschaltet werden, so das der LOW Zustand nun zwischen drei bis vier Millisekunden andauert.
Kommen wir zum Arduino Code. Anstatt der Methode analogRead, wird pulseIn(pinNumber, HIGH) verwendet. Der Ausgabewert kommt als ganze Zahl und stellt die Microsekunden dar. Wenn ein Signal von einem einfachen Empfänger gelesen wird, dann sollte ein Wert zwischen 900 bis 2000 als Ergebnis kommen.

// Digitaler Pin Nummer 3
int pin = 3;

void setup() {
 
  Serial.begin(9600);
 
  // Pin Eingang festlegen
  pinMode(pin, INPUT);
}

void loop() {
 
  // Pin Eingang einelsen
  int result = pulseIn(pin, HIGH);
 
  // Nur Inhalt im If ausführen,
  // wenn der Status sich geändert hat.
  if(result != lastValue)
  {
   // Member Field überschreiben.
    lastValue = result;
  
   // Buffer vorbereiten und
   // den Wert in zwei bytes aufteilen.
    byte ba[2];
    ba[0] = (byte)((result >> 8) & 0xff);
    ba[1] = (byte)(result & 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);
  }  

  delay(20);
}

Für das Programm auf dem Desktop kann der selbe Code Schnipsel verwendet werden, wie aus meinem Blog Post "Arduino Control (Teil 4) - Potentiometer Wert am PC ausgeben". Zur Vollständigkeit steht dieser im folgenden Abschnitt.

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} micro secounds", (int)buffer[0] << 8 | buffer[1]);
    }
}

Sinnvollerweise kann dieses Beispiel mit einer Fernsteuerung und einem Empfänger verwendet werden.

Quellcode zum Download
·         Für den Arduino reicht der Code aus dem Post aus.


Donnerstag, 24. Dezember 2015

Neu Verkabeln


Eine Schaltung zu entwerfen ist schon eine tolle Sache und wenn das Ganze auch noch gut verlötet ist, dann macht das schon einen professionellen Eindruck. Obwohl ich für einen Freizeitelektroniker relativ viel Übung habe, erreiche ich nicht immer ein überzeugendes Ergebnis. Das liegt oft an den Kabeln selbst, die meistens sehr bunt sind. Klar dienen die Farben zur Orientierung und sagen etwas über ihre Zuständigkeit aus, aber wenn sie bereits verlegt sind, benötige ich diese Funktion nicht mehr.


Im Normalfall werden die zu langen Kabel zusammengerollt und mit Kabelbinder zusammengehalten. Das reicht grundsätzlich aus, besonders dann, wenn noch nicht klar ist, wie alles verlegt wird.


Meine letzte unzufriedene Verkabelung war an meinem Quadrocopter. Viele Kabel waren zu lang und aufgewickelt. Auch hier zeigen sich die Leitungen in verschiedenen Farben. Das ergab ein sehr unordentliches Bild. Deshalb entschied ich, alles auf eine brauchbare Länge zu kürzen. Leider fehlte mir dazu eine Kleinigkeit.
Zunächst suchte ich nach Kabeln, die wie eine Schnur aussehen, bis ich vor einigen Monaten die Gewebeschläuche gefunden habe. Auf Ebay finden sich die Artikel unter den Begriffen wie Gewebeschlauch oder Geflechtschlauch.

Für die Verarbeitung des Gewebeschlauches gibt’s eine Sache zu tun. Damit der Gewebeschlauch sich nicht ausfranst, sollten mit einem Feuerzeug die Enden angesengt werden, bis sich die einzelnen Fäden miteinander verschmelzen.


Um das Ganze noch abzurunden, kann ich empfehlen, ein kleines Stück Schrumpfschlauch über die angesengten Enden zu ziehen.


Mit meinem Beispiel in der Zeitrafferaufnahme zeigen sich die einzelnen Schritte, wie die Verkabelung und die Verwendung des Schrumpfschlauches eingesetzt werden kann.


Dienstag, 12. Mai 2015

Beleuchtung mit dem ATtiny 45 (Ausbessern)

Quadrocopter_10

In meinem vorigen Post habe ich bereits geschrieben, dass die vorhandenen LEDs für meine Beleuchtung nicht alle vollständig durchgesteuert werden können. Der Grund liegt an dem verwendeten Spannungsregler, der für den Betrieb ca. 100mA zur Verfügung stellt und kurzzeitig auch bis zu 150mA. Die Lichtausbeute war somit nur eingeschränkt möglich.

Quadrocopter_12

Neu ist eine hintere LED Leiste mit fünf blauen und vier weißen LEDs. Dieser benötigt alleine bereits bis zu 200mA und da würde schon der einfache Spannungsregler nicht lange funktionieren. Nun mit dem etwas größer dimensionierten Spannungsregler sind solche Schwierigkeiten obsolet und am Programm muss nichts extra verändert werden, um Einsparungen für den Stromverbrauch vorzunehmen. Zudem können alle 16 LED RGBs (WS2812b) vollständig durchgeschaltet werden, ohne das die Spannung einbricht.

Quadrocopter_08

Kommen wir zu den Änderungen. Wie bereits erwähnt verwende ich einen anderen Spannungsregler von STMicroelectronics. Die Bezeichnung lautet L7805CV und fällt schon durch ein größeres Gehäuse auf, das der TO-220 Norm entspricht. Mit dem neuen kommen auch ungepolte Kondensatoren mit einer deutlichen kleineren Kapazität.

image

Die Schaltung ist dem Vorgänger sehr ähnlich und zeigt im Unterschied die neuen Anschlüsse für die hintere LED Leiste. Ebenfalls habe ich das Zusammenlöten der Komponenten so eingeplant, dass alles auf einer Platine Platz findet.

ATtiny45QuadrocopterLicht

Zusammengelötet und fast fertig auf der Platine.

Quadrocopter_09

Am Quellcode kann nun das Ansteuern des Pin 1 ergänzt werden. Damit wird später die hintere Lichtleiste ein- und ausgeschaltet.

// 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);
  // Neu. Um die LED Leiste ein- und auszuschalten.
 
pinMode(1, 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);
    // Die LED Leiste einschalten
   
analogWrite(1, 255);
    // 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);
    // Die LED Leiste ausschalten.
   
analogWrite(1, 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));
  }
}

Zuletzt dürfen zur Demo die Videos nicht fehlen.

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