Displays – Pollux Labs https://polluxlabs.net Arduino, ESP32 & ESP8266 | Projekte & Tutorials Sun, 04 Feb 2024 14:39:24 +0000 de-DE hourly 1 https://wordpress.org/?v=6.4.4 https://polluxlabs.net/wp-content/uploads/2020/05/cropped-pollux-labs-p-32x32.png Displays – Pollux Labs https://polluxlabs.net 32 32 So erzeugst du KI Bilder mit Python und deepAI https://polluxlabs.net/python-tutorials-und-projekte/so-erzeugst-du-ki-bilder-mit-python-und-deepai/ Fri, 27 Jan 2023 07:21:20 +0000 https://polluxlabs.net/?p=13559 So erzeugst du KI Bilder mit Python und deepAI Weiterlesen »

]]>
Bilder, die von einer künstlichen Intelligenz wie DALL-E oder DeepAI “gemalt” werden, sind in aller Munde. In diesem Tutorial erfährst du, wie du KI Bilder mithilfe eines Python Scripts erzeugst.

Du lädst dir hierfür die aktuelle Schlagzeile der BBC-Nachrichten von einer API und schickst diese an die künstliche Intelligenz von deepai.org – von dort erhältst du eine Illustration der Schlagzeile zurück auf deinen Computer, gemalt in einem Stil deiner Wahl.

Diese APIs benötigst du

In diesem Projekt kommen zwei Services zum Einsatz, die du über deren APIs ansteuerst: NewsAPI und DeepAI. Von ersterer fragst die aktuelle Schlagzeile der BBC ab. Hierfür benötigst du einen API Key, den du nach deiner kostenlosen Registrierung erhältst. Wie das geht, und wo du deinen API Key findest, haben wir in diesem Projekt beschrieben.

Mit DeepAI erzeugst du dann KI Bilder, indem du die Schlagzeile an deren API weiterleitest und als sogenannten Prompt verwendest. Das ist so etwas wie die “Malanweisung”, die du der künstlichen Intelligenz gibst. Hierfür kommt ein Diffusionsmodell zum Einsatz, das der Deutschlandfunk Kultur in diesem Beitrag anschaulich erklärt. Erstaunlich hierbei ist, dass die KI eigentlich kein Bild auf Basis deiner Anweisung erzeugt, sondern vielmehr aus einem großen Rauschen “freilegt”.

Aber zurück zur API von DeepAI. Auch um diese nutzen zu können, benötigst du einen kostenlosen Account dort. Du erhältst anschließend einige Gratis-Credits, die du bei Bedarf auch günstig aufstocken kannst. Nachdem du dein kostenloses Kontingent verbraucht hast, kostet dich ein Bild 5 Cent – ein Betrag, der den Spaß Wert ist, wie wir finden.

Deinen API Key von DeepAI findest du übrigens oben in deinem Profil. Auch diesen wirst du demnächst in deinem Python Script benötigen.

Bibliotheken installieren

Für dein Script benötigst du einige Bibliotheken, die du vielleicht noch nicht installiert hast: requests, newsapi und PIL. Du kannst sie mit diesen Befehlen installieren:

pip install requests
pip install newsapi-python
pip install Pillow

Du benötigst diese drei Bibliotheken für die API-Abfrage bei DeepAI und NewsAPI und um das Bild, das du zurück erhältst zu bearbeiten. Insgesamt importierst du zu Beginn des Scripts folgende Bibliotheken:

import requests
import webbrowser
import json
from newsapi import NewsApiClient
from PIL import Image
import os
import sys
import shutil
import random

Schlagzeilen von newsapi abrufen

Als nächstes besorgst du dir die neuesten Nachrichten von der BBC. Hier kommt die NewsAPI-Bibliothek zum Einsatz, die du gerade importiert hast. (Natürlich kannst du den Request auch anders gestalten.)

# NewsAPI
newsapi = NewsApiClient(api_key='DEIN API-Key von NewsAPI')

# Top-Schlagzeilen der BBC abrufen
headlines = newsapi.get_everything(sources='bbc-news',
                                   language='en',
                                   sort_by='publishedAt')

x = headlines.get('articles')
y = x[0]

# Die längere 'description' der Schlagzeile der Variable prompt zuweisen
print('Ich empfange die neueste BBC-Schlagzeile...')
prompt = y.get('description')

KI Bilder erzeugen

Danach kommt die künstliche Intelligenz ins Spiel. Um etwas Abwechslung ins Spiel zu bringen, bindest du vier verschiedene Stilrichtungen ein (galleries): “Old Style”, Pop Art, Renaissance, Abstrakt. Welcher Stil bei deiner Anfrage zum Einsatz kommt, bestimmst du mit einer Zufallszahl.

Je nachdem, welche Zahl gewürfelt wurde, steuerst du eine andere URL der API an:

# Zufällig eine von vier Stilrichtungen festlegen
randomGallery = random.randint(0,3)

if randomGallery == 0:
    galleryURL = 'https://api.deepai.org/api/old-style-generator'
elif randomGallery == 1:
    galleryURL = 'https://api.deepai.org/api/pop-art-generator'
elif randomGallery == 2:
    galleryURL = 'https://api.deepai.org/api/renaissance-painting-generator'
else:
    galleryURL = 'https://api.deepai.org/api/abstract-painting-generator'

print('Ich verwende den Stil von: ' + galleryURL)

r = requests.post(
    galleryURL,
    data={
        'text': prompt,
    },
    headers={'api-key': 'DEIN API-Key von DeepAI'}
)

url = r.json()
print(url['output_url'])

Wie du im Code oben siehst, dient die Description der BBC-Schlagzeile als prompt, den du in deinem Request an die API übermittelst. Ein mögliches Ergebnis im sogenannten “Old Style” sieht dann so aus:

Prompt: Former Detroit Lions linebacker Jessie Lemonier dies at the age of 25, the National Football League team announce.

DeepAI liefert dir über die API immer eine Collage aus vier quadratischen Bildern zurück. In diesem Python Script schneiden wir das Bild oben links aus und speichern es ab – mit dem Prompt als Dateinamen. Natürlich kannst du es auch unverändert ausschneiden, oder jedes einzelne Quadrat ausschneiden und separat speichern.

# Bild herunterladen
def download_image(url, file_name, headers):
     response = requests.get(url, headers=headers)
     if response.status_code == 200:
        with open(file_name, "wb") as f:
            f.write(response.content)
     else:
        print(response.status_code)

headers = {
    "User-Agent": "Chrome/51.0.2704.103",
}

url = url['output_url']

# Dateinamen = Prompt festlegen
file_name = "{}.jpg".format(prompt)

download_image(url, file_name, headers)

# Bild zuschneiden
print('Ich schneide das Bild zu...')
img = Image.open('{}'.format(file_name))
box = (0, 0, 512, 512)
img = img.crop(box)
img.save('{}'.format(file_name))

Zuletzt bleibt nur noch eins: Das neue Bild zu öffnen und zu präsentieren:

img.show()

Das vollständige Python Script

Hier nun das vollständige Script. Vergiss nicht, deine API Keys von NewsAPI und DeepAi einzutragen, bevor du loslegst.

# Copyright 2023, Pollux Labs
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the Software without restriction, including without
# limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
# Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in all copies or substantial portions
# of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
# TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
# 
# https://polluxlabs.net/python/so-erzeugst-du-ki-bilder-mit-python-und-deepai/

import requests
import webbrowser
import json
from newsapi import NewsApiClient
from PIL import Image
import os
import sys
import shutil
import random

# NewsAPI
newsapi = NewsApiClient(api_key='DEIN API-Key von NewsAPI')

# Top-Schlagzeilen der BBC abrufen
headlines = newsapi.get_everything(sources='bbc-news',
                                   language='en',
                                   sort_by='publishedAt')

x = headlines.get('articles')
y = x[0]

# Die längere 'description' der Schlagzeile der Variable prompt zuweisen
print('Ich empfange die neueste BBC-Schlagzeile...')
prompt = y.get('description')


# Bild von DeepAI empfangen

# Zufällig eine von vier Stilrichtungen festlegen
randomGallery = random.randint(0,3)

if randomGallery == 0:
    galleryURL = 'https://api.deepai.org/api/old-style-generator'
elif randomGallery == 1:
    galleryURL = 'https://api.deepai.org/api/pop-art-generator'
elif randomGallery == 2:
    galleryURL = 'https://api.deepai.org/api/renaissance-painting-generator'
else:
    galleryURL = 'https://api.deepai.org/api/abstract-painting-generator'

print('Ich verwende den Stil von: ' + galleryURL)

r = requests.post(
    galleryURL,
    data={
        'text': prompt,
    },
    headers={'api-key': 'DEIN API-Key von DeepAI'}
)

url = r.json()
print(url['output_url'])


print('Ich male dein Bild...')

# Bild herunterladen
def download_image(url, file_name, headers):
     response = requests.get(url, headers=headers)
     if response.status_code == 200:
        with open(file_name, "wb") as f:
            f.write(response.content)
     else:
        print(response.status_code)

headers = {
    "User-Agent": "Chrome/51.0.2704.103",
}

url = url['output_url']

# Dateinamen = Prompt festlegen
file_name = "{}.jpg".format(prompt)

download_image(url, file_name, headers)

# Bild zuschneiden
print('Ich schneide das Bild zu...')
img = Image.open('{}'.format(file_name))
box = (0, 0, 512, 512)
img = img.crop(box)
img.save('{}'.format(file_name))

# Bild anzeigen
img.show()

Bringe das Projekt in dein Wohnzimmer

Zum Schluss noch eine Idee für ein Raspberry Pi Projekt: Verbinde ein quadratisches Display, z.B. das HyperPixel 4.0 Square, mit deinem Raspberry Pi. Beides kannst du in einen Bilderrahmen stecken und das Python Script automatisch bei jedem Boot laufen lassen.

Damit jedoch nicht immer das gleiche Bild im Bilderrahmen steckt, könntest du noch dafür sorgen, dass es z.B. jede Stunde ausgetauscht wird.

Zusammengebaut könnte das Ganze dann so ausschauen:

]]>
Countdown zum nächsten SpaceX Raketenstart https://polluxlabs.net/esp8266-projekte/countdown-zum-naechsten-spacex-raketenstart/ Sat, 20 Mar 2021 16:18:28 +0000 https://polluxlabs.net/?p=4485 Countdown zum nächsten SpaceX Raketenstart Weiterlesen »

]]>
Wenn du an einen Raketenstart denkst, kommt dir bestimmt vieles in den Sinn. Sicherlich auch der obligatorische Countdown. Wie wäre es, wenn du daheim die Sekunden zum nächsten Launch einer Rakete von SpaceX herunterzählst?

Elon Musks Weltraumunternehmen betreibt eine API, von der du unter anderem die Daten des nächsten Starts beziehen kannst. Hierfür benötigst du nur einen ESP8266. Den Countdown kannst du stilecht auf einem 7-Segment Display darstellen. Und für die Beleuchtung beim Lift-off eignet sich ein NeoPixel LED-Ring.

Fortgeschrittene

1 – 2 Stunden

ca. 15 €

Für dieses Projekt benötigst du (Mengen s. Beschreibung):

Noch ein Hinweis vorab: Genau auf die Sekunde wirst den Lift-off der Rakete leider nicht treffen. Das liegt weniger an deinem Projekt, sondern daran, dass die meisten Raketen nicht ganz pünktlich sind. 😉 Zumindest haben wir bei unseren Tests beobachtet, dass der tatsächliche Start von der Angabe in der API immer um ein paar Sekunden abweicht.

Grundlegende Tutorials

In diesem Projekt kommt einiges zum Einsatz, für das du auf Pollux Labs passende Tutorials findest:

Schaue zunächst in die oben genannten Tutorials, wenn du ein paar der Themen noch nicht kennst oder erfahren möchtest, wie du ein 7-Segment Display oder den NeoPixel LED-Ring anschließt.

Im Folgenden konzentrieren wir uns auf den Start der nächsten Rakete von SpaceX – bzw. auf die Daten, die du hierfür benötigst.

Die SpaceX API

SpaceX betreibt eine sehr große Datenbank, aus der du dich kostenlos bedienen darfst. Hier findest du beispielsweise Daten zu Raketen, Modulen und Startrampen – aber natürlich auch zu vergangenen und kommenden Raketenstarts. Du findest sogar die aktuelle Position des Tesla Roadsters, der in den Orbit geschossen wurde.

SpaceX Roadster im Orbit
Foto: SpaceX

All diese Daten kannst du über eine API abrufen und weiterverarbeiten – und zwar auch mit deinem ESP8266. Für dieses Projekt benötigst du also die Daten zum nächsten Raketenstart. Diese findest du unter folgender Adresse:

https://api.spacexdata.com/v4/launches/next

Wenn du diese URL in deinem Browser aufrufst, findest eine ganze Menge Daten im JSON-Format. Unter anderem auch den Zeitpunkt des nächsten SpaceX-Starts als Unixzeit. In diesem Fall der 24.3.2021 um 9:58 MEZ.

"date_unix":1616576280

Diese URL verwendest du in deinem Sketch, um mit Hilfe der aktuellen Uhrzeit die Dauer bis zum nächsten Start – und somit den Countdown – zu berechnen.

Die Daten abrufen

Du findest den gesamten Sketch am Ende des Projekts. An dieser Stelle steigen wir direkt beim Abruf der Daten von der SpaceX API ein.

Hierfür hinterlegst du zunächst zu Beginn des Sketchs die URL der API und den Port, der für die sichere Übertragung via HTTPS zuständig ist: 443.

const char* host = "https://api.spacexdata.com/v4/launches/next";
const int httpsPort = 443;

Als nächstes kommt der Loop. Hier erstellst du zunächst die Instanz http von HTTPClient und verbindest dich mit der API:

HTTPClient http;
client.connect(host, httpsPort);
http.begin(client, host);

Danach prüfst du, ob die Verbindung steht und speicherst die JSON-Daten, die du von der API erhältst, in der Variablen payload. Anschließend dekodierst du sie und “ziehst” dir die oben genannte Zeitangabe als Unixtime. Diese Zeitangabe speicherst du in der Variablen launchTime.

if (http.GET() == HTTP_CODE_OK) {
  String payload = http.getString();
  DynamicJsonDocument doc(3072);
  deserializeJson(doc, payload);

  launchTime = doc["date_unix"]; //Startzeit speichern

Als nächstes berechnest du den Countdown. Hierfür benötigst du natürlich auch die aktuelle Uhrzeit. Diese hast du weiter oben im Sketch schon ermittelt und in der Variablen currentTime gespeichert (Schaue hierfür in den vollständigen Sketch).

countdown = launchTime - currentTime;

Den SpaceX Countdown anzeigen

Jetzt lässt du deinen Countdown laufen, bis die Startzeit erreicht wurde:

while (countdown != 0) {

Du zeigst zunächst die Sekunden, die es noch bis zum Start dauert, auf dem Display an. Hier kommt eine Funktion ins Spiel, die du im vollständigen Sketch findest:

drawDigits(countdown);

Danach ziehst du vom Wert in der Variablen countdown eine Sekunde ab und wartest mit deinem delay auch genau diese eine Sekunde, bevor du die nächste Zahl anzeigst.

countdown -= 1;
delay(1000);

Wenn der While-Loop ausgelaufen ist, die Variable countdown also eine Null enthält, löschst du das Display, startest dafür den LED-Ring und lässt ihn z.B. eine halbe Stunde angeschaltet.

lc.clearDisplay(0);

for (int i = 0; i < 12; i++) {
  pixels.setPixelColor(i, pixels.Color(255, 0, 0));
  pixels.show();
  delay(1);
}

delay(1800000); //30 Minuten

In diesem Beispiel leuchten alles LEDs auf dem Ring in einem satten Rot auf. Du kannst dir aber natürlich auch etwas raffinierteres überlegen!

Spacex Countdown ESP8266
Ein möglicher Aufbau für das Projekt

Und das war es auch schon! Zuletzt noch ein Hinweis: Wenn dein Delay am Ende des Sketchs ausgelaufen ist, folgt die nächste Abfrage der SpaceX API. Möglicherweise liegen dann aber noch keine neuen Daten vor. Bis das soweit ist, kann es mitunter einige Stunden oder auch Tage dauern – du könntest deinen ESP8266 also auch erst einmal gar keine neue Abfrage stellen lassen.

Sketch als .txt anschauen

#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecure.h>

WiFiClientSecure client;

//NTP
#include <NTPClient.h>
#include <WiFiUdp.h>
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);

//SpaceX API URL und Port
const char* host = "https://api.spacexdata.com/v4/launches/next";
const int httpsPort = 443;

//WLAN Zugangsdaten
const char* ssid = "NETWORK";
const char* password =  "PASSWORD";

//Variablen
long launchTime;
long currentTime;
long countdown;

//7-Segment-Display
#include <LedControl.h>
LedControl lc = LedControl(12, 15, 13, 1); //12=D6=DIN, 15=D8=CLK, 13=D7=CS
const int NUM_DIGITS = 8;

//NeoPixel LED-Ring
#include <Adafruit_NeoPixel.h>

int leds = 12; //Anzahl der LEDs
int ledPin = 14; //14=D5, Pin, an dem der NeoPixel angeschlossen ist

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(leds, ledPin, NEO_GRB + NEO_KHZ800);

void getCurrentTime() {

  timeClient.update();
  currentTime = timeClient.getEpochTime();
  
  Serial.print("Current Time= ");
  Serial.println(currentTime);
}

void drawDigits(int num) {
  for (int i = 0; i < NUM_DIGITS ; i++) {
    lc.setDigit(0, i, num % 10, false);
    num /= 10;
    if (num == 0)
      return;
  }
}

void setup() {
  Serial.begin(115200);
  client.setInsecure();

  //Einstellungen des 7-Segment-Displays
  lc.shutdown(0, false);
  lc.setIntensity(0, 8);
  lc.clearDisplay(0);

  //Einstellungen des NeoPixels
  pinMode (ledPin, OUTPUT);
  pixels.begin();
  pixels.setBrightness(255); //Helligkeit: 0 (aus) - 255

  for (int i = 0; i < 12; i++) {
    pixels.setPixelColor(i, pixels.Color(0, 0, 0));
    pixels.show();
    delay(1);
  }

  WiFi.begin(ssid, password); //Mit dem WLAN verbinden

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  delay(1000);
  Serial.println("Hello, world!");
}

void loop() {
  if ((WiFi.status() == WL_CONNECTED)) {

    getCurrentTime();

    HTTPClient http;
    client.connect(host, httpsPort);
    http.begin(client, host);

    if (http.GET() == HTTP_CODE_OK) {
      String payload = http.getString();
      DynamicJsonDocument doc(3072);
      deserializeJson(doc, payload);

      launchTime = doc["date_unix"]; //Startzeit speichern
      Serial.print("Launch Time: ");
      Serial.println(launchTime);

      countdown = launchTime - currentTime; //Countdown = Startzeit - aktuelle Zeit
    } else {
      Serial.print("Error on HTTP request (SpaceX): ");
      Serial.println(http.GET()); //Error Code
    }
  }

  while (countdown != 0) { //Solange die Startzeit nicht erreicht wurde
    Serial.print("Time Until Launch: ");
    Serial.println(countdown);
    drawDigits(countdown);
    countdown -= 1;
    delay(1000);
  }

  Serial.println("LAUNCH!"); // Startzeit = aktuelle Zeit
  lc.clearDisplay(0);

  for (int i = 0; i < 12; i++) {
    pixels.setPixelColor(i, pixels.Color(255, 255, 0));
    pixels.show();
    delay(1);
  }

  delay(1800000);
}
]]>
Beleuchte deine LEGO ISS im Rhythmus der echten Raumstation https://polluxlabs.net/esp8266-projekte/beleuchte-deine-lego-iss-im-rhythmus-der-echten-raumstation/ Tue, 13 Oct 2020 18:32:13 +0000 https://polluxlabs.net/?p=2036 Beleuchte deine LEGO ISS im Rhythmus der echten Raumstation Weiterlesen »

]]>
Hinweis: Leider ist dieses Projekt bis auf Weiteres nicht mehr umsetzbar, da die benötigte API zur Ermittlung der nächsten Überflüge nicht mehr online ist. Du kannst stattdessen mit diesem Tutorial die aktuelle Position der ISS ermitteln und auf einer Weltkarte anzeigen.

Wie wäre es, wenn deine LEGO ISS aufleuchten würde, sobald die echte International Space Station über ihr fliegt? In diesem Projekt lässt du genau das Wirklichkeit werden. Du lernst, wie du den Zeitpunkt des nächsten Überflugs herausfindest, damit einen Countdown programmierst und dann im richtigen Moment einen NeoPixel LED-Ring aufleuchten lässt. Los geht’s! 🙂

Für dieses Projekt benötigst du – abgesehen von der LEGO ISS – nur wenige Bauteile. Damit das Projekt gut aussieht, verwenden wir zwei Boxen aus dem 3D-Drucker – eine für den ESP8266 und den NeoPixel, die andere für das 7-Segment-Display.

Fortgeschrittene

1 – 2 Stunden – ohne Aufbau der LEGO ISS 😉

ca. 20 € plus ggfs. Kosten für den LEGO-Bausatz und 3D-Druck

Für dieses Projekt benötigst du (Mengen s. Beschreibung):

Angebot
LEGO 21321 Ideas Internationale Raumstation
LEGO 21321 Ideas Internationale Raumstation
Verpackungsabmessungen (L x B x H): 6.9 x 26.2 x 38.2 Zm; Beschreibung der Altersgruppe:...
117,49 €
Angebot
AZDelivery 5 x 5V RGB LED Ring Kompitabel mit WS2812B 12-Bit 38mm kompatibel mit Arduino inklusive E-Book!
AZDelivery 5 x 5V RGB LED Ring Kompitabel mit WS2812B 12-Bit 38mm kompatibel mit Arduino inklusive E-Book!
✅ 12 leuchtstarke LEDs. Einzeln adressierbar; ✅ Kompatibel mit Digispark u.v.m.; ✅...
16,99 €
ELEGOO Steckbrett 6er Set 170 Tie Points Mini Breadboard Kit für Arduino
ELEGOO Steckbrett 6er Set 170 Tie Points Mini Breadboard Kit für Arduino
Diese Teile sind gut um ganz kleine Schaltungen oder nur einen Chip zu verdraten.; 6...
7,99 €
AZDelivery 3 x Jumper Wire Kabel 40 STK. je 20 cm M2M Male to Male kompatibel mit Arduino und Raspberry Pi Breadboard
AZDelivery 3 x Jumper Wire Kabel 40 STK. je 20 cm M2M Male to Male kompatibel mit Arduino und Raspberry Pi Breadboard
✅ Länge der Kabel: 20 cm / 120 Stück pro Einheit / 120 Stück insgesamt; ✅...
6,99 €

Hinweis: Meistens werden die NeoPixel LED-Ringe unverlötet verkauft – du benötigst also noch einen Lötkolben plus Zubehör. Wenn du unsere Vorlagen für die Boxen verwenden möchtest, benötigst du auch einen 3D-Drucker und Filament.

Der Aufbau unter der LEGO ISS

Da die LEGO ISS auf einer Art Sockel steht, unter dem noch viel Platz ist, eignet sich dieser Ort besonders, um sie von unten zu beleuchten. Hier platzierst du also deinen ESP8266 und den NeoPixel-Ring. Das 7-Segment-Display für den Countdown bis zum nächsten Überflug liegt etwas abseits.

Aufbau ESP8266, Neopixel, Display unter der LEGO ISS

Auf dem Breadboard

Die Bauteile miteinander zu verbinden, dauert nur wenige Minuten. Verwende für den Aufbau die folgende Tabelle:

ESP8266 NeoPixel
3v3 VCC
GND GND
D5 IN
ESP8266 7-Segment-Display
3v3 VCC
GND GND
D6 DIN
D7 CS
D8 CLK

Noch zwei Hinweise: Wenn du unsere Vorlage für die Boxen aus dem 3D-Drucker verwendest, achte darauf, deinen ESP8266 an den glatten Rand des Mini-Breadboards zu setzen – die Seite, die keine Feder hat. Dann kannst du das USB-Kabel bequem durch ein Loch in der Box mit dem ESP8266 verbinden.

Unsere Box hat einen Innendurchmesser von 39 mm. Achte darauf, einen NeoPixel-Ring mit 37 mm Durchmesser zu verwenden. Diese werden jedoch teilweise fälschlicherweise mit einem Durchmesser von 39 mm verkauft. Egal wie, beide passen in die Box. 😉

So ungefähr sollte es aussehen, wenn du alles miteinander verbunden hast.

Die passenden Boxen

Natürlich kannst du dein Projekt auch “nackt” unter deine LEGO ISS stellen. Allerdings sieht es aufgeräumter aus, wenn du deine Bauteile in Boxen unterbringst. Wenn du möchtest, kannst du unsere Vorlagen verwenden und sie mit einem 3D-Drucker ausdrucken. Hier findest du je zwei Boxen mit Deckel – eine für den ESP8266 samt NeoPixel und eine für das 7-Segment-Display.

Hinweis: Du kannst die Boxen natürlich in deiner Lieblingsfarbe ausdrucken – der Deckel der Box für den ESP8266 plus NeoPixel sollte jedoch transparent sein, damit das Licht durchscheinen und deine LEGO ISS von unten beleuchten kann.

Du findest unsere Vorlagen hier bei uns als Download.

Und so sehen die Bauteile in den Boxen aus. Wie du siehst führt ein Kabelstrang aus der Box für den ESP8266 zum 7-Segment-Display in der anderen Box. Wir haben hierfür 10 cm lange Kabel verwendet, aber die Wahl liegt natürlich bei dir.

Alle Bauteile in den passenden Boxen

Und das war es auch schon mit der Hardware. Weiter geht es mit dem Sketch.

Der passende Sketch

Schauen wir uns die wichtigsten Teile des Codes genauer an.

Die benötigten Bibliotheken

Für dieses Projekt benötigst du einige Bibliotheken, um z.B. das 7-Segment-Display, den NeoPixel-Ring zu steuern und die aktuelle Uhrzeit abzufragen. Installiere die folgenden Bibliotheken in deinem Bibliotheksmanager, falls sie noch nicht in deiner Arduino IDE verfügbar sind:

ArduinoJson.h
ESP8266HTTPClient.h
WiFiClientSecure.h
Adafruit_NeoPixel.h
LedControl.h
NTPClient.h
WiFiUdp.h

Den ESP8266 mit dem Internet verbinden

Für dieses Projekt muss dein ESP8266 mit dem Internet verbunden sein. Zu diesem Thema haben wir ein eigenes Tutorial, in dem du lernst, wie das geht. Übrigens: Solltest du noch nie einen ESP8266 mit der Arduino IDE programmiert haben, lies hier nach, wie du die beiden verbindest.

Den nächsten Überflug der ISS ermitteln

Damit die Beleuchtung deiner LEGO ISS im Rhythmus der echten funktioniert, benötigst du zuerst die Überflugsdaten. Hier kommt die API von open-notify.org ins Spiel. Mit ihr kannst du kostenlos den nächsten Transit für deinen Standort mit deinem ESP8266 abfragen.

Trage deshalb zu Beginn des Sketchs deine Koordinaten ein. Falls du diese nicht kennst, kannst du sie z.B bei geoplaner.de ermitteln. Deine Höhe ist optional – wenn du sie weißt, wird das Ergebnis ein klein wenig genauer, wenn nicht, rechnet die API einfach mit einer Höhe von 100 Metern. Allerdings muss die Höhenangabe größer als Null sein – sonst funktioniert die API-Abfrage nicht.

Hier sind die Daten für Karlsruhe eingetragen:

const float latitude = 49.00; //Dein Breitengrad
const float longitude = 8.40; //Dein Längengrad
const float altitude = 115.00; //Deine Höhe über Normalnull

Im Sketch befindet sich die Funktion apiCall() – hier werden die Überflugsdaten der ISS für deinen Standort bei der API von open-notify.org abgerufen und weiterverarbeitet.

Zunächst die Abfrage: Mit der Funktion http.begin() rufst du die Daten von der API-Adresse ab. Hierfür benötigst den Breiten- und Längengrad sowie optional die Höhe, die du bereits oben in den jeweiligen Konstanten hinterlegt hast. Die URL innerhalb der Funktion erweiterst du deshalb ganz einfach mit diesen hinterlegten Daten:

http.begin("http://api.open-notify.org/iss-pass.json?lat=" + String(latitude) + "&lon=" + String(longitude) + "&alt=" + String(altitude) + "&n=5");

Die fertige URL für das Beispiel Karlsruhe lautet dann wie folgt. Der Parameter n=5 bestimmt die Anzahl der nächsten Überflüge, die berechnet werden soll – hier also 5.

http://api.open-notify.org/iss-pass.json?lat=49&lon=8.4&alt=115&n=5

Die Antwort der API auswerten

Wenn du diese Adresse testweise in deinem Browser öffnest, erhältst du ungefähr folgende Antwort:

Antwort der API

Hierbei handelt es sich um Daten im JSON-Format, mit denen du noch nichts anfangen kannst. Was du benötigst, sind die Daten, die im Key response stecken: duration (die Dauer des Überflugs) und risetime (der Zeitpunkt, wann die ISS über den Horizont steigt und von deinem Standort aus theoretisch sichtbar wird).

Das Angaben duration und risetime sind insgesamt fünf Mal in der response enthalten, da du die Abfrage mit n=5 entsprechend gestartet hast. Alle fünf zusammen befinden sich paarweise in einem Array. Das erste Paar ist hierbei der nächste Überflug, das zweite der übernächste und so weiter. Später werden wir das benötigte Paar aus dem Array picken.

Zunächst speicherst du jedoch diese JSON-Daten als Ganzes in der Variablen payload ab:

String payload = http.getString();

Anschließend kommt die Bibliothek ArduinoJson ins Spiel. Auch hierfür haben wir ein eigenes Tutorial, weshalb wir das Parsen der JSON-Daten hier überspringen.

Vielmehr springen wir gleich zum Teil, in dem du die Dauer und den Zeitpunkt des nächsten Überflugs abspeicherst. Wie du im Code gleich hier unten siehst, picken wir den ersten Eintrag des oben genannten Arrays mit [0].

JsonArray response = doc["response"];
duration = response[0]["duration"];
riseTime = response[0]["risetime"];

Wie lange dauert es noch, bis die ISS kommt?

Du hast jetzt den Zeitpunkt des nächsten Überflugs, aber dein ESP8266 weiß noch nicht, wie lange es bis dahin noch dauert. Hierfür befindet sich im Sketch eine andere Funktion: getCurrentTime()

Hier verwendest du das Network Time Protocol (NTP). Auch hierfür gibt es das passende Tutorial bei uns, in dem du weitere Details erfährst. Du ermittelst in dieser Funktion also die aktuelle Uhrzeit – und speicherst diese in der Variablen currentTime ab.

Den Zeitpunkt bis zum Erscheinen der ISS berechnest du dann wie folgt:

timeUntilRise = riseTime - currentTime;

In der Variablen timeUntilRise befindet sich nun also die Dauer bis zum nächsten Überflug – in Sekunden. Noch ein Hinweis: Sowohl die aktuelle Uhrzeit currentTime als auch den Zeitpunkt des Überflugs riseTime rufst du als Unixzeit ab. Hierbei handelt es sich um die Sekunden, die seit dem 1. Januar 1970 vergangen sind. Das hat den Vorteil, dass du von Zeitverschiebung, Sommer- und Winterzeit unabhängig bist: In die Variable timeUntilRise kommen einfach die Sekunden bis zum nächsten Transit der ISS.

Was aber, wenn der Zeitpunkt riseTime schon überschritten wurde, die API aber noch diesen Zeitpunkt als nächsten Überflug ausgibt? Hier liegt der Wert in riseTime unterhalb der aktuellen Uhrzeit currentTime. In diesem Fall nimmst du den zweiten Eintrag der API-Antwort, den du entsprechend mit [1] auswählst.

if (timeUntilRise < 0) { 
  duration = response[1]["duration"];
  riseTime = response[1]["risetime"];

Der Countdown

Apropos nächster Transit: Auf dem 7-Segment-Display soll ja ein Countdown bis zum nächsten Überflug erscheinen. Auch diesen Teil sparen wir hier aus, da du in diesem Tutorial nachlesen kannst, wie du ein 7-Segment-Display im Sketch ansteuerst. In diesem Projekt erfährst du alles zum Thema Countdown mit diesem Display.

Die LEGO ISS beleuchten

Nun wird es Zeit für etwas Licht. Wenn also die echte ISS über den Horizont steigt, soll die LEGO ISS beleuchtet werden.

Die beleuchtete LEGO ISS

Hier kommt der NeoPixel-Ring mit seinen LEDs ins Spiel. Du wirst es erraten haben, auch hierfür haben wir bereits ein Tutorial, in dem du nachlesen kannst, wie du einen NeoPixel-Ring verwendest.

Allerdings gehst du in diesem Projekt einen Schritt weiter: Der LED-Ring soll nicht nur aufleuchten, sondern auch noch für die Dauer des Überflugs seine Farbe verändern. Hierfür benötigst du wieder die Variable duration, die du oben mit der Überflugsdauer befüllt hast.

Diese Variable kommt nun in der Funktion map() zum Einsatz. Hier berechnest du jede Sekunde einen neuen Farbwert, den alle 12 LEDs auf dem Ring annehmen sollen – von Blau zu Beginn des Überflugs bis zu einem tiefen Rot, kurz bevor die ISS wieder hinter dem Horizont verschwindet.

for (int i = duration; i >= 0; i--) {
  int colorRed = map(i, 0, duration, 200, 0);
  int colorBlue = map(i, 0, duration, 0, 200);
  //Die neuen Farben auf dem NeoPixel ausgeben
  for (int j = 0; j < 12; j++) {
    pixels.setPixelColor(j, pixels.Color(colorRed, 0, colorBlue));
    pixels.show();
  }
  delay(1000);
}

Die Funktion map() ist auf den ersten Blick nicht ganz leicht zu verstehen, aber die offizielle Arduino-Dokumention erhellt dieses Thema ziemlich gut.

Experimentiere mit den RGB-Werten für den NeoPixel etwas herum, um den Farbverlauf nach deinen Wünschen anzupassen. Oder lösche diese Funktion ganz, um die ISS in nur einer Farbe zu beleuchten.

Und das war es. 🙂

]]>
Ein einfacher Arduino-Countdown mit Retro-Optik https://polluxlabs.net/arduino-projekte/ein-einfacher-arduino-countdown-mit-retro-optik/ Sat, 08 Aug 2020 11:08:22 +0000 https://polluxlabs.net/?p=2095 Ein einfacher Arduino-Countdown mit Retro-Optik Weiterlesen »

]]>
In diesem Projekt baust du dir einen Arduino-Countdown, der auf Knopfdruck einen Timer startet und die Sekunden auf einem Display herunterzählt.

Für das gewisse Etwas sorgt eine 7-Segment-Anzeige und der Umstand, dass du z.B. dein Ei nicht in 7 Minuten kochst, sondern in 420 Sekunden.

Das haben wir für dieses Projekt verwendet (Mengen siehe unten):

Der Aufbau

Für den Countdown benötigst du drei Bauteile: eine 7-Segment-Anzeige*, einen passiven Piezo-Summer und einen Button, den du mit einem Pull-down-Widerstand mit deinem Arduino verbindest.

In diesem Projekt verwenden wir einen Arduino Uno*, aber du kannst natürlich so gut wie jedes andere Board verwenden. Außerdem benötigst du noch ein Breadboard und ein paar Kabel.

Die 7-Segment-Anzeige anschließen

Los geht es mit dem Display, auf dem der Countdown läuft. Daran befinden sich fünf Pins, die du wie folgt an deinem Arduino anschließt:

7-Segment-AnzeigeArduino
VCC5V oder 3,3V
GNDGND
DIN12
CS10
CLK11

Wir verwenden ein Display mit 8 Ziffern, das dir ermöglichen würde, die Sekunden von gut drei Jahren herunterzuzählen. Du kannst aber natürlich auch ein kleineres verwenden – der später vorgestellte Sketch funktioniert mit jeder Anzeige, die per MAX7219- oder 7221-Chip und der Bibliothek LedControl.h gesteuert wird.

Der Startbutton samt Pull-down-Widerstand

Jeder gute Countdown benötigt natürlich einen Button, der ihn startet. Setze ihn über die Brücke deines Breadboards, sodass zwei Pins darüber und zwei darunter stecken.

Verbinde anschließend den linken Pin mit Plus. Den rechten Pin verbindest du einmal mit einem 10kOhm-Widerstand mit Minus – und außerdem mit einem Kabel mit dem Digitalpin 2 an deinem Arduino. Diesen sogenannten Pull-down-Widerstand benötigst du, damit dein Arduino zuverlässig eine 0 empfängt, solange du den Button nicht drückst. Sobald du ihn drückst, springt das Singal auf 1.

Hier erfährst du mehr über Pull-up- und Pull-down-Widerstände.

Anschluss des Buttons mit Pull-up-Widerstand

Der Piezo-Buzzer für den Alarm

Was, wenn die Zeit abgelaufen ist? Richtig, dann schlägt ein Piezo-Buzzer Alarm. Setze deinen Piezo auf das Breadboard und verbinde einen Pin mit Minus und den anderen mit dem Digitalpin 3.

Anschluss des Piezo-Buzzers

Und das war es auch schon. Schauen wir uns den Code an

Der Sketch für den Arduino-Timer

Die meisten Zeilen im Code benötigst du für den Countdown auf dem Display. In diesem Tutorial auf pollux labs lernst du, wie du eine 7-Segment-Anzeige steuerst, weshalb wir uns hier auf andere Aspekte des Sketchs konzentrieren.

Zu Beginn des Sketchs legst du die Pins für den Button und den Piezo-Summer fest:

const byte buttonPin = 2;
const byte buzzerPin = 3;

Anschließend erstellst du eine Variable, in der du die Sekunden festlegen kannst, die dein Arduino-Countdown herunterzählen soll:

___STEADY_PAYWALL___

long countdown = 10;

Als Typ verwendest du hier long, um große Zahlen speichern zu können, die eine 7-Segment-Anzeige voll ausschöpfen. Der Typ int reicht auf dem Arduino Uno nur für Zahlen im Bereich -32.768 bis 32.767, auf größeren Boards auch für mehr. Hier erfährst du mehr über dieses Thema.

Der Loop

In der Funktion void loop() geschieht eigentlich nicht viel. Hier wartet dein Sketch nur darauf, dass du den Button drückst und den Countdown startest:

void loop() {
  Serial.println(digitalRead(buttonPin));
  if (digitalRead(buttonPin) == 1) {
    timer();
  }
}

Hierfür liest du mit der Funktion digitalRead() den Button-Pin. Wenn du diesen drückst, springt der Wert auf 1, was die Funktion timer() startet, die wir uns jetzt genauer anschauen.

void timer() {
  number = countdown;
  Serial.println("Timer started!");
  while (number > 0) {
    numberIntoDigits();
    displayNumber();
    delay(1000);
    lc.clearDisplay(0);
    number--;
  }
  if (number == 0) {
    tone(buzzerPin, 440, 1000);
  }
}

Zunächst weist du den Wert der Variable countdown, den du zu Beginn festgelegt hast, einer Variablen number zu. Diese Variable verwenden und verändern wir während des Countdowns, sodass die ursprünglich von dir bestimmte Zeit in der Variablen countdown unberührt bleibt.

Warum? Nun, somit kannst du deinen Arduino-Countdown immer wieder starten, da nur die “Hilfsvariable” number verändert wird. 🙂

Im While-Loop startest du die beiden Funktionen numberIntoDigits() und displayNumber(), über die du in diesem Tutorial mehr erfährst. Anschließend wartest du eine Sekunde, löschst das Display und ziehst von der Zahl in der Variablen number eins ab. Dann beginnt der nächste Durchgang.

Sobald der Countdown bei der Null angekommen ist, ertönt dein Piezo:

  if (number == 0) {
    tone(buzzerPin, 440, 1000);
  }

Der Einfachheit halber spielt er im obigen Beispiel nur für eine Sekunde den Ton A (mit 440Hz). In diesem Tutorial erfährst du mehr darüber, wie du einen Piezo verwendest und damit Melodien spielst.

Hier nun der gesamte Sketch zum Herauskopieren und Hochladen:

#include "LedControl.h"

const byte buttonPin = 2;
const byte buzzerPin = 3;
long number;

//Trage hier die Sekunden ein, die heruntergezählt werden sollen
long countdown = 10;

//Ziffern
int a,b,c,d,e,f,g,h;

LedControl lc = LedControl(12, 11, 10, 1);

void numberIntoDigits() {

  h = number % 10;

  if (number > 9) {
    g = (number / 10) % 10;
  }
  if (number > 99) {
    f = (number / 100) % 10;
  }
  if (number > 999) {
    e = (number / 1000) % 10;
  }
  if (number > 9999) {
    d = (number / 10000) % 10;
  }
  if (number > 99999) {
    c = (number / 100000) % 10;
  }
  if (number > 999999) {
    b = (number / 1000000) % 10;
  }
  if (number > 9999999) {
    a = (number / 10000000) % 10;
  }
}

void displayNumber() {

  lc.setDigit(0, 0, h, false);

  if (number > 9) {
    lc.setDigit(0, 1, g, false);
  }
  if (number > 99) {
    lc.setDigit(0, 2, f, false);
  }
  if (number > 999) {
    lc.setDigit(0, 3, e, false);
  }
  if (number > 9999) {
    lc.setDigit(0, 4, d, false);
  }
  if (number > 99999) {
    lc.setDigit(0, 5, c, false);
  }
  if (number > 999999) {
    lc.setDigit(0, 6, b, false);
  }
  if (number > 9999999) {
    lc.setDigit(0, 7, a, false);
  }
}

void timer() {
  number = countdown;
  Serial.println("Timer started!");
  while (number > 0) {
    numberIntoDigits();
    displayNumber();
    delay(1000);
    lc.clearDisplay(0);
    number--;
  }
  if (number == 0) {
    tone(buzzerPin, 440, 1000);
  }
}

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(buzzerPin, OUTPUT);
  Serial.begin(115200);
  lc.shutdown(0, false);
  lc.setIntensity(0, 8);
  lc.clearDisplay(0);
}

void loop() {
  Serial.println(digitalRead(buttonPin));
  if (digitalRead(buttonPin) == 1) {
    timer();
  }
}

Wie geht es weiter?

Mögliche Verbesserungen für deinen Arduino-Countdown könnte eine Alarm-Melodie sein. Oder du versuchst dich an der Möglichkeit, die Zeit nicht im Sketch, sondern über Buttons auf dem Breadboard einstellen zu können.

Ein spannendes Projekt mit Countdown ist die LEGO ISS, die beim Überflug der echten ISS anfängt zu leuchten.

Fehlen dir noch Bauteile? Dann wirf einen Blick in unsere Übersicht der besten Arduino Starter Kits.

]]>
Eine 7-Segment-Anzeige am Arduino anschließen und verwenden https://polluxlabs.net/arduino-tutorials/eine-7-segment-anzeige-am-arduino-anschliessen-und-verwenden/ Tue, 04 Aug 2020 06:58:04 +0000 https://polluxlabs.net/?p=1996 Eine 7-Segment-Anzeige am Arduino anschließen und verwenden Weiterlesen »

]]>
Es gibt eine Vielzahl von Displays für den Arduino, aber keines davon hat so einen Old-School-Faktor wie die 7-Segment-Anzeige. Back To The Future? Bitte schön! In diesem Tutorial lernst du, wie du dieses Display anschließt und Zahlen darauf anzeigst.

Wir verwenden eine MAX7219 Anzeige, auf der du insgesamt 8 Ziffern darstellen kannst.

Der Anschluss am Arduino

Um die 7-Segment-Anzeige anzuschließen, benötigst du drei freie Digitalpins am Arduino. Du kannst das Display wahlweise mit 3,3V oder 5V betreiben. In diesem Tutorial erfolgt der Anschluss wie folgt:

Arduino7-Segment-Anzeige
GNDGND
3,3V oder 5VVCC
10CS
11CLK
12DIN

Meistens wird das Display mit verlöteten Pins ausgeliefert, sodass du 5 Kabel der Sorte male-female benötigst.

Die passende Bibliothek für die 7-Segment-Anzeige

Für die Steuerung der Anzeige gibt es eine passende Bibliothek, die dir das Leben erleichtert. Öffne also deinen Bibliotheksverwalter in der Arduino IDE, suche nach LedControl und installiere die aktuelle Version.

Bibliothek LedControl.h im Bibliotheksverwalter, um die 7-Segment-Anzeige zu steuern

Der Sketch für den ersten Test

Für den allerersten Gehversuch mit der 7-Segment-Anzeige soll eine einzige Ziffer auf dem Display genügen. Wie so oft ist der erste Schritt, die oben genannte Bibliothek einzubinden:

#include "LedControl.h"

Anschließend legst du fest, an welchen Digitalpins du das Display angeschlossen hast. Hierbei ist die Reihenfolge DIN, CLK, CS entscheidend. Das letzte Argument in der folgenden Codezeile ist die Anzahl der Displays, die du steuern möchtest. Theoretisch könntest du mit der Bibliothek so viele Ziffern darstellen, dass es für die globale Schuldenuhr der nächsten Jahrzehnte reichen würde – aber wir bleiben hier erst einmal bei einer 7-Segment-Anzeige. 😉

LedControl lc=LedControl(12,11,10,1);

Die Anzeige anschalten und eine Ziffer anzeigen

Kommen wir zur Funktion setup(). Hier erledigst du zu Beginn des Sketchs drei Dinge: das Display aus dem Sleep Mode aufwecken, die Helligkeit einstellen und alle Ziffern darauf löschen, die vielleicht noch darauf zu sehen sein könnten.

lc.shutdown(0,false);
lc.setIntensity(0,8);
lc.clearDisplay(0);

Was die Helligkeit angeht, kannst du der Funktion lc.setIntensity() eine Zahl von 0 bis 15 mitgeben.

Kommen wir also zum entscheidenden Moment. Ebenfalls in der Setup-Funktion schreiben wir in das erste Feld der 7-Segment-Anzeige (ganz rechts) die Ziffer 9:

  lc.setDigit(0, 0, 9, false);

Wenn du die 9 ins erste Feld ganz links schreiben möchtest, wäre der Code hierfür folgender. Wie üblich fängst du bei der 0 an zu zählen – und zwar von rechts. Das ganz linke Feld erhält dann die Nummer 7:

  lc.setDigit(0, 7, 9, false);

Was passiert, wenn du statt der 9 eine 10 einträgst? Dann wird diese Dezimalzahl im Hexadezimalsystem dargestellt, also mit dem Buchstaben A. Das geht bis zur Zahl 15, die dann entsprechend als F ausgegeben wird.

Lange Zahlen auf der 7-Segment-Anzeige darstellen

Jedes Feld der Anzeige mit einer Ziffer zu belegen funktioniert also, ist unter Umständen aber recht mühselig. Was, wenn du einfach die Zahl 12345678 auf einmal ausgeben möchtest? Mit zwei Hilfsfunktionen ist das kein Problem.

Zunächst definierst du 8 Variablen, die später die einzelnen Ziffern deiner Zahl enthalten. Die Variable a wird erste Ziffer und h die letzte Ziffer enthalten.

int a;
int b;
int c;
int d;
int e;
int f;
int g;
int h;

Anschließend benötigst du eine (auf den ersten Blick etwas komplizierte) Funktion, die deine Zahl in diese Ziffern aufteilt. Das bewerkstelligst du mit dem Operator Modulo, der den Rest der Division einer ganzen Zahl durch eine andere berechnet.

Die letzte Ziffer der Zahl 12345678 ist – die 8, die im Feld ganz rechts stehen soll. Mit folgender Rechnung erhältst du diese Ziffer und speicherst sie in der Variablen h:

h = number % 10;

Ausgeschrieben lautet diese Rechnung wie folgt: h = 12345678 : 10 = 1234567,8 – der Rest hinter dem Komma ist also die 8, unsere Ziffer ganz rechts.

Weiter geht es mit der vorletzten Ziffer. Hier prüfst du zunächst, ob die darzustellende Zahl überhaupt zwei Ziffern hat (hat sie, deine Zahl hat sogar 8). Falls ja teilst du sie zunächst durch 10 und erhältst dadurch die Zahl 1234567. Hier fällt die Nachkommastelle weg, da wir die Variable number ja mit long angelegt haben und bei diesem Typ die Nachkommastellen automatisch gestrichen werden, da er nur ganze Zahlen speichern kann.

Eine weitere Rechnung mit dem Modulo beschert dir dann die vorletzte Ziffer 7:

if (number > 9) {
  g = (number / 10) % 10;
}

Diese Rechnungen führst du für alle Ziffern in deiner Zahl aus, wie du unten im vollständigen Sketch sehen kannst. Sobald die Funktion durchgelaufen ist, musst du nur noch alle Ziffern auf die 7-Segment-Anzeige bringen. Hierfür verwendest du eine weitere Funktion, die prüft, wie viele Ziffern deine Zahl hat und diese in den Variablen a – h gespeicherten Ziffern darstellt:

lc.setDigit(0, 0, h, false);

if (number > 9) {
  lc.setDigit(0, 1, g, false);
}
.
.
.

Hier nun der gesamte Sketch, mit dem du Zahlen auf das Display bringst. Speichere zum Testen verschiedene, maximal achtstellige Zahlen in der Variable number.

#include "LedControl.h"

long number = 1234;

//Variablen für die einzelnen Ziffern
int a;
int b;
int c;
int d;
int e;
int f;
int g;
int h;

LedControl lc=LedControl(12,11,10,1);

void numberIntoDigits() {

  h = number % 10;

  if (number > 9) {
    g = (number / 10) % 10;
  }
  if (number > 99) {
    f = (number / 100) % 10;
  }
  if (number > 999) {
    e = (number / 1000) % 10;
  }
  if (number > 9999) {
    d = (number / 10000) % 10;
  }
  if (number > 99999) {
    c = (number / 100000) % 10;
  }
  if (number > 999999) {
    b = (number / 1000000) % 10;
  }
  if (number > 9999999) {
    a = (number / 10000000) % 10;
  }
}

void displayNumber() {

  lc.setDigit(0, 0, h, false);

  if (number > 9) {
    lc.setDigit(0, 1, g, false);
  }
  if (number > 99) {
    lc.setDigit(0, 2, f, false);
  }
  if (number > 999) {
    lc.setDigit(0, 3, e, false);
  }
  if (number > 9999) {
    lc.setDigit(0, 4, d, false);
  }
  if (number > 99999) {
    lc.setDigit(0, 5, c, false);
  }
  if (number > 999999) {
    lc.setDigit(0, 6, b, false);
  }
  if (number > 9999999) {
    lc.setDigit(0, 7, a, false);
  }
}

void setup() {
  lc.shutdown(0,false);
  lc.setIntensity(0,8);
  lc.clearDisplay(0);
  numberIntoDigits();
  displayNumber();
  }

void loop() { 
}

Effektiverer Code

Du kannst den Code oben auch komprimieren, sodass du nur noch eine Funktion benötigst. Definiere hierfür zunächst, wie viele Ziffern dein Display darstellen kann – in unserem Fall also 8. Anschließend erledigst du die Berechnung der einzelnen Ziffern und ihre Darstellung in fünf Zeilen Code:

const int NUM_DIGITS = 8;

void drawDigits(int num) {
  for (int i = 0; i < NUM_DIGITS ; i++) {
    lc.setDigit(0, i, num % 10, false);
    num /= 10;
    if (num == 0)
      return;
  }
}

Wie geht es weiter?

Weiter Anleitungen zu Bauteilen und vollständige Arduino Projekte findest du in unserem Buch für angehende Maker:

Baue die 7-Segment-Anzeige gleich in deinen DeLorean ein und ab ins Jahr 1985! Scherz beiseite, wie wäre es z.B. mit einem Retro-Timer? Oder du verpasst dem ISS Würfel oder deiner LEGO ISS einen Countdown, um die Gelegenheit nicht zu verpassen, die echte ISS vorüberfliegen zu sehen.

]]>
NeoPixel RGB LED Ring anschließen & verwenden https://polluxlabs.net/arduino-tutorials/neopixel-rgb-led-ring-anschliessen-verwenden/ Wed, 27 May 2020 06:00:00 +0000 https://polluxlabs.net/?p=1815 NeoPixel RGB LED Ring anschließen & verwenden Weiterlesen »

]]>
In diesem Tutorial erfährst du, wie du den Adafruit NeoPixel RGB LED Ring (oder einen kompatiblen Ring)* an deinem Arduino anschließt und verwendest. Den Ring gibt es mit unterschiedlich vielen LEDs, wir verwenden hier einen Ring mit 12.

Das Besondere am NeoPixel ist, dass du jede LED einzeln ansteuern und ihr auch einen individuellen RGB-Farbton zuweisen kannst. So kannst du ganz einfach Animationen mit tollen Farbverläufen zaubern.

Vorbereitungen & Anschluss des RGB LED Rings

In den meisten Fällen erhältst du den NeoPixel LED Ring ohne Pins. Um ihn verwenden zu können, musst du selbige also zunächst an die Anschlüsse GND, 5V und IN (oder auch DI) löten. Pass hierbei auf, dass du die Anschlüsse auf dem Ring nicht allzu lange erhitzt, ansonsten können sie sich lösen und das Bauteil wird unbrauchbar.

NeoPixel LED Ring with Pins

Wenn die Anschlüsse sitzen, verbinde GND und 5V mit den gleichnamigen Pins an deinem Arduino. Der Pin IN (oder DI) kommt an einen Digitalpin deiner Wahl – in unserem Beispiel-Sketch ist das der Pin 2.

Die passende Bibliothek

Wie für viele Bauteile gibt es auch für den NeoPixel RGB LED Ring eine Bibliothek, die dir das Leben erleichtert. Öffne deinen Bibliotheksmanager und suche nach Adafruit Neopixel. Installiere anschließend die neueste Version:

neopixel led ring bibliothek

Den RGB LED Ring ansteuern

Jetzt kann es auch schon losgehen. Kopiere den folgenden Sketch und lade ihn auf deinen Arduino. Wenn alles passt, leuchten alles LEDs auf deinem Ring nacheinander rot auf und gehen zusammen wieder aus.

//Bibliothek einbinden
#include <Adafruit_NeoPixel.h>

int leds = 12; //Anzahl der LEDs
int ledPin = 2; //Pin, an dem der NeoPixel angeschlossen ist

int red = 255; //Rot
int green = 0; //Grün
int blue = 0;  //Blau

//NeoPixel als "pixels" instanziieren
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(leds, ledPin, NEO_GRB + NEO_KHZ800);

void setup() {
  pinMode (ledPin, OUTPUT);
  pixels.begin();
  pixels.setBrightness(100); //Helligkeit: 0 (aus) - 255
}

void loop() {
  for (int i = 0; i < 12; i++) {
    pixels.setPixelColor(i, pixels.Color(red, green, blue));
    pixels.show();
    delay(500);
  }
  pixels.clear();
  delay(500);
}

Gehen wir den Sketch Schritt für Schritt durch: Als erstes bindest du die Bibliothek ein und definierst einige Variablen für die Anzahl der LEDs, den Anschluss des Rings und die Farbwerte.

#include <Adafruit_NeoPixel.h>

int leds = 12; //Anzahl der LEDs
int ledPin = 2; //Pin, an dem der LED Ring angeschlossen ist

int red = 255; //Rot
int green = 0; //Grün
int blue = 0;  //Blau

Mit einer RGB LED kannst du über 16 Millionen verschiedene Farben ausgeben, die sich aus den drei Einzelfarben Rot, Grün und Blau zusammensetzen. Für jede dieser Farben kannst du einen Wert zwischen 0 und 255 bestimmen – die Mischung macht’s!

Mit diesem Tool kannst du die passenden Einzelwerte für deine Wunschfarbe bestimmen.

Als nächstes erstellst du die Instanz pixels:

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(leds, ledPin, NEO_GRB + NEO_KHZ800);

Hier definierst du die Anzahl der LEDs auf deinem Ring mit Hilfe der Variablen leds und den Pin ledPin, an den dein NeoPixel RGB LED Ring angeschlossen ist. Die anderen Parameter sind erst einmal nicht wichtig.

Die Setup-Funktion

Hier definierst du den ledPin als OUTPUT und aktivierst den LED Ring. Zuletzt legst du die Helligkeit der LEDs fest:

void setup() {
  pinMode (ledPin, OUTPUT);
  pixels.begin();
  pixels.setBrightness(100); //Helligkeit: 0 (aus) - 255
}

Der Loop

Jede LED hat eine eigene Nummer von 0 bis 11, mit der du sie individuell ansteuerst. Gezählt wird normalerweise von der LED unten an den Anschlüssen im Uhrzeigersinn.

In diesem Tutorial schaltest du die LEDs nacheinander mit einer kurzen Verzögerung an. Hierfür bietet sich ein For-Loop an:

void loop() {
  for (int i = 0; i < 12; i++) {
    pixels.setPixelColor(i, pixels.Color(red, green, blue));
    pixels.show();
    delay(500);
  }
  pixels.clear();
  delay(500);
}

Innerhalb des For-Loops legst du zunächst die Farbe fest, die die LED i ausgeben soll. Hierfür stehen in der Funktion pixels.Color() die Einzelwerte, die du zu Beginn des Sketchs definiert hast:

pixels.setPixelColor(i, pixels.Color(red, green, blue));

Anschließend bringst du die LED mit pixels.show() zum Leuchten und wartest 500 Millisekunden. Anschließend kümmert sich der For-Loop um die nächste LED i.

Sind alle 12 LEDs erleuchtet springt der Sketch aus dem For-Loop und schaltet alle LEDs mit pixels.clear() wieder aus. Nach weiteren 500 Millisekunden beginnt dann alles wieder von vorne.

Wie geht es weiter?

Jetzt kennst du den Code für eine einfache Animation in einer Farbe. Deiner Fantasie sind jedoch keine Grenzen gesetzt, wie wäre es z.B. mit einer LEGO ISS, die für die Dauer des Überflug der echten ISS die Farbe wechselt? Du findest den Code für den ISS Tracker hier auf pollux labs.

Weitere Ideen findest du in unseren Arduino-Projekten.

]]>
LCD Hill Run – Ein Arduino Jump’n’Run https://polluxlabs.net/arduino-projekte/lcd-hill-run-ein-arduino-jumpnrun/ Thu, 19 Mar 2020 19:35:30 +0000 https://polluxlabs.net/?p=1243 LCD Hill Run – Ein Arduino Jump’n’Run Weiterlesen »

]]>

Wer den ganzen Tag Daten von Sensoren ausliest hat sich eine Runde Zocken am Abend verdient! 🙂 Für dieses kleine Arduino Jump’n’Run benötigst du nur wenige Bauteile (und einige Kabel). Du baust es in wenigen Minuten auf und kannst danach gleich loslegen.

LCD Hill Run in Action

Die Idee und der Code für dieses Spiel stammt von Miles C., der es unter der Linzenz CC BY-SA 4.0 im Arduino Project Hub veröffentlicht hat. Wir erläutern nicht den ganzen Sketch des Spiels, aber erklären dir eine tolle Funktion, die du vielleicht noch nicht kennst: attachInterrupt()

Für dieses Projekt benötigst du:

* Amazon Affiliate Links – Wenn du dort bestellst, erhalten wir eine kleine Provision.

So funktioniert das Spiel

Die “Story” des Spiels ist schnell erzählt: Du spielst ein kleine Figur, die auf einem LCD-Display von alleine rennt und Hindernissen ausweichen muss. Hierbei musst du entweder springen oder dich ducken. Für jedes überwundene Hindernis erhältst du einen Punkt. Sobald du an einem Hindernis hängen bleibst, hast du verloren und dir wird dein Punktestand angezeigt.

Der Aufbau des Projekts

Wie du auf dem Screenshot unten siehst, sind bei diesem Projekt viele Kabel im Spiel. Das LCD-Display benötigt besonders viele. Wenn du ein Display mit I²C und integriertem Potentiometer verwendest, kannst du die Kabelei um einiges reduzieren.

Baue das Spiel wie folgt auf und prüfe alle Verbindungen noch einmal bevor du loslegst:

Aufbau des Arduino Spiels Hill Run
Screenshot: Tinkercad

Der Sketch des Arduino Jump’n’Runs

Wir werden an dieser Stelle nicht auf jedes Detail eingehen, viele der Konzepte im folgenden Sketch findest du in diesen Projekten und Tutorials auf pollux labs ausführlich erklärt:

Eine Funktion im Sketch ist aber recht selten anzutreffen, obwohl sie sehr hilfreich sein kann: attachInterrupt()

Die Funktion attachInterrupt()

Schauen wir erst auf ein gängiges Konzept: In diesem Sketch möchtest du auf einen gedrückten Button reagieren.

void loop() {
  
  buttonState = digitalRead(buttonPin);

  if (buttonState == HIGH) {
    digitalWrite(ledPin, HIGH);
  }
  else {
    digitalWrite(ledPin, LOW);
  }
}

Hier wird zunächst mit digitalRead() der Zustand des Buttons gelesen und dann in einer if/else-Abfrage mit einer LED reagiert.

Das funktioniert, ist aber etwas unpraktisch, wenn du im Loop noch etwas vorhast als nur darauf zu warten, dass jemand den Button drückt. Besser ist es da, das Überwachen des Buttons einen sogenannten Interrupt erledigen zu lassen, denn damit kannst du mehrere Prozesse gleichzeitig ablaufen lassen. In diesem Spiel sind das das Auslesen der beiden Buttons und die Animationen auf deinem LCD-Display. So ein Interrupt kann folgendermaßen aussehen:

volatile int buttonState = 0;

void setup() {
 
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(buttonPin), pin_ISR, CHANGE);
}

void loop() {
}

void pin_ISR() {
  buttonState = digitalRead(buttonPin);
  digitalWrite(ledPin, buttonState);
}

Wie du siehst, ist hier der Loop sogar leer, die Abfrage des Buttons befindet sich jetzt im Setup. Das bedeutet, du hast im Loop Platz für andere Dinge. Die Funktion attachInterrupt() hat folgende Syntax:

attachInterrupt(digitalPinToInterrupt(pin), ISR, mode) 

Hierbei spielen die Parameter interrupt (der zu überwachende Pin), ISR (die beim Drücken des Buttons ausgeführte Funktion) und mode (Wann wird getriggert?) eine Rolle. Ausführliche Informationen findest du in der Arduino-Referenz.

Zurück zum Sketch des Spiels: Sobald du einen der beiden Buttons drückst, wird eine entsprechende Funktion aufgerufen, die deine Figur entweder springen – seeJumping() – oder sich ducken – seeDucking() –lässt.

Ansonsten besteht der Großteil des Sketchs dieses Arduino Jump’n’Runs aus Abfragen und Animationen, die dich auf den ersten Blick vermutlich ziemlich überrumpeln. Aber mit etwas Übung und Zeit wirst du auch durchsteigen – wenn du das möchtest und nicht einfach nur spielen willst. 🙂

Hier der gesamte Sketch:

/*
 * Copyright (c) 2020 by Miles C.
*/

#include <LiquidCrystal.h>
#include "pitches.h"
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

const int JUMP_PIN = 2;
const int BUZZER_PIN = 5;
const int DUCK_PIN = 3;

const int JUMP_PITCH = 2700; //sounds when button pressed
const int JUMP_PITCH_DURATION = 50; //sounds when button pressed
const int DUCK_PITCH = 1350; //sounds when button pressed
const int DUCK_PITCH_DURATION = 50; //sounds when button pressed
const int DIE_PITCH = 200; //sounds on death
const int DIE_PITCH_DURATION = 500; //sounds on death
const int TICKSPEED = 90; //ms per gametick, 1 gametick per hill move.
const int JUMP_LENGTH = 3; //chars jumped over when jump is pressed.
const byte stickStep1[8] = {
  B01110,
  B01110,
  B00101,
  B11111,
  B10100,
  B00110,
  B11001,
  B00001,
};
const byte stickStep2[8] = {
  B01110,
  B01110,
  B00101,
  B11111,
  B10100,
  B00110,
  B01011,
  B01000,
};
const byte stickJump[8] = {
  B01110,
  B01110,
  B00100,
  B11111,
  B00100,
  B11111,
  B10001,
  B00000,
};
const byte stickDuck[8] = {
  B00000,
  B00000,
  B00000,
  B01110,
  B01110,
  B11111,
  B00100,
  B11111,
};
const byte hill[8] = {
  B00000,
  B00000,
  B01110,
  B01110,
  B01110,
  B11111,
  B11111,
  B11111,
};
const byte crow1[8] = {
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B01110,
  B01110,
  B01110,
};
const byte crow2[8] {
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B01110,
  B01110,
  B01110,
};

volatile int jumpPhase = JUMP_LENGTH + 1;
int gameTick = 0;
int crowX = 40;
int hillX = 25;
bool playerY = 0;
volatile bool ducking = LOW;
bool loopBreaker = 1;
bool crowGo = 0;
int score = 0;

void setup() {
  pinMode(JUMP_PIN, INPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  lcd.begin(16, 2);
  lcd.createChar(0, hill);
  lcd.createChar(1, stickStep1);
  lcd.createChar(2, stickStep2);
  lcd.createChar(3, stickJump);
  lcd.createChar(4, stickDuck);
  lcd.createChar(5, crow1);
  lcd.createChar(6, crow2);
  attachInterrupt(digitalPinToInterrupt(JUMP_PIN), seeJumping, RISING);
  attachInterrupt(digitalPinToInterrupt(DUCK_PIN), seeDucking, CHANGE);
}

void loop() {
  playerY = 0;
  if (jumpPhase < JUMP_LENGTH) {
    playerY = 1;
  }

  drawSprites();

  loopBreaker = 1;
  if (hillX < 16) {
    if (crowX < hillX) {
      hillX += 8;
      loopBreaker = 0;
    }
    if (loopBreaker) {
      lcd.setCursor(hillX, 1);
      lcd.write((byte)0);
    }
  }
  if (hillX < 1) {
    if (jumpPhase < JUMP_LENGTH) {
      score++;
      hillX = 16 + rand() % 8;
    } else {
      endGame();
    }
  }
  if (crowX < 16) {
    lcd.setCursor(crowX, 0);
    if (gameTick % 8 < 4) {
      lcd.write((byte)5);
    } else {
      lcd.write((byte)6);
    }
  }
  if (crowX < 1) {
    if (ducking) {
      score++;
      crowX = 24 + rand() % 16;
    } else {
      endGame();
    }
  }
  lcd.setCursor(0, playerY);
  lcd.print(" ");
  jumpPhase++;
  hillX--;
  crowGo = !crowGo;
  crowX -= crowGo;
  gameTick++;
  delay(TICKSPEED);
}

void endGame() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Score: ");
  lcd.setCursor(7, 0);
  lcd.print(score);
  tone(BUZZER_PIN, DIE_PITCH, DIE_PITCH_DURATION);
  while (!digitalRead(JUMP_PIN)) {
    lcd.setCursor(0, 1);
    if (millis() % 500 < 250) {
      lcd.print("Jump to Continue");
    } else {
      lcd.print("                ");
    }
  }
  lcd.clear();
  score = 0;
  hillX = 25;
  crowX = 40;
}

void drawSprites() {
  lcd.setCursor(0, 1 - playerY);

  if (!ducking) {
    if (!playerY) {
      if ((gameTick % 4) < 2 ) {
        lcd.write((byte)1);
      } else {
        lcd.write((byte)2);
      }
    } else {
      lcd.write((byte)3);
    }
  } else {
    lcd.write((byte)4);
  }
  lcd.setCursor(1, 1);
  lcd.print("               ");
  lcd.setCursor(1, 0);
  lcd.print("               ");
}
void seeJumping() {
  if (jumpPhase > (JUMP_LENGTH + 2) && !ducking) {
    jumpPhase = 0;
    tone(BUZZER_PIN, JUMP_PITCH, JUMP_PITCH_DURATION);
  }

}
void seeDucking() {
  ducking = digitalRead(DUCK_PIN);
  if (ducking) {
    jumpPhase = JUMP_LENGTH;
    tone(BUZZER_PIN, DUCK_PITCH, DUCK_PITCH_DURATION);
  }
}
]]>
Bilder auf einem OLED-Display anzeigen https://polluxlabs.net/arduino-tutorials/bilder-auf-einem-oled-display-anzeigen/ Tue, 14 Jan 2020 13:03:21 +0000 https://polluxlabs.net/?p=835 Bilder auf einem OLED-Display anzeigen Weiterlesen »

]]>
Du kannst mit deinem Arduino (oder ESP8266, ESP32 etc.) neben Texten auch Bilder auf einem monochromen OLED-Display anzeigen lassen. Allerdings kannst du nicht einfach eine Bilddatei wie zum Beispiel ein JPEG dort erscheinen lassen. Die Sache ist etwas komplexer, aber mit den richtigen Tools trotzdem kein Problem.

Grundsätzliche Überlegungen

Das vermutlich gängigste OLED-Display für den Arduino hat eine Diagonale von 0.96″ und 128×64 Pixel. Das bedeutet, dass ein Bild für das Display natürlich auch nur über diese Größe verfügen kann. Soviel ist klar. 😉

Hinzu kommt, dass dieses OLED-Display nur weiße Pixel anzeigen kann, also monochrom ist. Mit dem schwarzen Hintergrund macht das dann jedoch immerhin zwei Farben. Das bedeutet, du kannst entweder etwas weißes auf schwarzem Hintergrund zeichnen – oder den Hintergrund weiß einfärben und darüber in Schwarz zeichnen.

Es ist also naheliegend, weniger von einem “Bild” zu sprechen, sondern eher von einem “Icon”.

Bilder konvertieren

Dein erster Schritt ist es also, ein Bild in Code zu konvertieren, damit dein Arduino es aufs Display bringen kann. Hierfür verwendest du am besten ein Online-Tool, wie zum Beispiel image2cpp, das du im folgenden kennenlernst.

Nehmen wir zum Beispiel dieses schicke UFO:

Dieses Icon ist bereits schwarz-weiss und hat mit 64×64 Pixeln eine geeignete Größe – es ist genauso hoch wie das Display. Jetzt sind es nur 4 einfache Schritte, um dieses Bild in Code konvertieren.

Lade zunächst dein Icon hoch:

Bild hochladen

Anschließend musst du ein paar kleinere Einstellungen vornehmen. Angenommen, du möchtest ein weißes Ufo auf schwarzem Hintergrund in der Mitte des Displays zentriert:

  • Stelle die Canvas size auf die Größe deines Displays (z.B. 128×64)
  • Wähle Black als Background color
  • Mach einen Haken bei Invert image colors
  • Mach einen weiteren Haken unter Center -> horizontally
Einstellungen für die Bildkonvertierung

Spiele etwas mit den Werten herum, um herauszufinden, was sie bewirken. Unter Brightness threshold kannst du die Linien deines Icons zum Beispiel feinjustieren. So ungefähr sollte dein Icon jetzt aussehen:

Fast geschafft! Jetzt fehlt nur noch der Code. Wähle im nächsten Bereich unter Code output format die Einstellung Arduino code. Unter Identifier kannst du deinem Icon einen Namen geben, mit dem du es später in deinem Sketch aufrufen und einbinden kannst.

Klicke zuletzt auf den Button Generate code und kopiere dir genau diesen Code aus dem Feld darunter heraus.

Output der Bildkonvertierung

Den Code im Sketch einbinden und das Icon anzeigen

Den frisch kopierten Code setzt du am besten gleich in deinen Sketch ein – und zwar noch vor die Funktion void setup().

Bevor du etwas auf deinem OLED-Display anzeigen lassen kannst, musst du in deinem Sketch ein paar Vorbereitungen treffen, wie zum Beispiel die nötigen Bibliotheken einbinden. Wenn du das noch nicht kennst, erfährst du alles weitere in diesem Projekt.

Nach deinen Vorbereitungen zauberst du das Icon nun wie folgt auf dein Display:

display.drawBitmap(0, 0, alien, 128, 64, WHITE); 
display.display();

Das war’s! Jetzt lass deiner Kreativität freien Lauf! 🙂

Wie wäre es mit die Projekt: Sende von deinem Smartphone Emojis nach Hause und zeige sie dort auf einem OLED-Display an.

]]>
Erinnerung an deinen Regenschirm mit dem ESP8266 https://polluxlabs.net/esp8266-projekte/erinnerung-an-deinen-regenschirm-mit-dem-esp8266/ Mon, 13 Jan 2020 21:17:44 +0000 https://polluxlabs.net/?p=786 Erinnerung an deinen Regenschirm mit dem ESP8266 Weiterlesen »

]]>
Hast du schon einmal deine Wohnung verlassen und bist dann auf der Straße im Regen gestanden? Dafür, dass das nicht noch einmal passiert, sorgst du mit diesem Projekt.

Mit einem ESP8266 rufst du über eine API die aktuelle Wetterlage ab und zeigst auf einem OLED-Display an, ob es regnet, schneit oder die Sonne scheint. Falls du draußen einen Regenschirm benötigst, erinnert dich das Display und eine LED daran, deinen Regenschirm mitzunehmen.

Ach ja: Damit dein ESP8266 nicht den ganzen Tag im Internet verbringt und ständig die Wetterdaten abruft, integrierst du noch eine Radar-Modul. So kannst du dein Projekt zum Beispiel an der Wohnungstür platzieren und es nur dann anspringen lassen, wenn du dich ihm näherst. So wirst du genau zur richtigen Zeit erinnert. 🙂

Anfänger

1 – 2 Stunden

ca. 15 €

Für dieses Projekt benötigst du (Mengen s. Beschreibung):

Der Aufbau

So ungefähr sollte das fertig aufgebaute Projekt aussehen:

Setze zuerst deinen ESP8266 auf dein Breadboard. Wir empfehlen hierfür ein NodeMCU Lua Amica, denn das ist schmal genug, dass du an den Pinouts noch Kabel einstecken kannst. Die neuere Version namens Lolin ist da im Nachteil und deshalb für Projekte auf Breadboards eher ungeeignet. Anschließend verbindest du deinen Microcontroller mit diesem 3 Bauteilen:

OLED-Display

In diesem Projekt verwendest du ein kleines OLD-Display mit I²C-Anschluss. Setze dein Display auf das Breadbaord und verbinde es zunächst mit einem der GND-Pins und einem 3,3V-Ausgang am Microcontroller. Anschließend verbindest du den Display-Pin SCL mit D1 und den Pin SDA mit D2. Mit den beiden Pins D1 und D2 kannst du per I²C mit deinem Display kommunizieren.

Radar-Modul RCWL-0516

Dieser Sensor ist ein einwandfreier Bewegungssensor mit einer Reichweite von 5 bis 7 Metern. Das Tolle an diesem Modul ist, dass es sogar Bewegungen durch ein Hindernis (zum Beispiel eine Box) erkennen kann.

Der Anschluss ist kinderleicht: Neben dem üblichen Anschluss von GND und 3,3V verbindest du den Pin OUT mit dem Pin D7 an deinem ESP8266.

Die LED

Nun zur allerleichtesten Übung, der LED. Verbinde die Anode (langes Bein) mit dem Pin D6 und die Kathode (kurzes Bein) mit Erde. Vergiss nicht, einen Widerstand zwischenzuschalten!

Der Code für dein Projekt

Etwas komplexer wird es jetzt, denn zunächst musst du dich für eine -kostenlosen- API registrieren, von der du die aktuelle Wetterlage an deinem Wohnort (oder an jedem anderen Ort der Erde) abrufen kannst.

Registriere dich zunächst auf https://openweathermap.org. Für einen Account benötigst du nur einen Usernamen, eine E-Mail-Adresse und ein Passwort. In deinem persönlichen Bereich hast du unter dem Menüpunkt API keys nun die Möglichkeit einen solchen API key zu erstellen. Diesen benötigst du später in deinem Arduino Sketch für die API-Abfrage der Wetterdaten. Wenn du das gemacht hast, kann es mit dem Code weitergehen.

___STEADY_PAYWALL___

Die benötigten Bibliotheken

Für dieses Projekt benötigst du 6 Bibliotheken. Falls du sie bisher in deiner Arduino IDE noch nicht installiert hast, hole das am besten gleich nach. Klicke hierfür auf den Menüpunkt Werkzeuge und anschließend auf Bibliotheken verwalten. Anschließend öffnet sich der sogenannte Bibliotheksverwalter, in dem du nach den jeweiligen Bibliotheken suchen kannst. Installiere jeweils die neueste Version.

Wenn du damit fertig bist, bindest du sie noch vor der Funktion void setup() am Anfang deines Sketchs ein:

#include <Wire.h> //I2C-Verbindung
#include <Adafruit_GFX.h> //OLED-Display
#include <Adafruit_SSD1306.h> //OLED-Display

#include <ESP8266WiFi.h> //WiFI
#include <ArduinoJson.h> //JSON
#include <ESP8266HTTPClient.h> //API-Abfrage

Zugangsdaten zum Internet und OLED-Display

Damit sich dein ESP8266 mit dem Internet verbinden kann, musst du deine Zugangsdaten hinterlegen. Gleich dahinter folgt etwas Code für die Kommunikation mit deinem Display:

// WIFI-Zugangsdaten
const char* ssid = "Dein Netzwerkname";
const char* password =  "Dein Passwort";


//OLED-Display
#define SCREEN_WIDTH 128 // Breite des Displays in Pixeln
#define SCREEN_HEIGHT 64 // Höhe des Displays in Pixeln

//Angaben zum OLED-Display und der Kommunikation per I2C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

Icons für alle (wichtigen) Wetterlagen

Auf deinem Display sollen später Icons erscheinen, die das aktuelle Wetter symbolisieren: Klarer Himmel, Wolken, Schnee, Nebel – und ein Regenschirm für Regen und Gewitter. Die Deklarationen dieser Icons im Code sind sehr lang. Deshalb findest du sie nicht an dieser Stelle, sondern im gesamten Arduino-Sketch, den du unten findest.

Die Setup-Funktion

In der Funktion void setup() definierst du die beiden Pins für die LED und den Radar-Sensor, bereitest du die Verbindung zum Seriellen Monitor vor, gibst die Adresse deines Displays an und legst die Schriftgröße und -farbe fest. 🙂

void setup() {

  pinMode (12, OUTPUT); //LED Pin (am ESP8266 D6)
  pinMode (13, INPUT); //Radar Pin (am ESP8266 D7)

  Serial.begin(115200); //Verbindung zum Seriellen Monitor

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Display-Addresse: 0x3C
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }

  display.setTextSize(1); //Schriftgröße
  display.setTextColor(WHITE); //Schriftfarbe
}

Der Loop

In der Funktion void loop() arbeitet dein Radar-Modul. Alle 100 Millisekunden prüft es, ob sich etwas in der Nähe bewegt. Ist das der Fall, verbindet sich dein ESP8266 mit dem Internet und startet die Abfrage der Wetterdaten von Openweather. Solange das nicht der Fall ist, läuft der Loop immer weiter und das OLED-Display bleibt dunkel.

void loop() {

  delay(100); //100 Millisekunden warten

  if (digitalRead(13) == 1) { //Sobald das Radar eine Bewegung registriert, startet die Internet-Verbindung
    WiFi.begin(ssid, password); //Internet-Verbindung starten

    while (WiFi.status() != WL_CONNECTED) { //Statusnachricht "Verbindung herstellen" solange nicht verbunden
      delay(1000);
      display.clearDisplay();
      display.setCursor(0, 10);
      display.println("Connecting to WiFi...");
      display.display();

    }

    delay(1000);
    display.clearDisplay();
    display.setCursor(0, 10);
    display.println("Hello, world!"); //Ausgabe, sobald die Verbindung zum Internet steht
    display.display();

    apiCall(); //Aufruf der Funktion für Abruf und Ausgabe der Wetterdaten
    
  } else {
    WiFi.disconnect(); //Wenn keine Bewegung registriert wird Internet-Verbindung beenden...
    digitalWrite(12, LOW); //...und die LED ausschalten
  }
}

Die Funktion apiCall()

Diese Funktion ist das Herzstück deines Codes! Hier startest du die Abfrage bei der API (ein sogenannter API Call), verarbeitest die in deinem ESP8266 ankommenden Daten und zeigst abhängig vom Wetter ein entsprechendes Icon auf deinem Display an. Zusätzlich gibst du noch die aktuelle Temperatur aus und lässt bei Regen die LED leuchten.

Dieser Code ist nicht ganz einfach. Deshalb schauen wir ihn uns Schritt für Schritt an:

Als allererstes definierst du natürlich die Funktion selbst und schreibst eine If-Abfrage, innerhalb der sich der gesamte folgende Code abspielt. Mit dieser Abfrage stellst du sicher, dass dieser nur ausgeführt wird, wenn die Verbindung zum Internet steht. Denn ohne Internet keine Wetterdaten. 🙂

void apiCall() {

  if ((WiFi.status() == WL_CONNECTED)) { //Netzwerkstatus checken

Wetterdaten abrufen und verarbeiten

Als nächstes erstellst du eine Instanz der Klasse HTTPClient namens http. Anschließend kommt die Abfrage bei Openweather. Hierfür verwendest du eine URL, in der die Art der Abfrage (aktuelles Wetter) und der gewünschte Ort definiert sind. Am Ende der URL steht dein API key, den du zu Beginn erstellt hast. Nähere Informationen erhältst du in der Dokumentation von Openweather.


    HTTPClient http; //Instanz von HTTPClient starten

    http.begin("http://api.openweathermap.org/data/2.5/weather?q=Berlin,de&units=metric&appid=DEIN API KEY"); //URL für die Abfrage

    int httpCode = http.GET(); //Antwort des Servers abrufen
    Serial.println(httpCode); //Antwort im Seriellen Monitor ausgeben

Jetzt folgt ein Check, ob die Abfrage funktioniert hat. In diesem Fall erhältst du vom Server die Antwort 200. Also schreibst du eine If-Abfrage, die allen folgenden Code nur ausführt, wenn die Server-Antwort positiv ausgefallen ist und du die gewünschten Daten erhalten hast.

Danach speicherst du diese Daten in der Variable payload und verarbeitest sie mit Hilfe der Bibliothek ArduinoJson. Die Erklärung, wie das genau funktioniert, würde den Rahmen hier sprengen. Nähere Erläuterungen findest du im Projekt Ein Newsticker per API Call & JSON und auf der Webseite des Entwicklers dieser Bibliothek.

    if (httpCode == 200) { //Die Antwort des Servers checken

      String payload = http.getString(); //Daten in eine Variable speichern

      const size_t capacity = JSON_ARRAY_SIZE(1) + 2 * JSON_OBJECT_SIZE(1) + 2 * JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(14) + 290;
      
      DynamicJsonDocument doc(capacity); //Größe des Speichers zur JSON-Verarbeitung festlegen

      DeserializationError error = deserializeJson(doc, payload); //JSON parsen

      http.end(); //Die Verbindung zum Server beenden

      if (error) { //Fehlermeldung bei fehlerhafter Verarbeitung
        Serial.print(F("deserializeJson() failed: "));
        Serial.println(error.c_str());
        return;
      }

In der Variable payload befinden sich nun die Wetterdaten im JSON-Format. Wie diese aussehen, kannst du sehen, wenn du die URL zur Abfrage aus deinem Sketch in deinem Browser aufrufst. Hier ein Beispiel für Berlin am Abend des 13. Januar 2020:

{"coord":{"lon":13.41,"lat":52.52},"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03n"}],"base":"stations","main":{"temp":3.2,"feels_like":-1.49,"temp_min":1.11,"temp_max":5,"pressure":1017,"humidity":86},"visibility":10000,"wind":{"speed":4.1,"deg":180},"clouds":{"all":40},"dt":1578947701,"sys":{"type":1,"id":1275,"country":"DE","sunrise":1578899517,"sunset":1578928632},"timezone":3600,"id":2950159,"name":"Berlin","cod":200}

Etwas schwer zu lesen, oder? 😉 Für deinen ESP8266 ist das jedoch kein Problem. Die Bibliothek ArduinoJson stellt dir hierfür alles zur Verfügung. Kurz gesagt, kannst du mit einer paar Zeilen Code genau die Daten herausfischen, die du brauchst. Über allem steht ein For-Loop, der dafür sorgt, das die kommenden Anzeigen und Animationen drei Mal angezeigt werden, bis das Display wieder erlischt:

      //Wetterlage und Temperatur ausgeben
      for (int j = 0; j < 3; j++) { // 3x Animation durchlaufen lassen bis zur nächsten Messung
        //Wetterdaten auslesen anhand von ID
        JsonObject weather_0 = doc["weather"][0];
        int weather_0_id = weather_0["id"]; // Wetter-ID
        Serial.println(weather_0_id);

Aus den Daten hast du jetzt die ID des aktuellen Wetters herausgelesen. Openweather vergibt nämlich jeder Wetterlage eine eigene dreistellige ID. So hat leichter Regen zum Beispiel die ID 500. Herabrieselnde Vulkanasche hingegen die ID 762! Alle IDs findest du hier.

Wetterdaten auf dem Display zeigen

Jetzt folgen eine Reihe von If-Abfragen, die das zum Wetter passende Icon auf deinem Display zeigen und animieren. Hier exemplarisch der ID-Bereich “Wolken” – das sind alle IDs zwischen 801 und 804. Nähere Erläuterungen findest du in den Kommentaren im Code. Interessant ist der For-Loop: Hier verschiebst du das Icon nach links, indem du es 128 Mal (die Breite des Icons) immer einen Pixel weiter links anzeigst. Das erzeugt den Eindruck einer Animation.

        if (weather_0_id > 800 && weather_0_id < 900) {
          //Cloud anzeigen und wegschieben
          display.clearDisplay(); //Display löschen
          display.drawBitmap(0, 0, clouds, 128, 64, WHITE); //Icon zeichnen...
          display.display(); //...und anzeigen
          digitalWrite(12, LOW); //LED ausschalten, da kein Regen
          delay(2000);
          for (int i = 0; i > -128; i--) { //Das Icon aus dem Display "schieben"
            display.clearDisplay();
            display.drawBitmap(i, 0, clouds, 128, 64, WHITE);
            display.display();
            delay(1);
          }

Es folgen weitere Abfragen per else if{} für die anderen Wetterlagen, die du unten im gesamten Sketch findest.

Jetzt fehlt noch die Anzeige der Temperatur. Auch diese liest du aus den JSON-Daten aus und bringst sie animiert auf dein Display:

//Temperatur anzeigen und animieren
        JsonObject main = doc["main"];
        int main_temp = (int)main["temp"]; // Daten in ein INT umwandeln und in Variable speichern
        String temp = String(main_temp) + " C"; //C für Celsius anhängen
        display.setTextSize(3); //Schriftgröße erhöhen
        display.setCursor(25, 20);
        display.println(temp);
        display.display();
        delay(2000);
        for (int i = 25; i > -144; i--) { //Animation
          display.clearDisplay();
          display.setCursor(i, 20);
          display.println(temp);
          display.display();
          delay(1);
        }

Zuletzt setzt du die Schriftgröße wieder auf 1 und schließt alle offenen Klammern. Das allerletzte else bezieht sich auf die Abfrage, ob die Antwort des Servers positiv (also 200) war und gibt eine Fehlermeldung zurück, falls das nicht so war.

Hier nun der vollständige Sketch. Wenn du ihn kopierst und verwendest, achte unbedingt darauf, deine eigenen WLAN-Daten und deinen API key von Openweather in die markierten Stellen einzutragen.

Wie geht es weiter?

Du hast jetzt ein Gerät gebaut, das dich an deinen Regenschirm erinnert. Integriere es in eine Box und versorge den ESP8266 zum Beispiel mit einer Powerbank über USB mit Strom. Diese Box kannst du in der Nähe deiner Wohnungstür platzieren, damit dich dein Projekt genau im richtigen Moment vor dem Regen draußen warnt.

Du denkst größer und an deinen eigenen Wetter-Server? Dann lerne hier, wie du deinen ESP8266 in einen Web Server verwandelst. Oder wie wäre es mit einer ESP8266 Wetterstation, die Daten auf einem Raspberry Pi sammelt und visualisiert?

Beachte jedoch: Zu 100% kannst du dich leider nicht auf die Wetterdaten aus dem Internet verlassen. Manchmal ist vielleicht ein prüfender Blick aus dem Fenster doch sicherer. 😉

]]>
Ein TFT-Display am Arduino anschließen https://polluxlabs.net/arduino-tutorials/ein-tft-display-am-arduino-anschliessen/ Wed, 13 Nov 2019 21:03:47 +0000 https://polluxlabs.net/?p=381 Ein TFT-Display am Arduino anschließen Weiterlesen »

]]>
Wenn dir LCD zu langweilig wird, oder dein Projekt ein Farbdisplay erfordert, wird es Zeit für ein TFT-Display!

Hier lernst du, wie du ein kleines, günstiges SPI-Display richtig mit deinem Arduino verbindest und etwas darauf anzeigen lassen kannst.

Hinweis: Dieses kleine Tutorial folgt weitestgehend dieser Anleitung auf randomnerdtutorials.com

Der richtige Anschluss

Das hier verwendete TFT-Display* hat 8 Pins, die du mit deinem Arduino Uno verbinden musst. Folge hierbei dem folgenden Plan:

Pin am TFT-DisplayPin am Arduino
LED3.3 V
SCK 13
SDA11
A0 oder DC9
RESET8
CS 10
GNDGND
VCC 5 V

Wenn du ein anderes Arduino-Modell verwendest, benötigst du möglicherweise eine andere Belegung der Pins. In der Dokumentation auf arduino.cc findest du weitere Hinweise.

Rückseite des TFT-Displays
Rückseite des TFT-Displays

Sobald du das Display richtig angeschlossen hast, kann es auch schon mit dem Programmieren losgehen.

Der Code für dein TFT-Display

Zunächst benötigst du zwei Bibliotheken, die du einbinden musst. Beide sollten bereits in deiner Arduino IDE vorinstalliert sein.

include <TFT.h>;
include <SPI.h>;

Die Bibliothek TFT.h benötigst du, um auf dem Display schreiben und zeichnen zu können. SPI.h hingegen ist für die Kommunikation zwischen Arduino und Display zuständig.

Als nächstes definierst du folgende 3 Pins. Anschließend erstellst du eine Instanz der Bibliothek TFT mit dem Namen TFTscreen.

#define cs 10
#define dc 9
#define rst 8

TFT TFTscreen = TFT(cs, dc, rst);

Die Setup-Funktion

Hier rufst du zunächst die Instanz auf, die du gerade erstellt hast.

TFTscreen.begin();

Danach löschst du das Display, indem du seine Hintergrundfarbe auf Schwarz setzt. Die 3 Zahlen in Klammern repräsentieren die RGB-Werte der Hintergrundfarbe – Rot, Grün, Blau. (0, 0, 0) ergibt die Farbe Schwarz. Jeder dieser Zahlen kann einen Wert zwischen 0 und 255 haben – 3x die Null ergibt Schwarz, 3x 255 Weiß. Dazwischen hast du die Möglichkeit von über 16 Millionen Farben. Lerne hier mehr über RGB.

TFTscreen.background(0, 0, 0); 

Zuletzt setzt du die Schriftgröße auf 2. Experimentiere mit größeren und kleineren Zahlen und beobachte die Zeichen auf deinem Display.

TFTscreen.setTextSize(2);

Der Loop

Hier wirst du den guten alten Text “Hello, world!” auf dein Display bringen. Aber nicht nur das, du wirst ihn auch in verschiedenen und zufällig erzeugten Farben anzeigen, um die Möglichkeiten deines Farbdisplays auszunutzen.

Kümmern wir uns zunächst um die zufälligen Farben. Wie du oben gelesen hast, besteht eine RGB-Farbe aus Rot, Grün und Blau. Jede einzelne dieser Farben kann einen Wert zwischen 0 und 255 besitzen. Diesen Wert ermittelst du mit der Funktion random() und weist ihn je einer Variablen zu:

  int redRandom = random(0, 255);
  int greenRandom = random (0, 255);
  int blueRandom = random (0, 255);

Anschließend legst du mit der Funktion TFTscreen.stroke() die per Zufall ermittelte Farbe des Textes fest und schreibst mit TFTscreen.text() in die Mitte des Displays:

TFTscreen.stroke(redRandom, greenRandom, blueRandom);
TFTscreen.text("Hello, World!", 6, 57);

Zu guter Letzt baust du noch einen Delay in den Loop ein, mit dem du die Geschwindigkeit des Farbwechsels bestimmst. Also zum Beispiel alle 200 Millisekunden:

delay(200);

Und das war’s! Wenn du den Code jetzt auf deinen Arduino hochlädst, sollte dein TFT-Display “Hello, World!” in wechselnden Farben anzeigen.

Hier der vollständige Code:

/*
 Rui Santos 
 Complete Project Details https://randomnerdtutorials.com
 */ 

 include <TFT.h>
 include <SPI.h>

 define cs   10
 define dc   9
 define rst  8

 TFT TFTscreen = TFT(cs, dc, rst);

 void setup() {

   TFTscreen.begin();
 
   TFTscreen.background(0, 0, 0);

   TFTscreen.setTextSize(2);
 }

 void loop() {

   int redRandom = random(0, 255);
   int greenRandom = random (0, 255);
   int blueRandom = random (0, 255);

   TFTscreen.stroke(redRandom, greenRandom, blueRandom);

   TFTscreen.text("Hello, World!", 6, 57);

   delay(200);
 }

Wie geht es weiter?

Weiter Anleitungen zu Bauteilen und vollständige Arduino Projekte findest du in unserem Buch für angehende Maker:

Du kannst nicht nur Text aufs Display bringen, sondern darauf auch zeichnen. Hierfür gibt es in der TFT-Bibliothek bereits Funktionen für Quadrate, Kreise, Rechtecke und so weiter. Auch die große Anzahl an Farben kannst du nutzen – mit einem Farbsensor kannst du Farben erkennen und sie auf dem TFT-Display anzeigen.

Viele Displays haben auch bereits einen SD-Kartenleser auf der Rückseite. Auf die SD-Karte kannst du zum Beispiel Fotos speichern und sie auf dem Display anzeigen lassen – auch hierfür findest du in der TFT-Bibliothek bereits eine fertige Funktion, die du verwenden kannst.

Doch lieber LCD? Lerne hier, wie du ein LCD-Display am Arduino anschließt.

Fehlen dir noch Bauteile? Dann wirf einen Blick in unsere Übersicht der besten Arduino Starter Kits.

]]>