60 Commits

Author SHA1 Message Date
0a8b96a45a increase image compression level and re-enabled thread 2025-01-22 13:46:47 +01:00
69eba455f9 added image compression to thread 2025-01-22 13:32:43 +01:00
e262325565 disabled image logick 2025-01-22 12:28:36 +01:00
ishak jmilou.ishak
f493665275 riep de functie nergens aan 2025-01-21 16:13:26 +01:00
ishak jmilou.ishak
899aa94b40 seperate yolo results because it updates now only when going to /yolo_results 2025-01-21 16:01:59 +01:00
ishak jmilou.ishak
d5524d7890 shouldn't have done POST 2025-01-21 15:09:23 +01:00
ishak jmilou.ishak
976840c6b2 forgot to do system prune 2025-01-21 14:28:40 +01:00
ishak jmilou.ishak
88364561ea got error when running new docker 2025-01-21 14:27:44 +01:00
ishak jmilou.ishak
64d2aedc3b feat: allow POST method for yolo_results endpoint 2025-01-21 14:16:26 +01:00
ishak jmilou.ishak
6597cb133a checking for error in db input 2025-01-21 14:10:31 +01:00
ishak jmilou.ishak
ec44cb955b feat: implement automatic reconnection for Kobuki when disconnected 2025-01-21 12:29:03 +01:00
ishak jmilou.ishak
c74b9a8758 refactor: use dynamic port detection for Kobuki communication setup 2025-01-21 12:26:41 +01:00
ishak jmilou.ishak
b20b9b693a changed portname to const char 2025-01-21 12:25:06 +01:00
ishak jmilou.ishak
99599a6c21 refactor: change portname parameter to const char* in startCommunication and improve USB device check logic 2025-01-21 12:23:20 +01:00
ishak jmilou.ishak
29ef742a94 fix: use const_cast for port string in Kobuki communication 2025-01-20 15:22:16 +01:00
ishak jmilou.ishak
0e9d9dda68 laat kobuki nu connecten op open ports 2025-01-20 15:18:37 +01:00
ishak jmilou.ishak
2c630bf89b refactor: improve Kobuki connection handling and add USB device check 2025-01-20 12:11:38 +01:00
ishak jmilou.ishak
ef3407b742 refactor: reorder includes and improve code formatting for readability 2025-01-20 11:15:45 +01:00
ishak jmilou.ishak
3d9a68ff7f added else statement 2025-01-20 11:09:12 +01:00
ishak jmilou.ishak
aedff1c2cc made more debug 2025-01-20 10:58:34 +01:00
ishak jmilou.ishak
c31689ac70 Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/technische-informatica-sm3/ti-projectten/rooziinuubii79 2025-01-16 13:55:25 +01:00
ishak jmilou.ishak
1ab718a472 new reconnect function 2025-01-16 13:55:24 +01:00
bbade2384c Merge branch 'usb-reconnect' into 'main'
opencv camera logic rewrite

See merge request technische-informatica-sm3/ti-projectten/rooziinuubii79!5
2025-01-16 12:36:32 +01:00
e04cff3d65 opencv camera logic rewrite 2025-01-16 12:28:40 +01:00
ishak jmilou.ishak
36aaee9bad removed commented code 2025-01-16 12:15:14 +01:00
7b51330675 update image refresh logic to be more optimized 2025-01-15 16:32:32 +01:00
3bb44ad4ab updated readme 2025-01-15 16:32:32 +01:00
ishak jmilou.ishak
fb12b20a0b changed colom name, addprint 2025-01-15 15:46:39 +01:00
ishak jmilou.ishak
1b3ccd1e72 commented yolor_result_db 2025-01-15 15:21:29 +01:00
ishak jmilou.ishak
a16abe068c returned to ohter function 2025-01-15 15:11:47 +01:00
ishak jmilou.ishak
9f7d7e7ac9 fixed insert into typo 2025-01-15 14:53:10 +01:00
ishak jmilou.ishak
6f34a0f554 Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/technische-informatica-sm3/ti-projectten/rooziinuubii79 2025-01-15 14:43:41 +01:00
ishak jmilou.ishak
364f6e5259 test of dit het probleem is voor camera 2025-01-15 14:43:40 +01:00
7c30d838f7 added thread.sleep to prevenet console flood 2025-01-15 14:40:38 +01:00
ishak jmilou.ishak
50bf777f78 cam does not work 2025-01-15 14:27:33 +01:00
ishak jmilou.ishak
95e2d292c9 Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/technische-informatica-sm3/ti-projectten/rooziinuubii79 2025-01-15 14:10:17 +01:00
ishak jmilou.ishak
3367f1dbd2 returen yolo result db 2025-01-15 14:09:46 +01:00
e273e175cb remove old code 2025-01-15 13:53:33 +01:00
06e08a2cfb camera reconnection added 2025-01-15 13:52:13 +01:00
ishak jmilou.ishak
4e78caa577 Comment out call to yolo_results_db function in on_message handler 2025-01-15 12:22:44 +01:00
ishak jmilou.ishak
5b0e843654 Add call to yolo_results_db function after processing YOLO results 2025-01-15 11:36:54 +01:00
ishak jmilou.ishak
8b66702605 changed function 2025-01-14 16:50:11 +01:00
ishak jmilou.ishak
d8b3ec2938 added thread 2025-01-14 16:39:52 +01:00
ishak jmilou.ishak
97076dfe05 Add Kobuki connection monitoring and automatic start/stop functionality 2025-01-14 16:35:51 +01:00
ishak jmilou.ishak
967bc8247c Refactor YOLO results handling by separating database insertion logic into a dedicated function 2025-01-14 15:37:08 +01:00
ishak jmilou.ishak
5d61579973 Refactor YOLO results endpoint to handle empty results and improve database insertion logic 2025-01-14 14:22:50 +01:00
ishak jmilou.ishak
ebd88e43ab Add error handling and database insertion for YOLO results 2025-01-14 13:23:48 +01:00
ishak jmilou.ishak
2fbe18be76 went back 2025-01-14 13:14:38 +01:00
ishak jmilou.ishak
74d9687af5 Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/technische-informatica-sm3/ti-projectten/rooziinuubii79 2025-01-14 12:30:56 +01:00
ishak jmilou.ishak
48023773c6 went back to older version. db get empty rows 2025-01-14 12:30:54 +01:00
56ac9cf687 change dockerfile command 2025-01-14 12:11:50 +01:00
ishak jmilou.ishak
3232ff121f changed db connection 2025-01-14 12:08:08 +01:00
5844387b19 merge foutje opgelost 2025-01-14 11:56:28 +01:00
ishak jmilou.ishak
b48243f831 changed sensor data to db in other function 2025-01-13 14:57:52 +01:00
317731ec87 python merge fix 2025-01-13 11:00:43 +01:00
441ca19578 repaired js after merge 2025-01-13 10:44:20 +01:00
7f807d0031 added g import from flask 2025-01-13 10:39:23 +01:00
c0ec6901c4 edited python requirements 2025-01-13 10:33:46 +01:00
2fa8fb2926 Merge branch '35-als-gebruiker-wil-ik-dat-mijn-data-word-opgeslagen-in-een-database-om-data-terug-te-zien' into 'main'
Resolve "Als gebruiker wil ik dat mijn data word opgeslagen in een database om data terug te zien"

Closes #35

See merge request technische-informatica-sm3/ti-projectten/rooziinuubii79!4
2025-01-13 10:27:00 +01:00
ishak jmilou.ishak
1fd88c7636 added some info on the readme 2025-01-08 15:19:03 +01:00
7 changed files with 357 additions and 115 deletions

View File

@@ -1,8 +1,70 @@
# TI-project - Kobuki
# TI-project - exploration robot Kobuki
## Description
This project is a kobuki that drives around in dangerous areas and detects objects in its path. It uses a camera to detect objects. The kobuki is able to drive around in a room and detect objects.
This project is a kobuki that drives around in dangerous areas and detects objects in its path. It uses a camera to detect objects. The purpose of this project is to explore dangerous areas without risking human lives. You are able to control the robot using controller on the website.
## Photos
![Kobuki](/docs/assets/KobukiPhoto.jpg)
## Installation
### Requirements
- Kobuki robot
- Raspberry Pi (minimum 3B)
- Camera
- power supply for Raspberry Pi
- laptop or computer
### Steps
1. **Install Python and Pip**
- Ensure you have Python installed on your system. You can download it from [python.org](https://www.python.org/).
- Pip is the package installer for Python. It usually comes with Python, but you can install it separately if needed.
2. **Clone Our Repository**
- Clone our repository to your local machine doing the following :
- Open your terminal
- Change the current working directory to the location where you want the cloned directory.
- Type `git clone https://gitlab.fdmci.hva.nl/technische-informatica-sm3/ti-projectten/rooziinuubii79.git
3. **Install the required packages**
- Install the following packages on the server: "docker docker-buildx mosquitto nginx"
- Install the following packages on the Raspberry Pi: "g++ make cmake", https://github.com/eclipse-paho/paho.mqtt.c, https://github.com/eclipse-paho/paho.mqtt.cpp
4. **Run the project**
#### Server side
- Run the following commands in the terminal to start the website:
- `cd src/Python/flask`
- `sudo docker buildx build -t flaskapp:latest .`
- `sudo docker run --network="host" --restart=always flaskapp:latest`
- Run the following commands in the terminal to start the MQTT broker:
- `cd src/config/server/`
- `mosquitto -c mosquitto.conf`
- Run the following commands in the terminal to start the Nginx server:
- `cd src/config/server/`
- `cp nginx.conf /etc/nginx/nginx.conf`
- `cp nginx-sites.conf /etc/nginx/sites-enable/nginx-sites.conf`
#### Raspberry Pi side
- Run the following commands to build and start the driver:
- `cd src/C++/Driver`
- `cmake ..`
- `make`
- `./kobuki_driver`
- Run the following commands to autostart the driver on startup of the Raspberry Pi:
- `cd src/config/rpi/`
- `cp kobukiDriver.service /etc/systemd/system/kobukiDriver.service`
- `systemctl enable kobukiDriver.service`
- `systemctl start kobukiDriver.service`
## Extra notes
Dont forget to change the IP address in the `src/C++/Driver/src/main.cpp` file to the IP address of the server.

View File

@@ -0,0 +1,78 @@
# Kobuki automatische reconnect
Mijn taak was om de kobuki automatisch te reconnecten als de verbinding verbroken werd met de pi. nu moet je telkens handmatig de pi laten connecten met de kobuki, dit is niet handig als iemand niet weet hoe dit moet.
De connectie word gemaakt met ttyUSB0. Dat is de eerste poort die wij kunnen gebruiken voor de kobuki.
```cpp
robot.startCommunication("/dev/ttyUSB0", true, null_ptr);
```
ik heb een functie gemaakt die kijkt of de pi nog is verbonden aan de kobuki. in de if statement kijkt hij elke 5 seconden of de ttyusb0 poort beschikbaar is.
```cpp
void checkKobukiConnection()
{
while (true)
{
std::lock_guard<std::mutex> lock(connectionMutex);
// Controleer of het apparaat beschikbaar is
if (!std::ifstream("/dev/ttyUSB0")){
if (kobuki_connected){
cout << "Kobuki disconnected: USB device not found." << endl;
kobuki_connected = false;
}
std::this_thread::sleep_for(std::chrono::seconds(5));
continue; // Probeer later opnieuw
}
```
Hier kijk ik dan of de kobuki is geconnect, zoniet dan moet ie weer connecten met ttyUSB0
```cpp
// Controleer of de Kobuki verbonden is
if (!robot.isConnected()){
if (kobuki_connected){
cout << "Kobuki disconnected." << endl;
kobuki_connected = false;
}
cout << "Attempting to reconnect Kobuki..." << endl;
robot.startCommunication("/dev/ttyUSB0", true, nullptr);
if (robot.isConnected()){
cout << "Kobuki reconnected successfully!" << endl;
kobuki_connected = true;
}
else{
cout << "Failed to reconnect Kobuki, retrying in 5 seconds..." << endl;
}
}
```
Nu heb ik het probleem dat als ik de kabel eruit steek en terug in de kobuki stop dat de pi niet meer wil connecten. Dit komt omdat het systeem denkt dat de poort "ttyUSB0" nog steeds gebruikt word. Als ik de kabel dan terug stop word de poort "ttyUSB1" gebruikt, omdat ttyusb0 niet word vrijgegeven.
```bash
ishak@raspberrypi:~ $ dmesg | tail -n 20
[10516.084132] usb 1-1.3: Product: iClebo Kobuki
[10516.084144] usb 1-1.3: Manufacturer: Yujin Robot
[10516.084155] usb 1-1.3: SerialNumber: kobuki_AI02MQMK
[10516.091210] ftdi_sio 1-1.3:1.0: FTDI USB Serial Device converter detected
[10516.091414] usb 1-1.3: Detected FT232R
[10516.099169] usb 1-1.3: FTDI USB Serial Device converter now attached to ttyUSB1
[10574.100491] usb 1-1.3: USB disconnect, device number 34
[10574.101596] ftdi_sio ttyUSB1: FTDI USB Serial Device converter now disconnected from ttyUSB1
[10574.101735] ftdi_sio 1-1.3:1.0: device disconnected
[10579.697816] usb 1-1.3: new full-speed USB device number 35 using dwc_otg
[10579.829776] usb 1-1.3: New USB device found, idVendor=0403, idProduct=6001, bcdDevice= 6.00
[10579.829821] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[10579.829836] usb 1-1.3: Product: iClebo Kobuki
[10579.829848] usb 1-1.3: Manufacturer: Yujin Robot
[10579.829860] usb 1-1.3: SerialNumber: kobuki_AI02MQMK
[10579.840148] ftdi_sio 1-1.3:1.0: FTDI USB Serial Device converter detected
[10579.840351] usb 1-1.3: Detected FT232R
[10579.842208] usb 1-1.3: FTDI USB Serial Device converter now attached to ttyUSB1
[10612.745819] hwmon hwmon1: Voltage normalised
[10614.761829] hwmon hwmon1: Undervoltage detected!
```

View File

@@ -1,5 +1,7 @@
#include <iostream>
#include <thread>
#include <fstream>
#include <filesystem>
#include "MQTT/MqttClient.h"
#include "KobukiDriver/CKobuki.h"
#include <opencv4/opencv2/opencv.hpp>
@@ -8,88 +10,165 @@
using namespace std;
using namespace cv;
CKobuki robot;
std::atomic<bool> kobuki_connected(false);
std::string readMQTT();
void parseMQTT(std::string message);
void CapnSend();
//ip, clientID, username, password
void checkKobukiConnection();
// ip, clientID, username, password
MqttClient client("ws://145.92.224.21/ws/", "KobukiRPI", "rpi", "rpiwachtwoordofzo"); // create a client object
std::string message = "stop";
std::string serializeKobukiData(const TKobukiData &data);
void sendKobukiData(TKobukiData &data);
std::string findKobukiPort()
{
for (const auto& entry : std::filesystem::directory_iterator("/dev"))
{
std::string device = entry.path().string();
if (device.find("ttyUSB") != std::string::npos)
{
return device; // Returneer de eerste gevonden poort
}
}
return ""; // Geen poort gevonden
}
void setup()
{
unsigned char *null_ptr(0);
robot.startCommunication("/dev/ttyUSB0", true, null_ptr);
//connect mqtt server and sub to commands
client.connect();
client.subscribe("home/commands");
std::string port = findKobukiPort();
unsigned char *null_ptr(0);
robot.startCommunication(const_cast<char*>(port.c_str()), true, null_ptr);
// connect mqtt server and sub to commands
client.connect();
client.subscribe("home/commands");
}
int main()
{
setup();
std::thread image (CapnSend);
std::thread safety([&]() { robot.robotSafety(&message); });
std::thread sendMqtt([&]() { sendKobukiData(robot.parser.data); });
while(true){
std::string message = readMQTT();
if (!message.empty()){
parseMQTT(message);
}
}
setup();
std::thread image(CapnSend);
std::thread safety([&](){ robot.robotSafety(&message); });
std::thread sendMqtt([&](){ sendKobukiData(robot.parser.data); });
std::thread connectionChecker(checkKobukiConnection);
connectionChecker.detach(); // Laat deze thread onafhankelijk draaien
sendMqtt.join();
safety.join();
image.join();
while (true)
{
std::string message = readMQTT();
if (!message.empty())
{
parseMQTT(message);
}
}
sendMqtt.join();
safety.join();
image.join();
}
std::mutex connectionMutex;
void checkKobukiConnection()
{
while (true)
{
std::lock_guard<std::mutex> lock(connectionMutex);
std::string port = findKobukiPort();
if (port.empty()) {
if (kobuki_connected) {
cout << "Kobuki disconnected: No USB device found." << endl;
kobuki_connected = false;
}
std::this_thread::sleep_for(std::chrono::seconds(5));
continue; // Probeer later opnieuw
}
// Controleer of de Kobuki verbonden is
if (!robot.isConnected()){
if (kobuki_connected){
cout << "Kobuki disconnected." << endl;
kobuki_connected = false;
}
cout << "Attempting to reconnect Kobuki..." << endl;
robot.startCommunication(const_cast<char*>(port.c_str()), true, nullptr);
if (robot.isConnected()){
cout << "Kobuki reconnected successfully!" << endl;
kobuki_connected = true;
}
else{
cout << "Failed to reconnect Kobuki, retrying in 5 seconds..." << endl;
}
}
// Wacht voordat je opnieuw controleert
std::this_thread::sleep_for(std::chrono::seconds(5));
}
}
std::string readMQTT()
{
static std::string lastMessage;
static std::string lastMessage;
std::string message = client.getLastMessage();
if (!message.empty() && message != lastMessage)
{
std::cout << "MQTT Message: " << message << std::endl;
lastMessage = message;
}
std::string message = client.getLastMessage();
if (!message.empty() && message != lastMessage)
{
std::cout << "MQTT Message: " << message << std::endl;
lastMessage = message;
}
// Add a small delay to avoid busy-waiting
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return lastMessage;
}
void parseMQTT(std::string message) {
if (message == "up") {
void parseMQTT(std::string message)
{
if (message == "up")
{
robot.forward(350);
} else if (message == "left") {
}
else if (message == "left")
{
robot.setRotationSpeed(4);
} else if (message == "right") {
}
else if (message == "right")
{
robot.setRotationSpeed(-4);
} else if (message == "down") {
}
else if (message == "down")
{
robot.forward(-350);
} else if (message == "stop") {
}
else if (message == "stop")
{
robot.sendNullMessage();
robot.sendNullMessage();
} else if (message == "estop") {
}
else if (message == "estop")
{
robot.forward(-400);
} else {
}
else
{
std::cout << "Invalid command" << std::endl;
}
}
void logToFile() {
while (true) {
void logToFile()
{
while (true)
{
TKobukiData robotData = robot.parser.data;
std::ofstream outputFile("log",
std::ios_base::app); // Open file in append mode to
// not overwrite own content
if (outputFile.is_open()) { // check if the file was opened successfully
if (outputFile.is_open())
{ // check if the file was opened successfully
// Get current time
std::time_t now = std::time(nullptr);
outputFile << "Timestamp: " << std::ctime(&now);
@@ -147,7 +226,9 @@ void logToFile() {
outputFile << "UDID1: " << robotData.extraInfo.UDID1 << "\n";
outputFile << "UDID2: " << robotData.extraInfo.UDID2 << "\n";
outputFile.close();
} else {
}
else
{
std::cerr << "Error opening file\n";
}
@@ -155,8 +236,10 @@ void logToFile() {
}
}
void sendIndividualKobukiData(const TKobukiData &data) {
while (true) {
void sendIndividualKobukiData(const TKobukiData &data)
{
while (true)
{
std::cout << "Kobuki Data wordt gepubliceerd naar kobuki/data/timestamp: "
<< data.timestamp << std::endl;
client.publishMessage("kobuki/data/timestamp",
@@ -244,7 +327,8 @@ void sendIndividualKobukiData(const TKobukiData &data) {
client.publishMessage("kobuki/data/extraInfo/UDID2",
std::to_string(data.extraInfo.UDID2));
if (!data.gyroData.empty()) {
if (!data.gyroData.empty())
{
const auto &latestGyro = data.gyroData.back();
client.publishMessage("kobuki/data/gyroData/x",
std::to_string(latestGyro.x));
@@ -258,7 +342,8 @@ void sendIndividualKobukiData(const TKobukiData &data) {
}
}
std::string serializeKobukiData(const TKobukiData &data) {
std::string serializeKobukiData(const TKobukiData &data)
{
std::string json =
"{\"timestamp\":" + std::to_string(data.timestamp) +
",\"BumperCenter\":" + std::to_string(data.BumperCenter) +
@@ -311,7 +396,8 @@ std::string serializeKobukiData(const TKobukiData &data) {
",\"UDID1\":" + std::to_string(data.extraInfo.UDID1) +
",\"UDID2\":" + std::to_string(data.extraInfo.UDID2) + "},\"gyroData\":[";
if (!data.gyroData.empty()) {
if (!data.gyroData.empty())
{
const auto &latestGyro = data.gyroData.back();
json += "{\"x\":" + std::to_string(latestGyro.x) +
",\"y\":" + std::to_string(latestGyro.y) +
@@ -321,18 +407,22 @@ std::string serializeKobukiData(const TKobukiData &data) {
json += "]}";
return json;
}
// create extra function to send the message every 100ms
// needed it so it can be threaded
void sendKobukiData(TKobukiData &data) {
while (true) {
client.publishMessage("kobuki/data", serializeKobukiData(data));
std::cout << "Sent data" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
void sendKobukiData(TKobukiData &data)
{
while (true)
{
client.publishMessage("kobuki/data", serializeKobukiData(data));
std::cout << "Sent data" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
void CapnSend() {
VideoCapture cap(0);
int COMPRESSION_LEVEL = 90;
VideoCapture cap(0); // Open the camera
if (!cap.isOpened()) {
cerr << "Error: Could not open camera" << endl;
return;
@@ -340,20 +430,37 @@ void CapnSend() {
Mat frame;
while (true) {
cap >> frame; // Capture a new image frame
if (frame.empty()) {
cerr << "Error: Could not capture image" << endl;
continue;
if (!cap.read(frame)) {
cout << "Reconnecting camera" << endl;
cap.release();
std::this_thread::sleep_for(std::chrono::seconds(1));
// Attempt to reconnect to the camera
cap.open(0);
if (!cap.isOpened()) {
cerr << "Error: Could not reconnect to camera" << endl;
std::this_thread::sleep_for(std::chrono::seconds(1)); // Wait before retrying
continue;
} else {
cout << "Reconnected to camera" << endl;
continue;
}
}
// Convert the image to a byte array
vector<uchar> buf;
imencode(".jpg", frame, buf);
auto* enc_msg = reinterpret_cast<unsigned char*>(buf.data());
// Publish the image data
client.publishMessage("kobuki/cam", string(enc_msg, enc_msg + buf.size()));
cout << "Sent image" << endl;
vector<uchar> imgbuf;
vector<int> compression_params;
compression_params.push_back(IMWRITE_JPEG_QUALITY); // Set JPEG quality
compression_params.push_back(COMPRESSION_LEVEL); // Adjust the quality level (0-100, lower = more compression)
// Encode the image into the byte buffer with the specified compression parameters
imencode(".jpg", frame, imgbuf, compression_params);
// Convert the vector<uchar> buffer to a string (no casting)
string enc_msg(imgbuf.begin(), imgbuf.end());
// Publish the compressed image data (MQTT, in this case)
client.publishMessage("kobuki/cam", enc_msg);
cout << "Sent compressed image" << endl;
std::this_thread::sleep_for(std::chrono::milliseconds(200)); // Send image every 200ms
}

View File

@@ -14,5 +14,5 @@ EXPOSE 5000
CMD ["python", "web/app.py"]
#build instruction: sudo docker buildx build -t flaskapp:latest .
#run instruction: sudo docker run --network="host" flaskapp:latest
#run instruction: sudo docker run --network="host" --restart=always flaskapp:latest
# need to use network host to connect to the host's mqtt server

View File

@@ -3,3 +3,4 @@ paho-mqtt==1.6.1
ultralytics==8.3.58
opencv-python-headless==4.6.0.66
numpy==1.23.4
mysql-connector-python==9.1.0

View File

@@ -1,4 +1,4 @@
from flask import Flask, Response, request, render_template, jsonify
from flask import Flask, Response, request, render_template, jsonify, g
import paho.mqtt.client as mqtt
from ultralytics import YOLO
import cv2
@@ -49,18 +49,6 @@ def on_message(client, userdata, message):
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):
global kobuki_message, latest_image
if message.topic == "kobuki/data":
kobuki_message = str(message.payload.decode("utf-8"))
with app.app_context():
sensor_data(kobuki_message) # Sla de data op in de database
elif message.topic == "kobuki/cam":
latest_image = message.payload
# Create an MQTT client instance
mqtt_client = mqtt.Client()
mqtt_client.username_pw_set("server", "serverwachtwoordofzo")
@@ -71,9 +59,6 @@ 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
# Database connectie-functie
def get_db():
if 'db' not in g: # 'g' is specifiek voor een request en leeft zolang een request duurt
@@ -100,6 +85,7 @@ def index():
@app.route('/control', methods=["GET", "POST"])
def control():
if request.authorization and request.authorization.username == 'ishak' and request.authorization.password == 'kobuki':
yolo_results_db()
return render_template('control.html')
else:
return ('Unauthorized', 401, {'WWW-Authenticate': 'Basic realm="Login Required"'})
@@ -122,17 +108,10 @@ def move():
cursor.close()
db_connection.close()
return jsonify({"status": "success", "direction": direction})
@app.route("/database")
def database():
db = get_db()
cursor = db.cursor()
cursor.execute("SELECT * FROM kobuki_data")
rows = cursor.fetchall()
cursor.close()
return str(rows)
def sensor_data(kobuki_message):
@app.route('/data', methods=['GET'])
def data():
try:
# Parse de JSON-string naar een Python-dictionary
data = json.loads(kobuki_message)
@@ -152,23 +131,21 @@ def sensor_data(kobuki_message):
# Database-insert
db = get_db()
cursor = db.cursor()
with db.cursor() as cursor:
# Zorg dat je tabel `kobuki_data` kolommen heeft: `name` en `value`
sql_sensor = "INSERT INTO kobuki_data (name, value) VALUES (%s, %s)"
cursor.executemany(sql_sensor, sensor_data_tuples)
# Commit en sluit de cursor
db.commit()
cursor.close()
# Zorg dat je tabel `kobuki_data` kolommen heeft: `name` en `value`
sql_sensor = "INSERT INTO kobuki_data (name, value) VALUES (%s, %s)"
cursor.executemany(sql_sensor, sensor_data_tuples)
# Commit en sluit de cursor
db.commit()
cursor.close()
except json.JSONDecodeError as e:
print(f"JSON decode error: {e}")
except mysql.connector.Error as err:
print(f"Database error: {err}")
@app.route('/data', methods=['GET'])
def data():
return kobuki_message
@app.route('/image')
@@ -184,10 +161,25 @@ def image():
@app.route('/yolo_results', methods=['GET'])
def yolo_results_endpoint():
global yolo_results
with lock:
return jsonify(yolo_results)
global yolo_results
return jsonify(yolo_results)
def yolo_results_db():
global yolo_results
with lock:
try:
db = get_db()
with db.cursor() as cursor:
sql_yolo = "INSERT INTO image (class, confidence) VALUES (%s, %s)"
yolo_tuples = [(result["class"], result["confidence"]) for result in yolo_results]
print(f"YOLO Tuples: {yolo_tuples}") # Debug statement
cursor.executemany(sql_yolo, yolo_tuples)
db.commit()
cursor.close()
except mysql.connector.Error as err:
print(f"Database error: {err}")
except Exception as e:
print(f"Unexpected error: {e}")
if __name__ == '__main__':
app.run(debug=True, port=5000)

View File

@@ -34,7 +34,8 @@ document.addEventListener("DOMContentLoaded", function() {
}
}
// Parse the data and show it on the website
// Parse the data and show it on the website
async function parseData() {
const data = await fetchData();
const sensorDataContainer = document.getElementById("sensor-data");
sensorDataContainer.innerHTML = ""; // Clear previous data
@@ -42,20 +43,21 @@ document.addEventListener("DOMContentLoaded", function() {
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
sensorDataContainer.appendChild(dataElement); // Add the element to the container
}
}
// Update the image
function updateImage() {
var img = document.getElementById("robot-image");
async function updateImage() {
let img = document.getElementById("robot-image");
img.src = "/image?" + new Date().getTime(); // Add timestamp to avoid caching
// Wait for 200 milliseconds before fetching the next image
setTimeout(updateImage, 200);
}
// Fetch and display sensor data every 1 second
setInterval(parseData, 1000);
// Update the image every 200 milliseconds
setInterval(updateImage, 100);
});
// Start updating the image
updateImage();
});