Autoren: Kevin Mudzcinski & Henry Fröse
Betreuer: Prof. Göbel & Prof. Schneider
→ zurück zur Übersicht: WS 20/21: Angewandte Elektrotechnik (BSE)
→ zurück zur Übersicht: WS 21/22: Angewandte Elektrotechnik (BSE)
→ zurück zur Übersicht: WS 22/23: Angewandte Elektrotechnik (BSE)
Einleitung
Im Rahmen des GET-Fachpraktikums [[1]] entsteht das Projekt „Überwachungskamera“. Sinn des Projektes ist es, ein mechatronisches System zu entwerfen, zu fertigen und zu testen. Dabei sollen vor allem die Kenntnisse aus dem Modul Mess- und Regelungstechnik zur Hilfe genommen werden.
Das System registriert mit Hilfe der Sensoren ungewöhnliche Ereignisse aufgrund von Bewegungen bzw. Geräuschen. Daraufhin macht die Kamera ein Foto und sendet dieses per Telegram-Bot [2] an den Nutzer.
An dem Projekt arbeiten die Mechatronik-Studenten Kevin Mudzcinski und Henry Fröse.
-
Abb. 1: Illustration Überwachungskamera
Anforderungen
Tabelle 1: Testbare, atomare Anforderungen
ID
|
Inhalt
|
Ersteller
|
Datum
|
Geprüft von
|
Datum
|
1
|
Die Kamera wird über USB-Anschluss mit Strom versorgt.
(Kann über Powerbank und Netzteil mit Strom versorgt werden)
|
Henry Fröse
|
01.10.2022
|
Kevin Mudzinski
|
11.10.2022
|
2
|
Der PIR-Sensor registriert Bewegungen.
(Digitales HIGH/LOW-Signal wird dem Arduino Übertragen - Schwellwert wird mittels Potentiometer eingestellt)
|
Henry Fröse
|
01.10.2022
|
Kevin Mudzinski
|
11.10.2022
|
3
|
Der Sound-Sensor registriert Geräusche.
(Digitales HIGH/LOW-Signal wird dem Arduino Übertragen - Schwellwert wird mittels Potentiometer eingestellt)
|
Henry Fröse
|
01.10.2022
|
Kevin Mudzinski
|
11.10.2022
|
4
|
Die ESP32-CAM erstellt ein Foto, wenn der Bewegungs- oder der Geräuschssensor ein HIGH-Signal dem Arduino überträgt.
|
Henry Fröse
|
01.10.2022
|
Kevin Mudzinski
|
11.10.2022
|
5
|
Der Microcontroller ist ins Heimnetzwerk mittels SSID und Passwort eingebunden.
|
Henry Fröse
|
01.10.2022
|
Kevin Mudzinski
|
11.10.2022
|
6
|
Das Bild wird mittels Telegram-Bot an den Benutzer übertragen.
(Iteration über ID-Liste der Telegram-Accounts der Benutzer - Automatische Benachrichtigung per Telegram-App)
|
Henry Fröse
|
01.10.2022
|
Kevin Mudzinski
|
11.10.2022
|
7
|
Es können mehrere Benutzer eingebunden werden.
(Iteration über ID-Liste der Telegram-Accounts der Benutzer - Müssen manuell eingefügt werden im Programmcode)
|
Henry Fröse
|
01.10.2022
|
Kevin Mudzinski
|
11.10.2022
|
8
|
Die Benutzer haben die Möglichkeit manuell ein Bild anzufordern.
(Benutzereingabe in der Telegram-App in den Chat des Bots - Befehl "/picture")
|
Henry Fröse
|
01.10.2022
|
Kevin Mudzinski
|
11.10.2022
|
Tabelle 1 zeigt die funktionalen Anforderungen.
Funktionaler Systementwurf/Technischer Systementwurf
-
Abb. 2: Technischer Systementwurf
-
Abb. 3: Funktionaler Systementwurf
Komponentenspezifikation
Tabelle 2: Liste aller Komponenten
ID
|
Komponente
|
Bezeichnung
|
Bild
|
1
|
PIR Sensor
|
HC-SR501
|
|
2
|
Mikrofon Soundsensor
|
KY-038
|
|
3
|
Entwicklungsplatine inkl. Kamera
|
ESP32-CAM
|
|
4
|
Gehäuse
|
3D-Druck PLA in schwarz
|
|
5
|
Datenkabel und Stromkabel
|
Litze 0.5mm^2 verschiedene Farben
|
|
6
|
Stromanschluss
|
1m USB-3.0-Female auf Micro-USB-3.0-Female Kabel
(Micro-USB Seite wird entfernt und abisoliert)
|
|
7
|
Verbrauchsmaterial interne Verkabelung
|
Schrumpfschlauch und Lötzinn
|
|
Umsetzung (HW/SW)
Gehäuse
Das komplette Gehäuse ist mittels 3D-Druck erstellt worden. Die Verbindung der einzelnen Komponenten ist mittels Schrauben gelöst worden, um die Kamera leicht auseinandernehmbar zu gestalten.
Um die Verschiedenen Teile stabil Drucken zu können wurden vereinzelt Komponenten, wie z.B. die Kamerarückwand und die Verbindung an die Halterung.
Das Gehäuse ist in 3 Schichten Unterteilt: 1. Vorderseite (Bietet Aussparungen für die Kamera, Mikrofon und PIR), 2. Mittelring (Dient zu Fixierung der Bauteile ohne diese Anzukleben / Festzuschrauben), 3. Die Rückseite (Bietet erhöhtes Volumen für die Verkabelung und Stromzufuhr)
Halterung
Die Halterung kann in 2 Dimensionen Hoch/Runter und Links/Rechts bewegt werden. Hierbei dienen Schrauben zur Fixierung der Position, indem sie mittels "Quetschscheiben" die Bewegung verhindern.
An der Rückseite bietet die Halterung eine Platte zur Befestigung mittels Schrauben für einen Gewindedurchmesser von 4mm in allen 4 Ecken.
Schaltung
Das Mikrofon und der PIR sind an digitalen Pins des Mikrokontrollers angeschlossen. Mittels Widerstand ist ein Schwellwert eingestellt worden.
Die Kamera sowie der Wifi-Chip sind direkt auf dem Mikrokontrollers implementiert.
Code
Die Implementierung von Telegramm und Das verschicken von Bildern ist in Anlehnung an "https://randomnerdtutorials.com/telegram-esp32-cam-photo-arduino/" implementiert worden.
//WIFI
#include <WiFi.h>
#include <WiFiClientSecure.h>
//TELEGRAM
#include <UniversalTelegramBot.h>
#include <ArduinoJson.h>
//CAMERA
#include "esp_camera.h"
#include "camera_pins.h"
//SENSOR
#define MOTION_PIN 2
bool motionState = false;
#define MIC_PIN 13
bool micState = false;
//WIFI
char* SSID_WIFI = "<SSID>";
char* PASSWORD_WIFI = "<PASSWORT>";
//TELEGRAM
String BOT_TOKEN = "<TOKEN:TOKEN>";
int USER_CHAT_ID_LENGTH = 1;
String USER_CHAT_IDS[] = {"<USER ID>", "<USER ID2>"};
//TELEGRAM
WiFiClientSecure client;
UniversalTelegramBot bot(BOT_TOKEN, client);
//REQUEST TIME
int requestDelay = 1000;
unsigned long lastTime;
void printNewMessage(int index) {
Serial.println("------------------------");
Serial.println("NEW MESSAGE:");
Serial.print("USER: ");
Serial.println(bot.messages[index].from_name);
Serial.print("USER ID: ");
Serial.println(bot.messages[index].chat_id);
Serial.print("TEXT: ");
Serial.println(bot.messages[index].text);
Serial.println("------------------------");
}
void processMessage(int messageNum) {
for (int i=0; i < messageNum; i++) {
printNewMessage(i);
String chat_id = String(bot.messages[i].chat_id);
if (chatIdIsInChatIdList(chat_id) == true) {
String text = bot.messages[i].text;
String user = bot.messages[i].from_name;
if (text == "/start") {
String response = "";
response += "Welcome, " + user + ".\n";
response += "Use the following commands to control your outputs.\n\n";
response += "/picture to take a picture \n";
response += "/start to get information\n";
bot.sendMessage(chat_id, response, "");
}
else if (text == "/picture") {
String response = "";
response += "Take an Image...";
bot.sendMessage(chat_id, response, "");
sendPicture(chat_id, false);
}
else {
String response = "";
response += "Unbekannter Befehl!\n";
response += "Bitte versuche es erneut.";
bot.sendMessage(chat_id, response, "");
}
} else {
bot.sendMessage(chat_id, "Unauthorized User", "");
continue;
}
}
}
bool chatIdIsInChatIdList(String chat_id) {
for (int i = 0; i < USER_CHAT_ID_LENGTH; i++) {
if (chat_id == USER_CHAT_IDS[i]){
return true;
}
}
return false;
}
String sendPicture(String chat_id, bool flash) {
const char* myDomain = "api.telegram.org";
String getAll = "";
String getBody = "";
camera_fb_t* fb = NULL;
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
delay(1000);
ESP.restart();
return "Camera capture failed";
}
Serial.println("Connect to " + String(myDomain));
if (client.connect(myDomain, 443)) {
Serial.println("Connection successful");
//X ==> Boundary
String head = "--X\r\nContent-Disposition: form-data; name=\"chat_id\"; \r\n\r\n" + chat_id + "\r\n--X\r\nContent-Disposition: form-data; name=\"photo\"; filename=\"esp32-cam.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
String tail = "\r\n--X--\r\n";
uint16_t imageLen = fb->len;
uint16_t extraLen = head.length() + tail.length();
uint16_t totalLen = imageLen + extraLen;
client.println("POST /bot" + BOT_TOKEN + "/sendPhoto HTTP/1.1");
client.println("Host: " + String(myDomain));
client.println("Content-Length: " + String(totalLen));
client.println("Content-Type: multipart/form-data; boundary=X");
client.println();
client.print(head);
uint8_t *fbBuf = fb->buf;
size_t fbLen = fb->len;
for (size_t n = 0; n < fbLen; n = n + 1024) {
if (n + 1024 < fbLen) {
client.write(fbBuf, 1024);
fbBuf += 1024;
}
else if (fbLen % 1024 > 0) {
size_t remainder = fbLen % 1024;
client.write(fbBuf, remainder);
}
}
client.print(tail);
esp_camera_fb_return(fb);
int waitTime = 10000; // timeout 10 seconds
long startTimer = millis();
boolean state = false;
while ((startTimer + waitTime) > millis())
{
Serial.print(".");
delay(100);
while (client.available())
{
char c = client.read();
if (c == '\n')
{
if (getAll.length() == 0) state = true;
getAll = "";
}
else if (c != '\r')
getAll += String(c);
if (state == true) getBody += String(c);
startTimer = millis();
}
if (getBody.length() > 0) break;
}
client.stop();
Serial.println(getBody);
}
else {
getBody = "Connected to api.telegram.org failed.";
Serial.println("Connected to api.telegram.org failed.");
}
return getBody;
}
void setup() {
startSerial();
connectToWifi();
setTelegramCertificate();
setupCamera();
}
void setupHardware() {
/*
pinMode(MOTION_PIN, INPUT);
pinMode(MIC_PIN, INPUT);
*/
}
void startSerial() {
Serial.begin(115200);
Serial.println("Start SERIAL");
}
void setTelegramCertificate() {
client.setCACert(TELEGRAM_CERTIFICATE_ROOT);
}
void connectToWifi() {
Serial.println("Connect to WIFI");
WiFi.begin(SSID_WIFI, PASSWORD_WIFI);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
}
void setupCamera() {
Serial.println("Setup CAMERA");
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
config.frame_size = FRAMESIZE_SVGA; //SVGA 800x600 / UXGA 1600x1200
config.jpeg_quality = 10;
config.fb_count = 2;
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Setup CAMERA failed with ERROR: ", err);
return;
}
}
void loop() {
checkSensors();
checkMessagingServer();
}
void checkSensors() {
//PIR MOTION SENSOR
//Serial.println(digitalRead(MOTION_PIN));
if (motionState == true && digitalRead(MOTION_PIN) == 0) {
motionState = false;
}
if (motionState == false && digitalRead(MOTION_PIN) == 1) {
for (int i = 0 ;i < USER_CHAT_ID_LENGTH; i++) {
bot.sendMessage(USER_CHAT_IDS[i], "MOTION detected" , "");
sendPicture(USER_CHAT_IDS[i], false);
}
motionState = true;
}
//MICROFON
Serial.println(digitalRead(MIC_PIN));
if (micState == true && digitalRead(MIC_PIN) == 0) {
micState = false;
}
if (micState == false && digitalRead(MIC_PIN) == 1) {
for (int i = 0 ;i < USER_CHAT_ID_LENGTH; i++) {
bot.sendMessage(USER_CHAT_IDS[i], "SOUND detected" , "");
sendPicture(USER_CHAT_IDS[i], false);
}
micState = true;
}
}
void checkMessagingServer() {
if (millis() > lastTime + requestDelay) {
int numOfMessages = bot.getUpdates(bot.last_message_received + 1);
if (numOfMessages != 0) {
bool newMessage = true;
while(newMessage) {
processMessage(numOfMessages);
// is there another new message
numOfMessages = bot.getUpdates(bot.last_message_received + 1);
if (numOfMessages == 0) {
newMessage = false;
}
}
}
lastTime = millis();
}
}
Zusammenbau
Komponententest
Ergebnis
Zusammenfassung
Lessons Learned
Projektunterlagen
Projektplan
Umsetzung (HW/SW)
Tabelle 3: Bearbeitung der Meilensteine
ID
|
Meilensteine
|
Erledigt am
|
Erledigt von
|
1
|
PIR Sensor wird vom Mikrocontroller eingelesen und detektiert Bewegung korrekt
|
12.10.2022
|
Henry Fröse
|
2
|
Mikrofon wird vom Mikrocontroller eingelesen und detektiert Lautstärke korrekt
|
12.10.2022
|
Henry Fröse
|
3
|
Inbetriebnahme der Kamera mittels enthaltenem Beispielprogramm
|
15.10.2022
|
Henry Fröse
|
4
|
Verbinden des Mikrocontrollers mit dem Heimnetzwerk
|
16.10.2022
|
Henry Fröse
|
5
|
Erstellung eines Telegramm-Bots
|
22.10.2022
|
Kevin Mudczinski
|
6
|
Verbindung zwischen Telegram-Bot und Mikrocontroller aufgebaut
|
22.10.2022
|
Kevin Mudczinski
|
7
|
Erstellung einfacher Testbefehle mit Textzurückgabe
|
24.10.2022
|
Kevin Mudczinski
|
8
|
Verschicken von Bilder mittels Telegram-Bot
|
28.10.2022
|
Kevin Mudczinski
|
9
|
Automatische Versendung von Bildern bei Bewegungen und Geräuschen
|
05.11.2022
|
Henry Fröse
|
10
|
Entwicklung eines Gehäuses
|
28.09.2022
|
Kevin Mudczinski
|
11
|
Entwicklung einer Wandhalterung für die Kamera
|
10.11.2022
|
Kevin Mudczinski
|
12
|
Löten und Zusammenbau der Kamera mit Sensoren
|
16.11.2022
|
Kevin Mudczinski
|
Projektdurchführung
YouTube Video
Weblinks
Literatur
→ zurück zur Übersicht: WS 22/23: Angewandte Elektrotechnik (BSE)