Merge branch 'main' into 35-als-gebruiker-wil-ik-dat-mijn-data-word-opgeslagen-in-een-database-om-data-terug-te-zien

This commit is contained in:
2025-01-13 10:26:29 +01:00
36 changed files with 2043 additions and 380 deletions

View File

@@ -1,13 +1,54 @@
from flask import Flask, request, render_template, jsonify, g
from flask import Flask, Response, request, render_template, jsonify
import paho.mqtt.client as mqtt
from ultralytics import YOLO
import cv2
import numpy as np
import threading
import mysql.connector
import json
app = Flask(__name__)
# Globale variabelen
# Load a model
model = YOLO("yolo11n.pt") # pretrained YOLO11n model
kobuki_message = ""
latest_image = None
processed_image = None
yolo_results = []
# Lock for thread-safe access to shared variables
lock = threading.Lock()
# List of class names (example for COCO dataset)
yolo_classes = list(model.names.values())
def on_message(client, userdata, message):
global kobuki_message, latest_image, processed_image, yolo_results
if message.topic == "kobuki/data":
kobuki_message = str(message.payload.decode("utf-8"))
elif message.topic == "kobuki/cam":
with lock: # Lock the shared variables between threads so they can't be accessed at the same time and you cant have half processed images
latest_image = np.frombuffer(message.payload, np.uint8)
latest_image = cv2.imdecode(latest_image, cv2.IMREAD_COLOR)
# Process the image with YOLO
results = model(latest_image)
yolo_results = []
processed_image = latest_image.copy() # Create a copy for processing
for result in results:
for box in result.boxes:
class_id = int(box.cls.item())
class_name = yolo_classes[class_id]
yolo_results.append({
"class": class_name,
"confidence": box.conf.item(),
"bbox": box.xyxy.tolist()
})
# Draw bounding box on the processed image
x1, y1, x2, y2 = map(int, box.xyxy[0])
cv2.rectangle(processed_image, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.putText(processed_image, f"{class_name} {box.conf.item():.2f}", (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
# Globale MQTT setup
def on_message(client,userdata, message):
@@ -26,6 +67,9 @@ mqtt_client.username_pw_set("server", "serverwachtwoordofzo")
mqtt_client.connect("localhost", 1884, 60)
mqtt_client.loop_start()
mqtt_client.subscribe("kobuki/data")
mqtt_client.subscribe("kobuki/cam")
mqtt_client.on_message = on_message # this line needs to be under the function definition otherwise it can't find which function it needs to use
mqtt_client.on_message = on_message # this line needs to be under the function definition otherwise it can't find which function it needs to use
@@ -60,11 +104,6 @@ def control():
else:
return ('Unauthorized', 401, {'WWW-Authenticate': 'Basic realm="Login Required"'})
@app.route('/data', methods=['GET'])
def data():
return kobuki_message
@app.route('/move', methods=['POST'])
def move():
data = request.get_json()
@@ -127,5 +166,28 @@ def sensor_data(kobuki_message):
except mysql.connector.Error as err:
print(f"Database error: {err}")
@app.route('/data', methods=['GET'])
def data():
return kobuki_message
@app.route('/image')
def image():
global processed_image
with lock: # Lock the shared variables between threads so they can't be accessed at the same time and you cant have half processed images
if processed_image is not None:
_, buffer = cv2.imencode('.jpg', processed_image)
return Response(buffer.tobytes(), mimetype='image/jpeg')
else:
return "No image available", 404
@app.route('/yolo_results', methods=['GET'])
def yolo_results_endpoint():
global yolo_results
with lock:
return jsonify(yolo_results)
if __name__ == '__main__':
app.run(debug=True, port=5000)
app.run(debug=True, port=5000)

View File

@@ -1,41 +1,61 @@
document.querySelectorAll(".btn").forEach(button => {
button.addEventListener("click", async function(event) { // Maak de functie async
event.preventDefault(); // voorkomt pagina-verversing
document.addEventListener("DOMContentLoaded", function() {
document.querySelectorAll(".btn").forEach(button => {
button.addEventListener("click", function(event) {
event.preventDefault(); // prevents page refresh
// Haal de waarde van de knop op
const direction = event.target.value;
// Get the value of the button
const direction = event.target.value;
try {
const response = await fetch("/move", {
fetch("/move", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ direction: direction })
})
.then(response => response.json())
.then(data => {
console.log("Success:", data);
})
.catch(error => {
console.error("Error:", error);
});
const data = await response.json();
console.log("Success:", data);
} catch (error) {
console.error("Error:", error);
}
});
});
// Fetch data from the server
async function fetchData() {
// Fetch data from the server
async function fetchData() {
try {
const response = await fetch("/data");
const data = await response.json();
return data;
} catch (error) {
console.error("Error:", error);
}
}
// Parse the data and show it on the website
const data = await fetchData();
const sensorDataContainer = document.getElementById("sensor-data");
sensorDataContainer.innerHTML = ""; // Clear previous data
//for each object in json array create a new paragraph element and append it to the sensorDataContainer
// For each object in JSON array, create a new paragraph element and append it to the sensorDataContainer
for (const [key, value] of Object.entries(data)) {
const dataElement = document.createElement("p");
dataElement.textContent = `${key}: ${value}`;
sensorDataContainer.appendChild(dataElement); // Voeg het element toe aan de container
}
});
}
// Update the image
function updateImage() {
var img = document.getElementById("robot-image");
img.src = "/image?" + new Date().getTime(); // Add timestamp to avoid caching
}
// Fetch and display sensor data every 1 second
setInterval(parseData, 1000);
// Update the image every 200 milliseconds
setInterval(updateImage, 100);
});

View File

@@ -167,4 +167,4 @@ th,td {
th {
background-color: #f2f2f2;
text-align: left;
}
}

Binary file not shown.