Eigenbau: Multisensorbox mit Datenlogger und Kamera v12.1 (Arduino-Projekt)

Geräte, welche mehrere oder spezielle Funktionen abdecken
Antworten
SpiritShack
Benutzeravatar
Markus
Gründungsmitglied
Gründungsmitglied
Administrator
Administrator
EPAS Austria
EPAS Austria
Beiträge: 1205
Registriert: So 6. Jul 2014, 00:16
Wohnort: Wien
Hat sich bedankt: 412 Mal
Danksagung erhalten: 490 Mal
Kontaktdaten:
Österreich

Eigenbau: Multisensorbox mit Datenlogger und Kamera v12.1 (Arduino-Projekt)

Beitrag von Markus »

Nach der SLS-Kamera, REM-Pod, EMF-Detektor und Portal ist dies bislang mein umfangreichstes Projekt. Basiskenntnisse der Elektrotechnik, Programmierung und Löten: alles zusammen in einem etwa 4 Monate andauernden Kampf mit der Materie und mit mir selbst.
Multisensorbox.jpg
Multisensorbox_1.jpg

Die Box

Das war von Anfang an eine echte Herausforderung und verlangte meiner Vorstellungskraft alles ab. Es musste eine Lösung sein, die einfach und praktikabel ist. Das Montieren der Teile muss einfach zu bewerkstelligen sein und diese müssen bei Bedarf auch leicht zugänglich sowie austauschbar sein (also z.B. nicht kleben). Und natürlich muss das Behältnis die Teile auch schützen.
  • Ebene 3
    Die oberste Ebene dient zur Aufbewahrung der Kamera, der IR-Leuchte und der Powerbank inkl. USB-Kabel. Diese wird vor dem Einsatz abgenommen, die Kamera und die Powerbank auf der Ebene 2 angeschlossen. Somit ist die Box einsatzbereit.
  • Ebene 2
    Dies ist die wichtigste bzw. Hauptebene. Hier sind auf der Unterseite der Arduino und das Breadboard montiert und auf der Oberseite alle Anzeigen, Schalter und Module sowie der Temperatursensor. Desweiteren ist außen an dieser Ebene die kleine Box mit den Sensoren angebracht.
  • Ebene 1
    Diese unterste Ebene dient zum Schutz des Arduino, des Breadboards und der Kabel.
Durch dieses Konzept sind alle Teile geschützt und zugänglich und mit Nylon-Abstandhalter sowie selbstsichernden Muttern oder Klettband befestigt (z.B. das Speicherkartenmodul oder der Temperatursensor). Der Transport ist gefahrlos und durch den Tragegriff im Deckel sehr einfach möglich. Die Ebenen und der Deckel werden mit den seitlichen Klappen miteinander fixiert.
Multisensorbox_vorne_geschlossen1.jpg
Multisensorbox_rueckseite.jpg
Multisensorbox_oben_geschlossen.jpg
Multisensorbox_vorne_geschlossen.jpg

Stromversorgung

Die Stromversorgung erfolgt mittels 5V-Powerbank über das Breadboard-Prototype Shield. Darauf sind alle Stromversorgungskabel der Sensoren und Module angelötet. Der Arduino wird ebenfalls von diesem Breadboard mit Strom versorgt. Der USB-Anschluss des Arduino dient nur mehr zur Datenübertragung zum PC und wird mit einem eigens dafür modifierten USB-Kabel verbunden. Bei diesem Kabel habe ich die Plus-Leitung getrennt, denn eine gleichzeitige Stromversorgung über das USB-Kabel und das Breadboard würde Rauchzeichen erzeugen.

Multisensorbox Startsequenz

Das Programm startet, sobald die Stromzufuhr aktiviert wird. Zuerst werden allen Sensoren und Module überprüft und mit "OK" am Display angezeigt. Sollte das Display nicht reagieren, blinken die 3 LEDs rechts unten. Ist die Kamera angeschlossen, wird deren Version angezeigt. Dann wartet das Programm, bis der Schalter umgelegt wird. Daraufhin läuft das Programm in einer Schleife. Der Schalter kann auch verwendet werden, um das Programm zu pausieren.
Multisensorbox_Start1.jpg
Multisensorbox_Loop.jpg
Multisensorbox_Start2.jpg

Sensoren, Module, Anzeigen und Schalter

Multisensorbox_Sensoren.jpg
Multisensorbox_oben_offen.jpg
Multisensorbox_Ebene2.jpg
Eine sehr frühe Version des Projektes
Eine sehr frühe Version des Projektes
Multisensorbox_oben_offen1.jpg
Multisensorbox_vorne_offen.jpg
Das angepasste Kabel der Kamera
Das angepasste Kabel der Kamera

Die Anzeigen

Multisensorbox_Ledstreifen.jpg
Multisensorbox_Display1.jpg
Das LED-Anzeigemodul verfügt über 8 LEDs. Die Programmierung ist so gestaltet, dass die entsprechenden LEDs bis zur gemessenen Entfernung in der zugehörigen Farbe aktiviert werden. Die 8 LEDs sind in 50cm-Abschnitte unterteilt sowie farblich 1m-Abschitte (2 LEDs für je einen Meter). Eine LED wird auf Blau geschalten, wenn eine Bewegung innerhalb eines Abschnittes wahrgenommen wird. Dies dient dazu, dass Bewegungen auch dann angezeigt werden, wenn sich diese nur innerhalb eines der 50cm-Abschnitte abspielen.
  • Weiß = 3 - 4m
  • Grün = 2 - 3m
  • Gelb = 1 - 2m
  • Rot = 0 - 1m
Das OLED-Display verfügt über 8 Zeilen:
  1. Uhr - zeigt das akuelle Datum und Uhrzeit (dieses wird durch die Batterie des Real Time Clock-Modules aktuell gehalten)
  2. Laser - zeigt die gemessene Entfernung des Lasersensors in cm sowie die Messgrenzen (berechnet durch die Messtoleranzen)
  3. Ultra - zeigt die gemessene Entfernung des Ultraschallsensors in cm sowie die Messgrenzen (berechnet durch die Messtoleranzen)
  4. Kamera - zeigt die Anzahl der gespeichrten Fotos (wenn die Kamera angeschlossen ist)
  5. Temp - zeigt die aktuelle und die letzte gemessene Temperatur sowie die Luftfeuchtigkeit
  6. Daten - zeigt die Anzahl der geschriebenen Datensätze sowie die Anzahl der Programmdurchläufe
  7. Lautst. - zeigt die aktuell eingestellte Lautstärke (0 - 10)
  8. Radar - zeigt "detected", wenn der Radarsensor eine Bewegung registriert hat (ein Radarsensor gibt keine Entfernung zurück, sondern nur ein Signal, wenn dieser eine Bewegung erkannt hat. Dies ist ebenso bei IR-Bewegungssensoren der Fall)
Messtoleranzen: Um nicht bei jeder kleinsten Bewegung einen Datensatz zu schreiben, habe ich einstellbare Messtoleranzen eingebaut. Aktuell betragen diese beim Laser- und beim Ultraschallsensor +/- 5cm. D.h. es wird nur dann ein Datensatz geschrieben, wenn sich die aktuelle Entfernungsmessung gegenüber der Letzten um mindestens plus oder minus 5cm geändert hat (der letzte Wert wird dann durch den Neuen ersetzt). Desweiteren wird zur besseren Erkennbarkeit neben der Entfernungsanzeige des Laser- und Ultraschallsensors ein * eingeblendet, wenn die jeweilige Messtoleranz über- oder unterschritten wird. Da sich die Temperatur auch immer leicht ändern kann, habe ich hier ebenfalls eine Messtoleranz gesetzt. Diese beträgt +/- 2 Grad.

Testvideo

Datenauswertung

Gespeichert werden folgende Daten:
  • Datum & Uhrzeit (inkl. Sekunden)
  • Lasersensor (in cm)
  • Temperatur
  • Luftfeuchtigkeit (in %)
  • Ultraschallsensor (in cm)
  • Radarsensor (Wert 10, wenn ausgelöst, ansonst 0)
  • Kamera (Wert 10, wenn ausgelöst, ansonst 0)
Einmalig werden am Anfang der Datei die Spaltenbezeichnungen geschrieben: "Datum Zeit Laser Temp Luft US Radar Foto"
Der Dateiname ist das aktuelle Datum in der Form "JJMMTT". Diese Textdatei wird mit Excel geöffnet, das Diagramm wird mittels eigener Vorlage erstellt.
Die Daten in Excel
Die Daten in Excel
Das Datendiagramm
Das Datendiagramm
Wie im Diagramm zu erkennen ist, sind die Daten des Ultraschallsensors sehr "eigenwillig". Dies ist jedoch nur in dieser Datenreihe der Fall. Trotzdem ist der Ultraschallsensor generell zur Entfernungsmessung nicht überall zuverläßig einsetzbar. Wenn der ausgesendete Schall z.B. auf Möbel oder eine schräge Wand trifft, wird dieser zerstreut und trifft in unterschiedlichen Stärken und Längen wieder auf den Sensor. Dies lässt sich bis zu einem gewissen Grad per Programmierung abschwächen, dennoch weisen die eingehenden Messungen oft starke Schwankungen auf. Versuche, dies mit diversen Filtern zu unterbinden, hätte zwar fallweise funktioniert, war jedoch nicht zielführend, denn die getesteten Filter haben den Programmablauf teils extrem verlangsamt.

Fotos der Kamera

Die Auflösung läßt sich auf 640x480, 320x240 oder 160x120 einstellen. Je höher die Auflösung, desto länger dauert das Schreiben auf die Speicherkarte. Da der Schreibvorgang den Programmablauf blockiert, habe ich 320x240 gewählt. Hierbei dauert das Speichern etwa 2 Sekunden. Die Reichweite des Bewegungssensors beträgt ca. 3m. Nachteil der Kamera: kein Autofokus.
Abstand ca. 50cm
Abstand ca. 50cm
IMAGE001.JPG (26.63 KiB) 1479 mal betrachtet
Abstand ca. 200cm
Abstand ca. 200cm
IMAGE003.JPG (27.21 KiB) 1479 mal betrachtet
Abstand ca. 200cm
Abstand ca. 200cm
IMAGE002.JPG (27.93 KiB) 1479 mal betrachtet
Foto vergrößert und bearbeitet
Foto vergrößert und bearbeitet
Mit dem EasyCAP USB 2.0 Audio und Video Grabber ist eine Live-Wiedergabe der Videoausgabe am PC oder Smartphone möglich (z.B. mittels VLC-Player).
Video-Screenshot
Video-Screenshot

Verwendete Teile

ELEGOO MEGA-R3 Starter Kit für Arduino Projekt
Ultimate Starter Kit (66,54 €)
81VW9Xgk06L._AC_SL1500_.jpg
DollaTek Prototype PCB for Arduino R3 Shield Board DIY (6,03 €)
81gd-+pipRL._AC_SL1500_.jpg
HALJIA RCWL-0516 Mikrowellen-Radarbewegungssensor
Erfassungsbereich: 120 Grad Kegelwinkel innerhalb von 7 Metern (7,04 €)
71YxZ2M8fDL._AC_SL1500_.jpg
ARCELI 8-Bit Neopixel WS2812 RGB LED-Entwicklungsboard-Modul
mit Vollfarbantrieb, 2 Stk. (2x 6,04 €)
51yiyrvQfrL._AC_SL1200_.jpg
EasyCAP USB 2.0 Audio und Video Grabber
mit Syntek STK1160 Chipsatz (11,90 €)
EasyCAP USB 2_0 Audio und Video Grabber.jpg
HALJIA Halterung für HC-SR04 Ultraschall Sensor (12,54 €)
41-Wxd6Yd3L._AC_.jpg
DollaTek 2.42-Zoll-128X64-OLED-Anzeigemodul IIC I2C (25,20 €)
61nRizKodlL._AC_SL1000_.jpg
EPMK PCB solderable Breadboard - Prototype Shield for Arduino
(4x volles breadboard) (14,50 €)
81XcLC+PvLL._SL1500_.jpg
ELEGOO Arduino Mega-R3 Mikrocontroller mit USB-Kabel (22,18 €)
71y9N2vnAyL._AC_SL1500_.jpg
CY Verlängerungskabel mit USB 2.0-Anschluss, Typ B
männlich zu weiblich, 50 cm (9,97 €)
41PnVCrHuFL._AC_.jpg
Rayher Sortierbox Aufbewahrung mit Griff,Transparent,
23,1x15,6x18,5cm,3 Etagen (14,11 €)
71cwNPyQMiL._AC_SL1500_.jpg
AZDelivery 5 x Jumper Wire Kabel
40 STK je 20 cm F2M Female to Male (10,07 €)
81orZkxoOVS._SL1500_.jpg
WiMas 175PCS Edelstahlmuttern, Selbstsichernd Sechskant
Sortiment Kit M2-M12 (nicht mehr erhältlich)
71PfYyteB+L._SL1200_.jpg
1120pcs Schrumpfschlauch, Schrumpfverhältnis 2: 1 (6 Farben/12 Größen) (13,10 €)
71EQZNA9CxL._SL1500_.jpg
BlueDot VL53L1X Laser-Entfernungssensor
Reichweite bis zu 4m (15,12 €)
71S16nFi0BL._AC_SL1500_.jpg
HC-SR04 Ultraschall-Entfernungsmesser
Entfernungsmessung von 2 cm bis zu 3 m (aus dem Kit)
71pc2wfJY1L._SL1500_.jpg
SanDisk Ultra microSDHC UHS-I Speicherkarte 32 GB (6,34 €)
81-FGYLR36L._AC_SL1500_.jpg
Adafruit VC0706 wetterfeste serielle TTL-JPEG-Kamera
mit NTSC-Video und IR-LEDs (32,62 €)
Adafruit wetterfeste serielle TTL-JPEG-Kamera.jpg
Amazon Brand - Umi 8tlg. Flachfräsbohrer-Set (12,10 €)
71Fjzx2QN+L._AC_SL1500_.jpg
Breadboard Jumper Wires, Male to Female
(15CM, Red x 60 Pieces Black x 60 Pieces) (16,69 €)
61VFbTJ-OLL._SL1200_.jpg
cablecc 90 D Links gewinkelt USB 2.0 A Stecker an Buchse Verlängerungskabel
mit Panel Mount Loch (8,05 €)
515qko+EQJL._AC_SL1200_.jpg
RUNCCI-YUN 16pcs DIN Stecker Buchse (9,06 €)
51iZSxAOeQL._SL1001_.jpg
Goodma 7 Stück Mini-Organizer-Aufbewahrungsbox
aus durchsichtigem Kunststoff mit Klappdeckel (14,11 €)
713aCCJO+ZL._AC_SL1500_.jpg
260 Stück M3 Nylon Sechskantschrauben
Mutter Schaltungs Abstandshalter (9,06 €)
817GvTkzW-L._AC_SL1500_.jpg
senvenelec (5 Stücke) Auto-Mini-Kippschalter mit 30cm vorverdrahtet, 3-Pin (9,00 €)
61JzslTGARL._AC_SL1000_.jpg
RUNCCI-YUN 20PCS Potentiometer kit,Linear Potentiometer (B5K B10K B20K B50K B100K) (11,09 €)
61+u19QnVbL._SL1000_.jpg
ANKKY Pin Header 2.54mm 40 Pin Stiftleiste 45 Stück (10,07 €)
71ZrmquEmpL._AC_SL1500_.jpg
Summe: 378,57 €

Die Kosten für dieses Projekt sind schockierend, jedoch sind nicht alle gekauften Teile verbaut. Zum Beispiel habe ich nur eines von den 4 Breadboards verwendet, ebenso nur einen Schalter von 5 oder Jumper Wire Kabel, Stiftleisten und Abstandhalter. D.h. diese Summe würde etwas geringer ausfallen, wenn man nur die einzelnen, verwendeten Teile zusammenrechnet.

Teile, die es nicht überlebt haben (R.I.P.)

Ich hatte anfangs alle Sensoren und Module direkt über den Arduino mit Strom versorgt. Und das war irgendwann zuviel. Diverse Teile sind durchgebrannt und haben die beiden Displays mitgerissen. Ein paar Drehpotenziometer habe ich gekillt, weil ich nicht wusste, dass man die Kabel nicht durch die Löcher anlöten darf, sondern nur an den Stiften.
ELEGOO Mega 2560 R3 Mikrocontroller Board (aus dem Kit)
71AlJdncSML._AC_SL1500_.jpg
Ein paar Drehpotenziometer
potis.jpg
GeeekPi 2-Pack I2C 1602 LCD-Anzeigemodul 16X2 Charakter (14,11 €)
617x0GQ4bEL._AC_SL1000_.jpg

Der Arduino-Code Version 12.1

Die Programmiersprache für den Arduino ist ähnlich wie C oder C++. Zu Beginn hatte ich absolut keine Ahnung davon, aber im Lauf des Herumprobierens lernt man das überraschenderweise relativ (!) schnell. Zuerst habe ich mit einzelnen Sensoren und Modulen angefangen, dann folgten verschiedene Kombinationen und schließlich habe ich dieses Projekt begonnen. Es entstanden viele, sehr sehr viele Versionen und Zwischenversionen bis alles funktionierte und korrekt "zusammenarbeitete".

Code: Alles auswählen

#include <Wire.h>
#include <TimeLib.h>
#include "RTClib.h"
RTC_DS3231 RTC;

#include <Adafruit_VC0706.h>
#define cameraconnection Serial1
Adafruit_VC0706 cam = Adafruit_VC0706(&cameraconnection);
#define chipSelect 53

#include <SPI.h>
#include <SD.h>
File DataFile;

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1        // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C  ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#include <VL53L1X.h>
VL53L1X sensor;

#include <DHT.h>
#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN 10
#define PIN1 12
#define NUMPIXELS 8
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel pixels1(NUMPIXELS, PIN1, NEO_GRB + NEO_KHZ800);
#define DELAYVAL 100  // Time (in milliseconds) to pause between pixels
int pixelbright = 3;

#include <TimerFreeTone.h>
#define TONE_PIN 9
int melody[] = { 1600, 1800, 2000, 2200 };
int duration[] = { 250, 250, 200, 50 };

#include <NewPing.h>
#define TRIGGER_PIN 4                                // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN 3                                   // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 400                             // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);  // NewPing setup of pins and maximum distance.

int minmax = 2;
int min;
int max;
int minold;
int maxold;
int sens_read = 0;
int sens_read_neu = 0;
int sens_read_old = 0;
int us_sens_read = 0;
int us_sens_read_neu = 0;
int us_minmax = 5;
int laser_minmax = 5;
int us_sens_read_min_old = 0;
int us_sens_read_max_old = 0;
int us_sens_read_min_akt = 0;
int us_sens_read_max_akt = 0;
int sens_read_min_old = 0;
int sens_read_max_old = 0;
int sens_read_min_akt = 0;
int sens_read_max_akt = 0;
int sens_read_min = 0;
int sens_read_max = 0;
bool write_us = false;
bool write_laser = false;
// Blau = Radar
// Weiss = Temperatur
bool writetemp = false;
String leerz("             ");
int LED1 = 6;
int LED2 = 11;
int LED3 = 7;
float h;
float t;
float h_neu = 0;
float t_neu = 0;
long loopzaehler = 1;
unsigned long lastPeriodStart;
const int periodDuration = 600;
unsigned long us_lastPeriodStart;
const int us_periodDuration = 600;
// 'oledlogo1', 128x64px
const unsigned char epd_bitmap_oledlogo1[] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, 0x00,
  0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, 0x00,
  0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, 0x00,
  0x00, 0x3b, 0x9f, 0xbe, 0x7c, 0xfc, 0xfc, 0xfb, 0xfe, 0x7e, 0x60, 0x37, 0xe6, 0x7e, 0x7e, 0x00,
  0x00, 0x3f, 0x9f, 0xbe, 0xfc, 0xfc, 0xfc, 0xfb, 0xfe, 0x7e, 0x60, 0x37, 0xe6, 0x7e, 0x7e, 0x00,
  0x00, 0x3f, 0x9f, 0xb8, 0xfc, 0xfc, 0xfc, 0xe3, 0xfe, 0x7e, 0x60, 0x37, 0xe6, 0x7e, 0x7e, 0x00,
  0x00, 0x3c, 0x1b, 0xb8, 0xec, 0xfc, 0xfc, 0xc3, 0xfe, 0x7e, 0x60, 0x37, 0xe6, 0x7e, 0x7e, 0x00,
  0x00, 0x38, 0x1f, 0xb8, 0xfc, 0xfc, 0xfc, 0xc3, 0xfe, 0x7e, 0x60, 0x3f, 0xe6, 0x7e, 0x7e, 0x00,
  0x00, 0x38, 0x1f, 0xb8, 0xfc, 0xfc, 0xfc, 0xc3, 0xfe, 0x7e, 0x67, 0x3f, 0xe6, 0x7e, 0x7e, 0x00,
  0x00, 0x18, 0x1f, 0x98, 0x7c, 0xec, 0xfc, 0xc3, 0x7e, 0x7e, 0x67, 0x3f, 0xe6, 0x7e, 0x6e, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xff, 0xfe, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0xff, 0xfe, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x71, 0x00, 0x01, 0x1c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x19, 0x80, 0x03, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x08, 0xf0, 0x1e, 0x20, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08, 0x18, 0x30, 0x21, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x08, 0x20, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x08, 0x20, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x08, 0x20, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x08, 0x20, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x08, 0x20, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x08, 0x20, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x08, 0x20, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x08, 0x20, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x08, 0x20, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x08, 0x20, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x08, 0x20, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x84, 0x08, 0x20, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x08, 0x20, 0xc2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x08, 0x20, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x08, 0x21, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xd8, 0x37, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x38, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0f, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 1040)
const int epd_bitmap_allArray_LEN = 1;
const unsigned char* epd_bitmap_allArray[1] = {
  epd_bitmap_oledlogo1
};

String outtime = "";
String outdate = "";
String fileoutdate = "";
String complete_output = "";
int datafilecount = 0;
int Radarmodul = 5;
int WERT;
int motionState = LOW;
int potivalue = 0;
int volvalue = 0;
bool camrunning = false;
int picanzahl = 0;
int CheckButtonPress2;
int CheckButtonPress1;
int pictaken = 0;

int spalte1 = 0;
int spalte2 = 48;
int spalte3 = 80;
int zeile1 = 0;
int zeile2 = 8;
int zeile3 = 16;
int zeile4 = 24;
int zeile5 = 32;
int zeile6 = 40;
int zeile7 = 48;
int zeile8 = 56;

String text1 = "Uhr";
String text2 = "Laser";
String text3 = "Ultra";
String text4 = "Kamera";
String text5 = "Temp";
String text6 = "Daten";
String text7 = "Lautst.";
String text8 = "Radar";
String Headeroutput = "Datum\tZeit\tLaser\tTemp\tLuft\tUS\tRadar\tFoto";

char timestamp[30];
// call back for file timestamps
void dateTime(uint16_t* date, uint16_t* time) {
  DateTime now = RTC.now();
  sprintf(timestamp, "%02d:%02d:%02d %2d/%2d/%2d \n", now.hour(), now.minute(), now.second(), now.month(), now.day(), now.year() - 2000);
  *date = FAT_DATE(now.year(), now.month(), now.day());
  *time = FAT_TIME(now.hour(), now.minute(), now.second());
}

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    ;  // wait for serial port to connect. Needed for native USB port only
  }
  Wire.begin();
  Wire.setClock(400000);  // use 400 kHz I2C
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    pinMode(LED1, OUTPUT);
    pinMode(LED2, OUTPUT);
    pinMode(LED3, OUTPUT);
    for (;;) {
      digitalWrite(LED1, HIGH);
      digitalWrite(LED2, HIGH);
      digitalWrite(LED3, HIGH);
      delay(1000);
      digitalWrite(LED1, LOW);
      digitalWrite(LED2, LOW);
      digitalWrite(LED3, LOW);
      delay(1000);
    }
  }
  display.clearDisplay();
  display.display();
  display.drawBitmap(0, 0, epd_bitmap_oledlogo1, 128, 64, WHITE);
  display.display();
  delay(2500);
  display.clearDisplay();
  display.display();
  display.setTextSize(1);                              // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);  // Draw white text
  display.cp437(true);                                 // Use full 256 char 'Code Page 437' font
  display.setCursor(spalte1, zeile1);
  display.print(text1);
  display.setCursor(spalte1, zeile2);
  display.print(text2);
  display.setCursor(spalte1, zeile3);
  display.print(text3);
  display.setCursor(spalte1, zeile4);
  display.print(text4);
  display.setCursor(spalte1, zeile5);
  display.print(text5);
  display.setCursor(spalte1, zeile6);
  display.print(text6);
  display.setCursor(spalte1, zeile7);
  display.print(text7);
  display.setCursor(spalte1, zeile8);
  display.print(text8);

  pinMode(LED1, OUTPUT);
  digitalWrite(LED1, HIGH);
  pinMode(LED2, OUTPUT);
  digitalWrite(LED2, HIGH);
  pinMode(LED3, OUTPUT);
  digitalWrite(LED3, HIGH);

  dht.begin();
  delay(1000);
  if (isnan(dht.readTemperature())) {
    Serial.println("");
    Serial.println("Temp Sensor failed !");
    display.setCursor(spalte2, zeile5);
    display.print("failed !");
  } else {
    Serial.println("");
    Serial.println("Temp Sensor OK");
    t = dht.readTemperature();
    display.setCursor(spalte2, zeile5);
    display.print(String(round(t)) + "C  ");
  }

  if (!RTC.begin()) {
    Serial.println("RTC ... initialization failed!");
    display.setCursor(spalte2, zeile1);
    display.print("failed !");
    //return;
  } else {
    Serial.println("RTC ... initialization done.");
    display.setCursor(spalte2, zeile1);
    display.print("OK");
  }
  // Nur zum Setzen der Zeit einmal freisetzen
  // Jahr, Monat, Tag, Stunde, Minute, Sekunde
  //RTC.adjust(DateTime(2023, 1, 29, 20, 28, 0));

  sensor.setTimeout(500);
  if (!sensor.init()) {
    Serial.println("Lasersensor ... initialization failed!");
    display.setCursor(spalte2, zeile2);
    display.print("failed !");
  } else {
    Serial.println("Lasersensor ... initialization done.");
    display.setCursor(spalte2, zeile2);
    display.print("OK");
  }

  // Use long distance mode and allow up to 50000 us (50 ms) for a measurement.
  // You can change these settings to adjust the performance of the sensor, but
  // the minimum timing budget is 20 ms for short distance mode and 33 ms for
  // medium and long distance modes. See the VL53L1X datasheet for more
  // information on range and timing limits.
  sensor.setDistanceMode(VL53L1X::Long);
  sensor.setMeasurementTimingBudget(33000);
  // Start continuous readings at a rate of one measurement every 50 ms (the
  // inter-measurement period). This period should be at least as long as the
  // timing budget.
  sensor.startContinuous(33);
  if (sensor.timeoutOccurred()) {
    Serial.println("Lasersensor Time out");
    return;
  }

  int tmpus = sonar.ping_cm();
  if (tmpus > 0) {
    Serial.println("US ... initialization done.");
    display.setCursor(spalte2, zeile3);
    display.print("OK");
  } else {
    Serial.println("US ... initialization failed!");
    display.setCursor(spalte2, zeile3);
    display.print("Ausser Reichw");
  }

  pixels.begin();
  pixels.setBrightness(pixelbright);
  pixels1.begin();
  pixels1.setBrightness(pixelbright);
  for (int i = 0; i < NUMPIXELS; i++) {  // For each pixel...
    // pixels.Color() takes RGB values, from 0,0,0 up to 255,255,255
    pixels.setPixelColor(i, pixels.Color(0, 150, 0));
    pixels1.setPixelColor(i, pixels1.Color(0, 150, 0));
    pixels.show();
    pixels1.show();
    delay(100);  // Pause before next pass through loop
  }

  Serial.print("SD card ... ");
  if (!SD.begin(53)) {
    Serial.println("initialization failed!");
    display.setCursor(spalte2, zeile6);
    display.print("failed !");
    while (1)
      ;
  } else {
    Serial.println("initialization done.");
    display.setCursor(spalte2, zeile6);
    display.print("OK");
  }

  for (int thisNote = 0; thisNote < 4; thisNote++) {                    // Loop through the notes in the array.
    TimerFreeTone(TONE_PIN, melody[thisNote], duration[thisNote], 10);  // Play thisNote for duration.
    delay(20);                                                          // Short delay between notes.
  }

  pinMode(Radarmodul, INPUT);

  if (cam.begin()) {
    delay(2000);
    Serial.println("Camera Found.");
    display.setCursor(spalte2, zeile4);
    char* reply = cam.getVersion();
    if (reply == 0) {
      Serial.print("Failed to get version");
    } else {
      int lenreply = String(reply).length();
      if (lenreply >= 13) {
        display.print(String(reply).substring(0, 12));
      } else {
        display.print(String(reply));
      }
    }
    //cam.setImageSize(VC0706_640x480);
    cam.setImageSize(VC0706_320x240);
    //cam.setImageSize(VC0706_160x120);
    cam.setMotionDetect(true);
    camrunning = !camrunning;
  } else {
    Serial.println("No camera found !");
    display.setCursor(spalte2, zeile4);
    display.print("Nicht vorh.");
  }

  pinMode(A0, INPUT);
  int potivalue = analogRead(A0);
  int volvalue = map(potivalue, 0, 1023, 10, 0);
  display.setCursor(spalte2, zeile7);
  display.print(volvalue);

  display.display();

  pinMode(8, INPUT_PULLUP);  // Button
  CheckButtonPress1 = digitalRead(8);
  CheckButtonPress2 = CheckButtonPress1;
  while (CheckButtonPress1 == CheckButtonPress2) {
    display.setCursor(spalte3 + 10, zeile7);
    display.print("WARTE");
    display.display();
    delay(500);
    display.setCursor(spalte3 + 10, zeile7);
    display.print("     ");
    display.display();
    delay(500);
    CheckButtonPress1 = digitalRead(8);
  }
  CheckButtonPress1 = digitalRead(8);
  CheckButtonPress2 = CheckButtonPress1;

  digitalWrite(LED1, LOW);
  digitalWrite(LED2, LOW);
  digitalWrite(LED3, LOW);

  pixels.clear();
  pixels.show();
  pixels1.clear();
  pixels1.show();

  display.clearDisplay();
  display.display();

  display.setCursor(spalte1, zeile1);
  display.print(text1);
  display.setCursor(spalte1, zeile2);
  display.print(text2);
  display.setCursor(spalte1, zeile3);
  display.print(text3);
  display.setCursor(spalte1, zeile4);
  display.print(text4);
  display.setCursor(spalte1, zeile5);
  display.print(text5);
  display.setCursor(spalte1, zeile6);
  display.print(text6);
  display.setCursor(spalte1, zeile7);
  display.print(text7);
  display.setCursor(spalte1, zeile8);
  display.print(text8);
  display.display();
}

void loop() {
  DateTime now = RTC.now();
  char timebuffer[20];
  char datebuffer[16];
  char filedatebuffer[16];
  sprintf(timebuffer, "%02u:%02u:%02u", now.hour(), now.minute(), now.second());
  sprintf(datebuffer, "%02u.%02u", now.day(), now.month());
  sprintf(filedatebuffer, "%02u%02u", now.month(), now.day());
  outdate = String(datebuffer) + "." + String(now.year()).substring(2, 4);
  fileoutdate = String(now.year()).substring(2, 4) + filedatebuffer;
  outtime = timebuffer;

  potivalue = analogRead(A0);
  volvalue = map(potivalue, 0, 1023, 10, 0);
  display.setCursor(spalte2, zeile7);
  display.print(String(volvalue) + "   ");

  write_laser = false;
  sens_read_neu = sensor.read() / 10;
  display.setCursor(spalte2, zeile2);
  display.print(leerz);
  display.setCursor(spalte2, zeile2);
  display.print(String(sens_read_neu));
  display.setCursor(spalte2 + 20, zeile2);
  display.print("(" + String(sens_read - laser_minmax) + "-" + String(sens_read + laser_minmax) + ")");
  if (abs(sens_read_neu - sens_read) > laser_minmax) {
    sens_read = sens_read_neu;
    display.setCursor(spalte1 + 121, zeile2);
    display.print("*");
    write_laser = true;
    TimerFreeTone(TONE_PIN, melody[2], duration[3], volvalue);
  } else {
    display.setCursor(spalte1 + 121, zeile2);
    display.print(" ");
  }

  pixels.clear();
  pixels.setBrightness(pixelbright);
  if (sens_read_neu < 50) {
    pixels.setPixelColor(0, pixels.Color(255, 0, 0));
    if ((sens_read != sens_read_neu) && (sens_read_neu < 50) && (sens_read_neu >= 0)) {
      pixels.setPixelColor(0, pixels.Color(0, 255, 255));
    }
  }
  if (sens_read_neu < 100) {
    pixels.setPixelColor(1, pixels.Color(255, 0, 0));
    if ((sens_read != sens_read_neu) && (sens_read_neu < 100) && (sens_read_neu >= 50)) {
      pixels.setPixelColor(1, pixels.Color(0, 255, 255));
    }
  }
  if (sens_read_neu < 150) {
    pixels.setPixelColor(2, pixels.Color(255, 255, 0));
    if ((sens_read != sens_read_neu) && (sens_read_neu < 150) && (sens_read_neu >= 100)) {
      pixels.setPixelColor(2, pixels.Color(0, 255, 255));
    }
  }
  if (sens_read_neu < 200) {
    pixels.setPixelColor(3, pixels.Color(255, 255, 0));
    if ((sens_read != sens_read_neu) && (sens_read_neu < 200) && (sens_read_neu >= 150)) {
      pixels.setPixelColor(3, pixels.Color(0, 255, 255));
    }
  }
  if (sens_read_neu < 250) {
    pixels.setPixelColor(4, pixels.Color(0, 255, 0));
    if ((sens_read != sens_read_neu) && (sens_read_neu < 250) && (sens_read_neu >= 200)) {
      pixels.setPixelColor(4, pixels.Color(0, 255, 255));
    }
  }
  if (sens_read_neu < 300) {
    pixels.setPixelColor(5, pixels.Color(0, 255, 0));
    if ((sens_read != sens_read_neu) && (sens_read_neu < 300) && (sens_read_neu >= 250)) {
      pixels.setPixelColor(5, pixels.Color(0, 255, 255));
    }
  }
  if (sens_read_neu < 350) {
    pixels.setPixelColor(6, pixels.Color(255, 255, 255));
    if ((sens_read != sens_read_neu) && (sens_read_neu < 350) && (sens_read_neu >= 300)) {
      pixels.setPixelColor(6, pixels.Color(0, 255, 255));
    }
  }
  if (sens_read_neu < 400) {
    pixels.setPixelColor(7, pixels.Color(255, 255, 255));
    if ((sens_read != sens_read_neu) && (sens_read_neu < 400) && (sens_read_neu >= 350)) {
      pixels.setPixelColor(7, pixels.Color(0, 255, 255));
    }
  }
  pixels.show();

  write_us = false;
  us_sens_read_neu = sonar.ping_cm();
  display.setCursor(spalte2, zeile3);
  display.print(leerz);
  display.setCursor(spalte2, zeile3);
  display.print(String(us_sens_read_neu));
  display.setCursor(spalte2 + 20, zeile3);
  display.print("(" + String(us_sens_read - us_minmax) + "-" + String(us_sens_read + us_minmax) + ")");
  if (abs(us_sens_read_neu - us_sens_read) > us_minmax) {
    us_sens_read = us_sens_read_neu;
    display.setCursor(spalte1 + 122, zeile3);
    display.print("*");
    write_us = true;
    TimerFreeTone(TONE_PIN, melody[1], duration[1], volvalue);
  } else {
    display.setCursor(spalte1 + 122, zeile3);
    display.print(" ");
  }
  delay(30);  // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.

  pixels1.clear();
  pixels1.setBrightness(pixelbright);
  if (us_sens_read_neu < 50) {
    pixels1.setPixelColor(0, pixels1.Color(255, 0, 0));
    if ((us_sens_read != us_sens_read_neu) && (us_sens_read_neu < 50) && (us_sens_read_neu >= 0)) {
      pixels1.setPixelColor(0, pixels1.Color(0, 255, 255));
    }
  }
  if (us_sens_read_neu < 100) {
    pixels1.setPixelColor(1, pixels1.Color(255, 0, 0));
    if ((us_sens_read != us_sens_read_neu) && (us_sens_read_neu < 100) && (us_sens_read_neu >= 50)) {
      pixels1.setPixelColor(1, pixels1.Color(0, 255, 255));
    }
  }
  if (us_sens_read_neu < 150) {
    pixels1.setPixelColor(2, pixels1.Color(255, 255, 0));
    if ((us_sens_read != us_sens_read_neu) && (us_sens_read_neu < 150) && (us_sens_read_neu >= 100)) {
      pixels1.setPixelColor(2, pixels1.Color(0, 255, 255));
    }
  }
  if (us_sens_read_neu < 200) {
    pixels1.setPixelColor(3, pixels1.Color(255, 255, 0));
    if ((us_sens_read != us_sens_read_neu) && (us_sens_read_neu < 200) && (us_sens_read_neu >= 150)) {
      pixels1.setPixelColor(3, pixels1.Color(0, 255, 255));
    }
  }
  if (us_sens_read_neu < 250) {
    pixels1.setPixelColor(4, pixels1.Color(0, 255, 0));
    if ((us_sens_read != us_sens_read_neu) && (us_sens_read_neu < 250) && (us_sens_read_neu >= 200)) {
      pixels1.setPixelColor(4, pixels1.Color(0, 255, 255));
    }
  }
  if (us_sens_read_neu < 300) {
    pixels1.setPixelColor(5, pixels1.Color(0, 255, 0));
    if ((us_sens_read != us_sens_read_neu) && (us_sens_read_neu < 300) && (us_sens_read_neu >= 250)) {
      pixels1.setPixelColor(5, pixels1.Color(0, 255, 255));
    }
  }
  if (us_sens_read_neu < 350) {
    pixels1.setPixelColor(6, pixels1.Color(255, 255, 255));
    if ((us_sens_read != us_sens_read_neu) && (us_sens_read_neu < 350) && (us_sens_read_neu >= 300)) {
      pixels1.setPixelColor(6, pixels1.Color(0, 255, 255));
    }
  }
  if (us_sens_read_neu < 400) {
    pixels1.setPixelColor(7, pixels1.Color(255, 255, 255));
    if ((us_sens_read != us_sens_read_neu) && (us_sens_read_neu < 400) && (us_sens_read_neu >= 350)) {
      pixels1.setPixelColor(7, pixels1.Color(0, 255, 255));
    }
  }
  pixels1.show();

  writetemp = 0;
  h_neu = dht.readHumidity();
  t_neu = dht.readTemperature();
  if (isnan(dht.readTemperature())) {
    Serial.println("Temp Sensor not working ");
  } else {
    display.setCursor(spalte2, zeile5);
    display.print(String(round(t_neu)) + "C (" + String(round(t)) + ") ");
    display.setCursor(spalte3 + 26, zeile5);
    display.print(String(round(h_neu)) + "%");
    if ((round(t_neu) < (round(t) - minmax)) || (round(t_neu) >= (round(t) + minmax))) {
      digitalWrite(LED2, HIGH);
      TimerFreeTone(TONE_PIN, melody[3], duration[2], volvalue);
      writetemp = true;
      t = t_neu;
    } else {
      digitalWrite(LED2, LOW);
    }
  }

  WERT = 0;
  WERT = digitalRead(Radarmodul);
  if (WERT == HIGH) {  // check if the input is HIGH
    if (motionState == LOW) {
      display.setCursor(spalte2, zeile8);
      display.print("detected");
      TimerFreeTone(TONE_PIN, melody[2], duration[2], volvalue);
      digitalWrite(LED1, HIGH);
      motionState = HIGH;
    }
  } else {
    if (motionState == HIGH) {
      display.setCursor(spalte2, zeile8);
      display.print("         ");
      digitalWrite(LED1, LOW);
      motionState = LOW;
    }
  }

  pictaken = 0;
  if (camrunning == true) {
    if (cam.motionDetected()) {
      cam.setMotionDetect(false);
      if (!cam.takePicture()) {
        display.setCursor(spalte2, zeile4);
        display.print("Fehler b. Speichern");
      } else {
        // set date time callback function
        SdFile::dateTimeCallback(dateTime);
        sprintf(timestamp, "%02d:%02d:%02d %2d/%2d/%2d \n", now.hour(), now.minute(), now.second(), now.month(), now.day(), now.year() - 2000);
        //Serial.println(timestamp);
        uint8_t imgsize = cam.getImageSize();
        display.setCursor(spalte2, zeile4);
        if (imgsize == VC0706_640x480) display.print("640x480");
        if (imgsize == VC0706_320x240) display.print("320x240");
        if (imgsize == VC0706_160x120) display.print("160x120");
        picanzahl = picanzahl + 1;
        display.setCursor(spalte3 + 30, zeile4);
        display.print(picanzahl);
        char filename[14] = "IMAGE000.JPG";
        for (int i = 0; i < 1000; i++) {
          sprintf(filename, "IMAGE%03d.JPG", i);
          // create if does not exist, do not open existing, write, sync after write
          if (!SD.exists(filename)) {
            break;
          }
        }
        digitalWrite(LED3, HIGH);
        TimerFreeTone(TONE_PIN, melody[3], duration[2], volvalue);
        File imgFile = SD.open(filename, FILE_WRITE);
        uint32_t jpglen = cam.frameLength();
        //Serial.print("Writing image to ");
        //Serial.println(filename);
        while (jpglen > 0) {
          uint8_t* buffer;
          uint8_t bytesToRead = min((uint64_t)64, jpglen);  // change 32 to 64 for a speedup but may not work with all setups!
          buffer = cam.readPicture(bytesToRead);
          imgFile.write(buffer, bytesToRead);
          jpglen -= bytesToRead;
        }
        imgFile.close();
        cam.resumeVideo();
        cam.setMotionDetect(true);
        digitalWrite(LED3, LOW);
        pictaken = 10;
      }
    }
  } else {
    display.setCursor(spalte2, zeile4);
    display.print("Nicht vorh.");
  }

  complete_output = outdate + "\t" + outtime + "\t" + sens_read_neu + "\t";
  complete_output = complete_output + String(round(t_neu)) + "\t" + String(round(h_neu)) + "\t";
  complete_output = complete_output + us_sens_read_neu + "\t" + (WERT * 10) + "\t" + pictaken;

  DataFile = SD.open(fileoutdate + ".txt", FILE_READ);
  if (DataFile) {
    if (DataFile.find("Datum")) {
      DataFile.close();
    } else {
      DataFile = SD.open(fileoutdate + ".txt", FILE_WRITE);
      if (DataFile) {
        DataFile.println(Headeroutput);
        DataFile.close();
      }
    }
  } else {
    DataFile = SD.open(fileoutdate + ".txt", FILE_WRITE);
    if (DataFile) {
      DataFile.println(Headeroutput);
      DataFile.close();
      Serial.println(Headeroutput);
    }
  }
  
  //Für seriellen Plotter !
  //Serial.print(sens_read);
  //Serial.print(" ");
  //Serial.print(sens_read_neu);
  //Serial.print(" ");
  //Serial.print(round(t_neu));
  //Serial.print(" ");
  //Serial.println(us_sens_read_neu);
  //Serial.print(" ");
  //Serial.print(WERT * 10);
  //Serial.print(" ");
  //Serial.println(pictaken);

  //Serial.println(String(pictaken) + " " + String(write_laser) + " " + String(write_us) + " " + String(writetemp) + " " + String(WERT));
  if ((pictaken == 0) && (write_laser == 0) && (write_us == 0) && (writetemp == 0) && (WERT == 0)) {
    //Do nothing !!!
  } else {
    DataFile = SD.open(fileoutdate + ".txt", FILE_WRITE);
    if (DataFile) {
      DataFile.println(complete_output);
      DataFile.close();
      //Serial.println(complete_output);
      datafilecount = datafilecount + 1;
      display.setCursor(spalte2, zeile6);
      display.print(String(datafilecount));
    } else {
      DataFile.println("error opening file");
    }
  }
  display.setCursor(spalte2 - 22, zeile1);
  display.print(outdate);
  display.setCursor(spalte3, zeile1);
  display.print(outtime);
  display.setCursor(spalte2 + 36, zeile6);
  display.print("(" + String(loopzaehler) + ")");
  display.display();
  h = h_neu;
  loopzaehler = loopzaehler + 1;

  if (CheckButtonPress1 == CheckButtonPress2) {
  } else {
    while (digitalRead(8) != CheckButtonPress2) {
      display.setCursor(spalte3 + 10, zeile7);
      display.print("PAUSE");
      display.display();
      delay(500);
      display.setCursor(spalte3 + 10, zeile7);
      display.print("     ");
      display.display();
      delay(500);
      CheckButtonPress1 = CheckButtonPress2;
    }
  }
  CheckButtonPress1 = digitalRead(8);
}
Bei Fragen & Problemen aller Art (oder nicht-funktionierenden Links, Videos, Grafiken, etc.) bitte per Rufzeichen-Symbol oben im Beitrag, per PN oder mittels Kontaktformular melden !
Info zu Werbeanzeigen und Unterstützung für Paranormal.wien !

Tags:
Benutzeravatar
Markus
Gründungsmitglied
Gründungsmitglied
Administrator
Administrator
EPAS Austria
EPAS Austria
Beiträge: 1205
Registriert: So 6. Jul 2014, 00:16
Wohnort: Wien
Hat sich bedankt: 412 Mal
Danksagung erhalten: 490 Mal
Kontaktdaten:
Österreich

Eigenbau: Multisensorbox mit Datenlogger und Kamera - Testlauf

Beitrag von Markus »

Um die Zuverlässigkeit über einen längeren Zeitraum zu testen, habe ich die Multisensorbox in meiner Computerecke (in Richtung Vorzimmer zeigend) aufgestellt und über 2 Stunden laufen lassen. Dabei hat sich bestätigt, dass die Kamera etwas langsam ist: wenn man flott nahe der Kamera vorbeigeht, ist meistens nur mehr das Hinterteil am Foto zu sehen. Korrigieren muss ich die Reichweite der Kamera-Bewegungserkennung: die 3m in meinem vorigen Beitrag stimmen zwar, jedoch nur bei Verwendung der IR-Leuchte. Ohne dieser beträgt die Reichweite etwa 2m. Zudem habe ich festgestellt, dass der Radarsensor einen Erfassungsbereich von 360° hat (vom Hersteller sind 120° angegeben).
  • Testlauf begonnen: 21.02.23 22:07:34
  • Testlauf beendet: 22.02.23 01:25:38
  • Dauer: 2 Stunden 18 Minuten
  • Programmdurchläufe: ca. 32000 (leider vergessen zu notieren)
  • Datensätze: 11813 (6382 + 5431)
  • Fotos: 28
  • Radar ausgelöst: 2380
Daten von 21.02.23 22:07:34 bis Mitternacht
Excel_diagramm1.jpg
Excel_Daten1.jpg
Daten von Mitternacht bis 22.02.23 01:25:38
Excel_diagramm2.jpg
Excel_Daten2.jpg
Hinweis: Die Legende befindet sich in der Mitte der Grafiken.
Diagramm laden
Diagramm laden
Bei Fragen & Problemen aller Art (oder nicht-funktionierenden Links, Videos, Grafiken, etc.) bitte per Rufzeichen-Symbol oben im Beitrag, per PN oder mittels Kontaktformular melden !
Info zu Werbeanzeigen und Unterstützung für Paranormal.wien !
Benutzeravatar
Markus
Gründungsmitglied
Gründungsmitglied
Administrator
Administrator
EPAS Austria
EPAS Austria
Beiträge: 1205
Registriert: So 6. Jul 2014, 00:16
Wohnort: Wien
Hat sich bedankt: 412 Mal
Danksagung erhalten: 490 Mal
Kontaktdaten:
Österreich

Eigenbau: Multisensorbox mit Datenlogger und Kamera (Mini-Update)

Beitrag von Markus »

motion-modules.jpg
Ein gewaltiges Problem bei Arduino-Projekten ist die Vielzahl an Sensoren und Modulen sowie die immer wieder auftauchenden, neueren und verbesserten Versionen derselben. Man entdeckt immer wieder was Neues und Besseres und verliert sich darin. Da hilft nur tief durchatmen, eine Pause einlegen und abschätzen, ob man das begehrte Teil wirklich braucht. Beim Ultraschallsensor für die Box habe ich keine Pause eingelegt :? .

Bereits im März habe ich den Nachfolger des SR04-Ultraschallsensors, den SRF05 (13,05 €), bestellt, allerdings habe ich mich bis jetzt vor dem Tausch gedrückt - das Montieren des Sensors ist nämlich eine ziemliche Fummelei. Aber heute habe ich es unter lautstarken Fluchen getan und es funktioniert alles. Am Code habe ich nichts geändert, da die neue Version kompatibel ist (nur die Uhrzeit der Real Time Clock habe ich wegen der blöden Sommerzeit neu gesetzt). Es gibt zwar eine eigene Programmbibliothek für den SRF05, welche allerdings nur marginale Anpassungen bietet. Getestet habe ich diese, ein Anpassen des Codes hätte sich jedoch nicht ausgezahlt.

Ich muss zugeben, dass sich das Ganze nicht wirklich ausgezahlt hat. Die neue Version ist etwas akkurater bei den Messwerten, dennoch hängen diese (wie bereits beschrieben) natürlich nach wie vor von den reflektierenden Flächen ab (Streuung). Aber was soll's ...
Vor der nächsten, aufgeregten Update-Überlegung sollte ich aber auf jeden Fall eine Nachdenkpause einlegen.
Bei Fragen & Problemen aller Art (oder nicht-funktionierenden Links, Videos, Grafiken, etc.) bitte per Rufzeichen-Symbol oben im Beitrag, per PN oder mittels Kontaktformular melden !
Info zu Werbeanzeigen und Unterstützung für Paranormal.wien !
Antworten
  • Vergleichbare Themen
    Antworten
    Zugriffe
    Letzter Beitrag

Zurück zu „Spezialgeräte“