This shows you the differences between two versions of the page.
|
iothings:proiecte:2022sric:motion-detection [2023/06/02 04:04] denis.zoican |
iothings:proiecte:2022sric:motion-detection [2023/06/02 08:25] (current) denis.zoican [Software Design] |
||
|---|---|---|---|
| Line 20: | Line 20: | ||
| - [[https://www.emag.ro/fire-cabluri-tata-tata-arduino-modulosy-20-cm-40-buc-5903689130493/pd/DSXWKRMBM/?cmpid=87002&gclid=CjwKCAjwg-GjBhBnEiwAMUvNW5PwIBJRkQa1B_L6_S4qtSAiKIHZwc8SP9CVTK0SFbi0vcymN0HNMhoC2AMQAvD_BwE | Connection wires]] | - [[https://www.emag.ro/fire-cabluri-tata-tata-arduino-modulosy-20-cm-40-buc-5903689130493/pd/DSXWKRMBM/?cmpid=87002&gclid=CjwKCAjwg-GjBhBnEiwAMUvNW5PwIBJRkQa1B_L6_S4qtSAiKIHZwc8SP9CVTK0SFbi0vcymN0HNMhoC2AMQAvD_BwE | Connection wires]] | ||
| - | === Hardware Schematics === | + | === Schematics === |
| {{:iothings:proiecte:2022sric:motion-detection-schema.png?700|}} | {{:iothings:proiecte:2022sric:motion-detection-schema.png?700|}} | ||
| Line 26: | Line 26: | ||
| ==== Software Design ==== | ==== Software Design ==== | ||
| - | The project was developed on 2 different boards: | + | The project was developed on 2 different boards: ESP32 and Raspberry Pi 4. |
| - | 1. ESP32 board - the code was written using Arduino IDE, where I used the Arduino libraries | + | |
| - | 2. Raspberry Pi 4 - the code was written in Python, where I used OpenCV and Flask | + | |
| - | 1. ESP32 board | + | === ESP32 board code === |
| The first part of the code is the setup part where I define the variables, constants, used libraries and the logic in the setup function. | The first part of the code is the setup part where I define the variables, constants, used libraries and the logic in the setup function. | ||
| Line 45: | Line 43: | ||
| //define sound speed in cm/uS | //define sound speed in cm/uS | ||
| #define SOUND_SPEED 0.034 | #define SOUND_SPEED 0.034 | ||
| - | #define CM_TO_INCH 0.393701 | ||
| - | #define WIFI_NETWORK "MERCUSYS_DCEE" | + | #define WIFI_NETWORK "WIFI_NAME" |
| - | #define WIFI_PASSWORD "74745814" | + | #define WIFI_PASSWORD "WIFI_PASS" |
| #define WIFI_TIMEOUT 20000 | #define WIFI_TIMEOUT 20000 | ||
| #define API_URL "http://ip-:5000/upload_photo" | #define API_URL "http://ip-:5000/upload_photo" | ||
| Line 58: | Line 55: | ||
| void setup() { | void setup() { | ||
| - | Serial.begin(115200); // Starts the serial communication | + | Serial.begin(115200); |
| pinMode(buzzerPin, OUTPUT); | pinMode(buzzerPin, OUTPUT); | ||
| - | pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output | + | pinMode(trigPin, OUTPUT); |
| - | pinMode(echoPin, INPUT); // Sets the echoPin as an Input | + | pinMode(echoPin, INPUT); |
| connectToWifi(); | connectToWifi(); | ||
| Line 74: | Line 71: | ||
| <code> | <code> | ||
| void connectToWifi(){ | void connectToWifi(){ | ||
| - | Serial.println("Connecting.. status: " + String(WiFi.status())); | ||
| WiFi.mode(WIFI_STA); | WiFi.mode(WIFI_STA); | ||
| WiFi.begin(WIFI_NETWORK,WIFI_PASSWORD); | WiFi.begin(WIFI_NETWORK,WIFI_PASSWORD); | ||
| Line 134: | Line 130: | ||
| } | } | ||
| </code> | </code> | ||
| + | |||
| + | The loop function contains the main logic of the project. We will calculate the distance every 1 second and if the distance is smaller than 50 cm, the buzzer will generate a high pitched sound for 5 seconds and the esp32 board will make a POST request to the raspberry pi 4 board. After this, a photo will be taken and will be saved in the database. | ||
| + | |||
| + | <code> | ||
| + | void loop() { | ||
| + | |||
| + | long distance = getDistance(); | ||
| + | |||
| + | if(distance < 50){ | ||
| + | tone(buzzerPin, 1000); | ||
| + | makeRequest(); | ||
| + | |||
| + | // Wait for 5 seconds | ||
| + | delay(5000); | ||
| + | noTone(buzzerPin); | ||
| + | | ||
| + | } | ||
| + | | ||
| + | delay(1000); | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | === Raspberry Pi 4 board code === | ||
| + | |||
| + | The code that is used on this board is written in Python. This board will play the role of a server that will store the images in a database. The web server is implemented using the Flask framework and the database is implemented using SQLlite. | ||
| + | In order to create the database, I used the following python code where I defined a table with id, name and the image content. | ||
| + | |||
| + | <code> | ||
| + | import sqlite3 | ||
| + | import os | ||
| + | |||
| + | database_path = "./database.db" | ||
| + | |||
| + | conn = sqlite3.connect(database_path) | ||
| + | cursor = conn.cursor() | ||
| + | |||
| + | cursor.execute(""" | ||
| + | CREATE TABLE IF NOT EXISTS images ( | ||
| + | id INTEGER PRIMARY KEY, | ||
| + | name TEXT, | ||
| + | image_data BLOB | ||
| + | ) | ||
| + | """) | ||
| + | |||
| + | conn.commit() | ||
| + | conn.close() | ||
| + | </code> | ||
| + | |||
| + | In order to capture a photo using the web cam, I used OpenCV, a library of functions for real-time computer vision. I implemented 3 endpoints: | ||
| + | |||
| + | 1. upload_photo | ||
| + | When it receives a POST request, a photo will be taken using the web cam and the image will be saved in the database. | ||
| + | |||
| + | 2. image/{id} | ||
| + | Is a GET endpoint and returns a image based on the received id. | ||
| + | |||
| + | 3. image | ||
| + | Is a GET endpoint and returns the latest image in the database. | ||
| + | |||
| + | <code> | ||
| + | from flask import Flask, send_file | ||
| + | import sqlite3 | ||
| + | import cv2 | ||
| + | |||
| + | |||
| + | app = Flask(__name__) | ||
| + | database_path = "./database.db" # SQLite database file | ||
| + | |||
| + | @app.route('/upload_photo', methods=['POST']) | ||
| + | def upload_photo(): | ||
| + | # Connect to database | ||
| + | conn = sqlite3.connect(database_path) | ||
| + | cursor = conn.cursor() | ||
| + | | ||
| + | # Capture a photo | ||
| + | cam = cv2.VideoCapture(0) | ||
| + | ret, frame = cam.read() | ||
| + | |||
| + | if not ret: | ||
| + | print("failed to grab frame") | ||
| + | return | ||
| + | |||
| + | photo_file_path = "opencv_photo.png" | ||
| + | |||
| + | # Read the photo file as binary | ||
| + | with open(photo_file_path, 'rb') as photo_file: | ||
| + | photo_data = photo_file.read() | ||
| + | |||
| + | # Insert the photo in database | ||
| + | cursor.execute("INSERT INTO images (name, image_data) VALUES (?, ?)", (photo_file_path, photo_data)) | ||
| + | |||
| + | conn.commit() | ||
| + | conn.close() | ||
| + | |||
| + | return "Photo was uploaded" | ||
| + | | ||
| + | @app.route('/image') | ||
| + | def get_image(): | ||
| + | # Connect to database | ||
| + | conn = sqlite3.connect(database_path) | ||
| + | cursor = conn.cursor() | ||
| + | |||
| + | # Retrieve the image from the database wih the highest ID | ||
| + | cursor.execute("SELECT image_data FROM images WHERE id= (SELECT MAX(id) from images)") | ||
| + | result = cursor.fetchone() | ||
| + | |||
| + | # Save the image data to a temporary file | ||
| + | image_data = result[0] | ||
| + | temp_file = "tempFile.jpg" # Path to temporary file | ||
| + | with open(temp_file, "wb") as file: | ||
| + | file.write(image_data) | ||
| + | |||
| + | # Close the database connection | ||
| + | conn.close() | ||
| + | |||
| + | # Send the image file | ||
| + | return send_file(temp_file, mimetype='image/jpeg') | ||
| + | | ||
| + | @app.route('/image/<image_id>') | ||
| + | def get_image_id(image_id): | ||
| + | # Connect to the database | ||
| + | conn = sqlite3.connect(database_path) | ||
| + | cursor = conn.cursor() | ||
| + | |||
| + | # Retrieve the image from the database based on the id | ||
| + | cursor.execute("SELECT image_data FROM images WHERE id=?", (image_id,)) | ||
| + | result = cursor.fetchone() | ||
| + | |||
| + | # Save the image data to a temporary file | ||
| + | image_data = result[0] | ||
| + | temp_file = "tempFile.jpg" | ||
| + | with open(temp_file, "wb") as file: | ||
| + | file.write(image_data) | ||
| + | |||
| + | # Close the database connection | ||
| + | conn.close() | ||
| + | |||
| + | # Send the image file | ||
| + | return send_file(temp_file, mimetype='image/jpeg') | ||
| + | |||
| + | if __name__ == '__main__': | ||
| + | app.run(host='0.0.0.0', port=5000) | ||
| + | |||
| + | </code> | ||
| + | |||
| + | The last photo can be viewed by accessing the url: raspberry-pi-ip:5000/image | ||
| + | === Demo === | ||
| + | |||
| + | YouTube link: https://www.youtube.com/watch?v=mqfNEk4cIAE | ||
| + | |||
| + | === References === | ||
| + | |||
| + | - [[https://docs.opencv.org/4.x/|OpenCV]] | ||
| + | - [[https://flask.palletsprojects.com/en/2.3.x/|Flask]] | ||
| + | - [[https://projecthub.arduino.cc/Isaac100/getting-started-with-the-hc-sr04-ultrasonic-sensor-7cabe1|HC-SR04]] | ||
| + | - [[https://www.sqlite.org/docs.html|SQLlite]] | ||