# Python-Sketch an der richtigen Stelle erstellen
nano /home/pi/bin/ausschalten.py
Python
# !/bin/python
# Simple script for shutting down the Raspberry Pi at the press of a button.
# by Inderpreet Singh
# https://www2.quartoknows.com/page/raspberry-pi-shutdown-button
import RPi.GPIO as GPIO
import time
import os
# Use the Broadcom SOC Pin numbers
# Setup the pin with internal pullups enabled and pin in reading mode.
GPIO.setmode(GPIO.BCM)
# oberste 2 Pins, direkt neben den USB-Ports
# GPIO 21 und GROUND
GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# Our function on what to do when the button is pressed
def Shutdown(channel):
os.system("sudo shutdown -h now")
# Add our function to execute when the button pressed event happens
GPIO.add_event_detect(21, GPIO.FALLING, callback=Shutdown, bouncetime=2000)
# Now wait!
while 1:
time.sleep(1)
Automatisches Starten des Codes
geschieht jeweils beim Neustart des Raspsi…
crontab -e öffnen
crontab -e
folgendes dort eintragen
# via 2 Kabel den Raspi ausschalten
@reboot python3 /home/pi/bin/ausschalten.py
Danach den Raspi neustarten, damit das Script ausschalten.py aktiviert wird!
Sobald sich jetzt die beiden Kabelende berühren, wird der Raspi ausgeschaltet…
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…
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…
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/
# 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.
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:
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:
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
Ihr könnt dieses Paket auch gerne als Template verwenden, wenn Ihr eigene p5-Sachen erstellen möchtet – die Sachen laufen auch auf Eurem Webserver…
Achtung
Die p5-Anweisung bei "setup()" ist etwas anders als beim p5-Webeditor, weil hier gezielt festlegt wird, wo der p5-Canvas "hingezeichnet" werden soll – nämlich innerhalb des "canvasContainer"…
Ihr müsst also Eure p5-Sketches, die Ihr im Webeditor erstellt habt, etwas anpassen:
p5.js
function setup() {
// Canvas-Element mit dem Namen "meinCanvas" erzeugen
// Breite (hier 900px) und Höhe (400px) festlegen
const meinCanvas = createCanvas(900, 400);
// das Figure-Element mit der ID "canvasContainer" ist das Elternelement
// schaut Euch die dazugehörige "index.html"-Datei an!
meinCanvas.parent('canvasContainer');
// ………
}
HTML
<body>
<!-- … -->
<main>
<!-- hier wird der Canvas via sketch.js eingefügt! -->
<figure id="canvasContainer"></figure>
</main>
<!-- -->
</body>
p5.js auf dem Raspi installiert
Die gerade gezeigte p5.js-Animation ist auch auf Euren Raspis installiert – Ihr könnt sie somit für Eure Bedürfnisse anpassen!
Das Dateiformat CSV steht für englisch Comma-Separated Values und beschreibt den Aufbau einer Textdatei zur Speicherung oder zum Austausch einfach strukturierter Daten. Die Dateinamenserweiterung lautet .csv.
CSV-Dateien sind auch vom Raspi sehr einfach zu erzeugen und dienen uns in den weiteren Schritten dazu, z.B. Sensordaten zu speichern. p5.js wiederum kann CSV-Dateien gut einlesen und visualisieren.
Alle Werte der rot umrandeten Spalte sollen abgefragt werden
Code-Beispiele
// Zeile 0, Eintrag 3
Eintrag = data_log.get(0, 3); // Ergebnis: 354
// Zeile 1, Eintrag 3
Eintrag = data_log.get(1, 3); // Ergebnis: 371
// wenn man alle Einträge der Spalte angezeigt haben möchte
// geht das mit einer for-Schleife…
var anzahl = data_log.getRowCount(); // wieviele Spalten?
for (var i = 0; i < anzahl; i++) {
// geht die Spalte 3 von oben bis unten durch
Eintrag = data_log.get(i, 3);
console.log("Wert: " + Eintrag); // gibt die Werte in der Konsole des Browsers aus
}
Javascript Arrays
Bitte schaut Euch diesen Film an!
Ein Javascript Array ist eine Datenstruktur, die mehrere Werte unter einem gemeinsamen Namen speichert. Auf diese Werte kann mit einem ganzzahligen Index zugegriffen werden. Die Reihenfolge der hinterlegten Daten wird durch deren Position im Array bestimmt.
Arrays kommen in praktisch allen Programmiersprachen vor und ermöglichen es z.B. viele einzelne Werte in einer einzigen Variable abzuspeichern.
Bei dem Beispiel mit den Helligkeitswerten verwenden wir Arrays, um die in der CSV-Datei abgespeicherten Werte so in p5.js zu „importieren“, dass man damit arbeiten kann.
p5.js
let data_log;
let hPunkte = []; // das Array der Helligkeitspunkte
function preload() {
data_log = loadTable("data_log.csv");
}
function setup() {
// liest alle Helligkeitswerte in das Array ein
// diese befinden sich in jeder Zeile an der 4. Stelle
// z.B. "2019-05-27,10:30:01,Helligkeit,144"
// da hier bei Null angefangen wird zu zählen, hier "3" verwenden
for (let i = 0; i < anzahl; i++) {
hPunkte[i] = data_log.getNum(i, 3);
}
// nächste Zeile gibt das in der Console aus
// was im Screenshot unten zu sehen ist
console.log(hPunkte);
}
Ausgabe in der Console
CSV-Werte in p5.js einlesen
Das macht noch nicht viel her, zeigt aber, wie man eine CSV-Datei in p5.js importieren und von dort einzelne Werte auslesen kann…
let data_log;
function preload() {
// einlesen der Werte in die Variable "data_log"
// Relative Pfade beachten!
data_log = loadTable("data_log.csv");
}
function setup() {
// …
// ======== 1 =========
// Text-Ausgabe des Wertes der Zelle (0,0)
text("1) Die Zelle an Stelle (0,0) hat folgenden Inhalt: " + data_log.get(0, 0), 24, 60);
// ======== 2 =========
// Text-Ausgabe des Wertes der Zelle (13,1)
text("2) Die Zelle an Stelle (13,1) hat folgenden Inhalt: " + data_log.get(13, 1), 24, 80);
// ======== 3 =========
// Text-Ausgabe des Wertes der Zelle (19,3)
text("3) Die Zelle an Stelle (19,3) hat folgenden Inhalt: " + data_log.get(19, 3), 24, 100);
// ======== 4 =========
text("4) Auflistung der ersten 15 Werte der 4. Spalte:", 550, 30);
// liest die ersten 15 Helligkeitswerte aus;
// diese befinden sich in jeder Zeile an der 4. Stelle
for (let i = 0; i < 15; i++) {
text(data_log.getNum(i, 3), 550, 60 + 20 * i);
}
}
CSV-Datei einlesen und einzelne Werte darstellen
Hier werden ausgewählte Helligkeitswerte, die in der Datei data_log.csv enthalten sind, als Balken dargestellt.
let data_log;
let hPunkte = []; // das Array der Helligkeitspunkte
function preload() {
data_log = loadTable('data_log.csv');
}
function setup() {
// …
// wieviele Zeilen enthält die Datei "data_log.csv"
let anzahl = data_log.getRowCount();
// liest alle Helligkeitswerte in das Array ein
// diese befinden sich in jeder Zeile an der 4. Stelle
// z.B. "2019-05-27,10:30:01,Helligkeit,144"
// da hier bei Null angefangen wird zu zählen, hier "3" verwenden
for (let i = 0; i < anzahl; i++) {
hPunkte[i] = data_log.getNum(i, 3);
}
let b = 220; // Breite des Rechtecks
let a = b + 10; // Abstand der Rechtecke
// ==== Rechtecke, bei dem die Höhe dem Wert des jeweiligen Eintrags bei hPunkte entspricht ===
// Rechteck mit Wert des Eintrags 0
fill(255, 0, 0);
rect(18, 50, b, hPunkte[0]);
// Text-Ausgabe des Wertes
fill(255);
text(`Eintrag 0:\nHelligkeitswert: ${hPunkte[0]}`, 22, hPunkte[0] + 20);
// Rechteck mit Wert des Eintrags 2
fill(0, 255, 0);
rect(18 + a, 50, b, hPunkte[2]);
// Text-Ausgabe des Wertes
fill(0);
text(`Eintrag 2:\nHelligkeitswert: ${hPunkte[2]}`, 22 + a, hPunkte[2] + 20);
// Rechteck mit Wert des Eintrags 4
fill(0, 0, 255);
rect(18 + a * 2, 50, b, hPunkte[4]);
// Text-Ausgabe des Wertes
fill(255);
text(`Eintrag 4:\nHelligkeitswert: ${hPunkte[4]}`, 22 + a * 2, hPunkte[4] + 20);
// Rechteck mit Wert des LETZTEN Eintrag
fill('orange');
rect(18 + a * 3, 50, b, hPunkte[anzahl - 1]);
// Text-Ausgabe des Wertes
fill(0);
text(
`Letzter Eintrag:\nHelligkeitswert: ${hPunkte[anzahl - 1]}`,
22 + a * 3,
hPunkte[anzahl - 1] + 20
);
}
CSV-Datei einlesen und alle Werte darstellen
Hier werden alle Helligkeitswerte, die in der Datei data_log.csv enthalten sind, als Balken dargestellt.
let data_log;
let hPunkte = []; // das Array der Helligkeitspunkte
function preload() {
data_log = loadTable("data_log.csv");
}
function setup() {
// ∞
// wieviele Zeilen enthält die Datei "data_log.csv"
let anzahl = data_log.getRowCount();
// liest alle Helligkeitswerte in das Array ein
for (let i = 0; i < anzahl; i++) {
hPunkte[i] = data_log.getNum(i, 3);
}
let b = 35; // Breite des Rechtecks
let a = b + 4; // Abstand der Rechtecke
let anfang = 50; // obere Kante der Rechtecke usw.
// Rechtecke im Hintergrund hilft der Lesbarkeit
fill(220);
for (let i = 0; i < anzahl; i++) {
rect(18 + i * a, anfang, b, 420);
}
for (let i = 0; i < anzahl; i++) {
// zeichnen der Rechtecke, abhängig vom Helligkeitswert
fill("orange");
rect(18 + i * a, anfang, b, hPunkte[i]);
// Nummerierung der Balken
fill("black");
textSize(16);
text(i, 24 + i * a, anfang + 20);
// Ausgabe des jeweiligen Wertes am unteren Rand des Graphes
textSize(12);
text(hPunkte[i], 24 + i * a, anfang + 412);
}
// 4 waagrechte Linien alle 100px ("skala") zur Orientierung
// als letztes gezeichnet, damit oberhalb der Rechteck-Flächen
stroke(240);
let skala = 100;
for (let i = 0; i < 4; i++) {
line(18, anfang + skala * i, width, anfang + skala * i);
}
}
Arduino und Raspi zusammen verwenden
Arduino und Raspi sind eine super Kombination, wenn man das einfache Einlesen von Sensordaten (Arduino) mit den umfangreichen Möglichkeiten des Raspis (Webserver, Datenvisualisierung via p5.js …) verbinden möchte!
Arduino am Raspi anschließen
Die Ardunio-IDE schaut auf dem Raspi fast genauso aus wie bei Mac/Windows
Arduino auf dem Raspi finden
Schliesst dazu den Arduino am Raspi via USB an und startet auf dem Raspi die Arduino IDE – verbindet Euch dazu via VNC mit Eurem Raspi
Kontrolliert – wie auf Mac/PC auch – das das richtige Board („Arduino Uno“) und der richtige Port ausgewählt ist
Merkt Euch die Angaben bei Port: Wir brauchen diese gleich in einem Python-Script
Bei mir heisst der Port /dev/ttyACM0
Bitte beachtet folgende Schritte, wenn der Arduino am Raspi nicht gefunden wird:
Abfragen, ob Arduino erkannt wird:
Da sollte in einer Zeile etwas mit „Arduino“ vorkommen, dann wird er schon mal erkannt!
lsusb
Abfragen, an welchem Port der Arduino angeschlossen ist:
Dazu folgenden Befehl einmal mit angeschlossenem Arduino ausführen und einmal ohne – in der Ausgabe sollte dadurch ein Eintrag wegfallen – dieser ist dann der Port des Arduinos! Hier also der Port /dev/ttyACM0
ls /dev/tty*
Arduino-Helligkeitswerte in CSV-Datei einlesen, Schritt 1
Neu an dem unten aufgeführten Script ist, dass dieses nicht ständig ausgeführt wird, sondern wartet, bis vom Raspi die Aufforderung dazu geschickt wird – dies geschieht durch das Verschicken des Buchstaben A. Wie der Raspi das macht, seht Ihr auf den nächsten Slides!
Details zum Arduino-Code und zum richtigen Breadboard-Aufbau findet Ihr im ersten Script zu Arduino
Bitte ladet und testet dieses Arduino-Script auf Eurem Mac/PC BEVOR Ihr das Arduino-Board in einem nächsten Schritt an den Raspi anschliesst!
Anmerkungen zum Arduino-Sketch
der Arduino übergibt die Werte erst an den Raspberry, wenn dieser ihn dazu auffordert!
Dies geschieht durch das Schicken des Buchstaben "A" an den Arduino via Python/Raspberry Pi
"serial_arduino_to_pi.py" wird bei jedem Neustart des Raspis unter "crontab -e" aktiviert
"serial_arduino_auffordern.py" wird im gewollten Abstand (z.B. alle 15min) ebenfalls unter "crontab -e" aktiviert
Arduino
// Pin Zuweisung bei A0; Widerstand 10 kOhm
int fotozelle = A0;
// für Abfrage, ob vom Raspi etwas via Serial geschickt wurde
int incomingByte = 0;
void setup() {
pinMode(fotozelle, INPUT);
Serial.begin(9600);
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
// Erst wenn der Buchstabe "A" geschickt wurde, soll Arduino was an Raspi schicken
if (incomingByte == 65) {
int hell = analogRead(fotozelle); // Wert, den Fotozelle ausgibt, wird gelesen
// das Komma ist sehr wichtig, damit die CSV-Datei korrekt formatiert ist!
Serial.print("Helligkeit,");
Serial.println(hell); // Ausgabe des Helligkeitswertes der Foto-Zelle
}
}
}
Tip
Ihr könnt testen, ob das Arduino-Script funktioniert, indem Ihr im Serial Monitor den Buchstaben A eingebt und auf Send klickt…
Speichern
Speichert den Arduino-Sketch mit dem Namen helligkeitswert_an_raspi_schicken
Arduino-Helligkeitswerte in CSV-Datei einlesen, Schritt 2
Achtung: Die Python-Scripte verwenden den Port /dev/ttyACM0 – wenn bei Euch ein andere Port von Arduino genutzt wird, müsst Ihr das in beiden Scripten noch anpassen!
Auf den Raspi müssen Ordner angelegt und Python-Skripte gespeichert werden:
Ordner anlegen
legt folgende zwei Ordner im „Webbereich“ das Raspis an
Das Script serial_arduino_to_pi.py liest die Werte, die vom Arduino kommen, alle 60sek ein und speichert diese als CSV im Ordner /var/www/html/fotoresistor/daten
serial_arduino_to_pi.py
#!/user/bin/env python
# -*- coding: UTF-8 -*-
import os
import time
from time import sleep
from datetime import datetime
import serial
# hier richtigen Serial-Port des Arduinos angeben!
# Arduino Uno
port = "/dev/ttyACM0"
# Achtung, hier die richtige Bautrate fuer den Arduino eintragen
ser = serial.Serial(port, 9600)
ser.flushInput()
# Pfad und Dateiname
pfadDatei = "/var/www/html/fotoresistor/daten/data_log.csv"
# Geschwindigkeit muss identisch wie bei Arduino-Script sein!
s1 = serial.Serial(port,9600)
s1.flushInput()
file = open(pfadDatei, "a")
while True:
if s1.inWaiting()>0:
# formatierte Datum- und Zeit-Kombination
now = datetime.now().strftime('%Y-%m-%d,%H:%M:%S')
# gibt den Helligkeiswert jeweil in einer Zeile aus
inputValue =s1.readline()
# "\r" geht, macht aber eigenartiges Sonderzeichen auf naechster Zeile!
# "\n" macht jeweils eine Leerzeile
file.write(str(now)+","+inputValue+"\n")
file.flush()
# Script wartet 1 Minute (60), bis es sich wiederholt
time.sleep(60)
file.close()
serial_arduino_auffordern.py
#!/user/bin/env python
# -*- coding: UTF-8 -*-
# https://classes.engineering.wustl.edu/ese205/core/index.php?title=Serial_Communication_between_Raspberry_Pi_%26_Arduino
import serial
import sys
# Achtung, hier den richtigen Port fuer den Arduino eintragen
ser = serial.Serial('/dev/ttyACM0', 9600)
ser.flushInput()
# das Python-Script verschickt via SerialPort nur den Buchstaben "A"
# auf dem Arduino wird dieses ausgelesen und nur dann eine Messung von Temp und Feuchtigkeit
# an den Raspi geschickt
string1 = "A"
string1_encode = string1.encode()
ser.write(string1_encode)
sys.exit()
Wenn das Interval für das Script „serial_arduino_auffordern.py“ länger (z.B. 15min) ist, spielt das keine Rolle.
Arduino-Helligkeitswerte in CSV-Datei einlesen, Schritt 3
Achtung: Ihr müsst den Raspi neustarten, nachdem Ihr folgende Sachen bei crontab -e eingetragen habt!
Um die Python-Scripte (vorheriges Slide) automatisch auszuführen, müssen diese im crontab -e angegeben werden
crontab -e
crontab -e
# Script beim Starten des Raspi
# liest die Werte, die vom Arduino kommen, alle 60sek ein und speichert diese als CSV
# im Ordner "/var/www/html/fotoresistor/daten"
# wenn das Interval fuer das Script "serial_arduino_auffordern.py" laenger (z.B. 15min) ist, spielt das keine Rolle
@reboot /usr/bin/python /home/pi/bin/serial_arduino_to_pi.py
# fordert den Arduino jede 15 Minute auf, Werte zu schicken
# einfach hier die gewuenschten Zeitabstaende einstellen,
# es muss NICHTS in den Python- oder Arduino-Scripts geaendert werden
# das kuerzeste Intervall, das man einstellen kann, ist 1 min!
*/15 * * * * /usr/bin/python /home/pi/bin/serial_arduino_auffordern.py
Neustart erforderlich
…sonst würde das Script bei „@reboot“ nicht ausgeführt…
sudo reboot
Damit erhält man eine CSV-Datei, die z.B. alle 15min mit einem weiteren Helligkeitswert befüllt wird:
Das Python-Script serial_arduino_to_pi.py fügt dabei automatisch Datum und Uhrzeit ein, so dass man gleich einen Timestamp hat, wann die Messung durchgeführt wurde…
Helligkeitswerte kontrollieren
Nachdem Arduino und Raspi eine Zeitlang gelaufen sind, könnt Ihr schon mal kontrollieren, ob Helligkeitswerte aufgezeichnet wurden:
Verbinden Euch dazu via SSH mit Eurem Raspi und lasst Euch dann die Werte direkt im Terminal anzeigen
Terminal
# die letzten 30 Zeilen
tail -n 30 /var/www/html/fotoresistor/daten/data_log.csv
Beachtet, dass bei der Datei jeweils eine Zeile leer ist – zum Glück stört p5.js das nicht beim Einlesen der Werte…
Arduino-Helligkeitswerte in p5.js visualisieren
Nachdem jetzt die Helligkeitswerte als CSV-Datei auf dem Raspi vorliegen, können diese wieder mit p5.js visualisiert und im Browser angezeigt werden.
Vorbereiteter Code
Ladet die vorbereiteten fotoresistor_p5_sachen.zip herunter und fügt diesen auf Euren Raspis an der richtigen Stelle ein. Ihr könnt dies z.B. gut via SFTP machen:
Entpacken der Daten und Löschen der Zip-Datei
cd /var/www/html/fotoresistor && unzip fotoresistor_p5_sachen.zip && rm fotoresistor_p5_sachen.zip
Datenstruktur
Nach erfolgreichem Einfügen sollte Eure Datenstruktur bei /var/www/html/fotoresistor folgendermaßen aussehen:
.
|-- assets
| |-- c
| | `-- style.css
| |-- f
| | |-- roboto-bold-webfont.woff2
| | `-- roboto-regular-webfont.woff2
| `-- js
| `-- p5.min.js
|-- daten
| `-- data_log.csv <-- diese Datei wird ständig aktualisert und enthält die Helligkeitswerte
|-- demo.txt
|-- graph.js
`-- index.html
Beachtet, dass sich die Anzahl der Datensätze z.B. beim Reload des Browserfensters aktualisiert!
Automatischer „Refresh“ der HTML-Seite
Im <head>-Bereich der HTML-Datei habe ich folgende Angaben eingefügt, die dafür sorgen, dass die Seite alle 15min aktualisiert wird und das keine Dateien im Cache gespeichert werden:
HTML
<head>
<!-- … -->
<!-- alle 15 min aktualisieren -->
<meta http-equiv="refresh" content="900">
<!-- verhindert, dass Daten im Cache gespeichert werden -->
<meta http-equiv=”Pragma” content=”no-cache”>
<meta http-equiv=”Expires” content=”-1″>
<meta http-equiv=”CACHE-CONTROL” content=”NO-CACHE”>
<!-- … -->
</head>
Der Raspi hat 4 USB-Ports – z.B. für USB-Sticks, um große Datenmengen zu speichern. Linux bietet die Möglichkeit, den USB-Stick direkt einem beliebigen Ordner (beispielsweise home/pi/vieleFotos) zuzuweisen. Alles, was in diesen Ordner gespeichert wird, landet direkt auf dem USB-Stick.
Vorbereitung
den gewünschten Ordner anlegen und gleich dorthin wechseln
mkdir /home/pi/vieleFotos && cd /home/pi/vieleFotos
Pfad zum gewünschten Ordner abfragen
pwd
Format des USB-Sticks
Der Stick darf nicht für Mac formatiert sein! Zuverlässig geht es, wenn Ihr entweder einen neuen USB-Stick verwendet (diese sind passend für Windows formatiert) oder Ihr nutzt z.B. das Festplatten-Dienstprogramm am Mac um den Stick zu formatieren:
UUID des USB-Sticks abfragen
den USB-Stick einstecken und mit folgendem Befehl die UUID des Sticks abfragen – diese ist für jeden Stick einmalig
sudo blkid -o list -w /dev/null
Stick mit dem Ordner /home/pi/vieleFotos verbinden
Danach den Raspi neustarten. Jetzt sollte der USB-Stick bei /home/pi/vieleFotos eingebunden sein – Ihr könnt das kontrollieren, indem Ihr noch mal folgendes eingebt:
sudo blkid -o list -w /dev/null
Jetzt werden alle Sachen, die Ihr bei /home/pi/vieleFotos speichert, direkt auf dem USB-Stick gesichert. Probiert es mal aus, schaltet den Raspi aus und steckt diesen an Euren Mac/PC – die abgespeicherten Sachen sind dort ebenfalls sichtbar.
Das ist z.B. auch praktisch, wenn Ihr viele Fotos mit dem Raspi macht. Dann könnt Ihr diese einfach auf Euren Mac/PC übertragen…
Chromium fullscreen starten
Startet man den Browser Chromiumfullscreen, wird der Inhalt des Browserfensters bildschirmfüllend angezeigt – alle Buttons, die Adressleiste usw. werden komplett ausgeblendet.
@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-Events via Teensy auslösen
Teensy ist eine kostengünstige Weiterentwicklung von Arduino. Man kann damit einfach eine Tastatur simulieren und somit einem PC (oder Raspi) Befehle erteilen.
Teensys und auch ein paar andere Arduino-Microprozessoren können einem angeschlossenen Computer (Mac, Windows, Linux…) „vorgaukeln“, dass sie eine Tastatur sind. Damit kann man am Teensy z.B. einfach Hardware-Buttons oder – wie hier gezeigt – „Leitfähigkeitssensoren“ anschliessen, die dann Buchstaben (hier j, l, u) an den PC schicken. Am PC ist es dann z.B. via Javascript (oder p5.js) relativ einfach, auf diese Tastatureingaben zu reagieren.
Besonders wichtig ist die Angabe bei USB Type – dort müsst Ihr Keyboard auswählen!
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!
const int ledPin = 13;
const int grenzWert = 3000;
// 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(500);
}
// 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);
if (data > grenzWert) {
// nicht nötig, zeigt aber, wenn Grenzwert überschritten ist
digitalWrite(ledPin, HIGH);
// Ausgabe im Serial-Monitor, auch optional
Serial.println(data);
Keyboard.println(buchstabe);
} else {
digitalWrite(ledPin, LOW);
}
}
Javascript
// hier die richtigen Buchstaben angeben,
// die Ihr bei "Teensyduino" festgelegt habt
const buchstabeLinks = "j";
const buchstabeRechts = "u";
const buchstabeReset = "l";
// ==================== ab hier müsst Ihr nichts mehr ändern ====================
// wenn Ihr die Benamung der Sektionen beibehaltet…
const linkesKabelErgebnis = document.querySelector("#linkesKabel span");
const rechtesKabelErgebnis = document.querySelector("#rechtesKabel span");
// sobald jemand eine der oben genannten Tasten drückt,
// zählt der Zähler links oder rechts um "1" hoch
// das könnt Ihr auch direkt an Eurem Mac/PC probieren
// auch dort die index-Datei im Browser öffnen und dann
// auf Eurer Tastatur "j" oder "u" eingeben
// wenn Teensy angeschlossen ist und die Website den Focus hat,
// zählen die Elemente hoch, sobald Teensy einen der Buchstaben verschickt
// optional habe ich noch das "l" als Reset-Button eingefügt,
// damit könnten beide Zähler weider auf "0" gesetzt werden
window.addEventListener(
"keyup",
function (event) {
let taste = event.key;
if (taste === buchstabeLinks) {
let aktWertLinks = parseInt(linkesKabelErgebnis.textContent);
linkesKabelErgebnis.textContent = aktWertLinks + 1;
} else if (taste === buchstabeRechts) {
let aktWertRechts = parseInt(rechtesKabelErgebnis.textContent);
rechtesKabelErgebnis.textContent = aktWertRechts + 1;
} else if (taste === buchstabeReset) {
linkesKabelErgebnis.textContent = 0;
rechtesKabelErgebnis.textContent = 0;
}
},
true
);
Falls Ihr kein Teensy zur Verfügung habt, könnt Ihr auf Eurer PC-Tastatur die Buchstaben j, l, u eingeben und sehen, was passiert…
Buttons via Teensy als Keyboard-Events verwenden
Hardware-Buttons können mit Teensy ebenfalls als Keyboard-Events an Mac/PC (oder Raspi) übergeben werden – und dann abhängig von der gerade offenen Application verwendet werden, z.B. auch als Shortcuts in Programmen wie Photoshop…
Bitte beachtet für die grundlegenen Einstellungen von Teensy das Beispiel „Keyboard-Events via Teensy auslösen“ (vorherige Seite)!
Besonders wichtig ist wieder die Angabe bei USB Type – dort müsst Ihr Keyboard auswählen!
Arduino
/*
Buttons to USB Keyboard Example
You must select Keyboard from the "Tools > USB Type" menu
This example code is in the public domain.
das Original-Beispiel mit allen 10 Buttons befindet sich bei:
File>Examples>Teensy>USB_Keyboard>Buttons
PIN 0, 1, 2 befinden sich auf der linken Seite des Teensys,
wenn der USB-Stecker oben liegt
https://www.pjrc.com/store/teensylc.html
*/
#include <Bounce.h>
/*
Create Bounce objects for each button. The Bounce object
automatically deals with contact chatter or "bounce", and
it makes detecting changes very simple.
*/
Bounce button0 = Bounce(0, 10);
Bounce button1 = Bounce(1, 10); // 10 = 10 ms debounce time
Bounce button2 = Bounce(2, 10); // which is appropriate for
void setup() {
/*
Configure the pins for input mode with pullup resistors.
The pushbuttons connect from each pin to ground. When
the button is pressed, the pin reads LOW because the button
shorts it to ground. When released, the pin reads HIGH
because the pullup resistor connects to +5 volts inside
the chip. LOW for "on", and HIGH for "off" may seem
backwards, but using the on-chip pullup resistors is very
convenient. The scheme is called "active low", and it's
very commonly used in electronics... so much that the chip
has built-in pullup resistors!
*/
pinMode(0, INPUT_PULLUP);
pinMode(1, INPUT_PULLUP);
pinMode(2, INPUT_PULLUP);
}
void loop() {
/*
Update all the buttons. There should not be any long
delays in loop(), so this runs repetitively at a rate
faster than the buttons could be pressed and released.
*/
button0.update();
button1.update();
button2.update();
/*
Check each button for "rising" edge
Type a message on the Keyboard when each button releases.
For many types of projects, you only care when the button
is pressed and the release isn't needed.
rising = low (pressed - button connects pin to ground)
to high (not pressed - voltage from pullup resistor)
*/
/*
Ihr könnt entscheiden, ob die Keyboard-Botschaft beim Drücken ODER beim Loslassen
des jeweiligen Buttons übertragen wird
in der Praxis ist es bestimmt besser, wenn Ihr nur einen einzelen Buchstaben sendet
also z.B. Keyboard.println("a");
*/
if (button0.risingEdge()) {
Keyboard.println("B0 gedrueckt");
}
if (button1.risingEdge()) {
Keyboard.println("B1 gedrueckt");
}
if (button2.risingEdge()) {
Keyboard.println("B2 gedrueckt");
}
/*
Check each button for "falling" edge.
Type a message on the Keyboard when each button presses
Update the Joystick buttons only upon changes.
falling = high (not pressed - voltage from pullup resistor)
to low (pressed - button connects pin to ground)
*/
if (button0.fallingEdge()) {
Keyboard.println("B0 losgelassen");
}
if (button1.fallingEdge()) {
Keyboard.println("B1 losgelassen");
}
if (button2.fallingEdge()) {
Keyboard.println("B2 losgelassen");
}
}
Joystick via Teensy verwenden
Teensy kann auch einen (Gamer-)Joystick bzw. eine Mouse simulieren. Ihr müsst in Teensyduino bei USB-Type auswählen, was simuliert werden soll.
Der hier gezeigte Arduino-Code gibt über den Serial Monitor lediglich aus, wie die Werte sich ändern, wenn Ihr den Joystick benutzt!
Arduino
int SensorWertX = 0;
int SensorWertY = 0;
int SensorWertT = 0;
int xAchse = A0; // Auslesen des Wertes, der an A0 anliegt. Hier : VRx - X-Achse
int yAchse = A1; // Auslesen des Wertes, der an A1 anliegt. Hier : VRy - Y-Achse
int TasterMitte = A2; // Auslesen des Wertes, der an A2 anliegt. Hier : Taster (zum Herunterdrücken)
void setup() {
Serial.begin(9600);
}
void loop() {
SensorWerteAusgabe();
delay(500);
}
void SensorWerteAusgabe(){
SensorWertX = analogRead(xAchse);
Serial.print("xAchse:");
Serial.println(SensorWertX, DEC);
SensorWertY = analogRead(yAchse);
Serial.print("yAchse:");
Serial.println(SensorWertY, DEC);
SensorWertT = analogRead(TasterMitte);
Serial.print("TasterMitte:");
Serial.println(SensorWertT, DEC);
Serial.println("-------------------------------------");
}
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 Mikrofons „KY-037“.
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.
Bei Fritzing gab es nicht das Mikrofon „KY-037“, das 4 Anschlüsse hat. Für den gezeigten Sketch könnt Ihr den Anschluss „D0" leer lassen.
Arduino
// WICHTIG! You must select Keyboard from the "Tools > USB Type" menu!
#include <Bounce.h>
Bounce button0 = Bounce(0, 10);
int wert = 0;
bool uebertragen = 0; // toggelt bei Tastendruck zwischen 0 und 1, nur bei "1" wird "wert" via Keyboard uebertragen
const int ledPin = 13; // LED soll leuchten, wenn Übertragung stattfindet
void setup() {
pinMode(0, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
}
void loop() {
uebertragungAnAus();
// wenn Uebertragung aktiv ist, wird der Sensorwert des Microfons
// via Keyboard an den PC/Mac/Raspi übertragen
if (uebertragen == 1) {
wert = analogRead(A0);
// Ausgabe der "Lautstaerke" als Zahlenreihe
Keyboard.println(wert);
}
delay(100);
}
// toggelt, ob die Übertragung stattfinden soll oder nicht
// wird übertragen, leuchtet die LED auf PIN13
void uebertragungAnAus() {
button0.update();
if (button0.risingEdge()) {
if (uebertragen == 0) {
uebertragen = 1;
digitalWrite(ledPin, HIGH);
} else {
uebertragen = 0;
digitalWrite(ledPin, LOW);
}
}
}
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 "Mikrofon") 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];
}
// console.log(teensyWerte);
// die CSS-Angabe "width" wird hier via Javascript angepasst
// '0.9' = Skalierung des Graphen
teensyGraph.style.width = `${teensyWerte * 0.9}px`;
werte.textContent = teensyWerte;
// zurücksetzten der Variablen
buffer = [];
teensyWerte = "";
} else {
buffer.push(taste);
}
},
true
);