mirror of
https://gitlab.fdmci.hva.nl/technische-informatica-sm3/ti-projectten/rooziinuubii79.git
synced 2025-08-05 12:54:57 +00:00
Compare commits
42 Commits
d0bfef2296
...
06dd2d9f48
Author | SHA1 | Date | |
---|---|---|---|
|
06dd2d9f48 | ||
|
7d3a5fa9a3 | ||
|
3bca04053a | ||
|
82363d393c | ||
|
1964589abc | ||
|
8d339851dd | ||
|
79c2073d29 | ||
|
ffbf3347f4 | ||
|
64452b78b4 | ||
|
c87ebc565c | ||
|
39659fffab | ||
|
a4ae0170a0 | ||
|
ed475cd19f | ||
|
a9c37ec470 | ||
|
369120b16b | ||
|
ec71028270 | ||
|
7560b0f67a | ||
|
331de940cc | ||
|
ec0b32a221 | ||
|
3aa77f5314 | ||
|
e59f235b91 | ||
|
2e4f048ed9 | ||
|
9a3829cdb2 | ||
|
015b2db819 | ||
|
6ef739f794 | ||
|
ec2a08c656 | ||
|
89421ccf34 | ||
|
1c081451aa | ||
|
2396d61eae | ||
|
fa17893b1b | ||
|
07d88eef7d | ||
|
d066f68ad2 | ||
|
d90ac72591 | ||
|
a2aa80804e | ||
|
612af45f59 | ||
|
3ff1b22346 | ||
|
1a4056ff77 | ||
|
8517a0d558 | ||
|
092e4f5aeb | ||
|
9eb9822cff | ||
|
fe64267307 | ||
|
72a0fadef8 |
51
docs/Infrastructure/uml.md
Normal file
51
docs/Infrastructure/uml.md
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
```mermaid
|
||||||
|
classDiagram
|
||||||
|
class CKobuki {
|
||||||
|
+enableCommands(bool commands)
|
||||||
|
+loop(void *user_data, TKobukiData &Kobuki_data)
|
||||||
|
+startCommunication(char *portname, bool CommandsEnabled, void *userDataL)
|
||||||
|
+measure()
|
||||||
|
+setLed(int led1, int led2)
|
||||||
|
+setTranslationSpeed(int mmpersec)
|
||||||
|
+setRotationSpeed(double radpersec)
|
||||||
|
+setArcSpeed(int mmpersec, int radius)
|
||||||
|
+setSound(int noteinHz, int duration)
|
||||||
|
+setPower(int value)
|
||||||
|
+goStraight(long double distance)
|
||||||
|
+forward(int speedvalue)
|
||||||
|
+doRotation(long double th)
|
||||||
|
}
|
||||||
|
|
||||||
|
class FlaskApp {
|
||||||
|
+on_message(client, message)
|
||||||
|
+get_db()
|
||||||
|
+close_db(error)
|
||||||
|
+index()
|
||||||
|
+control()
|
||||||
|
+move()
|
||||||
|
}
|
||||||
|
|
||||||
|
class MQTTClient {
|
||||||
|
+connect()
|
||||||
|
+subscribe(topic)
|
||||||
|
+getLastMessage()
|
||||||
|
+isConnected()
|
||||||
|
}
|
||||||
|
|
||||||
|
FlaskApp --> MQTTClient : uses
|
||||||
|
FlaskApp --> CKobuki : controls
|
||||||
|
|
||||||
|
class RPI {
|
||||||
|
+KobukiCommunication()
|
||||||
|
+ESP32Communication()
|
||||||
|
+Camera()
|
||||||
|
}
|
||||||
|
|
||||||
|
class ESP32 {
|
||||||
|
+TVOC()
|
||||||
|
+DHT11()
|
||||||
|
}
|
||||||
|
|
||||||
|
RPI --> MQTTClient : communicates
|
||||||
|
MQTTClient --> CKobuki : communicates
|
||||||
|
RPI --> ESP32 : communicates
|
@@ -68,28 +68,14 @@ int CKobuki::connect(char *comportT) {
|
|||||||
HCom = open(comportT, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
HCom = open(comportT, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||||
|
|
||||||
if (HCom == -1) {
|
if (HCom == -1) {
|
||||||
printf("Kobuki connected\n");
|
std::cerr <<"unable to connect. retry in 1 second" << std::endl;
|
||||||
return HCom;
|
return HCom;
|
||||||
} else {
|
} else {
|
||||||
set_interface_attribs2(HCom, B115200,
|
set_interface_attribs2(HCom, B115200,0); // set speed to 115,200 bps, 8n1 (no parity)
|
||||||
0); // set speed to 115,200 bps, 8n1 (no parity)
|
|
||||||
set_blocking2(HCom, 0); // set no blocking
|
set_blocking2(HCom, 0); // set no blocking
|
||||||
/* struct termios settings;
|
|
||||||
tcgetattr(HCom, &settings);
|
|
||||||
|
|
||||||
cfsetospeed(&settings, B115200); // baud rate
|
|
||||||
settings.c_cflag &= ~PARENB; // no parity
|
|
||||||
settings.c_cflag &= ~CSTOPB; // 1 stop bit
|
|
||||||
settings.c_cflag &= ~CSIZE;
|
|
||||||
settings.c_cflag |= CS8 | CLOCAL; // 8 bits
|
|
||||||
settings.c_lflag &= ~ICANON; // canonical mode
|
|
||||||
settings.c_cc[VTIME]=1;
|
|
||||||
settings.c_oflag &= ~OPOST; // raw output
|
|
||||||
|
|
||||||
tcsetattr(HCom, TCSANOW, &settings); // apply the settings*/
|
|
||||||
tcflush(HCom, TCOFLUSH);
|
tcflush(HCom, TCOFLUSH);
|
||||||
|
|
||||||
printf("Kobuki connected\n");
|
std::cout<<"Kobuki connected" << std::endl;
|
||||||
return HCom;
|
return HCom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,7 +238,7 @@ void CKobuki::setSound(int noteinHz, int duration) {
|
|||||||
pocet = write(HCom, &message, 9);
|
pocet = write(HCom, &message, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CKobuki::startCommunication(char *portname, bool CommandsEnabled,
|
void CKobuki::startCommunication(char *portname, bool CommandsEnabled,
|
||||||
void *userDataL) {
|
void *userDataL) {
|
||||||
if(connect(portname) != -1){
|
if(connect(portname) != -1){
|
||||||
enableCommands(CommandsEnabled);
|
enableCommands(CommandsEnabled);
|
||||||
|
@@ -60,7 +60,7 @@ public:
|
|||||||
|
|
||||||
long loop(void *user_data, TKobukiData &Kobuki_data);
|
long loop(void *user_data, TKobukiData &Kobuki_data);
|
||||||
|
|
||||||
bool startCommunication(char *portname,bool CommandsEnabled,void *userDataL);
|
void startCommunication(char *portname,bool CommandsEnabled,void *userDataL);
|
||||||
int measure(); //thread function, contains an infinite loop and reads data
|
int measure(); //thread function, contains an infinite loop and reads data
|
||||||
void setLed(int led1 = 0, int led2 = 0); //led1 green/red 2/1, //led2 green/red 2/1
|
void setLed(int led1 = 0, int led2 = 0); //led1 green/red 2/1, //led2 green/red 2/1
|
||||||
void setTranslationSpeed(int mmpersec);
|
void setTranslationSpeed(int mmpersec);
|
||||||
|
@@ -1,13 +1,10 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cmath>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include "MQTT/MqttClient.h"
|
#include "MQTT/MqttClient.h"
|
||||||
#include "KobukiDriver/CKobuki.h"
|
#include "KobukiDriver/CKobuki.h"
|
||||||
#include <opencv4/opencv2/opencv.hpp>
|
#include <opencv4/opencv2/opencv.hpp>
|
||||||
#include <opencv4/opencv2/core.hpp>
|
#include <opencv4/opencv2/core.hpp>
|
||||||
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace cv;
|
using namespace cv;
|
||||||
CKobuki robot;
|
CKobuki robot;
|
||||||
@@ -15,21 +12,24 @@ CKobuki robot;
|
|||||||
std::string readMQTT();
|
std::string readMQTT();
|
||||||
void parseMQTT(std::string message);
|
void parseMQTT(std::string message);
|
||||||
void CapnSend();
|
void CapnSend();
|
||||||
// ip, clientID, username, password
|
MqttClient client("ws://145.92.224.21/ws/", "KobukiRPI", "rpi","rpiwachtwoordofzo"); // create a client object
|
||||||
MqttClient client("ws://145.92.224.21/ws/", "KobukiRPI", "rpi",
|
|
||||||
"rpiwachtwoordofzo"); // create a client object
|
|
||||||
std::string message = "stop";
|
std::string message = "stop";
|
||||||
std::string serializeKobukiData(const TKobukiData &data);
|
std::string serializeKobukiData(const TKobukiData &data);
|
||||||
void sendKobukiData(TKobukiData &data);
|
void sendKobukiData(TKobukiData &data);
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
unsigned char *null_ptr(0);
|
unsigned char *null_ptr(0);
|
||||||
|
std::cout << "Attempting to start communication with Kobuki..." << std::endl;
|
||||||
robot.startCommunication("/dev/ttyUSB0", true, null_ptr);
|
robot.startCommunication("/dev/ttyUSB0", true, null_ptr);
|
||||||
|
if (!robot.isConnected()) {
|
||||||
|
std::cerr << "Failed to start communication with Kobuki." << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "Successfully started communication with Kobuki." << std::endl;
|
||||||
|
}
|
||||||
// connect mqtt server and sub to commands
|
// connect mqtt server and sub to commands
|
||||||
|
|
||||||
client.connect();
|
client.connect();
|
||||||
client.subscribe("home/commands");
|
client.subscribe("home/commands");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
@@ -40,6 +40,16 @@ int main() {
|
|||||||
std::thread sendMqtt([&]() { sendKobukiData(robot.parser.data); });
|
std::thread sendMqtt([&]() { sendKobukiData(robot.parser.data); });
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
if (!robot.isConnected()) {
|
||||||
|
std::cout << "Kobuki is not connected anymore. Reconnecting..." << std::endl;
|
||||||
|
robot.startCommunication("/dev/ttyUSB0", true, nullptr);
|
||||||
|
while (!robot.isConnected()) {
|
||||||
|
std::cout << "Attempting to reconnect..." << std::endl;
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
}
|
||||||
|
std::cout << "Reconnected to Kobuki." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
std::string message = readMQTT();
|
std::string message = readMQTT();
|
||||||
if (!message.empty()) {
|
if (!message.empty()) {
|
||||||
parseMQTT(message);
|
parseMQTT(message);
|
||||||
@@ -62,7 +72,7 @@ std::string readMQTT() {
|
|||||||
|
|
||||||
// Add a small delay to avoid busy-waiting
|
// Add a small delay to avoid busy-waiting
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
return message;
|
return lastMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseMQTT(std::string message) {
|
void parseMQTT(std::string message) {
|
||||||
@@ -326,6 +336,13 @@ std::string serializeKobukiData(const TKobukiData &data) {
|
|||||||
// needed it so it can be threaded
|
// needed it so it can be threaded
|
||||||
void sendKobukiData(TKobukiData &data) {
|
void sendKobukiData(TKobukiData &data) {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
// if(!robot.isConnected()){
|
||||||
|
// std::cout << "Kobuki is not connected anymore" << std::endl;
|
||||||
|
// robot.startCommunication("/dev/ttyUSB0", true, nullptr);
|
||||||
|
// while(!robot.isConnected()){
|
||||||
|
// std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
client.publishMessage("kobuki/data", serializeKobukiData(data));
|
client.publishMessage("kobuki/data", serializeKobukiData(data));
|
||||||
std::cout << "Sent data" << std::endl;
|
std::cout << "Sent data" << std::endl;
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
from flask import Flask, request, render_template, jsonify, g
|
from flask import Flask, request, render_template, jsonify, g
|
||||||
import paho.mqtt.client as mqtt
|
import paho.mqtt.client as mqtt
|
||||||
import mysql.connector
|
import mysql.connector
|
||||||
|
import json
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
@@ -9,10 +10,12 @@ kobuki_message = ""
|
|||||||
latest_image = None
|
latest_image = None
|
||||||
|
|
||||||
# Globale MQTT setup
|
# Globale MQTT setup
|
||||||
def on_message(client, message):
|
def on_message(client,userdata, message):
|
||||||
global kobuki_message, latest_image
|
global kobuki_message, latest_image
|
||||||
if message.topic == "kobuki/data":
|
if message.topic == "kobuki/data":
|
||||||
kobuki_message = str(message.payload.decode("utf-8"))
|
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":
|
elif message.topic == "kobuki/cam":
|
||||||
latest_image = message.payload
|
latest_image = message.payload
|
||||||
|
|
||||||
@@ -24,6 +27,9 @@ mqtt_client.connect("localhost", 1884, 60)
|
|||||||
mqtt_client.loop_start()
|
mqtt_client.loop_start()
|
||||||
mqtt_client.subscribe("kobuki/data")
|
mqtt_client.subscribe("kobuki/data")
|
||||||
|
|
||||||
|
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
|
# Database connectie-functie
|
||||||
def get_db():
|
def get_db():
|
||||||
if 'db' not in g: # 'g' is specifiek voor een request en leeft zolang een request duurt
|
if 'db' not in g: # 'g' is specifiek voor een request en leeft zolang een request duurt
|
||||||
@@ -54,6 +60,11 @@ def control():
|
|||||||
else:
|
else:
|
||||||
return ('Unauthorized', 401, {'WWW-Authenticate': 'Basic realm="Login Required"'})
|
return ('Unauthorized', 401, {'WWW-Authenticate': 'Basic realm="Login Required"'})
|
||||||
|
|
||||||
|
@app.route('/data', methods=['GET'])
|
||||||
|
def data():
|
||||||
|
return kobuki_message
|
||||||
|
|
||||||
|
|
||||||
@app.route('/move', methods=['POST'])
|
@app.route('/move', methods=['POST'])
|
||||||
def move():
|
def move():
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
@@ -65,19 +76,14 @@ def move():
|
|||||||
|
|
||||||
db_connection = get_db()
|
db_connection = get_db()
|
||||||
cursor = db_connection.cursor()
|
cursor = db_connection.cursor()
|
||||||
sql = "INSERT INTO command (command) VALUES (%s)"
|
sql_command = "INSERT INTO command (command) VALUES (%s)"
|
||||||
value = direction
|
cursor.execute(sql_command, (direction,))
|
||||||
cursor.execute(sql, (value,))
|
|
||||||
db_connection.commit()
|
db_connection.commit()
|
||||||
cursor.close()
|
cursor.close()
|
||||||
db_connection.close()
|
db_connection.close()
|
||||||
|
|
||||||
return jsonify({"status": "success", "direction": direction})
|
return jsonify({"status": "success", "direction": direction})
|
||||||
|
|
||||||
@app.route('/data', methods=['GET'])
|
|
||||||
def data():
|
|
||||||
return jsonify(kobuki_message)
|
|
||||||
|
|
||||||
@app.route("/database")
|
@app.route("/database")
|
||||||
def database():
|
def database():
|
||||||
db = get_db()
|
db = get_db()
|
||||||
@@ -87,5 +93,39 @@ def database():
|
|||||||
cursor.close()
|
cursor.close()
|
||||||
return str(rows)
|
return str(rows)
|
||||||
|
|
||||||
|
def sensor_data(kobuki_message):
|
||||||
|
try:
|
||||||
|
# Parse de JSON-string naar een Python-dictionary
|
||||||
|
data = json.loads(kobuki_message)
|
||||||
|
|
||||||
|
# Maak een lijst van tuples met de naam en waarde van elk veld
|
||||||
|
sensor_data_tuples = [(name, float(value)) for name, value in data.items() if isinstance(value, (int, float))]
|
||||||
|
|
||||||
|
# Extra informatie of nested data (zoals "extraInfo" of "gyroData") kun je apart verwerken
|
||||||
|
if "extraInfo" in data:
|
||||||
|
for key, value in data["extraInfo"].items():
|
||||||
|
sensor_data_tuples.append((f"extraInfo_{key}", float(value)))
|
||||||
|
|
||||||
|
if "gyroData" in data:
|
||||||
|
for i, gyro in enumerate(data["gyroData"]):
|
||||||
|
for axis, value in gyro.items():
|
||||||
|
sensor_data_tuples.append((f"gyroData_{i}_{axis}", float(value)))
|
||||||
|
|
||||||
|
# Database-insert
|
||||||
|
db = get_db()
|
||||||
|
cursor = db.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()
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
print(f"JSON decode error: {e}")
|
||||||
|
except mysql.connector.Error as err:
|
||||||
|
print(f"Database error: {err}")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(debug=True, port=5000)
|
app.run(debug=True, port=5000)
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
{% extends 'base.html' %} {% block head %}
|
{% extends 'base.html' %}
|
||||||
|
{% block head %}
|
||||||
<link rel="stylesheet" href="../static/style.css" />
|
<link rel="stylesheet" href="../static/style.css" />
|
||||||
{% endblock %} {% block content %}
|
{% endblock %}
|
||||||
|
{% block content %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
@@ -11,8 +13,8 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="image-section">
|
<div class="robot-image">
|
||||||
<!-- <img src="kobuki.jpg" alt="Kobuki Robot" id="robot-image" /> -->
|
<img src="/image" alt="Kobuki Camera Feed" id="robot-image" />
|
||||||
</div>
|
</div>
|
||||||
<div class="button-section">
|
<div class="button-section">
|
||||||
<form id="form" action="/move" method="post">
|
<form id="form" action="/move" method="post">
|
||||||
@@ -42,7 +44,8 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="../static/script.js"></script>
|
<script src="../static/script.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
{% endblock %}
|
{% endblock %}
|
Reference in New Issue
Block a user