Digitales Prototyping: Raspberry Pi: GPIO, Motion, Teensy / 2022-06-19 / Matthias Edler-Golla, CC BY-SA 4.0



Themen heute

Raspberry Pi

  • Foto mit Hardware-Button machen
  • Foto mit Bewegungsmelder machen
  • Foto mit Ultraschall-Abstandsmesser machen
  • Bei Knopfdruck einen zufälligen Sound abspielen
  • Motion: Livestream der Kamera
  • Livestream innerhalb einer Website
  • Chromium fullscreen starten
  • Keyboard Hacking
  • Teensy Microcontroller
  • Mit Teensy die Tastatur simulieren
  • Abstandwerte via Keyboard-Simulation übertragen

Foto mit Hardware-Button machen

Sobald der Button gedrückt ist, wird ein Foto gemacht. Es reicht auch, wenn man zwei Kabel zusammenhält…

Damit habt Ihr sehr viele Möglichkeiten, Fotos auszulösen:

  • Ein Brett, auf das man tritt
  • Eine Tür, die sich schliesst

Aufbau

Erstellen des Codes

# Python-Sketch an der richtigen Stelle erstellen
nano /home/pi/bin/camera_button.py

Python

# https://gpiozero.readthedocs.io/en/stable/recipes.html#button
# https://github.com/nikrawlinson/timelapse

# Macht ein Foto, wenn ein Button gedrückt wird
# es geht auch, wenn man die 2 Kabel "kurzschliesst", 
# also die Enden zusammenhaelt!

import time
import os
from datetime import datetime
from gpiozero import Button
from signal import pause
from picamera import PiCamera

def fotoMachen():

    # Zeitstempel erstellen
    uhrzeitDatum = datetime.now()
    zeitstempel = uhrzeitDatum.strftime("%y-%m-%d-%H-%M-%S")

    # Benamung, Typ und Speicherort des Bildes
    name = "-foto-1024x768"
    pfad = "/home/pi/Austausch/"
    dateiendung = ".jpg"
    dateiname = pfad + zeitstempel + name + dateiendung

    camera = PiCamera()

    # Größe des Bildes in Pixel
    camera.resolution = (1024, 768)

    # 1 Sekunde Verzoegerung, bevor das Foto gemacht wird - nicht unbedingt noetig!
    time.sleep(1)
    camera.capture(dateiname)
    camera.close()

    meldung = "Foto gemacht!"
    print(zeitstempel + ": " + meldung)

# GPIO-PIN-2: siehe Abbildung!
# Ein Kabel bei PIN2, das andere bei GROUND
button = Button(2)

button.when_pressed = fotoMachen

# aus der Library "signal"
# Cause the process to sleep until a signal is received;
pause()

Code manuell starten

# Python starten
python3 /home/pi/bin/camera_button.py

Automatisches Starten des Codes

geschieht jeweils beim Neustart des Raspsi…

crontab -e öffnen

crontab -e

folgendes dort eintragen

# via python3 und den 2 Kabeln Fotos aufnehmen
@reboot python3 /home/pi/bin/camera_button.py &

Danach den Raspi neustarten, damit das Script camera_button.py aktiviert wird!

PS: Das Script speichert die Datei bei /home/pi/Austausch/. Dieser Ordner ist als Austausch-Server via Samba festgelegt und sollte direkt an Eurem Mac/PC auftauchen, wenn Ihr Euch im gleichen Wlan befindet. Siehe dazu mein damaliges Script…


Foto mit Bewegungsmelder machen

Der Bewegungsmelder macht ein Foto, sobald dieser eine Bewegung bemerkt…

MagPi Magazin

Ganz viel des Beispiels habe ich aus dem Artikel „Turn Your Photos Into Time-Lapse Videos“ im MagPi Magazin 118! Ihr könnt Euch dieses hier kostenlos herunterladen…

Verkabelung

Achtung

Da können ganz schön viele Bilder zusammenkommen. Da macht es wahrscheinlich Sinn, einen USB-Stick einzubinden und die Bilder dort zu speichern…

Python

# https://github.com/nikrawlinson/timelapse
# https://projects.raspberrypi.org/en/projects/getting-started-with-picamera

import time
import os
from datetime import datetime
from gpiozero import MotionSensor
from picamera import PiCamera

# Sensor an GPIO-Pin 4
pir = MotionSensor(4)

def thegrab():
    thetime = datetime.now()
    detectiontime = thetime.strftime("%y-%m-%d-%H-%M-%S")

    # Meldung nur sichtbar, wenn man das Script direkt via Command-Zeile startet
    # python3 /home/pi/bin/python/timelapse.py
    meldung = ": Motion detected!"
    print(detectiontime + meldung)

    # Benamung, Typ und Speicherort des Bildes
    name = "_bewegung_1200x1024"
    # Ablageort der Bilder
    pfad = "/home/pi/Austausch/"
    extension = ".jpg"
    # zusammenbau der Variablen
    filename = pfad + detectiontime + name + extension

    camera = PiCamera()

    # Größe des Bildes in Pixel
    camera.resolution = (1200, 1024)

    time.sleep(2)
    camera.capture(filename)
    camera.close()

while True:
    # Bewegungsmelder wartet, dass er Bewebung entdeckt
    pir.wait_for_motion()
    # Funktion "thegrap()" wird ausgeführt
    thegrab()
    time.sleep(30)

Speichern des Python-Codes

Speichert den Python-Code „timelapse.py“ an folgender Stelle:

nano /home/pi/bin/timelapse.py

Manuelles Starten des Codes

python3 /home/pi/bin/timelapse.py

Automatisches Starten des Codes

geschieht jeweils beim Neustart des Raspsi…

crontab -e öffnen

crontab -e

folgendes dort eintragen

# via python3 und dem PIR-Sensor Fotos aufnehmen
@reboot python3 /home/pi/bin/python/timelapse.py &

Danach den Raspi neustarten, damit das Script timelapse.py aktiviert wird!

PS: Das Script speichert die Datei bei /home/pi/Austausch/. Dieser Ordner ist als Austausch-Server via Samba festgelegt und sollte direkt an Eurem Mac/PC auftauchen, wenn Ihr Euch im gleichen Wlan befindet. Siehe dazu mein damaliges Script…


Foto mit Ultraschall-Abstandsmesser machen

Der Ultraschall-Abstandsmesser löst ein Foto aus, wenn jemand näher als einen festgelegten Abstand kommt…

Aufbau

Anordnung der GPIO-Pins

Python

# https://gpiozero.readthedocs.io/en/stable/recipes.html#distance-sensor
# https://tutorials-raspberrypi.de/entfernung-messen-mit-ultraschallsensor-hc-sr04/

import RPi.GPIO as GPIO
import time
import os
from datetime import datetime
from gpiozero import MotionSensor
from picamera import PiCamera

#GPIO Modus (BOARD / BCM)
GPIO.setmode(GPIO.BCM)

#GPIO Pins zuweisen
GPIO_TRIGGER = 18
GPIO_ECHO = 24

#Richtung der GPIO-Pins festlegen (IN / OUT)
GPIO.setup(GPIO_TRIGGER, GPIO.OUT)
GPIO.setup(GPIO_ECHO, GPIO.IN)

# weitgehend identisch mit dem Code von "camera_button.py"
def fotoMachen():

    # Zeitstempel erstellen
    uhrzeitDatum = datetime.now()
    zeitstempel = uhrzeitDatum.strftime("%y-%m-%d-%H-%M-%S")

    # Benamung, Typ und Speicherort des Bildes
    name = "-foto-1024x768"
    pfad = "/home/pi/Austausch/"
    dateiendung = ".jpg"
    dateiname = pfad + zeitstempel + name + dateiendung

    camera = PiCamera()

    # Groesse des Bildes in Pixel
    camera.resolution = (1024, 768)

    # kurze Verzoegerung, bevor das Foto gemacht wird - nicht unbedingt noetig!
    time.sleep(0.3)
    camera.capture(dateiname)
    camera.close()

    meldung = "Foto gemacht!"
    print(zeitstempel + ": " + meldung)

def distanz():
    # setze Trigger auf HIGH
    GPIO.output(GPIO_TRIGGER, True)

    # setze Trigger nach 0.01ms aus LOW
    time.sleep(0.00001)
    GPIO.output(GPIO_TRIGGER, False)

    StartZeit = time.time()
    StopZeit = time.time()

    # speichere Startzeit
    while GPIO.input(GPIO_ECHO) == 0:
        StartZeit = time.time()

    # speichere Ankunftszeit
    while GPIO.input(GPIO_ECHO) == 1:
        StopZeit = time.time()

    # Zeit Differenz zwischen Start und Ankunft
    TimeElapsed = StopZeit - StartZeit
    # mit der Schallgeschwindigkeit (34300 cm/s) multiplizieren
    # und durch 2 teilen, da hin und zurueck
    distanz = (TimeElapsed * 34300) / 2

    # hier den gewuenschten Abstand festlegen,
    # ab wann ein Foto gemacht werden soll
    # aktuell sind es 30cm
    if distanz < 30:
        print("kleiner Abstand")
        # Aufruf der Funktion "fotoMachen()"
        fotoMachen()

    # gibt den akt. Abstand im Terminal aus
    # wenn nicht gewünscht, auskommentieren
    return distanz

try:
    while True:
        abstand = distanz()
        print ("Gemessene Entfernung = %.1f cm" % abstand)
        time.sleep(0.3)

    # Beim Abbruch durch STRG+C resetten
except KeyboardInterrupt:
    print("Messung vom User gestoppt")
    GPIO.cleanup()

Speichern des Python-Codes

Speichert den Python-Code „ultraschall_abstand_foto.py“ an folgender Stelle:

nano /home/pi/bin/ultraschall_abstand_foto.py

Manuelles Starten des Codes

python3 /home/pi/bin/ultraschall_abstand_foto.py

Automatisches Starten des Codes

geschieht jeweils beim Neustart des Raspsi…

crontab -e öffnen

crontab -e

folgendes dort eintragen

# via python3 und dem Ultraschall-Abstandsmesser Fotos aufnehmen
@reboot python3 /home/pi/bin/python/ultraschall_abstand_foto.py &

Danach den Raspi neustarten, damit das Script timelapse.py aktiviert wird!

PS: Das Script speichert die Datei bei /home/pi/Austausch/. Dieser Ordner ist als Austausch-Server via Samba festgelegt und sollte direkt an Eurem Mac/PC auftauchen, wenn Ihr Euch im gleichen Wlan befindet. Siehe dazu mein damaliges Script…

Für weitere Details siehe:


Bei Knopfdruck einen zufälligen Sound abspielen

Jedesmal wenn man den Knopf drückt (oder die Kabel kurzschließt), wird ein zufällig ausgewählter Sound abgespielt

Vorbereitung

Schliesst am Raspi einen Aktiv-Lautsprecher oder einen Kopfhörer an.

Damit Ihr Sounds hören könnt, müsst Ihr am Raspi die Lautstärke einstellen – dazu den Alsamixer starten und mit den senkrechten Pfeiltasten auf Eurer Tastatur die Lautstärke wie gewünscht einstellen.

alsamixer

Sound-Dateien

Es funktionieren hierbei nur Sounds, die als .wav-Dateien abgespeichert sind!

  • birds.wav
  • dogs.wav
  • horses.wav

Tip: Bei freesound.org könnt Ihr kostenlos viele Sounds herunterladen…

Sound probeweise abspielen

Gebt folgendes ein, um probeweise einen Sound abzuspielen und den Lautsprecher zu testen:

aplay /home/pi/Austausch/sounds/bird.wav*

* Hier richtigen Namen und Pfad eingeben!

Mit aplay könnt Ihr einiges mehr machen, hier findet Ihr die Optionen

# hat viele Optionen:
aplay -h

Speichert die Sounds bei Austausch – dann könnt Ihr diese direkt zwischen Raspi und MAC/PC austauschen, wenn Ihr Euch im gleichen Wlan-Netz befindet…

# Speicherort für die Sound-Dateien
/home/pi/Austausch/sounds/

Aufbau

wie bei Foto mit Hardware-Button machen

  • GPIO-PIN-2: siehe Abbildung!
  • Ein Kabel bei PIN2, das andere bei GROUND

Python

# https://pynative.com/python-random-choice/
# https://learn.sparkfun.com/tutorials/python-programming-tutorial-getting-started-with-the-raspberry-pi/experiment-2-play-sounds
# spielt zufällig einen Sound aus einer Liste ab

import time
import RPi.GPIO as GPIO
from pygame import mixer

import random

def zufallsSound():
    # liste der sounds ohne Dateiendung!
    # keine Sonderzeichen, keine Leerraeume!
    sounds_list = ['applause-1','barkingDogs','bird','carEngine','modemDial']

    # hiermit wird zufaellig eine Sounddatei aus der Liste ausgewaehlt
    randomSound = random.choice(sounds_list)

    # Speicherort der Dateien
    pfad = '/home/pi/Auswahl/sounds/'
    endung = '.wav'

    # Zusammenbau 
    mySound = pfad + randomSound + endung

    # globale Variable, sonst geht es nicht!
    global ton 
    ton = mixer.Sound(mySound)

    # Ausgabe im Terminal
    print(mySound)

    # Der Sound "ton" wird abgespielt
    ton.play()

# An welchem GPIO-Pin haengt der Button?
btn_pin = 2

# Set up pins
GPIO.setmode(GPIO.BCM)
GPIO.setup(btn_pin, GPIO.IN)

# Initialize pygame mixer
mixer.init()

# Remember the current and previous button states
current_state = True
prev_state = True

# If button is pushed, play sound
try:
    while True:
        current_state = GPIO.input(btn_pin)
        if (current_state == False) and (prev_state == True):
            # https://stackoverflow.com/questions/54444765/check-if-a-pygame-mixer-channel-is-playing-a-sound
            # solange der Sound laeuft, kann kein neuer Sound ausgewaehlt werden!
            if mixer.Channel(0).get_busy() == True:
                print("Sound spielt gerade")
            else:
                zufallsSound()
        prev_state = current_state

# When you press ctrl+c, this will be called
finally:
    GPIO.cleanup()

Speichern des Python-Codes

Speichert den Python-Code „random_sound.py“ an folgender Stelle:

nano /home/pi/bin/random_sound.py

Manuelles Starten des Codes

python3 /home/pi/bin/random_sound.py

Automatisches Starten des Codes

geschieht jeweils beim Neustart des Raspsi…

crontab -e öffnen

crontab -e

folgendes dort eintragen

# via python3 und einem Button zufaellig Sounds abspielen
@reboot python3 /home/pi/bin/python/random_sound.py &

Danach den Raspi neustarten, damit das Script random_sound.py aktiviert wird! Sobald Ihr jetzt die 2 Kabel kurzschliesst und Eurer Lautsprächer an ist, sollte ein zufälliger Sound ertönen…


Motion

Meine besten „Wildtieraufnahmen“ mit der Raspi-Kamera…

Motion is a highly configurable program that monitors video signals from many types of cameras. Set it up to monitor your security cameras, watch birds, check in on your pet, create timelapse videos and more.


Motion: Livestream der Kamera

Anschließen der Kamera

Bitte beachtet beim Anschliessen der Kamera, dass der Raspi ausgeschaltet ist! Ein detaillierte Anweisung zum Anschließen findet Ihr im letzten Script.

Motion

Mit Motion könnt Ihr die Kamera des Raspis nutzen, um live Videos zu streamen!

Starten von Motion

sudo motion

Anhalten von Motion

sudo killall motion

Ansehen des Livestreams

Ihr könnt Euch den Livestream direkt im Browser ansehen:

http://fk12pi-a.local:8081
http://fk12pi-b.local:8081
http://fk12pi-c.local:8081
http://fk12pi-d.local:8081

und local auf dem Raspi mit Desktop/Chromium

localhost:8081

Die eigenartige Endung :8081 ist der „Port“, auf dem die Kamera ihr Bild live streamt – auch dies kann man individuell einstellen…

andere Livestreams

Wenn die anderen auch Motion gestartet haben, könnt Ihr Euch deren Livestream ebenfalls im Browser ansehen, dazu einfach die URL ändern…


Livestream innerhalb einer Website

Der Live-Stream von Motion kann wie ein „normales“ Bild in einer HTML-Datei eingebunden werden:

Achtung: Motion muss dafür natürlich gestartet werden!

sudo motion

Einbinden des Livestreams innerhalb eines HTML-Dokumentes

Den Motion-Livestream könnte Ihr – wie ein „normales“ Bild – direkt im HTML-Code einbinden:

<!-- hier die richtige Adresse angeben! -->
<img src="http://fk12pi-a.local:8081" alt="Livestream Kamera">

Das komplette HTML-Dokument könnte dann so aussehen:

HTML

<!DOCTYPE html>
<html>
  <head>
    <title>Livestream Kamera</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta charset="utf-8" />
    <style>
        body {font-family:Verdana,sans-serif;}
        img {width:100%;height:auto;}
        main {width:90%;max-width:1024px;margin:3% auto;}
        h1 {font-weight:normal;font-size:100%;}
    </style>
  </head>
  <body>
    <main>
        <!-- Anpassen -->
        <h1>Livestream Kamera fk12pi-a</h1>

        <!-- hier die richtige Adresse angeben! -->
        <img src="http://fk12pi-a.local:8081" alt="Livestream Kamera">
    </main>
  </body>
</html>

Übung

Probiert es doch selber mal aus! Erzeugt direkt auf dem Raspi im Ordner /var/www/html/ eine Datei demo-motion.html und fügt das oben gezeigte HTML dort ein – richtige URL Eures Raspis nicht vergessen…

cd /var/www/html/ && nano demo-motion.html

Browser-Ansicht

Anschliessend könnt Ihr im Browser schauen, ob es geklappt hat – auch hier die richtige Adresse angeben:

http://fk12pi-a.local/demo-motion.html
http://fk12pi-b.local/demo-motion.html
http://fk12pi-c.local/demo-motion.html

und wie immer local:

localhost/demo-motion.html

Motion konfigurieren

Motion hat eine sehr umfangreiche Konfigurationsdatei, in der Ihr sehr viele Aspekte von Motion einstellen könnt!

Falls Ihr etwas neu konfigurieren möchet: Bitte erstellt zuerst eine Sicherungskopie der exist. Datei, bevor Ihr daran etwas ändert!

Original-Datei als Kopie speichern

sudo cp /etc/motion/motion.conf /etc/motion/motion_ORIGINAL.conf

Config-Datei mit Nano editieren

sudo nano /etc/motion/motion.conf

Lest Euch in den Kommentaren inmnerhalb der Datei motion.conf durch, was alles möglich ist – hier ein paar wichtige Einstellungen zusammengefasst:

# folgende Einstellung solltet Ihr noch machen, damit das Terminal für andere Sachen "frei" wird
# habe ich vergessen, einzuschalten…
# Start in daemon (background) mode and release terminal (default: off)
daemon on

# Rotate image this number of degrees. The rotation affects all saved images as
# well as movies. Valid values: 0 (default = no rotation), 90, 180 and 270.
rotate 0

# Image width (pixels). Valid range: Camera dependent, default: 320
# Breite des Bildes, max. gehen 3280px, aber das wird SEHR langsam
width 1024

# Image height (pixels). Valid range: Camera dependent, default: 240
# Höhe des Bildes, max. gehen 2464px, aber das wird SEHR langsam
height 768

# Maximum number of frames to be captured per second.
# Valid range: 2-100. Default: 100 (almost no limit).
# mehr schafft der Raspi meist nicht
framerate 15

# Threshold for number of changed pixels in an image that
# triggers motion detection (default: 1500)
# wenn sich 1500px von einem Bild auf das nächste ändern,
# wird z.B. ein Standfoto aufgenommen
# kleiner Wert = Motion wird sensibler für Veränderungen
threshold 1500

# Event Gap is the seconds of no motion detection that triggers the end of an event.
# An event is defined as a series of motion images taken within a short timeframe.
# Recommended value is 60 seconds (Default). The value -1 is allowed and disables
# events causing all Motion to be written to one single movie file and no pre_capture.
# If set to 0, motion is running in gapless mode. Movies don't have gaps anymore. An
# event ends right after no more motion is detected and post_capture is over.
# verkürzt die Zeit, wenn Ihr häufiger Bilder von Events machen möchtet
# so "pausiert" Motion erst mal 60sek, nachdem sich ein Event ereignet hat…
event_gap 60

# Output 'normal' pictures when motion is detected (default: off)
# Valid values: on, off, first, best, center
# When set to 'first', only the first picture of an event is saved.
# Picture with most motion of an event is saved when set to 'best'.
# Picture with motion nearest center of picture is saved when set to 'center'.
# Can be used as preview shot for the corresponding movie.
# meine Einstellung ist "best", erzeugt eine vernünftige Anzahl von Standfotos von Events
# probiert die Einstellungen aus, teilweise entstehen sehr viele Fotos ohne Mehrwert…
output_pictures best

# The quality (in percent) to be used by the jpeg and webp compression (default: 75)
# Qualität des aufgenommenen Shots
quality 75

# Use ffmpeg to encode videos of motion (default: off)
# keine Filme speichern, sonst würden kurze Filmausschnitte des Events gespeichert
ffmpeg_output_movies off

# Make automated snapshot every N seconds (default: 0 = disabled)
# Motion kann regelmäßig ein Foto machen, auch wenn keine Bewegung erkannt wird
snapshot_interval 0

# Locate and draw a box around the moving object.
# Valid values: on, off, preview (default: off)
# Set to 'preview' will only draw a box in preview_shot pictures.
# zeichnet z.B. einen roten Rahmen um den Bereich, wo Bewegung erkannt wird
locate_motion_mode off

# Target base directory for pictures and films
# Recommended to use absolute path. (Default: current working directory)
# wichtige Einstellung, die festlegt, wohin die Shots gespeichert werden
# hier liegt der Ordner so, dass man auf die Bilder via Webserver online zugreifen kann
target_dir /var/www/html/motion/

# File path for motion triggered images (jpeg, ppm or .webp) relative to target_dir
# Default: %v-%Y%m%d%H%M%S-%q
# Default value is equivalent to legacy oldlayout option
# For Motion 3.0 compatible mode choose: %Y/%m/%d/%H/%M/%S-%q
# File extension .jpg, .ppm or .webp is automatically added so do not include this
# Set to 'preview' together with best-preview feature enables special naming
# convention for preview shots. See motion guide for details
# Einstellung, wie Bilder gespeicher werden: 
# Diese erhalten Datum und Uhrzeit in den Dateinamen
picture_filename %v-%Y%m%d%H%M%S-%q

# The mini-http server listens to this port for requests (default: 0 = disabled)
# wichtige Einstellung, legt fest, auf welchem "Port" Motion den Live-Stream "verschickt"
# hier Port 8081 – siehe URL im Browser…
stream_port 8081

# Maximum framerate for stream streams (default: 1)
# sollte gleichen Wert haben wie normale framerate (weiter oben)
stream_maxrate 15

# Restrict stream connections to localhost only (default: on)
# muss "off" sein, sonst kann man den Stream nicht von einem anderen Rechner aus sehen!
stream_localhost off

Um diese Einstellungen in Nano zu finden, könnt ich mit ctrl + w nach einem Begriff suchen…

Motion neustarten

Damit Eure Änderungen wirksam werden, müsst Ihr Motion neustarten

sudo killall motion && sudo motion

Chromium fullscreen starten

Startet man den Browser Chromium fullscreen, wird der Inhalt des Browserfensters bildschirmfüllend angezeigt – alle Buttons, die Adressleiste usw. werden komplett ausgeblendet.

Locale Dateien anzeigen

bitte schaut Euch dazu den Punkt Webserver des Raspis verwenden an!

Chromium via Terminal starten

das geht auch via SSH!

# locale Website
chromium-browser --display=:0 --kiosk http://localhost

# Süddeutsche Zeitung
chromium-browser --display=:0 --kiosk http://sz.de

Zum Beenden des Browser ctrl c eingeben…

Chromium automatisch bei jedem Neustart starten

das muss wieder bei crontab -e gemacht werden

crontab -e

dort folgendes eingeben

@reboot chromium-browser --display=:0 --kiosk http://localhost

# oder z.B.
@reboot chromium-browser --display=:0 --kiosk http://sz.de

dann den Raspi neustarten.

Nach kurzer Zeit wird auf dem Monitor, der direkt am Raspi angeschlossen ist, die gewünschte Website fullscreen angezeigt.

Habt Ihr eine Tastatur direkt am Raspi angeschlossen, könnt Ihr mit alt F4 Chromium beenden.


Keyboard Hacking

Eine alte Tastatur kann gut so „gehackt“ werden, dass diese als innovatives Eingabemedium genutzt werden kann!

Der angeschlossene Computer denkt dann immer noch, dass es sich um eine Tastatur handelt…


Teensy Microcontroller

https://www.pjrc.com/store/teensylc.html

Teensy ist ein „Arduino Derivat“ mit einigen zusätzlichen Möglichkeiten: Man kann damit z.B. Keyboard-Events simulieren – d.h. der PC/Mac „denkt“, dass der Mircocontroller eine Tastatur ist. Das ist oft super praktisch!


Teensy mit der Arduino IDE verwenden

Um die Teensy Boards mit der Arduino IDE nutzen zu können, müsst Ihr zuerst Teensy-spezifische Software installieren:

Schritt 1

Folgenden Code bei Arduino IDE>Prefences einfügen:

https://www.pjrc.com/teensy/package_teensy_index.json

Schritt 2

  1. Auf der linken Seite der Arduino IDE den Board Manager anklicken
  2. Dort im Suchfeld teensy eingeben
  3. Auf INSTALL drücken

Weiterführendes

https://www.pjrc.com/teensy/first_use.html


Teensy Board und Port auswählen

Wie bei den Arduino-Boards auch, muss man auch bei den Teensys das richtige Board und den richtigen Port auswählen, bevor man Daten übertragen kann.

Board auswählen

Port auswählen


Mit Teensy die Tastatur simulieren

Um mit dem Teensy ein Keyboard zu simulieren, muss dieses ausgewählt sein!


Mit Teensy Buchschraben schreiben

Der Teensy ist hier an einen Raspberry Pi angeschlossen, es geht aber genauso mit einem Mac oder PC!

Folgender Code gibt die Buchstaben "j", "l" oder "u" aus, sobald eines der Kabel-Enden berührt wird:

Achtung

Passt auf, dass Ihr z.B. ein leeres Text-Dokument geöffnet habt, bevor Ihr die Kabel-Enden berührt, sonst werden die Buchstaben vielleicht an Stellen eingetippt, die Ihr gar nicht möchtet!

Arduino

// http://little-scale.blogspot.com/2017/05/teensy-36-basics-touchread.html
// wenn die Werte hoch sind, soll dem Computer ein Keyboard.print-Event
// geschickt werden, der dann z.B. auf einer Website eine Veränderung via Javascript auslöst

// WICHTIG! You must select Keyboard from the "Tools > USB Type" menu!

// die eingebaute LED
const int ledPin = 13;

// ausprobieren, evtl. anpassen
// wird dieser Wert überschritten, wird der jeweilige Keyboard-Event ausgelöst
const int grenzWert = 3000;

// Hier nachsehen, wo die Kabel eingesteckt werden sollen
// PIN-Layout: https://www.pjrc.com/teensy/card6a_rev4_web.pdf

int touchRead_pin_1 = 0;   // Pin 0, Ausgabe von 'j'
int touchRead_pin_2 = 23;  // Pin 23, Ausgabe von 'u'
int touchRead_pin_3 = 16;  // Pin 16, Ausgabe von 'l' (loeschen)

int data;

void setup() {
  Serial.begin(57600);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // Buchstaben mit Single-Quotes angeben!
  // hier könnten beliebig viele pin_auslese_Events festgelegt werden
  // der Teensy LC hat 11 Touch-Pins
  pin_auslesen(touchRead_pin_1, 'j');
  pin_auslesen(touchRead_pin_2, 'u');
  pin_auslesen(touchRead_pin_3, 'l');

  // nicht zu kurze Pause einbauen!
  delay(200);
}

// geht der Kapazitätswert des jeweiligen Pins über den festgelegten Grenzwert
// wird der jeweils gewünschte Buchstabe via "Keyboard" versendet
void pin_auslesen(int welchePin, char buchstabe) {
  data = touchRead(welchePin);

  // Ausgabe des Kapazitätswertes, der ständig gemessen wird
  // fürs Funktionieren der Buchstabenausgabe nicht nötig
  // nur zur Kontrolle, hiermit werden die Pins einzeln angezeigt und ausgegeben
  Serial.print("Pin ");
  Serial.print(welchePin);
  Serial.print(", Kapazitätswert: ");
  Serial.println(data);

  if (data > grenzWert) {
    // nicht nötig, zeigt aber, wenn Kapazitäts-Grenzwert überschritten ist
    // und ein Buchstabe geschickt wird
    digitalWrite(ledPin, HIGH);

    // Ausgabe im Serial-Monitor, auch optional
    Serial.print("Buchstabe: ");
    Serial.println(buchstabe);

    Keyboard.println(buchstabe);
  } else {
    digitalWrite(ledPin, LOW);
  }
}

Mit Javascript die Keyboard-Events von Teensy verwenden

Die via Teensy „getippten“ Buchstaben können via Javascript auf einer Website verwendet werden, um z.B. unterschiedliche Bilder zu zeigen

Anwendungsbeispiel

Ihr seid in einer Ausstellung und wenn Ihr eine der Touch-Flächen berührt, zeigt der Monitor eine andere Abbildung…

Demo

Schaut Euch die Demo online an oder ladet Euch den Code zum Ausprobieren herunter!

Wenn Ihr keinen Teensy angeschlossen habt, könnt Ihr die Website auch testen, indem Ihr die Tasten j, l, u auf Eurer Tastatur eingebt!

Arduino

Der Code ist identisch mit dem auf dem vorherigem Slide! Wenn Ihr das Beispiel herunterladet, ist dieser dort auch enthalten…

HTML

[…]
<main>
    <!-- diese <figures> werden via Teensy sichtbar/unsichtbar gemacht -->
    <figure id="kaiser">
        <img src="./p/kaiser.jpg" alt="Wilder Kaiser">
        <figcaption>Wilder Kaiser</figcaption>
    </figure>
    <figure id="simssee">
        <img src="./p/simssee.jpg" alt="Simssee">
        <figcaption>Simssee</figcaption>
    </figure>
    <figure id="tegernsee">
        <img src="./p/tegernsee.jpg" alt="Tegernsee">
        <figcaption>Tegernsee</figcaption>
    </figure>
</main>
[…]

CSS

[…]
/* 
die Elemente sind zuerst komplett unsichtbar (opacity: 0)
und werden dann via Javascript sichtbar gemacht
indem sie jeweils die Klasse "sichtbar" zugeteilt bekommen
*/
main figure {
    opacity: 0;
    transition: .8s all;
}

/* wird via Javascript ein-/ausgeschaltet */
.sichtbar {
    opacity: 1;
}

.sichtbar figcaption {
    transform: translateY(0);
}
[…]

Javascript

// die 3 Figure-Elemente via Javascript ansprechbar machen
const kaiser = document.querySelector('#kaiser');
const simssee = document.querySelector('#simssee');
const tegernsee = document.querySelector('#tegernsee');

// hier die richtigen Buchstaben angeben,
// die Ihr bei "Teensyduino" festgelegt habt
const kaiserButton = 'j';
const simsseeButton = 'u';
const tegernseeButton = 'l';

// erstes Bild soll gleich sichtbar sein
kaiser.classList.add('sichtbar');

// entfernt die Klasse bei dem Element, das gerade noch sichtbar war
// sonst überlagern sich die Bilder und sind nicht sichtbar
function sichtbarkeitWeg() {
    let sichtbar = document.querySelector('.sichtbar');
    sichtbar.classList.remove('sichtbar');
}

// Javascript "lauscht", ob etwas mit der Tastatur gemacht wird
// und Teensy simuliert ja eine Tastatur…
window.addEventListener(
    'keyup',
    function (event) {
        let taste = event.key;
        // console.log(taste);
        if (taste === kaiserButton) {
            sichtbarkeitWeg();
            kaiser.classList.add('sichtbar');
        } else if (taste === simsseeButton) {
            sichtbarkeitWeg();
            simssee.classList.add('sichtbar');
        } else if (taste === tegernseeButton) {
            sichtbarkeitWeg();
            tegernsee.classList.add('sichtbar');
        }
    },
    true
);

Mit Teensy-Buttons zwischen Websites wechseln

Auf einer (lokalen) Website werden jeweils unterschiedliche HTML-Seiten geladen, wenn man einen der Teensy-Buttons betätigt.

Anwendungsbeispiel

Ihr seid in einer Ausstellung und wenn Ihr eine der Touch-Flächen berührt, zeigt der Monitor eine andere Erklärungsseite

Demo

Schaut Euch die Demo online an oder ladet Euch den Code zum Ausprobieren herunter!

Wenn Ihr keinen Teensy angeschlossen habt, könnt Ihr die Website auch testen, indem Ihr die Tasten j, l, u auf Eurer Tastatur eingebt!

Arduino

Der Code ist identisch mit dem auf dem vorherigem Slide! Wenn Ihr das Beispiel herunterladet, ist dieser dort auch enthalten…

Javascript

// wenn eine der 3 Tasten gedrückt wird,
// wird auf die entsprechende HTML-Seite gewechselt
window.addEventListener(
  "keydown",
  function (event) {
    // auf welche Taste wird gerade gedrückt?
    // wie gesagt: Die Tasten simuliert z.B. der Teensy
    let taste = event.key;
    if (taste === "j") {
      window.location.assign("interaction.html");
    } else if (taste === "l") {
      window.location.assign("userexperiencedesign.html");
    } else if (taste === "u") {
      window.location.assign("userinterface.html");
    }
  },
  true
);

Abstandwerte via Keyboard-Simulation übertragen

Die Teensy-Keyboard-Simulation kann man auch verwenden, um Sensordaten in Echtzeit an einen Mac/PC (oder Raspi) zu übertragen.

Hier gezeigt an der Übertragung der Ausgabewerte des schon bekannten Ultraschall-Abstandsmessers

Bitte beachtet für die grundlegenen Einstellungen von Teensy das Beispiel „Keyboard-Events via Teensy auslösen“ (vorherige Seite)!

Vorsichtsmaßnahme

Damit der Teensy nicht sofort anfängt, Werte an den Mac/PC/Raspi zu übertragen, habe ich einen Hardware-Button eingebaut. Erst wenn man auf diesen drückt, fängt die Übertragung an. So kann z.B. erst das Browserfenster (oder eine leeres Texteditor-Datei) in den Focus schieben, bevor die Daten via Keyboard übertragen werden. Drückt man noch mal auf den Knopf, wird die Übertragung wieder gestoppt.

Arduino

// WICHTIG! You must select Keyboard from the "Tools > USB Type" menu!

// ============= ultraschall ===============

#include <NewPing.h>
const int TRIGGER_PIN = 23;
const int ECHO_PIN = 22;
int MAX_DISTANCE = 200;  // bis 200cm Abstand messen
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
int cm = 0;  //Abstand in cm

// ============= led und taste ===============

int led = 13;
int taste = A0;
int tastenZustand = 0;
int ledZustand = -1;  // 1 = led an, -1 = led aus

void setup() {
  pinMode(led, OUTPUT);
  pinMode(taste, INPUT);
}

void loop() {
  // Abfrage, ob Taste gedrückt wurde
  tastenZustand = digitalRead(taste);

  // immer wenn taste gedrück wurde, ändert sich ledZustand…
  if (tastenZustand == HIGH) {
    // bei jedem Betätigen der Taste wird der ledZustand getoggelt
    ledZustand = -ledZustand;
  }

  // nur wenn die LED leuchtet, werden Messungen gemacht!
  if (ledZustand == 1) {
    digitalWrite(led, HIGH);

    delay(100);  // min 29
    cm = sonar.ping_cm();

    // Ausgabe im Serial-Monitor (zur Kontrolle…)
    Serial.print("Ping: ");
    Serial.print(cm);
    Serial.println("cm");

    // Übertragung des Wertes "cm" als Keyboard-Event
    Keyboard.println(cm);

  } else {
    digitalWrite(led, LOW);
  }

  delay(200);
}

Javascript

Javascript „fängt“ die übergebenen Zahlenwerte ab und verwendet diese, um die Breite des roten Balkens damit anzupassen:

    // ===================== Keyboard-Funktionalität =====================

    // Teensy schickt Daten (hier "Ultaschall") an PC
    // dabei simuliert Teensy das Keyboard

    // speichert die Werte, die vom Teensy kommen, in ein Array
    let buffer = [];
    // der TextString aus dem "buffer"-Werten
    let teensyWerte = '';

    // Graph, der die Werte anzeigt
    const teensyGraph = document.querySelector('#teensyGraph');

    // Textausgabe des aktuellen Wertes
    const werte = document.querySelector('#werte');

    window.addEventListener(
        'keydown',
        function (event) {
            let taste = event.key;
            // die Übergabe vom Teensy endet mit einem "ENTER" (neue Zeile)
            // das wird abgefragt und an dieser Stelle wird
            // der Graph aktualisiert und buffer und teensyWerte wieder zurückgesetzt
            if (event.code == 'Enter') {
                for (let i = 0; i < buffer.length; i++) {
                    teensyWerte = teensyWerte + buffer[i];
                }

                // 200 ist max_distance (im Arduino-Sketch festgelegt)
                const max_distance = 200;
                let prozWerte = (teensyWerte / max_distance) * 100;

                // Ausgabe der Prozent-Werte in der Konsole
                // console.log(`${prozWerte}%`);

                teensyGraph.style.width = `${prozWerte}%`;
                werte.textContent = teensyWerte;

                // zurücksetzten der Variablen
                buffer = [];
                teensyWerte = '';
            } else {
                buffer.push(taste);
            }
        },
        true
    );

Online-Demo

Schaut Euch die Demo an oder ladet den Code herunter.


Gemeinsames Abschlussprojekt

FK12-Entdecker: Neue Perspektiven

gemeinsame Aufgabenstellung für die Kurse 403.2 Technisches Design (Prof. Florian Petri) und 403.1 Dig. Prototyping (Prof. Matthias Edler-Golla)

Wendet das in den beiden Kursen erlernte Wissen zu analogem und digitalem Prototyping an, um funktionale Prototypen zu erstellen – baut „FK12-Entdecker“! Die umgesetzten Prototypen ermöglichen es neue Blicke auf die Außen- und Innenräume unserer Fakultät zu werfen und dem Gebäude so manches bisher unentdeckte zu entlocken. Die erzeugten Artefakte können stationär sein, sich aber auch kriechend, fahrend, fliegend (…) fortbewegen. Sie sollen selbstständig Filme, Fotos, Geräusche oder andere Sensor-Daten aufzeichnen, so dass diese nachträglich betrachtet, angehört oder visuell (z.B. als Info-Grafiken) ausgewertet werden können.

Spielregeln

  • Zu konzipieren und umzusetzen sind physische Prototypen der „FK12-Entdecker.“
  • Die funktionalen Prototypen sind in der Lage selbstständig Filme, Fotos, Geräusche oder andere Sensor-Daten im oder rund um das Fakultätsgebäude aufzuzeichnen.
  • Die Prototypen bestehen ausschließlich aus digital zu fertigenden Bauteilen (3D-Druck, CNC-Fräsen, Laser-Cutten) sowie den benötigten elektronischen Bauteilen (Arduinos, Raspberry Pis und Sensoren).
  • Die verwendeten Arduinos, Raspberry Pis und Sensoren müssen so verbaut sein, dass diese wieder schadlos ausgebaut werden können.
  • Alle digital gefertigten Bauteile müssen austauschbar und die Objekte somit reparierbar sein.
  • Teams von max. 3 Leuten.

Am Ende abzugeben

  • Dokumentation, die es anderen ermöglicht, die gezeigten Projekte nachzubauen
  • Verwendeter Code zum Kopieren
  • Dateien zur digitalen Fertigung der Prototypen (z.B. STL-Dateien) auf 3D-Drucker, CNC-Fräse oder Lasercutter
  • Fotos der Objekte
  • Fotos aus der Entwicklungs- und Testphase
  • entstandene Filme, Datenaufzeichnungen etc.

Danke

Alle Scripte durchsuchen

Weitere Vorträge: