From ee7099654eb58f298a9c01dae033b3b13545ac61 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 12:25:08 +0200 Subject: [PATCH 01/79] test in another branch --- src/C++/Driver/src/test.cpp | 79 ++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index f846e7d..b2862c7 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -1,8 +1,8 @@ #include "CKobuki.h" -#include -#include -#include #include "graph.h" +#include +#include +#include using namespace std; CKobuki robot; @@ -11,57 +11,56 @@ int command(); const int forward = 1; const int ROTATE = 2; -int main() -{ - unsigned char *null_ptr(0); - robot.startCommunication("/dev/ttyUSB0", true, null_ptr); - usleep(1 * 1000 * 1000); - thread mv(command); - usleep(30 * 1000 * 1000); - mv.join(); //only exit once thread one is done running +int main() { + unsigned char *null_ptr(0); + robot.startCommunication("/dev/ttyUSB0", true, null_ptr); + usleep(1 * 1000 * 1000); + thread mv(command); + usleep(30 * 1000 * 1000); + mv.join(); // only exit once thread one is done running } // int checkCenterCliff() // { // while (true) // { -// std::cout << "cliffsensordata:" << robot.parser.data.CliffSensorCenter << std::endl; +// std::cout << "cliffsensordata:" << +// robot.parser.data.CliffSensorCenter << std::endl; // } // } // int checkWheelDrop(){ // while (true) // { -// std::cout << "wheeldropdata:" << robot.parser.data.WheelDropLeft << std::endl; +// std::cout << "wheeldropdata:" << robot.parser.data.WheelDropLeft +// << std::endl; // } // } -int command(){ - cout << "choose between forward and rotate" << endl; - cout << "What must the robot do?"; - cin >> input; +int command() { + std::cout << "choose between forward and rotate" << endl; + std::cout << "What must the robot do?"; + cin >> input; - switch(input){ - case forward:{ - int distance; - std::cout >> "Enter distance to move forward: "; - std::cin >> distance; - robot.goStraight(distance); - } - - case ROTATE:{ - int angle; - std::cout >> "Enter angle to rotate: "; - std::cin >> angle; - robot.doRotation(angle); - } - robot.goStraight(-1); - break; - - default: - cout << "Invalid input" << endl; - break; - } - + switch (input) { + case forward: { + int distance; + std::cout >> "Enter distance to move forward: "; + std::cin >> distance; + robot.goStraight(distance); + } break; + + case ROTATE: { + int angle; + std::cout >> "Enter angle to rotate: "; + std::cin >> angle; + robot.doRotation(angle); + robot.goStraight(-1); + + } break; + + default: + cout << "Invalid input" << endl; + break; + } } - From 7db10d2238955b6d56c4f4f0c6f860e68cd53da1 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 12:28:23 +0200 Subject: [PATCH 02/79] fixing error --- src/C++/Driver/src/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index b2862c7..087eac4 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -46,7 +46,7 @@ int command() { case forward: { int distance; std::cout >> "Enter distance to move forward: "; - std::cin >> distance; + cin >> distance; robot.goStraight(distance); } break; From 423b8a8dee38dbe52132a01ed730c942e871328d Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 12:29:57 +0200 Subject: [PATCH 03/79] made variable input --- src/C++/Driver/src/test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index 087eac4..2f3faf0 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -38,6 +38,7 @@ int main() { // } int command() { + char input; std::cout << "choose between forward and rotate" << endl; std::cout << "What must the robot do?"; cin >> input; From 06f152d455354a30348234634d72748c888c617f Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 12:33:22 +0200 Subject: [PATCH 04/79] uncomment cliff and wheel sensor --- src/C++/Driver/src/test.cpp | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index 2f3faf0..5c2c63e 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -20,22 +20,19 @@ int main() { mv.join(); // only exit once thread one is done running } -// int checkCenterCliff() -// { -// while (true) -// { -// std::cout << "cliffsensordata:" << -// robot.parser.data.CliffSensorCenter << std::endl; -// } -// } +int checkCenterCliff() { + while (true) { + std::cout << "cliffsensordata:" << robot.parser.data.CliffSensorCenter + << std::endl; + } +} -// int checkWheelDrop(){ -// while (true) -// { -// std::cout << "wheeldropdata:" << robot.parser.data.WheelDropLeft -// << std::endl; -// } -// } +int checkWheelDrop() { + while (true) { + std::cout << "wheeldropdata:" << robot.parser.data.WheelDropLeft + << std::endl; + } +} int command() { char input; From 3f5c35245137fa823204d770ba44e94bfbbf0861 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 12:41:12 +0200 Subject: [PATCH 05/79] fixed some small problems --- src/C++/Driver/src/test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index 5c2c63e..cf0329b 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -8,8 +8,8 @@ using namespace std; CKobuki robot; int command(); -const int forward = 1; -const int ROTATE = 2; +const char forward = '1'; +const char rotate = '2'; int main() { unsigned char *null_ptr(0); @@ -43,14 +43,14 @@ int command() { switch (input) { case forward: { int distance; - std::cout >> "Enter distance to move forward: "; + std::cout << "Enter distance to move forward: "; cin >> distance; robot.goStraight(distance); } break; case ROTATE: { int angle; - std::cout >> "Enter angle to rotate: "; + std::cout << "Enter angle to rotate: "; std::cin >> angle; robot.doRotation(angle); robot.goStraight(-1); From dcd28e358789bd95bff4455c700a24580885f4ea Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 12:43:46 +0200 Subject: [PATCH 06/79] Made some variables full caps --- src/C++/Driver/src/test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index cf0329b..3a5cc56 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -8,8 +8,8 @@ using namespace std; CKobuki robot; int command(); -const char forward = '1'; -const char rotate = '2'; +const char FORWARD = '1'; +const char ROTATE = '2'; int main() { unsigned char *null_ptr(0); @@ -41,7 +41,7 @@ int command() { cin >> input; switch (input) { - case forward: { + case FORWARD: { int distance; std::cout << "Enter distance to move forward: "; cin >> distance; From 618ad37cffd0e2b05cede461fc383e920a2d602a Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 12:53:42 +0200 Subject: [PATCH 07/79] added some std --- src/C++/Driver/src/test.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index 3a5cc56..411d7a6 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -15,6 +15,7 @@ int main() { unsigned char *null_ptr(0); robot.startCommunication("/dev/ttyUSB0", true, null_ptr); usleep(1 * 1000 * 1000); + std::cout << "choose between forward and rotate" << endl; thread mv(command); usleep(30 * 1000 * 1000); mv.join(); // only exit once thread one is done running @@ -22,29 +23,26 @@ int main() { int checkCenterCliff() { while (true) { - std::cout << "cliffsensordata:" << robot.parser.data.CliffSensorCenter - << std::endl; + std::cout << "cliffsensordata:" << robot.parser.data.CliffSensorCenter << std::endl; } } int checkWheelDrop() { while (true) { - std::cout << "wheeldropdata:" << robot.parser.data.WheelDropLeft - << std::endl; + std::cout << "wheeldropdata:" << robot.parser.data.WheelDropLeft << std::endl; } } int command() { char input; - std::cout << "choose between forward and rotate" << endl; std::cout << "What must the robot do?"; - cin >> input; + std::cin >> input; switch (input) { case FORWARD: { int distance; std::cout << "Enter distance to move forward: "; - cin >> distance; + std::cin >> distance; robot.goStraight(distance); } break; @@ -53,8 +51,6 @@ int command() { std::cout << "Enter angle to rotate: "; std::cin >> angle; robot.doRotation(angle); - robot.goStraight(-1); - } break; default: From 9e5eb6e19fcf7e3e67807cb5134c27d485e30798 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 12:55:57 +0200 Subject: [PATCH 08/79] removed line in parser --- src/C++/Driver/src/KobukiParser.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/C++/Driver/src/KobukiParser.cpp b/src/C++/Driver/src/KobukiParser.cpp index 8a62c73..82d70c0 100644 --- a/src/C++/Driver/src/KobukiParser.cpp +++ b/src/C++/Driver/src/KobukiParser.cpp @@ -96,7 +96,6 @@ int KobukiParser::parseKobukiMessage(TKobukiData &output, unsigned char *data) { break; default: - std::cerr << "Unknown data type: " << std::hex << static_cast(dataType) << std::dec << std::endl; checkedValue += dataLength; break; } From b5874dbf9eb4327c6761f974aff4485aa1d6f1a9 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 13:02:53 +0200 Subject: [PATCH 09/79] checking if it can start over again when finishing --- src/C++/Driver/src/test.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index 411d7a6..0fc594d 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -19,6 +19,12 @@ int main() { thread mv(command); usleep(30 * 1000 * 1000); mv.join(); // only exit once thread one is done running + + while (true) { + command(); + } + + return 0; } int checkCenterCliff() { From 45bd2196ef412178919f50c81568cf1afd02b8c7 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 13:10:03 +0200 Subject: [PATCH 10/79] making a loop so it doesnt stop --- src/C++/Driver/src/test.cpp | 55 ++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index 0fc594d..5e24fa3 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -15,52 +15,51 @@ int main() { unsigned char *null_ptr(0); robot.startCommunication("/dev/ttyUSB0", true, null_ptr); usleep(1 * 1000 * 1000); - std::cout << "choose between forward and rotate" << endl; thread mv(command); usleep(30 * 1000 * 1000); mv.join(); // only exit once thread one is done running - - while (true) { - command(); - } - - return 0; } int checkCenterCliff() { while (true) { - std::cout << "cliffsensordata:" << robot.parser.data.CliffSensorCenter << std::endl; + std::cout << "cliffsensordata:" << robot.parser.data.CliffSensorCenter + << std::endl; } } int checkWheelDrop() { while (true) { - std::cout << "wheeldropdata:" << robot.parser.data.WheelDropLeft << std::endl; + std::cout << "wheeldropdata:" << robot.parser.data.WheelDropLeft + << std::endl; } } int command() { char input; - std::cout << "What must the robot do?"; - std::cin >> input; - switch (input) { - case FORWARD: { - int distance; - std::cout << "Enter distance to move forward: "; - std::cin >> distance; - robot.goStraight(distance); - } break; + while (true) { + std::cout << "choose between forward and rotate" << endl; + std::cout << "What must the robot do?"; + std::cin >> input; - case ROTATE: { - int angle; - std::cout << "Enter angle to rotate: "; - std::cin >> angle; - robot.doRotation(angle); - } break; + switch (input) { + case FORWARD: { + int distance; + std::cout << "Enter distance to move forward: "; + std::cin >> distance; + robot.goStraight(distance); + } break; - default: - cout << "Invalid input" << endl; - break; + case ROTATE: { + int angle; + std::cout << "Enter angle to rotate: "; + std::cin >> angle; + robot.doRotation(angle); + } break; + + default: + cout << "Invalid input" << endl; + break; + } } -} +} \ No newline at end of file From 4a5862dd6a6b81e8e9299e6d8aec276c718cf677 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 13:10:45 +0200 Subject: [PATCH 11/79] making some explanation better --- src/C++/Driver/src/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index 5e24fa3..bcd7442 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -38,7 +38,7 @@ int command() { char input; while (true) { - std::cout << "choose between forward and rotate" << endl; + std::cout << "choose between forward = 1 and rotate = 2" << endl; std::cout << "What must the robot do?"; std::cin >> input; From ca2154cb6f682cc02bdbe3e4bf987d965501ee01 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 13:14:08 +0200 Subject: [PATCH 12/79] fixed the input text --- src/C++/Driver/src/test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index bcd7442..b7adcfb 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -8,8 +8,8 @@ using namespace std; CKobuki robot; int command(); -const char FORWARD = '1'; -const char ROTATE = '2'; +const string FORWARD = "forward"; +const string ROTATE = "rotate"; int main() { unsigned char *null_ptr(0); @@ -38,7 +38,7 @@ int command() { char input; while (true) { - std::cout << "choose between forward = 1 and rotate = 2" << endl; + std::cout << "choose between forward or rotate" << endl; std::cout << "What must the robot do?"; std::cin >> input; From 89592c17d3b3b716c9c7581dca9436291947599c Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 13:15:51 +0200 Subject: [PATCH 13/79] fixing error --- src/C++/Driver/src/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index b7adcfb..40f1292 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -8,8 +8,8 @@ using namespace std; CKobuki robot; int command(); -const string FORWARD = "forward"; -const string ROTATE = "rotate"; +const std::string FORWARD = "forward"; +const std::string ROTATE = "rotate"; int main() { unsigned char *null_ptr(0); From 8a7747ca138ac72e2af033b60d8ac5b157996c9d Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 13:24:04 +0200 Subject: [PATCH 14/79] fixed text input --- src/C++/Driver/src/test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index 40f1292..ed16512 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -8,8 +8,8 @@ using namespace std; CKobuki robot; int command(); -const std::string FORWARD = "forward"; -const std::string ROTATE = "rotate"; +const char FORWARD = '1'; +const char ROTATE = '2'; int main() { unsigned char *null_ptr(0); @@ -38,7 +38,7 @@ int command() { char input; while (true) { - std::cout << "choose between forward or rotate" << endl; + std::cout << "choose between forward = 1 or rotate = 2" << endl; std::cout << "What must the robot do?"; std::cin >> input; From 5d11d4866b22d1f30dc2e3153cc0e9b6596fb737 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 13:28:03 +0200 Subject: [PATCH 15/79] removed invalid checksum. added info text --- src/C++/Driver/src/KobukiParser.cpp | 2 +- src/C++/Driver/src/test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/C++/Driver/src/KobukiParser.cpp b/src/C++/Driver/src/KobukiParser.cpp index 82d70c0..e65d60c 100644 --- a/src/C++/Driver/src/KobukiParser.cpp +++ b/src/C++/Driver/src/KobukiParser.cpp @@ -4,7 +4,7 @@ int KobukiParser::parseKobukiMessage(TKobukiData &output, unsigned char *data) { int rtrnvalue = checkChecksum(data); if (rtrnvalue != 0) { - std::cerr << "Invalid checksum" << std::endl; + // std::cerr << "Invalid checksum" << std::endl; return -2; } diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index ed16512..5d65714 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -52,7 +52,7 @@ int command() { case ROTATE: { int angle; - std::cout << "Enter angle to rotate: "; + std::cout << "Enter angle to rotate in degrees: "; std::cin >> angle; robot.doRotation(angle); } break; From c062ad30f406f9fdbc5d915de3f408bdab209180 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 13:44:08 +0200 Subject: [PATCH 16/79] added comments --- src/C++/Driver/src/test.cpp | 40 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index 5d65714..c1fd407 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -5,60 +5,60 @@ #include using namespace std; -CKobuki robot; -int command(); +// Globale instantie van de CKobuki-klasse +CKobuki robot; + +// Functieprototypes +int command(); +int checkCenterCliff(); +int checkWheelDrop(); + +// Constante karakters voor invoeropties const char FORWARD = '1'; const char ROTATE = '2'; int main() { + // Start communicatie met de robot unsigned char *null_ptr(0); robot.startCommunication("/dev/ttyUSB0", true, null_ptr); usleep(1 * 1000 * 1000); + + // Start een nieuwe thread voor de command-functie thread mv(command); usleep(30 * 1000 * 1000); - mv.join(); // only exit once thread one is done running -} - -int checkCenterCliff() { - while (true) { - std::cout << "cliffsensordata:" << robot.parser.data.CliffSensorCenter - << std::endl; - } -} - -int checkWheelDrop() { - while (true) { - std::cout << "wheeldropdata:" << robot.parser.data.WheelDropLeft - << std::endl; - } + mv.join(); // Wacht tot de command-thread klaar is + } +// Functie om commando's van de gebruiker te verwerken int command() { char input; while (true) { + // Vraag de gebruiker om een commando std::cout << "choose between forward = 1 or rotate = 2" << endl; std::cout << "What must the robot do?"; std::cin >> input; + // Verwerk de invoer van de gebruiker switch (input) { case FORWARD: { int distance; std::cout << "Enter distance to move forward: "; std::cin >> distance; - robot.goStraight(distance); + robot.goStraight(distance); // Beweeg de robot naar voren } break; case ROTATE: { int angle; std::cout << "Enter angle to rotate in degrees: "; std::cin >> angle; - robot.doRotation(angle); + robot.doRotation(angle); // Draai de robot } break; default: - cout << "Invalid input" << endl; + cout << "Invalid input" << endl; // Ongeldige invoer break; } } From c9643464a299d6e41a868777ab05397d3ecdaa62 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 8 Oct 2024 13:51:59 +0200 Subject: [PATCH 17/79] changed something --- src/C++/Driver/src/test.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index c1fd407..64bac26 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -14,10 +14,6 @@ int command(); int checkCenterCliff(); int checkWheelDrop(); -// Constante karakters voor invoeropties -const char FORWARD = '1'; -const char ROTATE = '2'; - int main() { // Start communicatie met de robot unsigned char *null_ptr(0); @@ -43,14 +39,14 @@ int command() { // Verwerk de invoer van de gebruiker switch (input) { - case FORWARD: { + case 1: { int distance; std::cout << "Enter distance to move forward: "; std::cin >> distance; robot.goStraight(distance); // Beweeg de robot naar voren } break; - case ROTATE: { + case 2: { int angle; std::cout << "Enter angle to rotate in degrees: "; std::cin >> angle; From ff93036a00e9caf9ea6f6167f2b80500514e6ad8 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Wed, 9 Oct 2024 14:10:34 +0200 Subject: [PATCH 18/79] changed website --- .gitignore | 1 + docs/Ishak/feedback.md | 2 ++ src/C++/Driver/src/test.cpp | 2 -- src/Python/flask/web/static/style.css | 4 +--- 4 files changed, 4 insertions(+), 5 deletions(-) create mode 100644 docs/Ishak/feedback.md diff --git a/.gitignore b/.gitignore index e4449ed..908a659 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ src/C++/Driver/Makefile src/C++/Driver/vgcore* src/C++/Driver/cmake_install.cmake src/C++/Driver/Makefile +src/Python/flask/web/_pycache_ \ No newline at end of file diff --git a/docs/Ishak/feedback.md b/docs/Ishak/feedback.md new file mode 100644 index 0000000..b9c6f1b --- /dev/null +++ b/docs/Ishak/feedback.md @@ -0,0 +1,2 @@ +# Feedback expert review + diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index 64bac26..6a48e47 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -11,8 +11,6 @@ CKobuki robot; // Functieprototypes int command(); -int checkCenterCliff(); -int checkWheelDrop(); int main() { // Start communicatie met de robot diff --git a/src/Python/flask/web/static/style.css b/src/Python/flask/web/static/style.css index aa40415..1c989b5 100644 --- a/src/Python/flask/web/static/style.css +++ b/src/Python/flask/web/static/style.css @@ -10,7 +10,7 @@ body { .navbar { display: flex; justify-content: space-between; - max-width: 70rem; + max-width: 80%; background-color: #fff; border: 1px solid #f0f0f0; border-radius: 50px; @@ -56,8 +56,6 @@ body { position: relative; width: 150px; height: 150px; - margin-left: auto; - margin-right: auto; } .btn { From 06e211b5080e19cb0a9aeac1bec50d1f8f65be3b Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Wed, 9 Oct 2024 15:45:13 +0200 Subject: [PATCH 19/79] testing if robot can go backwards --- src/C++/Driver/src/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index 6a48e47..1c1e762 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -31,7 +31,7 @@ int command() { while (true) { // Vraag de gebruiker om een commando - std::cout << "choose between forward = 1 or rotate = 2" << endl; + std::cout << "choose between forward/backwards = 1 or rotate = 2" << endl; std::cout << "What must the robot do?"; std::cin >> input; @@ -39,7 +39,7 @@ int command() { switch (input) { case 1: { int distance; - std::cout << "Enter distance to move forward: "; + std::cout << "Enter distance to move forward or backwards: "; std::cin >> distance; robot.goStraight(distance); // Beweeg de robot naar voren } break; From 30628cf16ea6dc54d295463e5880404d2fdc03cc Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Wed, 9 Oct 2024 16:08:26 +0200 Subject: [PATCH 20/79] test --- src/C++/Driver/src/test.cpp | 1 - src/Python/flask/web/templates/index.html | 31 ++++++++++------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index 1c1e762..0ca781d 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -22,7 +22,6 @@ int main() { thread mv(command); usleep(30 * 1000 * 1000); mv.join(); // Wacht tot de command-thread klaar is - } // Functie om commando's van de gebruiker te verwerken diff --git a/src/Python/flask/web/templates/index.html b/src/Python/flask/web/templates/index.html index b824f80..c32b2d8 100644 --- a/src/Python/flask/web/templates/index.html +++ b/src/Python/flask/web/templates/index.html @@ -1,19 +1,16 @@ -{%extends 'base.html'%} - -{%block head%} - -{%endblock%} - -{%block content%} +{%extends 'base.html'%} {%block head%} {%endblock%} {%block content%}
-
- Kobuki Robot -
-
- - - - -
+
+ Kobuki Robot +
+
+ + + + +
-{%endblock%} \ No newline at end of file +
+

Sensor Data

+
+{%endblock%} From d3b7aafc762026cd0203f6e9868ebbd4a59ea4d4 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Wed, 9 Oct 2024 16:08:59 +0200 Subject: [PATCH 21/79] removed backward --- src/C++/Driver/src/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index 0ca781d..b82c630 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -30,7 +30,7 @@ int command() { while (true) { // Vraag de gebruiker om een commando - std::cout << "choose between forward/backwards = 1 or rotate = 2" << endl; + std::cout << "choose between forward = 1 or rotate = 2" << endl; std::cout << "What must the robot do?"; std::cin >> input; @@ -38,7 +38,7 @@ int command() { switch (input) { case 1: { int distance; - std::cout << "Enter distance to move forward or backwards: "; + std::cout << "Enter distance to move forward: "; std::cin >> distance; robot.goStraight(distance); // Beweeg de robot naar voren } break; From 4716ce4edef3bc7019c5a55cb5dec0e437398cfc Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Wed, 9 Oct 2024 16:10:53 +0200 Subject: [PATCH 22/79] test --- src/C++/Driver/src/test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index b82c630..6a48e47 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -22,6 +22,7 @@ int main() { thread mv(command); usleep(30 * 1000 * 1000); mv.join(); // Wacht tot de command-thread klaar is + } // Functie om commando's van de gebruiker te verwerken From c711ee5682ead5a5fe9077e074799439754b0877 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Wed, 9 Oct 2024 16:18:12 +0200 Subject: [PATCH 23/79] 1 --- src/C++/Driver/src/test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index 6a48e47..64bac26 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -11,6 +11,8 @@ CKobuki robot; // Functieprototypes int command(); +int checkCenterCliff(); +int checkWheelDrop(); int main() { // Start communicatie met de robot From 0cca80d04fc56c49aa5531e56dcb43d81ef919ce Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Wed, 9 Oct 2024 16:35:25 +0200 Subject: [PATCH 24/79] fixed problem --- src/C++/Driver/src/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/C++/Driver/src/test.cpp b/src/C++/Driver/src/test.cpp index 64bac26..16cadf1 100644 --- a/src/C++/Driver/src/test.cpp +++ b/src/C++/Driver/src/test.cpp @@ -29,7 +29,7 @@ int main() { // Functie om commando's van de gebruiker te verwerken int command() { - char input; + int input; while (true) { // Vraag de gebruiker om een commando From 9de0bbf50e6a1f2842ea756018f3b0d046ac905d Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Thu, 10 Oct 2024 12:11:40 +0200 Subject: [PATCH 25/79] no idea what this is --- .../flask/web/__pycache__/app.cpython-311.pyc | Bin 0 -> 914 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/Python/flask/web/__pycache__/app.cpython-311.pyc diff --git a/src/Python/flask/web/__pycache__/app.cpython-311.pyc b/src/Python/flask/web/__pycache__/app.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ddfe8666509599b9c069ef91b551c7d5fc7aed8e GIT binary patch literal 914 zcmZ`$J8K(35Z=9q?xeG^2?j+b7#AsYDdfV1i4lPih+H`ag%sl8IBD0G@IA!d9kErN zjle3?*`+Im#Qrf-P+_hTgapzls1qqNd$Np_$FMUyGkp8aV?Qo0XAnr?*{{PV7@@B` zn2B`njK70(i3lRtMh>oEN2mxG35a4UcHz|x=u|2am9FJkG=CFe5lO^0>H^^A0aQu- z_pLQQxtCWFuzm;hK-$|h!IJS-%U-2h2 z28$-eSG&gEyO*0@lQ64R52$M}&ucXrZWvY@jh*L)&uYfOX;AlEG1m>*-id#$mi%vJ#GSEr*(BEW&)T%)Bt5$#4mIEV9u3qx?iIIvxpa`hsPFhqv#4 z1~U>d#&;;+`_~z!w1{^0&b+o4i9;-1_E!)W@jWKX&n&B GihcujnZv{Y literal 0 HcmV?d00001 From a8fcf0e0f8fd5d916dab3cd525b6733b9516e93d Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Thu, 10 Oct 2024 12:24:15 +0200 Subject: [PATCH 26/79] added curly brackets --- src/C++/Driver/src/CKobuki.cpp | 997 ++++++++++++++++----------------- 1 file changed, 471 insertions(+), 526 deletions(-) diff --git a/src/C++/Driver/src/CKobuki.cpp b/src/C++/Driver/src/CKobuki.cpp index 9b4687d..57518be 100755 --- a/src/C++/Driver/src/CKobuki.cpp +++ b/src/C++/Driver/src/CKobuki.cpp @@ -4,302 +4,281 @@ #include #include - // plot p; static std::vector vectorX; static std::vector vectorY; static std::vector vectorGyroTheta; // obsluha tty pod unixom -int set_interface_attribs2(int fd, int speed, int parity) -{ - struct termios tty; - memset(&tty, 0, sizeof tty); - if (tcgetattr(fd, &tty) != 0) - { - printf("error %d from tcgetattr", errno); - return -1; - } +int set_interface_attribs2(int fd, int speed, int parity) { + struct termios tty; + memset(&tty, 0, sizeof tty); + if (tcgetattr(fd, &tty) != 0) { + printf("error %d from tcgetattr", errno); + return -1; + } - cfsetospeed(&tty, speed); - cfsetispeed(&tty, speed); + cfsetospeed(&tty, speed); + cfsetispeed(&tty, speed); - tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars - // disable IGNBRK for mismatched speed tests; otherwise receive break - // as \000 chars - // tty.c_iflag &= ~IGNBRK; // disable break processing - tty.c_lflag = 0; // no signaling chars, no echo, - // no canonical processing - tty.c_oflag = 0; // no remapping, no delays - tty.c_cc[VMIN] = 0; // read doesn't block - tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout + tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars + // disable IGNBRK for mismatched speed tests; otherwise receive break + // as \000 chars + // tty.c_iflag &= ~IGNBRK; // disable break processing + tty.c_lflag = 0; // no signaling chars, no echo, + // no canonical processing + tty.c_oflag = 0; // no remapping, no delays + tty.c_cc[VMIN] = 0; // read doesn't block + tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout - tty.c_iflag &= ~(IGNBRK | INLCR | ICRNL | IXON | IXOFF | - IXANY); // shut off xon/xoff ctrl + tty.c_iflag &= ~(IGNBRK | INLCR | ICRNL | IXON | IXOFF | + IXANY); // shut off xon/xoff ctrl - tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls, - // enable reading - tty.c_cflag &= ~(PARENB | PARODD); // shut off parity - tty.c_cflag |= parity; - tty.c_cflag &= ~CSTOPB; - tty.c_cflag &= ~CRTSCTS; + tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls, + // enable reading + tty.c_cflag &= ~(PARENB | PARODD); // shut off parity + tty.c_cflag |= parity; + tty.c_cflag &= ~CSTOPB; + tty.c_cflag &= ~CRTSCTS; - if (tcsetattr(fd, TCSANOW, &tty) != 0) - { - printf("error %d from tcsetattr", errno); - return -1; - } - return 0; + if (tcsetattr(fd, TCSANOW, &tty) != 0) { + printf("error %d from tcsetattr", errno); + return -1; + } + return 0; } -void set_blocking2(int fd, int should_block) -{ - struct termios tty; - memset(&tty, 0, sizeof tty); - if (tcgetattr(fd, &tty) != 0) - { - printf("error %d from tggetattr", errno); - return; - } +void set_blocking2(int fd, int should_block) { + struct termios tty; + memset(&tty, 0, sizeof tty); + if (tcgetattr(fd, &tty) != 0) { + printf("error %d from tggetattr", errno); + return; + } - tty.c_cc[VMIN] = should_block ? 1 : 0; - tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout + tty.c_cc[VMIN] = should_block ? 1 : 0; + tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout - if (tcsetattr(fd, TCSANOW, &tty) != 0) - printf("error %d setting term attributes", errno); + if (tcsetattr(fd, TCSANOW, &tty) != 0) + printf("error %d setting term attributes", errno); } -int CKobuki::connect(char *comportT) -{ - HCom = open(comportT, O_RDWR | O_NOCTTY | O_NONBLOCK); +int CKobuki::connect(char *comportT) { + HCom = open(comportT, O_RDWR | O_NOCTTY | O_NONBLOCK); - if (HCom == -1) - { - printf("Kobuki nepripojeny\n"); - return HCom; - } - else - { - set_interface_attribs2(HCom, B115200, - 0); // set speed to 115,200 bps, 8n1 (no parity) - set_blocking2(HCom, 0); // set no blocking - /* struct termios settings; - tcgetattr(HCom, &settings); + if (HCom == -1) { + printf("Kobuki nepripojeny\n"); + return HCom; + } else { + set_interface_attribs2(HCom, B115200, + 0); // set speed to 115,200 bps, 8n1 (no parity) + 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 + 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); + tcsetattr(HCom, TCSANOW, &settings); // apply the settings*/ + tcflush(HCom, TCOFLUSH); - printf("Kobuki pripojeny\n"); - return HCom; - } + printf("Kobuki pripojeny\n"); + return HCom; + } } -unsigned char *CKobuki::readKobukiMessage() -{ - unsigned char buffer[1]; - ssize_t Pocet; - buffer[0] = 0; - unsigned char *null_buffer(0); - // citame kym nezachytime zaciatok spravy - do - { - Pocet = read(HCom, buffer, 1); - } while (buffer[0] != 0xAA); - // mame zaciatok spravy (asi) - if (Pocet == 1 && buffer[0] == 0xAA) - { - // citame dalsi byte - do - { +unsigned char *CKobuki::readKobukiMessage() { + unsigned char buffer[1]; + ssize_t Pocet; + buffer[0] = 0; + unsigned char *null_buffer(0); + // citame kym nezachytime zaciatok spravy + do { + Pocet = read(HCom, buffer, 1); + } while (buffer[0] != 0xAA); + // mame zaciatok spravy (asi) + if (Pocet == 1 && buffer[0] == 0xAA) { + // citame dalsi byte + do { - Pocet = read(HCom, buffer, 1); + Pocet = read(HCom, buffer, 1); - } while (Pocet != 1); // na linuxe -1 na windowse 0 + } while (Pocet != 1); // na linuxe -1 na windowse 0 - // a ak je to druhy byte hlavicky - if (Pocet == 1 && buffer[0] == 0x55) - { - // precitame dlzku - Pocet = read(HCom, buffer, 1); + // a ak je to druhy byte hlavicky + if (Pocet == 1 && buffer[0] == 0x55) { + // precitame dlzku + Pocet = read(HCom, buffer, 1); - // ReadFile(hCom, buffer, 1, &Pocet, NULL); - if (Pocet == 1) - { - // mame dlzku.. nastavime vektor a precitame ho cely - int readLenght = buffer[0]; - unsigned char *outputBuffer = - (unsigned char *)calloc(readLenght + 4, sizeof(char)); - outputBuffer[0] = buffer[0]; - int pct = 0; + // ReadFile(hCom, buffer, 1, &Pocet, NULL); + if (Pocet == 1) { + // mame dlzku.. nastavime vektor a precitame ho cely + int readLenght = buffer[0]; + unsigned char *outputBuffer = + (unsigned char *)calloc(readLenght + 4, sizeof(char)); + outputBuffer[0] = buffer[0]; + int pct = 0; - do - { - Pocet = 0; - int readpoc = (readLenght + 1 - pct); - Pocet = read(HCom, outputBuffer + 1 + pct, readpoc); + do { + Pocet = 0; + int readpoc = (readLenght + 1 - pct); + Pocet = read(HCom, outputBuffer + 1 + pct, readpoc); - pct = pct + (Pocet == -1 ? 0 : Pocet); - } while (pct != (readLenght + 1)); + pct = pct + (Pocet == -1 ? 0 : Pocet); + } while (pct != (readLenght + 1)); - // tu si mozeme ceknut co chodi zo serial intefejsu Kobukiho - // for(int i=0;i> 8, 0x00, 0x00, 0x00}; - message[13] = message[2] ^ message[3] ^ message[4] ^ message[5] ^ message[6] ^ - message[7] ^ message[8] ^ message[9] ^ message[10] ^ - message[11] ^ message[12]; - +void CKobuki::setPower(int value) { + if (value == 1) { + unsigned char message[8] = {0xaa, 0x55, 0x04, 0x0C, 0x02, 0xf0, 0x00, 0xAF}; uint32_t pocet; - pocet = write(HCom, &message, 14); + pocet = write(HCom, &message, 8); + } } -void CKobuki::setRotationSpeed(double radpersec) -{ - int speedvalue = radpersec * 230.0f / 2.0f; - unsigned char message[14] = {0xaa, - 0x55, - 0x0A, - 0x0c, - 0x02, - 0xf0, - 0x00, - 0x01, - 0x04, - speedvalue % 256, - speedvalue >> 8, - 0x01, - 0x00, - 0x00}; - message[13] = message[2] ^ message[3] ^ message[4] ^ message[5] ^ message[6] ^ - message[7] ^ message[8] ^ message[9] ^ message[10] ^ - message[11] ^ message[12]; +void CKobuki::setTranslationSpeed(int mmpersec) { + unsigned char message[14] = {0xaa, 0x55, 0x0A, 0x0c, 0x02, + 0xf0, 0x00, 0x01, 0x04, mmpersec % 256, + mmpersec >> 8, 0x00, 0x00, 0x00}; + message[13] = message[2] ^ message[3] ^ message[4] ^ message[5] ^ message[6] ^ + message[7] ^ message[8] ^ message[9] ^ message[10] ^ + message[11] ^ message[12]; - uint32_t pocet; - pocet = write(HCom, &message, 14); + uint32_t pocet; + pocet = write(HCom, &message, 14); } -void CKobuki::setArcSpeed(int mmpersec, int radius) -{ - if (radius == 0) - { - setTranslationSpeed(mmpersec); - return; +void CKobuki::setRotationSpeed(double radpersec) { + int speedvalue = radpersec * 230.0f / 2.0f; + unsigned char message[14] = {0xaa, + 0x55, + 0x0A, + 0x0c, + 0x02, + 0xf0, + 0x00, + 0x01, + 0x04, + speedvalue % 256, + speedvalue >> 8, + 0x01, + 0x00, + 0x00}; + message[13] = message[2] ^ message[3] ^ message[4] ^ message[5] ^ message[6] ^ + message[7] ^ message[8] ^ message[9] ^ message[10] ^ + message[11] ^ message[12]; + + uint32_t pocet; + pocet = write(HCom, &message, 14); +} + +void CKobuki::setArcSpeed(int mmpersec, int radius) { + if (radius == 0) { + setTranslationSpeed(mmpersec); + return; + } + + int speedvalue = + mmpersec * ((radius + (radius > 0 ? 230 : -230)) / 2) / radius; + unsigned char message[14] = {0xaa, + 0x55, + 0x0A, + 0x0c, + 0x02, + 0xf0, + 0x00, + 0x01, + 0x04, + speedvalue % 256, + speedvalue >> 8, + radius % 256, + radius >> 8, + 0x00}; + message[13] = message[2] ^ message[3] ^ message[4] ^ message[5] ^ message[6] ^ + message[7] ^ message[8] ^ message[9] ^ message[10] ^ + message[11] ^ message[12]; + uint32_t pocet; + pocet = write(HCom, &message, 14); +} + +void CKobuki::setSound(int noteinHz, int duration) { + int notevalue = floor((double)1.0 / ((double)noteinHz * 0.00000275) + 0.5); + unsigned char message[9] = {0xaa, 0x55, 0x05, + 0x03, 0x03, notevalue % 256, + notevalue >> 8, duration % 256, 0x00}; + message[8] = message[2] ^ message[3] ^ message[4] ^ message[5] ^ message[6] ^ + message[7]; + + uint32_t pocet; + pocet = write(HCom, &message, 9); +} + +void CKobuki::startCommunication(char *portname, bool CommandsEnabled, + void *userDataL) { + connect(portname); + enableCommands(CommandsEnabled); + userData = userDataL; + + int pthread_result; + pthread_result = + pthread_create(&threadHandle, NULL, KobukiProcess, (void *)this); + if (pthread_result != 0) { + std::cerr << "Error creating thread: " << pthread_result << std::endl; + } +} + +int CKobuki::measure() { + while (stopVlakno == 0) { + unsigned char *message = readKobukiMessage(); + if (message == NULL) { + // printf("vratil null message\n"); + continue; } + int ok = parser.parseKobukiMessage(parser.data, message); - int speedvalue = - mmpersec * ((radius + (radius > 0 ? 230 : -230)) / 2) / radius; - unsigned char message[14] = {0xaa, - 0x55, - 0x0A, - 0x0c, - 0x02, - 0xf0, - 0x00, - 0x01, - 0x04, - speedvalue % 256, - speedvalue >> 8, - radius % 256, - radius >> 8, - 0x00}; - message[13] = message[2] ^ message[3] ^ message[4] ^ message[5] ^ message[6] ^ - message[7] ^ message[8] ^ message[9] ^ message[10] ^ - message[11] ^ message[12]; - uint32_t pocet; - pocet = write(HCom, &message, 14); -} - -void CKobuki::setSound(int noteinHz, int duration) -{ - int notevalue = floor((double)1.0 / ((double)noteinHz * 0.00000275) + 0.5); - unsigned char message[9] = {0xaa, 0x55, 0x05, - 0x03, 0x03, notevalue % 256, - notevalue >> 8, duration % 256, 0x00}; - message[8] = message[2] ^ message[3] ^ message[4] ^ message[5] ^ message[6] ^ - message[7]; - - uint32_t pocet; - pocet = write(HCom, &message, 9); -} - -void CKobuki::startCommunication(char *portname, bool CommandsEnabled, void *userDataL) -{ - connect(portname); - enableCommands(CommandsEnabled); - userData = userDataL; - - int pthread_result; - pthread_result = pthread_create(&threadHandle, NULL, KobukiProcess, (void *)this); - if (pthread_result != 0) { - std::cerr << "Error creating thread: " << pthread_result << std::endl; + // maximalne moze trvat callback funkcia 20 ms, ak by trvala viac, nestihame + // citat + if (ok == 0) { + loop(userData, parser.data); } -} - -int CKobuki::measure() -{ - while (stopVlakno == 0) - { - unsigned char *message = readKobukiMessage(); - if (message == NULL) - { - // printf("vratil null message\n"); - continue; - } - int ok = parser.parseKobukiMessage(parser.data, message); - - // maximalne moze trvat callback funkcia 20 ms, ak by trvala viac, nestihame - // citat - if (ok == 0) - { - loop(userData, parser.data); - } - free(message); - } - return 0; + free(message); + } + return 0; } // int CKobuki::parseKobukiMessage(TKobukiData &output, unsigned char *data) @@ -320,25 +299,20 @@ int CKobuki::measure() // if (data[checkedValue] != 0x0F) // return -1; // checkedValue++; -// output.timestamp = data[checkedValue + 1] * 256 + data[checkedValue]; -// checkedValue += 2; -// output.BumperCenter = data[checkedValue] && 0x02; -// output.BumperLeft = data[checkedValue] && 0x04; -// output.BumperRight = data[checkedValue] && 0x01; -// checkedValue++; -// output.WheelDropLeft = data[checkedValue] && 0x02; -// output.WheelDropRight = data[checkedValue] && 0x01; -// checkedValue++; -// output.CliffCenter = data[checkedValue] && 0x02; -// output.CliffLeft = data[checkedValue] && 0x04; -// output.CliffRight = data[checkedValue] && 0x01; -// checkedValue++; -// output.EncoderLeft = data[checkedValue + 1] * 256 + data[checkedValue]; -// checkedValue += 2; -// output.EncoderRight = data[checkedValue + 1] * 256 + data[checkedValue]; -// checkedValue += 2; -// output.PWMleft = data[checkedValue]; +// output.timestamp = data[checkedValue + 1] * 256 + +// data[checkedValue]; checkedValue += 2; output.BumperCenter = +// data[checkedValue] && 0x02; output.BumperLeft = +// data[checkedValue] && 0x04; output.BumperRight = +// data[checkedValue] && 0x01; checkedValue++; output.WheelDropLeft +// = data[checkedValue] && 0x02; output.WheelDropRight = +// data[checkedValue] && 0x01; checkedValue++; output.CliffCenter = +// data[checkedValue] && 0x02; output.CliffLeft = data[checkedValue] +// && 0x04; output.CliffRight = data[checkedValue] && 0x01; // checkedValue++; +// output.EncoderLeft = data[checkedValue + 1] * 256 + +// data[checkedValue]; checkedValue += 2; output.EncoderRight = +// data[checkedValue + 1] * 256 + data[checkedValue]; checkedValue +// += 2; output.PWMleft = data[checkedValue]; checkedValue++; // output.PWMright = data[checkedValue]; // checkedValue++; // output.ButtonPress = data[checkedValue]; @@ -369,10 +343,10 @@ int CKobuki::measure() // if (data[checkedValue] != 0x07) // return -4; // checkedValue++; -// output.GyroAngle = data[checkedValue + 1] * 256 + data[checkedValue]; -// checkedValue += 2; -// output.GyroAngleRate = data[checkedValue + 1] * 256 + data[checkedValue]; -// checkedValue += 5; // 3 unsued +// output.GyroAngle = data[checkedValue + 1] * 256 + +// data[checkedValue]; checkedValue += 2; output.GyroAngleRate = +// data[checkedValue + 1] * 256 + data[checkedValue]; checkedValue +// += 5; // 3 unsued // } // else if (data[checkedValue] == 0x05) // { @@ -457,16 +431,14 @@ int CKobuki::measure() // if (data[checkedValue] != 0x10) // return -10; // checkedValue++; -// output.digitalInput = data[checkedValue + 1] * 256 + data[checkedValue]; -// checkedValue += 2; -// output.analogInputCh0 = data[checkedValue + 1] * 256 + data[checkedValue]; -// checkedValue += 2; -// output.analogInputCh1 = data[checkedValue + 1] * 256 + data[checkedValue]; -// checkedValue += 2; -// output.analogInputCh2 = data[checkedValue + 1] * 256 + data[checkedValue]; -// checkedValue += 2; -// output.analogInputCh3 = data[checkedValue + 1] * 256 + data[checkedValue]; -// checkedValue += 8; // 2+6 +// output.digitalInput = data[checkedValue + 1] * 256 + +// data[checkedValue]; checkedValue += 2; output.analogInputCh0 = +// data[checkedValue + 1] * 256 + data[checkedValue]; checkedValue +// += 2; output.analogInputCh1 = data[checkedValue + 1] * 256 + +// data[checkedValue]; checkedValue += 2; output.analogInputCh2 = +// data[checkedValue + 1] * 256 + data[checkedValue]; checkedValue +// += 2; output.analogInputCh3 = data[checkedValue + 1] * 256 + +// data[checkedValue]; checkedValue += 8; // 2+6 // } // else if (data[checkedValue] == 0x13) // { @@ -474,17 +446,20 @@ int CKobuki::measure() // if (data[checkedValue] != 0x0C) // return -11; // checkedValue++; -// output.extraInfo.UDID0 = data[checkedValue + 3] * 256 * 256 * 256 + +// output.extraInfo.UDID0 = data[checkedValue + 3] * 256 * 256 * 256 +// + // data[checkedValue + 2] * 256 * 256 + // data[checkedValue + 1] * 256 + // data[checkedValue]; // checkedValue += 4; -// output.extraInfo.UDID1 = data[checkedValue + 3] * 256 * 256 * 256 + +// output.extraInfo.UDID1 = data[checkedValue + 3] * 256 * 256 * 256 +// + // data[checkedValue + 2] * 256 * 256 + // data[checkedValue + 1] * 256 + // data[checkedValue]; // checkedValue += 4; -// output.extraInfo.UDID2 = data[checkedValue + 3] * 256 * 256 * 256 + +// output.extraInfo.UDID2 = data[checkedValue + 3] * 256 * 256 * 256 +// + // data[checkedValue + 2] * 256 * 256 + // data[checkedValue + 1] * 256 + // data[checkedValue]; @@ -499,135 +474,116 @@ int CKobuki::measure() // return 0; // } -long double CKobuki::gyroToRad(signed short GyroAngle) -{ +long double CKobuki::gyroToRad(signed short GyroAngle) { - long double rad; - if (GyroAngle < 0) - { - rad = GyroAngle + 360; - } - else - { - rad = GyroAngle; - } - return (long double)rad * PI / 180.0; + long double rad; + if (GyroAngle < 0) { + rad = GyroAngle + 360; + } else { + rad = GyroAngle; + } + return (long double)rad * PI / 180.0; } -long CKobuki::loop(void *user_data, TKobukiData &Kobuki_data) -{ - if (iterationCount == 0) - { - prevLeftEncoder = Kobuki_data.EncoderLeft; - prevRightEncoder = Kobuki_data.EncoderRight; - prevTimestamp = Kobuki_data.timestamp; - prevGyroTheta = gyroToRad(Kobuki_data.GyroAngle); - iterationCount++; - } - - int dLeft; - if (abs(Kobuki_data.EncoderLeft - prevLeftEncoder) > 32000) - { - dLeft = Kobuki_data.EncoderLeft - prevLeftEncoder + - (Kobuki_data.EncoderLeft > prevLeftEncoder ? -65536 : +65536); - } - else - { - dLeft = Kobuki_data.EncoderLeft - prevLeftEncoder; - } - - int dRight; - if (abs(Kobuki_data.EncoderRight - prevRightEncoder) > 32000) - { - dRight = Kobuki_data.EncoderRight - prevRightEncoder + - (Kobuki_data.EncoderRight > prevRightEncoder ? -65536 : +65536); - } - else - { - dRight = Kobuki_data.EncoderRight - prevRightEncoder; - } - - long double dGyroTheta = prevGyroTheta - gyroToRad(Kobuki_data.GyroAngle); - - if (dGyroTheta > PI) - { - dGyroTheta -= 2 * PI; - } - if (dGyroTheta < -1 * PI) - { - dGyroTheta += 2 * PI; - } - - gyroTheta += dGyroTheta; - - uint16_t dTimestamp = Kobuki_data.timestamp - prevTimestamp; - - long double mLeft = dLeft * tickToMeter; - long double mRight = dRight * tickToMeter; - - if (mLeft == mRight) - { - x = x + mRight; - } - else - { - x = x + (b * (mRight + mLeft)) / (2 * (mRight - mLeft)) * - (sin((mRight - mLeft) / b + theta) - sin(theta)); - y = y + (b * (mRight + mLeft)) / (2 * (mRight - mLeft)) * - (cos((mRight - mLeft) / b + theta) - cos(theta)); - theta = (mRight - mLeft) / b + theta; - } - - displacement = (mRight + mLeft) / 2; - integratedGyroTheta = integratedGyroTheta + dGyroTheta; - gx = gx + displacement * cos(integratedGyroTheta + dGyroTheta / 2); - - gy = gy + displacement * sin(integratedGyroTheta + dGyroTheta / 2); - - totalLeft += dLeft; - totalRight += dRight; - - // ak je suma novej a predchadzajucej vacsia ako 65536 tak to pretieklo? - directionL = (prevLeftEncoder < Kobuki_data.EncoderLeft ? 1 : -1); - directionR = (prevRightEncoder < Kobuki_data.EncoderRight ? 1 : -1); - dTimestamp = (Kobuki_data.timestamp < prevTimestamp - ? prevTimestamp - Kobuki_data.timestamp + 65536 - : dTimestamp); - +long CKobuki::loop(void *user_data, TKobukiData &Kobuki_data) { + if (iterationCount == 0) { prevLeftEncoder = Kobuki_data.EncoderLeft; prevRightEncoder = Kobuki_data.EncoderRight; prevTimestamp = Kobuki_data.timestamp; prevGyroTheta = gyroToRad(Kobuki_data.GyroAngle); + iterationCount++; + } - // std::cout << "X: " << x - // << " Y: " << y - // << " Theta: " << theta - // << "Gyro theta:" << gyroTheta - // << std::endl; + int dLeft; + if (abs(Kobuki_data.EncoderLeft - prevLeftEncoder) > 32000) { + dLeft = Kobuki_data.EncoderLeft - prevLeftEncoder + + (Kobuki_data.EncoderLeft > prevLeftEncoder ? -65536 : +65536); + } else { + dLeft = Kobuki_data.EncoderLeft - prevLeftEncoder; + } - static long counter = 0; + int dRight; + if (abs(Kobuki_data.EncoderRight - prevRightEncoder) > 32000) { + dRight = Kobuki_data.EncoderRight - prevRightEncoder + + (Kobuki_data.EncoderRight > prevRightEncoder ? -65536 : +65536); + } else { + dRight = Kobuki_data.EncoderRight - prevRightEncoder; + } - vectorX.push_back(gx); - vectorY.push_back(gy); - vectorGyroTheta.push_back(gyroTheta); + long double dGyroTheta = prevGyroTheta - gyroToRad(Kobuki_data.GyroAngle); - // if (counter % 100 == 0) { - // p.plot_data(vectorY, vectorX); - // } - counter++; + if (dGyroTheta > PI) { + dGyroTheta -= 2 * PI; + } + if (dGyroTheta < -1 * PI) { + dGyroTheta += 2 * PI; + } - return 0; + gyroTheta += dGyroTheta; + + uint16_t dTimestamp = Kobuki_data.timestamp - prevTimestamp; + + long double mLeft = dLeft * tickToMeter; + long double mRight = dRight * tickToMeter; + + if (mLeft == mRight) { + x = x + mRight; + } else { + x = x + (b * (mRight + mLeft)) / (2 * (mRight - mLeft)) * + (sin((mRight - mLeft) / b + theta) - sin(theta)); + y = y + (b * (mRight + mLeft)) / (2 * (mRight - mLeft)) * + (cos((mRight - mLeft) / b + theta) - cos(theta)); + theta = (mRight - mLeft) / b + theta; + } + + displacement = (mRight + mLeft) / 2; + integratedGyroTheta = integratedGyroTheta + dGyroTheta; + gx = gx + displacement * cos(integratedGyroTheta + dGyroTheta / 2); + + gy = gy + displacement * sin(integratedGyroTheta + dGyroTheta / 2); + + totalLeft += dLeft; + totalRight += dRight; + + // ak je suma novej a predchadzajucej vacsia ako 65536 tak to pretieklo? + directionL = (prevLeftEncoder < Kobuki_data.EncoderLeft ? 1 : -1); + directionR = (prevRightEncoder < Kobuki_data.EncoderRight ? 1 : -1); + dTimestamp = (Kobuki_data.timestamp < prevTimestamp + ? prevTimestamp - Kobuki_data.timestamp + 65536 + : dTimestamp); + + prevLeftEncoder = Kobuki_data.EncoderLeft; + prevRightEncoder = Kobuki_data.EncoderRight; + prevTimestamp = Kobuki_data.timestamp; + prevGyroTheta = gyroToRad(Kobuki_data.GyroAngle); + + // std::cout << "X: " << x + // << " Y: " << y + // << " Theta: " << theta + // << "Gyro theta:" << gyroTheta + // << std::endl; + + static long counter = 0; + + vectorX.push_back(gx); + vectorY.push_back(gy); + vectorGyroTheta.push_back(gyroTheta); + + // if (counter % 100 == 0) { + // p.plot_data(vectorY, vectorX); + // } + counter++; + + return 0; } - - - // tells the kobuki to go a few meters forward or backward, the sign decides -// the function compensates for walking straight with the controller, internally it uses setArcSpeed and -// uses encoder data as feedback -void CKobuki::goStraight(long double distance){ - long double u_translation = 0; // controlled magnitude, speed of the robot in motion - long double w_translation = distance; // requested value +// the function compensates for walking straight with the controller, internally +// it uses setArcSpeed and uses encoder data as feedback +void CKobuki::goStraight(long double distance) { + long double u_translation = + 0; // controlled magnitude, speed of the robot in motion + long double w_translation = distance; // requested value // controller parameters long double Kp_translation = 4500; @@ -636,150 +592,139 @@ void CKobuki::goStraight(long double distance){ int lower_thresh_translation = 40; int translation_start_gain = 20; - long double u_rotation = 0; // controlled magnitude - long double w_rotation = 0; - long double Kp_rotation = 57; - long double e_rotation = 0; + long double u_rotation = 0; // controlled magnitude + long double w_rotation = 0; + long double Kp_rotation = 57; + long double e_rotation = 0; - x = 0; - y = 0; - theta = 0; + x = 0; + y = 0; + theta = 0; - long i = 5; - //send command and hold until robot reaches point - while (fabs(x - w_translation) > 0.005 && x < w_translation) - { - e_translation = w_translation - x; - u_translation = Kp_translation * e_translation; + long i = 5; + // send command and hold until robot reaches point + while (fabs(x - w_translation) > 0.005 && x < w_translation) { + e_translation = w_translation - x; + u_translation = Kp_translation * e_translation; - e_rotation = w_rotation - theta; - if (!e_rotation == 0) - u_rotation = Kp_rotation / e_rotation; + e_rotation = w_rotation - theta; + if (!e_rotation == 0) + u_rotation = Kp_rotation / e_rotation; - // limit translation speed - if (u_translation > upper_thresh_translation) - u_translation = upper_thresh_translation; - if (u_translation < lower_thresh_translation) - u_translation = lower_thresh_translation; + // limit translation speed + if (u_translation > upper_thresh_translation) + u_translation = upper_thresh_translation; + if (u_translation < lower_thresh_translation) + u_translation = lower_thresh_translation; - // rewrite starting speed with line - if (i < u_translation) - { - u_translation = i; - } - - if (fabs(u_rotation) > 32767) - { - u_rotation = -32767; - } - - if (u_rotation == 0) - { - u_rotation = -32767; - } - //send command to robot - this->setArcSpeed(u_translation, u_rotation); - - // increment starting speed - i = i + translation_start_gain; + // rewrite starting speed with line + if (i < u_translation) { + u_translation = i; } - this->setTranslationSpeed(0); + + if (fabs(u_rotation) > 32767) { + u_rotation = -32767; + } + + if (u_rotation == 0) { + u_rotation = -32767; + } + // send command to robot + this->setArcSpeed(u_translation, u_rotation); + + // increment starting speed + i = i + translation_start_gain; + } + this->setTranslationSpeed(0); } /// the method performs the rotation, it rotates using the regulator, the /// gyroscope serves as feedback, because it is much more accurate than encoders -void CKobuki::doRotation(long double th) -{ - long double u = 0; // controlled variable, angular speed of the robot during movement - long double w = th; // desired value in radians - long double Kp = PI; - long double e = 0; - int thresh = PI / 2; +void CKobuki::doRotation(long double th) { + long double u = + 0; // controlled variable, angular speed of the robot during movement + long double w = th; // desired value in radians + long double Kp = PI; + long double e = 0; + int thresh = PI / 2; - theta = 0; - x = 0; - y = 0; - gyroTheta = 0; + theta = 0; + x = 0; + y = 0; + gyroTheta = 0; - long double i = 0; + long double i = 0; - if (w > 0) - { - while (gyroTheta < w) - { - e = w - gyroTheta; - u = Kp * e; + if (w > 0) { + while (gyroTheta < w) { + e = w - gyroTheta; + u = Kp * e; - if (u > thresh) - u = thresh; - if (u < 0.4) - u = 0.4; + if (u > thresh) { + u = thresh; + } + if (u < 0.4) { + u = 0.4; + } + if (i < u) { + u = i; + } - if (i < u) - { - u = i; - } - - std::cout << "Angle: " << gyroTheta << " required:" << w << std::endl; - this->setRotationSpeed(-1 * u); - usleep(25 * 1000); - i = i + 0.1; - } + std::cout << "Angle: " << gyroTheta << " required:" << w << std::endl; + this->setRotationSpeed(-1 * u); + usleep(25 * 1000); + i = i + 0.1; } - else - { - while (gyroTheta > w) - { - e = w - gyroTheta; - u = Kp * e * -1; + } else { + while (gyroTheta > w) { + e = w - gyroTheta; + u = Kp * e * -1; - if (u > thresh) - u = thresh; - if (u < 0.4) - u = 0.4; + if (u > thresh) + u = thresh; + if (u < 0.4) + u = 0.4; - if (i < u) - { - u = i; - } + if (i < u) { + u = i; + } - std::cout << "Angle: " << gyroTheta << " required:" << w << std::endl; - this->setRotationSpeed(u); - usleep(25 * 1000); - i = i + 0.1; - } + std::cout << "Angle: " << gyroTheta << " required:" << w << std::endl; + this->setRotationSpeed(u); + usleep(25 * 1000); + i = i + 0.1; } + } - std::cout << "Rotation done" << std::endl; - this->setRotationSpeed(0); - usleep(25*1000); + std::cout << "Rotation done" << std::endl; + this->setRotationSpeed(0); + usleep(25 * 1000); } -// combines navigation to a coordinate and rotation by an angle, performs movement to -// the selected coordinate in the robot's coordinate system -void CKobuki::goToXy(long double xx, long double yy) -{ - long double th; +// combines navigation to a coordinate and rotation by an angle, performs +// movement to the selected coordinate in the robot's coordinate system +void CKobuki::goToXy(long double xx, long double yy) { + long double th; - yy = yy * -1; + yy = yy * -1; - th = atan2(yy, xx); - doRotation(th); + th = atan2(yy, xx); + doRotation(th); - long double s = sqrt(pow(xx, 2) + pow(yy, 2)); + long double s = sqrt(pow(xx, 2) + pow(yy, 2)); - // resetnem suradnicovu sustavu robota - x = 0; - y = 0; - iterationCount = 0; - theta = 0; + // resetnem suradnicovu sustavu robota + x = 0; + y = 0; + iterationCount = 0; + theta = 0; - // std::cout << "mam prejst: " << s << "[m]" << std::endl; + // std::cout << "mam prejst: " << s << "[m]" << std::endl; - goStraight(s); + goStraight(s); - usleep(25 * 1000); - return; + usleep(25 * 1000); + return; } void CKobuki::forward(int speedvalue, long double distance) { @@ -789,22 +734,22 @@ void CKobuki::forward(int speedvalue, long double distance) { int actual_speed = speedvalue; int actual_radius = 0; // Pure translation (straight line) -unsigned char message[11] = { - 0xaa, // Start byte 1 - 0x55, // Start byte 2 - 0x08, // Payload length (the first 2 bytes dont count) - 0x01, // payload type (0x01 = control command) - 0x04, // Control byte or additional identifier - actual_speed % 256, // Lower byte of speed value - actual_speed >> 8, // Upper byte of speed value - 0x00, // Placeholder for radius - 0x00, // Placeholder for radius - 0x00 // Placeholder for checksum -}; + unsigned char message[11] = { + 0xaa, // Start byte 1 + 0x55, // Start byte 2 + 0x08, // Payload length (the first 2 bytes dont count) + 0x01, // payload type (0x01 = control command) + 0x04, // Control byte or additional identifier + actual_speed % 256, // Lower byte of speed value + actual_speed >> 8, // Upper byte of speed value + 0x00, // Placeholder for radius + 0x00, // Placeholder for radius + 0x00 // Placeholder for checksum + }; -// Calculate checksum -message[10] = message[2] ^ message[3] ^ message[4] ^ message[5] ^ message[6] ^ - message[7] ^ message[8] ^ message[9]; + // Calculate checksum + message[10] = message[2] ^ message[3] ^ message[4] ^ message[5] ^ message[6] ^ + message[7] ^ message[8] ^ message[9]; // Send the message uint32_t pocet; From 5d1c0fd44ce11338eddd072c71c208ef0c8ad4a2 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Thu, 10 Oct 2024 13:01:48 +0200 Subject: [PATCH 27/79] change some values --- src/C++/Driver/src/CKobuki.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/C++/Driver/src/CKobuki.cpp b/src/C++/Driver/src/CKobuki.cpp index 57518be..2879f9c 100755 --- a/src/C++/Driver/src/CKobuki.cpp +++ b/src/C++/Driver/src/CKobuki.cpp @@ -644,9 +644,9 @@ void CKobuki::doRotation(long double th) { long double u = 0; // controlled variable, angular speed of the robot during movement long double w = th; // desired value in radians - long double Kp = PI; + long double Kp = 2.0; long double e = 0; - int thresh = PI / 2; + long double thresh = 1.0; theta = 0; x = 0; From ebfacd52b45a3aee1c64cee5eb5bd11b1392e9b3 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Thu, 10 Oct 2024 13:19:57 +0200 Subject: [PATCH 28/79] test rotation --- src/C++/Driver/src/CKobuki.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/C++/Driver/src/CKobuki.cpp b/src/C++/Driver/src/CKobuki.cpp index 2879f9c..8a56f37 100755 --- a/src/C++/Driver/src/CKobuki.cpp +++ b/src/C++/Driver/src/CKobuki.cpp @@ -644,9 +644,9 @@ void CKobuki::doRotation(long double th) { long double u = 0; // controlled variable, angular speed of the robot during movement long double w = th; // desired value in radians - long double Kp = 2.0; + long double Kp = PI; long double e = 0; - long double thresh = 1.0; + long double thresh = PI / 2; theta = 0; x = 0; From 55c24eabf7393eff1f620e79e6b5c43833f28b7a Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Wed, 16 Oct 2024 16:26:51 +0200 Subject: [PATCH 29/79] wrote message and connect function for the mqtt connection to pi --- .gitignore | 3 ++- src/Python/flask/web/app.py | 16 +++++------ src/Python/flask/web/templates/index.html | 12 +++++---- src/Python/socket/socketServer.py | 33 +++++++++++------------ 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/.gitignore b/.gitignore index 908a659..7482133 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ src/C++/Driver/Makefile src/C++/Driver/vgcore* src/C++/Driver/cmake_install.cmake src/C++/Driver/Makefile -src/Python/flask/web/_pycache_ \ No newline at end of file +src/Python/flask/web/_pycache_ +venv \ No newline at end of file diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index 5b555b0..4bcc928 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -1,4 +1,5 @@ -from flask import Flask, render_template +from flask import Flask, request, render_template +import paho.mqtt.publish as publish app = Flask(__name__) @@ -6,12 +7,11 @@ app = Flask(__name__) def index(): return render_template('index.html') -@app.route('/control', methods=['POST']) -def control(): - return("hello") - +@app.route('/move', methods=['POST']) +def move(): + direction = request.form['direction'] + publish.single("home/commands", direction, hostname="ishak.ishakpi.ddns.net") + return "Message sent" if __name__ == '__main__': - app.run(debug=True) - - + app.run(debug=True) \ No newline at end of file diff --git a/src/Python/flask/web/templates/index.html b/src/Python/flask/web/templates/index.html index c32b2d8..0ab2680 100644 --- a/src/Python/flask/web/templates/index.html +++ b/src/Python/flask/web/templates/index.html @@ -4,13 +4,15 @@ Kobuki Robot
- - - - +
+ + + + +
-

Sensor Data

+

Sensor Data

{%endblock%} diff --git a/src/Python/socket/socketServer.py b/src/Python/socket/socketServer.py index 1bff9ef..023c0fc 100644 --- a/src/Python/socket/socketServer.py +++ b/src/Python/socket/socketServer.py @@ -1,20 +1,17 @@ -import socket +import paho.mqtt.client as mqtt -HOST = "127.0.0.1" # Listen on all available interfaces -PORT = 4024 # Port to listen on (non-privileged ports are > 1023) +def on_connect(client, userdata, flags, rc): + print("Connected with result code " + str(rc)) + client.subscribe("move") -with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.bind((HOST, PORT)) - s.listen() - print(f"Server listening on {HOST}:{PORT}") - conn, addr = s.accept() - with conn: - print(f"Connected by {addr}") - conn.sendall(b"hallo\n") - while True: - data = conn.recv(2048) - if data: - print("Received:", repr(data)) - conn.sendall(b"message received\n") - if not data: - break \ No newline at end of file +def on_message(client, userdata, msg): + command = msg.payload.decode() + print(f"Received command: {command}") + # Voeg hier je code toe om het commando uit te voeren + +client = mqtt.Client() +client.on_connect = on_connect +client.on_message = on_message + +client.connect("ishak.ishakpi.ddns.net", 1883, 60) +client.loop_forever() \ No newline at end of file From 2aeb41af7cae47f26e3d400c0c1e1f03b1cbc0e2 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Wed, 16 Oct 2024 16:27:36 +0200 Subject: [PATCH 30/79] cpp code for receiving message --- src/C++/Socket/main.cpp | 75 +++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 44 deletions(-) diff --git a/src/C++/Socket/main.cpp b/src/C++/Socket/main.cpp index 1449e3a..6098121 100644 --- a/src/C++/Socket/main.cpp +++ b/src/C++/Socket/main.cpp @@ -1,53 +1,40 @@ #include -#include -#include +#include "mqtt/async_client.h" -using boost::asio::ip::tcp; +const std::string SERVER_ADDRESS("tcp://localhost:1883"); +const std::string CLIENT_ID("pi_client"); +const std::string TOPIC("button/pressed"); + +class callback : public virtual mqtt::callback +{ +public: + void message_arrived(mqtt::const_message_ptr msg) override { + std::cout << "Message arrived: " << msg->get_payload_str() << std::endl; + } +}; int main() { + mqtt::async_client client(SERVER_ADDRESS, CLIENT_ID); + callback cb; + client.set_callback(cb); + + mqtt::connect_options connOpts; + connOpts.set_keep_alive_interval(20); + connOpts.set_clean_session(true); + try { - // Create an io_context object - boost::asio::io_context io_context; + client.connect(connOpts)->wait(); + client.subscribe(TOPIC, 1)->wait(); + } + catch (const mqtt::exception& exc) { + std::cerr << "Error: " << exc.what() << std::endl; + return 1; + } - // Resolve the server address and port - tcp::resolver resolver(io_context); - tcp::resolver::results_type endpoints = resolver.resolve("127.0.0.1", "4024"); - - // Create and connect the socket - tcp::socket socket(io_context); - boost::asio::connect(socket, endpoints); - - std::cout << "Connected to the server." << std::endl; - - // Receive initial message from the server - boost::asio::streambuf buffer; - boost::asio::read_until(socket, buffer, "\n"); - std::istream is(&buffer); - std::string initial_message; - std::getline(is, initial_message); - std::cout << "Initial message from server: " << initial_message << std::endl; - - // Send and receive messages - while (true) { - // Send a message to the server - std::string message; - std::cout << "Enter message: "; - std::getline(std::cin, message); - message += "\n"; // Add newline to mark the end of the message - boost::asio::write(socket, boost::asio::buffer(message)); - - // Receive a response from the server - boost::asio::streambuf response_buffer; - boost::asio::read_until(socket, response_buffer, "\n"); - std::istream response_stream(&response_buffer); - std::string reply; - std::getline(response_stream, reply); - std::cout << "Reply from server: " << reply << std::endl; - } - - } catch (std::exception& e) { - std::cerr << "Exception: " << e.what() << std::endl; + // Houd de verbinding actief + while (true) { + std::this_thread::sleep_for(std::chrono::seconds(1)); } return 0; -} \ No newline at end of file +} From ab38b4928bf5cdf0da444fe87a2c72de0a37f883 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Wed, 16 Oct 2024 17:11:11 +0200 Subject: [PATCH 31/79] changed port --- src/Python/flask/web/app.py | 2 +- src/Python/socket/socketServer.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index 4bcc928..fcfb3b9 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -10,7 +10,7 @@ def index(): @app.route('/move', methods=['POST']) def move(): direction = request.form['direction'] - publish.single("home/commands", direction, hostname="ishak.ishakpi.ddns.net") + publish.single("move", direction, hostname="ishak.ishakpi.ddns.net") return "Message sent" if __name__ == '__main__': diff --git a/src/Python/socket/socketServer.py b/src/Python/socket/socketServer.py index 023c0fc..a144225 100644 --- a/src/Python/socket/socketServer.py +++ b/src/Python/socket/socketServer.py @@ -13,5 +13,5 @@ client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message -client.connect("ishak.ishakpi.ddns.net", 1883, 60) +client.connect("ishak.ishakpi.ddns.net", 83, 60) client.loop_forever() \ No newline at end of file From 0e1099a608be077f16c70aadf1b16eddaee16cff Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Thu, 17 Oct 2024 12:02:47 +0200 Subject: [PATCH 32/79] changed ip --- src/Python/socket/socketServer.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Python/socket/socketServer.py b/src/Python/socket/socketServer.py index a144225..41d2c55 100644 --- a/src/Python/socket/socketServer.py +++ b/src/Python/socket/socketServer.py @@ -1,5 +1,8 @@ -import paho.mqtt.client as mqtt +from flask import Flask +from flask_mqtt import Mqtt +app = Flask(__name__) +mqtt = Mqtt(app) def on_connect(client, userdata, flags, rc): print("Connected with result code " + str(rc)) client.subscribe("move") @@ -13,5 +16,5 @@ client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message -client.connect("ishak.ishakpi.ddns.net", 83, 60) +client.connect("145.109.226.204", 83, 60) client.loop_forever() \ No newline at end of file From 17333a69392c3f6448d5269fb8a915f275485e60 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Thu, 17 Oct 2024 12:04:11 +0200 Subject: [PATCH 33/79] changed ip --- src/Python/flask/web/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index fcfb3b9..21073ea 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -10,7 +10,7 @@ def index(): @app.route('/move', methods=['POST']) def move(): direction = request.form['direction'] - publish.single("move", direction, hostname="ishak.ishakpi.ddns.net") + publish.single("move", direction, hostname="145.109.226.204") return "Message sent" if __name__ == '__main__': From 9aec5eaaa47608d9e21099a5a4741043748815d6 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Mon, 21 Oct 2024 09:55:06 +0200 Subject: [PATCH 34/79] Refactor MQTT connection and message sending in Flask app --- src/Python/flask/web/app.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index 21073ea..33c2679 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -1,17 +1,21 @@ from flask import Flask, request, render_template -import paho.mqtt.publish as publish +import paho.mqtt.client as mqtt app = Flask(__name__) +mqtt_client = mqtt.Client() + +# Verbinding maken met de Raspberry Pi (broker) +mqtt_client.connect("ishakpi.ddns.net", 1883, 60) + @app.route('/') def index(): return render_template('index.html') @app.route('/move', methods=['POST']) def move(): - direction = request.form['direction'] - publish.single("move", direction, hostname="145.109.226.204") - return "Message sent" + mqtt_client.publish("website/knop", "Knop ingedrukt!") + return "Bericht verzonden!" if __name__ == '__main__': app.run(debug=True) \ No newline at end of file From 2dadabba1868113a2adb33b54bb942a7ddacb068 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Mon, 21 Oct 2024 09:56:07 +0200 Subject: [PATCH 35/79] Refactor MQTT connection and message receiving in C++ Socket code --- src/C++/Socket/main.cpp | 45 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/C++/Socket/main.cpp b/src/C++/Socket/main.cpp index 6098121..f44e437 100644 --- a/src/C++/Socket/main.cpp +++ b/src/C++/Socket/main.cpp @@ -1,39 +1,38 @@ #include -#include "mqtt/async_client.h" +#include -const std::string SERVER_ADDRESS("tcp://localhost:1883"); -const std::string CLIENT_ID("pi_client"); -const std::string TOPIC("button/pressed"); +const std::string ADDRESS("tcp://localhost:1883"); // Brokeradres (Raspberry Pi) +const std::string CLIENT_ID("cpp_subscriber"); +const std::string TOPIC("website/knop"); -class callback : public virtual mqtt::callback -{ -public: + +class callback : public virtual mqtt::callback { void message_arrived(mqtt::const_message_ptr msg) override { - std::cout << "Message arrived: " << msg->get_payload_str() << std::endl; + std::cout << "Ontvangen bericht: '" << msg->get_topic() << "' : " << msg->to_string() << std::endl; + // Doe iets met het bericht, bijvoorbeeld een GPIO-activering } }; int main() { - mqtt::async_client client(SERVER_ADDRESS, CLIENT_ID); + + mqtt::async_client client(ADDRESS, CLIENT_ID); callback cb; client.set_callback(cb); - mqtt::connect_options connOpts; - connOpts.set_keep_alive_interval(20); - connOpts.set_clean_session(true); - try { - client.connect(connOpts)->wait(); - client.subscribe(TOPIC, 1)->wait(); - } - catch (const mqtt::exception& exc) { - std::cerr << "Error: " << exc.what() << std::endl; - return 1; - } + std::cout << "Verbinden met broker..." << std::endl; + client.connect()->wait(); + std::cout << "Verbonden!" << std::endl; - // Houd de verbinding actief - while (true) { - std::this_thread::sleep_for(std::chrono::seconds(1)); + std::cout << "Abonneren op topic: " << TOPIC << std::endl; + client.subscribe(TOPIC, 1)->wait(); + + while (true) { + // Houd de client draaiende om berichten te blijven ontvangen + } + } catch (const mqtt::exception& exc) { + std::cerr << exc.what() << std::endl; + return 1; } return 0; From 82bc53e2c75668c8ac9dea4730e8cb36f90e2e91 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Mon, 21 Oct 2024 10:49:57 +0200 Subject: [PATCH 36/79] include paho mqtt --- src/Python/socket/socketServer.py | 35 ++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/Python/socket/socketServer.py b/src/Python/socket/socketServer.py index 41d2c55..97e677a 100644 --- a/src/Python/socket/socketServer.py +++ b/src/Python/socket/socketServer.py @@ -2,19 +2,30 @@ from flask import Flask from flask_mqtt import Mqtt app = Flask(__name__) -mqtt = Mqtt(app) -def on_connect(client, userdata, flags, rc): - print("Connected with result code " + str(rc)) - client.subscribe("move") -def on_message(client, userdata, msg): - command = msg.payload.decode() +# MQTT configuratie +app.config['MQTT_BROKER_URL'] = '145.109.226.204' +app.config['MQTT_BROKER_PORT'] = 1883 +app.config['MQTT_USERNAME'] = 'ishak' +app.config['MQTT_PASSWORD'] = 'kobuki' +app.config['MQTT_KEEPALIVE'] = 60 +app.config['MQTT_TLS_ENABLED'] = False # TLS uitschakelen indien niet nodig + +mqtt = Mqtt(app) + +# Callback voor wanneer de verbinding tot stand komt +@mqtt.on_connect() +def handle_connect(client, userdata, flags, rc): + print(f"Connected with result code {rc}") + mqtt.subscribe("move") + +# Callback voor wanneer een bericht binnenkomt +@mqtt.on_message() +def handle_mqtt_message(client, userdata, message): + command = message.payload.decode() print(f"Received command: {command}") # Voeg hier je code toe om het commando uit te voeren -client = mqtt.Client() -client.on_connect = on_connect -client.on_message = on_message - -client.connect("145.109.226.204", 83, 60) -client.loop_forever() \ No newline at end of file +# Start de Flask applicatie +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000) From a87cb1b12e29276c57c61059825d0ce4c810c9f7 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Mon, 21 Oct 2024 11:12:04 +0200 Subject: [PATCH 37/79] added username and password --- src/C++/Socket/main.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/C++/Socket/main.cpp b/src/C++/Socket/main.cpp index f44e437..0d92b7b 100644 --- a/src/C++/Socket/main.cpp +++ b/src/C++/Socket/main.cpp @@ -1,5 +1,6 @@ #include #include +#include const std::string ADDRESS("tcp://localhost:1883"); // Brokeradres (Raspberry Pi) const std::string CLIENT_ID("cpp_subscriber"); @@ -14,10 +15,13 @@ class callback : public virtual mqtt::callback { }; int main() { - + mqtt::async_client client(ADDRESS, CLIENT_ID); callback cb; client.set_callback(cb); + client.set_user_name("ishak"); + client.set_password("kobuki"); + try { std::cout << "Verbinden met broker..." << std::endl; From 4c7f70c07484a1a9975a332dbdcbd9ccd4e75c5a Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Mon, 21 Oct 2024 11:15:49 +0200 Subject: [PATCH 38/79] changed adress --- src/C++/Socket/main.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/C++/Socket/main.cpp b/src/C++/Socket/main.cpp index 0d92b7b..a5e7524 100644 --- a/src/C++/Socket/main.cpp +++ b/src/C++/Socket/main.cpp @@ -1,11 +1,9 @@ #include #include -#include - -const std::string ADDRESS("tcp://localhost:1883"); // Brokeradres (Raspberry Pi) -const std::string CLIENT_ID("cpp_subscriber"); -const std::string TOPIC("website/knop"); +const std::string ADDRESS("tcp://ishak.ishakpi.ddns.net:1883"); +const std::string CLIENT_ID("raspberry_pi_client"); +const std::string TOPIC("home/commands"); class callback : public virtual mqtt::callback { void message_arrived(mqtt::const_message_ptr msg) override { @@ -15,17 +13,18 @@ class callback : public virtual mqtt::callback { }; int main() { - mqtt::async_client client(ADDRESS, CLIENT_ID); callback cb; client.set_callback(cb); - client.set_user_name("ishak"); - client.set_password("kobuki"); + mqtt::connect_options connOpts; + connOpts.set_clean_session(true); + connOpts.set_user_name("ishak"); + connOpts.set_password("kobuki"); try { std::cout << "Verbinden met broker..." << std::endl; - client.connect()->wait(); + client.connect(connOpts)->wait(); std::cout << "Verbonden!" << std::endl; std::cout << "Abonneren op topic: " << TOPIC << std::endl; @@ -40,4 +39,4 @@ int main() { } return 0; -} +} \ No newline at end of file From 2efa191c07d54c11872ea3d58f7d510721ef5461 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Mon, 21 Oct 2024 12:55:37 +0200 Subject: [PATCH 39/79] added username and password --- src/Python/flask/web/app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index 33c2679..f6f0d71 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -6,6 +6,7 @@ app = Flask(__name__) mqtt_client = mqtt.Client() # Verbinding maken met de Raspberry Pi (broker) +mqtt_client.username_pw_set("ishak", "kobuki") mqtt_client.connect("ishakpi.ddns.net", 1883, 60) @app.route('/') From 7e5103bce289e1a091cdd79e5ac3429d5d6e2340 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Mon, 21 Oct 2024 13:49:29 +0200 Subject: [PATCH 40/79] changed adress from tcp so ssl --- src/C++/Socket/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/C++/Socket/main.cpp b/src/C++/Socket/main.cpp index a5e7524..def1160 100644 --- a/src/C++/Socket/main.cpp +++ b/src/C++/Socket/main.cpp @@ -1,7 +1,7 @@ #include #include -const std::string ADDRESS("tcp://ishak.ishakpi.ddns.net:1883"); +const std::string ADDRESS("ssl://ishak.ishakpi.ddns.net:1883"); const std::string CLIENT_ID("raspberry_pi_client"); const std::string TOPIC("home/commands"); From 6c1e44151ea70ce9902eb8f1cebd7b9154e0c424 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Mon, 21 Oct 2024 14:12:17 +0200 Subject: [PATCH 41/79] changed address of broker --- src/C++/Socket/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/C++/Socket/main.cpp b/src/C++/Socket/main.cpp index def1160..d70eaf3 100644 --- a/src/C++/Socket/main.cpp +++ b/src/C++/Socket/main.cpp @@ -1,14 +1,14 @@ #include #include -const std::string ADDRESS("ssl://ishak.ishakpi.ddns.net:1883"); +const std::string ADDRESS("tcp://localhost:1883"); const std::string CLIENT_ID("raspberry_pi_client"); const std::string TOPIC("home/commands"); class callback : public virtual mqtt::callback { void message_arrived(mqtt::const_message_ptr msg) override { std::cout << "Ontvangen bericht: '" << msg->get_topic() << "' : " << msg->to_string() << std::endl; - // Doe iets met het bericht, bijvoorbeeld een GPIO-activering + // Doe iets met het bericht, bijvoorbeeld een GP.IO-activering } }; From 34cfa6125722d1364e1cfe3893da2bf5d7f8b225 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 22 Oct 2024 12:16:40 +0200 Subject: [PATCH 42/79] changed version op mqtt --- src/C++/Socket/main.cpp | 50 +++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/C++/Socket/main.cpp b/src/C++/Socket/main.cpp index d70eaf3..999669a 100644 --- a/src/C++/Socket/main.cpp +++ b/src/C++/Socket/main.cpp @@ -6,37 +6,39 @@ const std::string CLIENT_ID("raspberry_pi_client"); const std::string TOPIC("home/commands"); class callback : public virtual mqtt::callback { - void message_arrived(mqtt::const_message_ptr msg) override { - std::cout << "Ontvangen bericht: '" << msg->get_topic() << "' : " << msg->to_string() << std::endl; - // Doe iets met het bericht, bijvoorbeeld een GP.IO-activering - } + void message_arrived(mqtt::const_message_ptr msg) override { + std::cout << "Ontvangen bericht: '" << msg->get_topic() + << "' : " << msg->to_string() << std::endl; + // Doe iets met het bericht, bijvoorbeeld een GP.IO-activering + } }; int main() { - mqtt::async_client client(ADDRESS, CLIENT_ID); - callback cb; - client.set_callback(cb); + mqtt::async_client client(ADDRESS, CLIENT_ID); + callback cb; + client.set_callback(cb); - mqtt::connect_options connOpts; - connOpts.set_clean_session(true); - connOpts.set_user_name("ishak"); - connOpts.set_password("kobuki"); + mqtt::connect_options connOpts; + connOpts.set_clean_session(true); + connOpts.set_user_name("ishak"); + connOpts.set_password("kobuki"); + connOpts.set_mqtt_version(MQTTVERSION_5); // Stel de MQTT-versie in (bijv. MQTT 5.0) - try { - std::cout << "Verbinden met broker..." << std::endl; - client.connect(connOpts)->wait(); - std::cout << "Verbonden!" << std::endl; + try { + std::cout << "Verbinden met broker..." << std::endl; + client.connect(connOpts)->wait(); + std::cout << "Verbonden!" << std::endl; - std::cout << "Abonneren op topic: " << TOPIC << std::endl; - client.subscribe(TOPIC, 1)->wait(); + std::cout << "Abonneren op topic: " << TOPIC << std::endl; + client.subscribe(TOPIC, 1)->wait(); - while (true) { - // Houd de client draaiende om berichten te blijven ontvangen - } - } catch (const mqtt::exception& exc) { - std::cerr << exc.what() << std::endl; - return 1; + while (true) { + // Houd de client draaiende om berichten te blijven ontvangen } + } catch (const mqtt::exception &exc) { + std::cerr << exc.what() << std::endl; + return 1; + } - return 0; + return 0; } \ No newline at end of file From 995b3858ab0a944eab320c0fe6cbe935d50804cb Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 22 Oct 2024 12:27:29 +0200 Subject: [PATCH 43/79] Update MQTT version to 3.1.1 and change address to use SSL - In main.cpp, update the MQTT version to 3.1.1 and change the address to use SSL instead of TCP. - In app.py, create a new MQTT client using MQTTv311 protocol. --- src/C++/Socket/main.cpp | 2 +- src/Python/flask/web/app.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/C++/Socket/main.cpp b/src/C++/Socket/main.cpp index 999669a..6a70d41 100644 --- a/src/C++/Socket/main.cpp +++ b/src/C++/Socket/main.cpp @@ -22,7 +22,7 @@ int main() { connOpts.set_clean_session(true); connOpts.set_user_name("ishak"); connOpts.set_password("kobuki"); - connOpts.set_mqtt_version(MQTTVERSION_5); // Stel de MQTT-versie in (bijv. MQTT 5.0) + connOpts.set_mqtt_version(MQTTVERSION_3_1_1); // Voor MQTT 3.1.1 try { std::cout << "Verbinden met broker..." << std::endl; diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index f6f0d71..d048d64 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -8,6 +8,7 @@ mqtt_client = mqtt.Client() # Verbinding maken met de Raspberry Pi (broker) mqtt_client.username_pw_set("ishak", "kobuki") mqtt_client.connect("ishakpi.ddns.net", 1883, 60) +client = mqtt.Client(protocol=mqtt.MQTTv311) @app.route('/') def index(): From ce2956e504c3f7c3938918df599c66ed2838ddcb Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 22 Oct 2024 12:48:27 +0200 Subject: [PATCH 44/79] Update MQTT address to use SSL and change broker address --- src/C++/Socket/main.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/C++/Socket/main.cpp b/src/C++/Socket/main.cpp index 6a70d41..0ffb7c7 100644 --- a/src/C++/Socket/main.cpp +++ b/src/C++/Socket/main.cpp @@ -1,7 +1,9 @@ #include #include +#include // Voor std::this_thread::sleep_for +#include // Voor std::chrono::seconds -const std::string ADDRESS("tcp://localhost:1883"); +const std::string ADDRESS("tcp://ishakpi.ddns.net:1883"); // Aanpassen indien nodig const std::string CLIENT_ID("raspberry_pi_client"); const std::string TOPIC("home/commands"); @@ -11,6 +13,14 @@ class callback : public virtual mqtt::callback { << "' : " << msg->to_string() << std::endl; // Doe iets met het bericht, bijvoorbeeld een GP.IO-activering } + + void connection_lost(const std::string& cause) override { + std::cerr << "Verbinding verloren. Oorzaak: " << cause << std::endl; + } + + void delivery_complete(mqtt::delivery_token_ptr token) override { + std::cout << "Bericht afgeleverd!" << std::endl; + } }; int main() { @@ -32,13 +42,15 @@ int main() { std::cout << "Abonneren op topic: " << TOPIC << std::endl; client.subscribe(TOPIC, 1)->wait(); + // Houd de client draaiende om berichten te blijven ontvangen while (true) { - // Houd de client draaiende om berichten te blijven ontvangen + std::this_thread::sleep_for(std::chrono::seconds(1)); // Wacht om CPU-gebruik te verminderen } + } catch (const mqtt::exception &exc) { - std::cerr << exc.what() << std::endl; + std::cerr << "Fout: " << exc.what() << std::endl; return 1; } return 0; -} \ No newline at end of file +} From cc1a03c04cccf0f54d57bf00b63e7b98033ff279 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 22 Oct 2024 12:52:22 +0200 Subject: [PATCH 45/79] Update MQTT address to use SSL and change broker address --- src/C++/Socket/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/C++/Socket/main.cpp b/src/C++/Socket/main.cpp index 0ffb7c7..c8f2790 100644 --- a/src/C++/Socket/main.cpp +++ b/src/C++/Socket/main.cpp @@ -3,7 +3,7 @@ #include // Voor std::this_thread::sleep_for #include // Voor std::chrono::seconds -const std::string ADDRESS("tcp://ishakpi.ddns.net:1883"); // Aanpassen indien nodig +const std::string ADDRESS("mqtt://ishakpi.ddns.net:1883"); // Aanpassen indien nodig const std::string CLIENT_ID("raspberry_pi_client"); const std::string TOPIC("home/commands"); From 714910d61ee93c9b9612c2bd4f3d9e6d53ad95ab Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 22 Oct 2024 13:03:18 +0200 Subject: [PATCH 46/79] Update MQTT topic to publish button press event --- src/Python/flask/web/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index d048d64..e6bf3f4 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -16,7 +16,7 @@ def index(): @app.route('/move', methods=['POST']) def move(): - mqtt_client.publish("website/knop", "Knop ingedrukt!") + mqtt_client.publish("home.commands", "Knop ingedrukt!") return "Bericht verzonden!" if __name__ == '__main__': From 5739655e9753000ad8c5b3b464d0c203f0c2cd17 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 22 Oct 2024 14:38:54 +0200 Subject: [PATCH 47/79] Update MQTT topic to publish button press event --- src/Python/flask/web/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index e6bf3f4..b70a311 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -16,7 +16,7 @@ def index(): @app.route('/move', methods=['POST']) def move(): - mqtt_client.publish("home.commands", "Knop ingedrukt!") + mqtt_client.publish("home/commands", "Knop ingedrukt!") return "Bericht verzonden!" if __name__ == '__main__': From 0b40f63af0a3c9f57708fa9ed4fb4b1f3376fefa Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Tue, 22 Oct 2024 14:53:14 +0200 Subject: [PATCH 48/79] made print to see if message is sent correctly --- src/Python/flask/web/app.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index b70a311..de37ea0 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -8,7 +8,6 @@ mqtt_client = mqtt.Client() # Verbinding maken met de Raspberry Pi (broker) mqtt_client.username_pw_set("ishak", "kobuki") mqtt_client.connect("ishakpi.ddns.net", 1883, 60) -client = mqtt.Client(protocol=mqtt.MQTTv311) @app.route('/') def index(): @@ -16,8 +15,12 @@ def index(): @app.route('/move', methods=['POST']) def move(): - mqtt_client.publish("home/commands", "Knop ingedrukt!") - return "Bericht verzonden!" + result = mqtt_client.publish("home/commands", "Knop ingedrukt!") + if result.rc == mqtt.MQTT_ERR_SUCCESS: + print("Bericht succesvol gepubliceerd") + else: + print("Fout bij het publiceren van bericht") + return "Bericht verzonden!" if __name__ == '__main__': app.run(debug=True) \ No newline at end of file From 416631350db3c6ce1a00ecb0f0468a0c6ef0cc6f Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Wed, 23 Oct 2024 13:10:26 +0200 Subject: [PATCH 49/79] update gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7482133..84cc5d1 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,6 @@ src/C++/Driver/vgcore* src/C++/Driver/cmake_install.cmake src/C++/Driver/Makefile src/Python/flask/web/_pycache_ -venv \ No newline at end of file +venv +build/ +log \ No newline at end of file From 5b2570dacec6459d75a11640685844bb9b1bcfd7 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Wed, 23 Oct 2024 11:52:31 +0000 Subject: [PATCH 50/79] made cmakelists and edited ip adress --- src/C++/Socket/CMakeLists.txt | 15 +++++++++++++++ src/C++/Socket/main.cpp | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/C++/Socket/CMakeLists.txt diff --git a/src/C++/Socket/CMakeLists.txt b/src/C++/Socket/CMakeLists.txt new file mode 100644 index 0000000..1f31293 --- /dev/null +++ b/src/C++/Socket/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.10) +set(CMAKE_CXX_STANDARD 23) + +# Find the Paho MQTT C++ library +find_library(PAHO_MQTTPP_LIBRARY paho-mqttpp3 PATHS /usr/local/lib) +find_library(PAHO_MQTT_LIBRARY paho-mqtt3a PATHS /usr/local/lib) + +# Include the headers +include_directories(/usr/local/include) + +# Add the executable +add_executable(my_program main.cpp) + +# Link the libraries +target_link_libraries(my_program ${PAHO_MQTTPP_LIBRARY} ${PAHO_MQTT_LIBRARY}) diff --git a/src/C++/Socket/main.cpp b/src/C++/Socket/main.cpp index c8f2790..9a6529e 100644 --- a/src/C++/Socket/main.cpp +++ b/src/C++/Socket/main.cpp @@ -3,7 +3,7 @@ #include // Voor std::this_thread::sleep_for #include // Voor std::chrono::seconds -const std::string ADDRESS("mqtt://ishakpi.ddns.net:1883"); // Aanpassen indien nodig +const std::string ADDRESS("mqtt://localhost:1883"); // Aanpassen indien nodig const std::string CLIENT_ID("raspberry_pi_client"); const std::string TOPIC("home/commands"); From 481ae4f2c39a9862f8f383595a5eb85be43fe4f2 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Wed, 23 Oct 2024 14:18:36 +0200 Subject: [PATCH 51/79] reorginisatie --- src/C++/{Socket => MQTT}/CMakeLists.txt | 0 src/C++/{Socket => MQTT}/a.out | Bin src/C++/{Socket => MQTT}/main.cpp | 0 src/Python/socket/socketServer.py | 31 ------------------------ 4 files changed, 31 deletions(-) rename src/C++/{Socket => MQTT}/CMakeLists.txt (100%) rename src/C++/{Socket => MQTT}/a.out (100%) rename src/C++/{Socket => MQTT}/main.cpp (100%) delete mode 100644 src/Python/socket/socketServer.py diff --git a/src/C++/Socket/CMakeLists.txt b/src/C++/MQTT/CMakeLists.txt similarity index 100% rename from src/C++/Socket/CMakeLists.txt rename to src/C++/MQTT/CMakeLists.txt diff --git a/src/C++/Socket/a.out b/src/C++/MQTT/a.out similarity index 100% rename from src/C++/Socket/a.out rename to src/C++/MQTT/a.out diff --git a/src/C++/Socket/main.cpp b/src/C++/MQTT/main.cpp similarity index 100% rename from src/C++/Socket/main.cpp rename to src/C++/MQTT/main.cpp diff --git a/src/Python/socket/socketServer.py b/src/Python/socket/socketServer.py deleted file mode 100644 index 97e677a..0000000 --- a/src/Python/socket/socketServer.py +++ /dev/null @@ -1,31 +0,0 @@ -from flask import Flask -from flask_mqtt import Mqtt - -app = Flask(__name__) - -# MQTT configuratie -app.config['MQTT_BROKER_URL'] = '145.109.226.204' -app.config['MQTT_BROKER_PORT'] = 1883 -app.config['MQTT_USERNAME'] = 'ishak' -app.config['MQTT_PASSWORD'] = 'kobuki' -app.config['MQTT_KEEPALIVE'] = 60 -app.config['MQTT_TLS_ENABLED'] = False # TLS uitschakelen indien niet nodig - -mqtt = Mqtt(app) - -# Callback voor wanneer de verbinding tot stand komt -@mqtt.on_connect() -def handle_connect(client, userdata, flags, rc): - print(f"Connected with result code {rc}") - mqtt.subscribe("move") - -# Callback voor wanneer een bericht binnenkomt -@mqtt.on_message() -def handle_mqtt_message(client, userdata, message): - command = message.payload.decode() - print(f"Received command: {command}") - # Voeg hier je code toe om het commando uit te voeren - -# Start de Flask applicatie -if __name__ == '__main__': - app.run(host='0.0.0.0', port=5000) From d768be0b18c9ee632394a69f0ecd60086c46bb12 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Wed, 23 Oct 2024 14:22:48 +0200 Subject: [PATCH 52/79] added mqtt_client loop --- src/Python/flask/web/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index de37ea0..b5a71bf 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -8,7 +8,7 @@ mqtt_client = mqtt.Client() # Verbinding maken met de Raspberry Pi (broker) mqtt_client.username_pw_set("ishak", "kobuki") mqtt_client.connect("ishakpi.ddns.net", 1883, 60) - +mqtt_client.loop_forever() @app.route('/') def index(): return render_template('index.html') From e523018fec94367e5c0bc13e8741471cae12f695 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Wed, 23 Oct 2024 12:24:58 +0000 Subject: [PATCH 53/79] mqtt loop so it doesnt disconect --- src/Python/flask/web/app.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index b5a71bf..ba28f0b 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -7,8 +7,8 @@ mqtt_client = mqtt.Client() # Verbinding maken met de Raspberry Pi (broker) mqtt_client.username_pw_set("ishak", "kobuki") -mqtt_client.connect("ishakpi.ddns.net", 1883, 60) -mqtt_client.loop_forever() +mqtt_client.connect("localhost", 1883, 60) +mqtt_client.loop_start() @app.route('/') def index(): return render_template('index.html') @@ -23,4 +23,4 @@ def move(): return "Bericht verzonden!" if __name__ == '__main__': - app.run(debug=True) \ No newline at end of file + app.run(debug=True) From 5a4c3967041f9f869ed9987ecc027086b9afc50e Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Wed, 23 Oct 2024 14:27:40 +0200 Subject: [PATCH 54/79] Delete a.out --- src/C++/MQTT/a.out | Bin 470608 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 src/C++/MQTT/a.out diff --git a/src/C++/MQTT/a.out b/src/C++/MQTT/a.out deleted file mode 100755 index 7b51d7ad3d6d2c1bca220b3dabae9bd1e632c12d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 470608 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

=$;QPWbInW z>=-oFLbiVhi@2#5%?)CZ-8dgL4W2xE+rk{62{iHY=?2f|0^u^w1!|$-Qmi{99sU3x zUP~Dg+w0DFc70HNdoKshO?mvOAHn9U;wXn>MLtm>ppVy@+$>`tIS2D>NAMla;(3B#Sn9)pT zA7~=Iec)(SIfl-HDxsgC8V%iJ9rP$ChCZ_SW(ilyGb~UiI=>yG5Jmi5^?Q!5)0b@V zaet@=i*CD?J+tRn+Btdsa=|k2y+Z*nL zh6N@4RA#(}vlqn8gysQ6U2;)km@q*bV?027Qd%qICxiXu#;~}gFyoUqikcI|zU>BA z=>yx_jPaL#%22p2)E)&N)X{T!!yApY-+j|(rZl@N*<>3G{7^8_`7CrD_TuFc$0)6viaCh4fPsrUn(-Nj@T_!H`W#%XIZj~s)`4V zKM{QgsmC5Du|6KjRWjtZmv>-fnQA1}`?x#s85vo0gq)*+h-h~{-=g;hF;+m_JVhI5 zJ(}MFSr6%z`aBe}&Z~2O2rC0~x)UWS-(}Add%5<}p0Vh{z;(+*uImvXB~=JNn-0D( z&)bX96@HokvqPZi_#SYUMnX$V5`+VXfL+^T_*DKk?K94GV*YnT7fH9oP!5z49pAg2 z{n`ZZ&sVf&HTo2Xb0krKzDP1}k8z+a6Ax>f!{Tt#R)b4KZIy4{t{$ggE#m8XslMLJ z-?+-Xc=HygdGz*fws}k1Q@~Xpoo`)l#*>>r9N*|~ef67*KSYT6hJXEju)2Tq_U3Vh zk5FINOZ5|=vrt5tdH<;KGn#WoFVKHmOxADSQpNSnTT)(l^Y#}1z|ZC+Sor4c=pHkG zkm1(%H+Zf53vW6cLSlvLr+|e>v-$1%dbLvTR1cQR0d9caN&ZgnMjwqg=F1#R$3wi! z93P1Pd&^g$K9S#MIG+-e`_1$G`Pc9^{}}%J$MxG?{(<_7eErw;_vH)yuKVZT!ax2g z{3owp=-12FKXQK=fB&b0f1lvr?(6?Y{d)QOw}RjQCxU-p1h4-;^y}s8uY=zYU;lUT z^Z)y=|9URh|NrXO%h!AT`hQY?4X=NI@Bg#-PhS6b^#{n;`(LRS(mm3%lh^-E_3bxf ze5H?+*Z+fmS^Yr1{x|ZA`uD@<|L6GrUpv=-|A*=q&=`041b|pmiN0qQa_QeNBZCL`SN(|NGU&#mR zH~CfY^}i2ZfAmHDf_(k__w@q|UZ?;0=6?uY|DW{Kla#Ojy!@j68eaeZq+c)3|IHui zzv-|4dGG*!9lYQF9K8O&`1jT8l|pRd18{yYEm!Q*`MzXz|M z{M+gP%GdAca5;a%&;LL1GkVWI&_B4pP_Mr~S6{==3;+Fp;kEw)y&nJ3pYZjv-s-1z z|H=FOKls7Fi2vmEU-ajH+41@E`ai(-pdBKw|4aS)ztpe)m9_`+`M;LG=&!%Ri)ru6 z>;K+=p#JvvzE@v=rI&-wFa43vmHYZvg3te}TD|VCKB})r>SgBt<@NIQ-w0m+5B2N+ zp?>|}3>HjYCtv?|@cK75>T}f8S&zWh7*Pwrdn-#>%z$+fHB mRR90O-%uC+@HhOQ%IC`O{!5wH|F3^bt@ytiyde1JoBtn4+!NOT From 76315649f7a747616c61c0f3bc515f1068644761 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Wed, 23 Oct 2024 14:32:03 +0200 Subject: [PATCH 55/79] Refactor move function to publish direction from request form --- src/Python/flask/web/app.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index ba28f0b..057a902 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -15,7 +15,8 @@ def index(): @app.route('/move', methods=['POST']) def move(): - result = mqtt_client.publish("home/commands", "Knop ingedrukt!") + direction = request.form['direction'] + result = mqtt_client.publish("home/commands", direction) if result.rc == mqtt.MQTT_ERR_SUCCESS: print("Bericht succesvol gepubliceerd") else: From 9d6816f21029dfc943cc29af330d31ea4a844a22 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Wed, 23 Oct 2024 14:56:39 +0200 Subject: [PATCH 56/79] making page stay on the same page when pressing button --- src/Python/flask/web/app.py | 4 ++-- src/Python/flask/web/templates/index.html | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index 057a902..fef83d8 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -1,4 +1,4 @@ -from flask import Flask, request, render_template +from flask import Flask, request, render_template, redirect import paho.mqtt.client as mqtt app = Flask(__name__) @@ -21,7 +21,7 @@ def move(): print("Bericht succesvol gepubliceerd") else: print("Fout bij het publiceren van bericht") - return "Bericht verzonden!" + return redirect('/') if __name__ == '__main__': app.run(debug=True) diff --git a/src/Python/flask/web/templates/index.html b/src/Python/flask/web/templates/index.html index 0ab2680..434dfa1 100644 --- a/src/Python/flask/web/templates/index.html +++ b/src/Python/flask/web/templates/index.html @@ -5,10 +5,10 @@

- - - - + + + +
From bf276d5d81c46794da71e570ce09e2f0c509f5ce Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Wed, 23 Oct 2024 14:59:12 +0200 Subject: [PATCH 57/79] removed type of button --- src/Python/flask/web/templates/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Python/flask/web/templates/index.html b/src/Python/flask/web/templates/index.html index 434dfa1..2315a8a 100644 --- a/src/Python/flask/web/templates/index.html +++ b/src/Python/flask/web/templates/index.html @@ -5,7 +5,7 @@
- + From 89968e40a06bcfb3c6151c6e6ac0124a85106676 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Wed, 23 Oct 2024 15:00:31 +0200 Subject: [PATCH 58/79] REMOVED TYPE OF BUTTON --- src/Python/flask/web/templates/index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Python/flask/web/templates/index.html b/src/Python/flask/web/templates/index.html index 2315a8a..0ab2680 100644 --- a/src/Python/flask/web/templates/index.html +++ b/src/Python/flask/web/templates/index.html @@ -6,9 +6,9 @@
- - - + + +
From 30933b0ca7f5742ebc4e59067a16e1068391aba4 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Wed, 23 Oct 2024 15:08:23 +0200 Subject: [PATCH 59/79] Refactor button handling in index.html and app.py --- src/Python/flask/web/app.py | 24 +++++++++++------------ src/Python/flask/web/templates/index.html | 10 +++++----- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index fef83d8..0383626 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -1,4 +1,4 @@ -from flask import Flask, request, render_template, redirect +from flask import Flask, request, render_template import paho.mqtt.client as mqtt app = Flask(__name__) @@ -9,19 +9,17 @@ mqtt_client = mqtt.Client() mqtt_client.username_pw_set("ishak", "kobuki") mqtt_client.connect("localhost", 1883, 60) mqtt_client.loop_start() -@app.route('/') -def index(): - return render_template('index.html') -@app.route('/move', methods=['POST']) -def move(): - direction = request.form['direction'] - result = mqtt_client.publish("home/commands", direction) - if result.rc == mqtt.MQTT_ERR_SUCCESS: - print("Bericht succesvol gepubliceerd") - else: - print("Fout bij het publiceren van bericht") - return redirect('/') +@app.route('/', methods=['GET', 'POST']) +def index(): + if request.method == 'POST': + direction = request.form['direction'] + result = mqtt_client.publish("home/commands", direction) + if result.rc == mqtt.MQTT_ERR_SUCCESS: + message = "Bericht succesvol gepubliceerd" + else: + message = "Fout bij het publiceren van bericht" + return render_template('index.html', message=message) if __name__ == '__main__': app.run(debug=True) diff --git a/src/Python/flask/web/templates/index.html b/src/Python/flask/web/templates/index.html index 0ab2680..28a99f2 100644 --- a/src/Python/flask/web/templates/index.html +++ b/src/Python/flask/web/templates/index.html @@ -4,11 +4,11 @@ Kobuki Robot
-
- - - - + + + + +
From dc77c104e6b32d1a7623c809b72faebcb69e3640 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Wed, 23 Oct 2024 16:17:19 +0200 Subject: [PATCH 60/79] attempt to make mqtt class --- .gitignore | 6 ++- src/C++/MQTT/mqttclass/CMakeLists.txt | 15 ++++++++ src/C++/MQTT/mqttclass/MqttClient.cpp | 55 +++++++++++++++++++++++++++ src/C++/MQTT/mqttclass/MqttClient.h | 30 +++++++++++++++ src/C++/MQTT/mqttclass/main.cpp | 9 +++++ 5 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 src/C++/MQTT/mqttclass/CMakeLists.txt create mode 100644 src/C++/MQTT/mqttclass/MqttClient.cpp create mode 100644 src/C++/MQTT/mqttclass/MqttClient.h create mode 100644 src/C++/MQTT/mqttclass/main.cpp diff --git a/.gitignore b/.gitignore index 84cc5d1..1db0c74 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,8 @@ src/C++/Driver/Makefile src/Python/flask/web/_pycache_ venv build/ -log \ No newline at end of file +log +CMakeFiles/ +Makefile +CMakeCache.txt +cmake_install.cmake diff --git a/src/C++/MQTT/mqttclass/CMakeLists.txt b/src/C++/MQTT/mqttclass/CMakeLists.txt new file mode 100644 index 0000000..1f31293 --- /dev/null +++ b/src/C++/MQTT/mqttclass/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.10) +set(CMAKE_CXX_STANDARD 23) + +# Find the Paho MQTT C++ library +find_library(PAHO_MQTTPP_LIBRARY paho-mqttpp3 PATHS /usr/local/lib) +find_library(PAHO_MQTT_LIBRARY paho-mqtt3a PATHS /usr/local/lib) + +# Include the headers +include_directories(/usr/local/include) + +# Add the executable +add_executable(my_program main.cpp) + +# Link the libraries +target_link_libraries(my_program ${PAHO_MQTTPP_LIBRARY} ${PAHO_MQTT_LIBRARY}) diff --git a/src/C++/MQTT/mqttclass/MqttClient.cpp b/src/C++/MQTT/mqttclass/MqttClient.cpp new file mode 100644 index 0000000..c2b2fc9 --- /dev/null +++ b/src/C++/MQTT/mqttclass/MqttClient.cpp @@ -0,0 +1,55 @@ +#include "MqttClient.h" + +MqttClient::MqttClient(const std::string& address, const std::string& clientId, const std::string& username, const std::string& password) + : client_(address, clientId), username_(username), password_(password) { + client_.set_callback(callback_); + connOpts_.set_clean_session(true); + connOpts_.set_mqtt_version(MQTTVERSION_3_1_1); // For MQTT 3.1.1 + if (!username_.empty() && !password_.empty()) { //if username and password are not empty also set those otherwise log in anonymously + connOpts_.set_user_name(username_); + connOpts_.set_password(password_); + } +} + +void MqttClient::connect() { + try { + std::cout << "Connecting to broker..." << std::endl; + client_.connect(connOpts_)->wait(); + std::cout << "Connected!" << std::endl; + } catch (const mqtt::exception& exc) { + std::cerr << "Error: " << exc.what() << std::endl; + throw; + } +} + +void MqttClient::subscribe(const std::string& topic, int qos) { + try { + std::cout << "Subscribing to topic: " << topic << std::endl; + client_.subscribe(topic, qos)->wait(); + } catch (const mqtt::exception& exc) { + std::cerr << "Error: " << exc.what() << std::endl; + throw; + } +} + +/// @brief only needed if program doesnt loop itself +void MqttClient::run() { + // Keep the client running to receive messages + while (true) { + std::this_thread::sleep_for(std::chrono::seconds(1)); // Wait to reduce CPU usage + } +} + +void MqttClient::Callback::message_arrived(mqtt::const_message_ptr msg) { + std::cout << "Received message: '" << msg->get_topic() + << "' : " << msg->to_string() << std::endl; + // Do something with the message, e.g., trigger a GPIO action +} + +void MqttClient::Callback::connection_lost(const std::string& cause) { + std::cerr << "Connection lost. Cause: " << cause << std::endl; +} + +void MqttClient::Callback::delivery_complete(mqtt::delivery_token_ptr token) { + std::cout << "Message delivered!" << std::endl; +} \ No newline at end of file diff --git a/src/C++/MQTT/mqttclass/MqttClient.h b/src/C++/MQTT/mqttclass/MqttClient.h new file mode 100644 index 0000000..3f11986 --- /dev/null +++ b/src/C++/MQTT/mqttclass/MqttClient.h @@ -0,0 +1,30 @@ +#ifndef MQTTCLIENT_H +#define MQTTCLIENT_H + +#include +#include +#include + +class MqttClient { +public: + MqttClient(const std::string& address, const std::string& clientId, const std::string& username = "", const std::string& password = ""); + void connect(); + void subscribe(const std::string& topic, int qos = 1); + void run(); + +private: + class Callback : public virtual mqtt::callback { + public: + void message_arrived(mqtt::const_message_ptr msg) override; //overide the main functions in the original class + void connection_lost(const std::string& cause) override; + void delivery_complete(mqtt::delivery_token_ptr token) override; + }; + + mqtt::async_client client_; + mqtt::connect_options connOpts_; + Callback callback_; + std::string username_; + std::string password_; +}; + +#endif // MQTTCLIENT_H \ No newline at end of file diff --git a/src/C++/MQTT/mqttclass/main.cpp b/src/C++/MQTT/mqttclass/main.cpp new file mode 100644 index 0000000..0d53a61 --- /dev/null +++ b/src/C++/MQTT/mqttclass/main.cpp @@ -0,0 +1,9 @@ +#include "MqttClient.h" + +int main(){ + MqttClient client("mqtt://localhost:1883", "raspberry_pi_client", "ishak", "kobuki"); + client.connect(); + client.subscribe("home/commands"); + + return 0; +} \ No newline at end of file From 07451d01886d7abf9769a156a71445e1ac443ae6 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Wed, 23 Oct 2024 17:03:42 +0200 Subject: [PATCH 61/79] fixed error --- src/Python/flask/web/app.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index 0383626..7d07c0a 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -12,13 +12,12 @@ mqtt_client.loop_start() @app.route('/', methods=['GET', 'POST']) def index(): + message = '' if request.method == 'POST': direction = request.form['direction'] result = mqtt_client.publish("home/commands", direction) if result.rc == mqtt.MQTT_ERR_SUCCESS: message = "Bericht succesvol gepubliceerd" - else: - message = "Fout bij het publiceren van bericht" return render_template('index.html', message=message) if __name__ == '__main__': From 2cd52981fc5be816465e0449d81516f1a1d363aa Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Wed, 23 Oct 2024 19:29:20 +0200 Subject: [PATCH 62/79] edited cmakelist --- src/C++/MQTT/mqttclass/CMakeLists.txt | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/C++/MQTT/mqttclass/CMakeLists.txt b/src/C++/MQTT/mqttclass/CMakeLists.txt index 1f31293..7b704e9 100644 --- a/src/C++/MQTT/mqttclass/CMakeLists.txt +++ b/src/C++/MQTT/mqttclass/CMakeLists.txt @@ -8,8 +8,16 @@ find_library(PAHO_MQTT_LIBRARY paho-mqtt3a PATHS /usr/local/lib) # Include the headers include_directories(/usr/local/include) -# Add the executable -add_executable(my_program main.cpp) +cmake_minimum_required(VERSION 3.9) +project(mqtt receiver) + +set(SOURCE_FILES + main.cpp + MqttClient.cpp + MqttClient.h + ) -# Link the libraries target_link_libraries(my_program ${PAHO_MQTTPP_LIBRARY} ${PAHO_MQTT_LIBRARY}) + +add_executable(kobuki_control ${SOURCE_FILES}) +#target_link_libraries(kobuki_control ) \ No newline at end of file From 8a0fb065d80deb1d83f000cbf593ec2f0b11098b Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Wed, 23 Oct 2024 19:34:40 +0200 Subject: [PATCH 63/79] cmakelists --- src/C++/MQTT/mqttclass/CMakeLists.txt | 28 +++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/C++/MQTT/mqttclass/CMakeLists.txt b/src/C++/MQTT/mqttclass/CMakeLists.txt index 7b704e9..ad70666 100644 --- a/src/C++/MQTT/mqttclass/CMakeLists.txt +++ b/src/C++/MQTT/mqttclass/CMakeLists.txt @@ -1,6 +1,9 @@ cmake_minimum_required(VERSION 3.10) set(CMAKE_CXX_STANDARD 23) +# Project name +project(mqtt_receiver) + # Find the Paho MQTT C++ library find_library(PAHO_MQTTPP_LIBRARY paho-mqttpp3 PATHS /usr/local/lib) find_library(PAHO_MQTT_LIBRARY paho-mqtt3a PATHS /usr/local/lib) @@ -8,16 +11,21 @@ find_library(PAHO_MQTT_LIBRARY paho-mqtt3a PATHS /usr/local/lib) # Include the headers include_directories(/usr/local/include) -cmake_minimum_required(VERSION 3.9) -project(mqtt receiver) - +# Set source files set(SOURCE_FILES - main.cpp - MqttClient.cpp - MqttClient.h - ) + main.cpp + MqttClient.cpp + MqttClient.h +) -target_link_libraries(my_program ${PAHO_MQTTPP_LIBRARY} ${PAHO_MQTT_LIBRARY}) +# Add the executable +add_executable(mqtt_receiver ${SOURCE_FILES}) -add_executable(kobuki_control ${SOURCE_FILES}) -#target_link_libraries(kobuki_control ) \ No newline at end of file +# Link the libraries +target_link_libraries(mqtt_receiver ${PAHO_MQTTPP_LIBRARY} ${PAHO_MQTT_LIBRARY}) + +# Include directories for headers +target_include_directories(mqtt_receiver PRIVATE) + +find_package(Threads REQUIRED) +target_link_libraries(mqtt_receiver Threads::Threads) From 411982cf35e667b0c730ad3290a8892d7aff80e9 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Wed, 23 Oct 2024 19:38:50 +0200 Subject: [PATCH 64/79] test --- src/C++/MQTT/mqttclass/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/C++/MQTT/mqttclass/main.cpp b/src/C++/MQTT/mqttclass/main.cpp index 0d53a61..b166518 100644 --- a/src/C++/MQTT/mqttclass/main.cpp +++ b/src/C++/MQTT/mqttclass/main.cpp @@ -4,6 +4,7 @@ int main(){ MqttClient client("mqtt://localhost:1883", "raspberry_pi_client", "ishak", "kobuki"); client.connect(); client.subscribe("home/commands"); + client.run(); return 0; } \ No newline at end of file From 5fe14a2f8fe934406774e7d5cf84ed63645dd97d Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Thu, 24 Oct 2024 12:14:52 +0200 Subject: [PATCH 65/79] Refactor button handling in index.html and app.py --- src/Python/flask/web/app.py | 23 ++++++------ src/Python/flask/web/static/script.js | 19 ++++++++++ src/Python/flask/web/templates/index.html | 44 ++++++++++++++--------- 3 files changed, 60 insertions(+), 26 deletions(-) create mode 100644 src/Python/flask/web/static/script.js diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index 7d07c0a..085eba0 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -1,4 +1,4 @@ -from flask import Flask, request, render_template +from flask import Flask, request, render_template, jsonify import paho.mqtt.client as mqtt app = Flask(__name__) @@ -10,15 +10,18 @@ mqtt_client.username_pw_set("ishak", "kobuki") mqtt_client.connect("localhost", 1883, 60) mqtt_client.loop_start() -@app.route('/', methods=['GET', 'POST']) +@app.route('/') def index(): - message = '' - if request.method == 'POST': - direction = request.form['direction'] - result = mqtt_client.publish("home/commands", direction) - if result.rc == mqtt.MQTT_ERR_SUCCESS: - message = "Bericht succesvol gepubliceerd" - return render_template('index.html', message=message) + return render_template('index.html') + +@app.route('/move', methods=['POST']) +def move(): + direction = request.form['direction'] + result = mqtt_client.publish("home/commands", direction) + if result.rc == mqtt.MQTT_ERR_SUCCESS: + return jsonify({"message": "Bericht succesvol gepubliceerd"}), 200 + else: + return jsonify({"message": "Fout bij het publiceren van bericht"}), 500 if __name__ == '__main__': - app.run(debug=True) + app.run(debug=True) \ No newline at end of file diff --git a/src/Python/flask/web/static/script.js b/src/Python/flask/web/static/script.js new file mode 100644 index 0000000..1e1f33c --- /dev/null +++ b/src/Python/flask/web/static/script.js @@ -0,0 +1,19 @@ +document.querySelectorAll('button').forEach(button => { + button.addEventListener('click', function() { + const direction = this.value; + fetch('/move', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ direction: direction }), + }) + .then(response => response.json()) + .then(data => { + document.getElementById('response').innerText = data.message; + }) + .catch(error => { + document.getElementById('response').innerText = 'Er is een fout opgetreden: ' + error; + }); + }); +}); \ No newline at end of file diff --git a/src/Python/flask/web/templates/index.html b/src/Python/flask/web/templates/index.html index 28a99f2..cb9f211 100644 --- a/src/Python/flask/web/templates/index.html +++ b/src/Python/flask/web/templates/index.html @@ -1,18 +1,30 @@ {%extends 'base.html'%} {%block head%} {%endblock%} {%block content%} -
-
- Kobuki Robot -
-
-
- - - - -
-
-
-
-

Sensor Data

-
+ + + + + + Kobuki + + +
+
+ Kobuki Robot +
+
+
+ + + + +
+
+
+
+

Sensor Data

+
+ + + + {%endblock%} From c84c0d2cef3105e6240c7044e897b197152dc1e5 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Thu, 24 Oct 2024 12:20:24 +0200 Subject: [PATCH 66/79] Refactor button handling in index.html form action --- src/Python/flask/web/templates/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Python/flask/web/templates/index.html b/src/Python/flask/web/templates/index.html index cb9f211..eb6d459 100644 --- a/src/Python/flask/web/templates/index.html +++ b/src/Python/flask/web/templates/index.html @@ -12,7 +12,7 @@ Kobuki Robot
-
+ From 0089be40d3d6f20f902e72003a89a17b3c524dd7 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Thu, 24 Oct 2024 10:22:24 +0000 Subject: [PATCH 67/79] flask bugfix --- src/Python/flask/web/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Python/flask/web/app.py b/src/Python/flask/web/app.py index 085eba0..3647d55 100644 --- a/src/Python/flask/web/app.py +++ b/src/Python/flask/web/app.py @@ -10,7 +10,7 @@ mqtt_client.username_pw_set("ishak", "kobuki") mqtt_client.connect("localhost", 1883, 60) mqtt_client.loop_start() -@app.route('/') +@app.route('/', methods=["POST"]) def index(): return render_template('index.html') @@ -24,4 +24,4 @@ def move(): return jsonify({"message": "Fout bij het publiceren van bericht"}), 500 if __name__ == '__main__': - app.run(debug=True) \ No newline at end of file + app.run(debug=True) From d35a79c1ca79727615537bbe214e51bd1fa6d3d6 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Thu, 24 Oct 2024 12:09:50 +0200 Subject: [PATCH 68/79] moved folder --- src/C++/{MQTT/mqttclass => Driver/src/MQTT}/CMakeLists.txt | 0 src/C++/{MQTT/mqttclass => Driver/src/MQTT}/MqttClient.cpp | 0 src/C++/{MQTT/mqttclass => Driver/src/MQTT}/MqttClient.h | 0 src/C++/{MQTT/mqttclass => Driver/src/MQTT}/main.cpp | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/C++/{MQTT/mqttclass => Driver/src/MQTT}/CMakeLists.txt (100%) rename src/C++/{MQTT/mqttclass => Driver/src/MQTT}/MqttClient.cpp (100%) rename src/C++/{MQTT/mqttclass => Driver/src/MQTT}/MqttClient.h (100%) rename src/C++/{MQTT/mqttclass => Driver/src/MQTT}/main.cpp (100%) diff --git a/src/C++/MQTT/mqttclass/CMakeLists.txt b/src/C++/Driver/src/MQTT/CMakeLists.txt similarity index 100% rename from src/C++/MQTT/mqttclass/CMakeLists.txt rename to src/C++/Driver/src/MQTT/CMakeLists.txt diff --git a/src/C++/MQTT/mqttclass/MqttClient.cpp b/src/C++/Driver/src/MQTT/MqttClient.cpp similarity index 100% rename from src/C++/MQTT/mqttclass/MqttClient.cpp rename to src/C++/Driver/src/MQTT/MqttClient.cpp diff --git a/src/C++/MQTT/mqttclass/MqttClient.h b/src/C++/Driver/src/MQTT/MqttClient.h similarity index 100% rename from src/C++/MQTT/mqttclass/MqttClient.h rename to src/C++/Driver/src/MQTT/MqttClient.h diff --git a/src/C++/MQTT/mqttclass/main.cpp b/src/C++/Driver/src/MQTT/main.cpp similarity index 100% rename from src/C++/MQTT/mqttclass/main.cpp rename to src/C++/Driver/src/MQTT/main.cpp From 6546dcbdd6b5940da2adf39bd97e01d83764b5af Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Thu, 24 Oct 2024 12:13:31 +0200 Subject: [PATCH 69/79] re-orginasation --- .../Driver/src/{ => KobukiDriver}/CKobuki.cpp | 0 .../Driver/src/{ => KobukiDriver}/CKobuki.h | 0 .../src/{ => KobukiDriver}/KobukiParser.cpp | 0 .../src/{ => KobukiDriver}/KobukiParser.h | 0 src/C++/Driver/src/{ => KobukiDriver}/graph.h | 0 .../Driver/src/MQTT/{main.cpp => example.cpp} | 0 src/C++/Driver/src/main.cpp | 18 ++++++++++++++---- 7 files changed, 14 insertions(+), 4 deletions(-) rename src/C++/Driver/src/{ => KobukiDriver}/CKobuki.cpp (100%) rename src/C++/Driver/src/{ => KobukiDriver}/CKobuki.h (100%) rename src/C++/Driver/src/{ => KobukiDriver}/KobukiParser.cpp (100%) rename src/C++/Driver/src/{ => KobukiDriver}/KobukiParser.h (100%) rename src/C++/Driver/src/{ => KobukiDriver}/graph.h (100%) rename src/C++/Driver/src/MQTT/{main.cpp => example.cpp} (100%) diff --git a/src/C++/Driver/src/CKobuki.cpp b/src/C++/Driver/src/KobukiDriver/CKobuki.cpp similarity index 100% rename from src/C++/Driver/src/CKobuki.cpp rename to src/C++/Driver/src/KobukiDriver/CKobuki.cpp diff --git a/src/C++/Driver/src/CKobuki.h b/src/C++/Driver/src/KobukiDriver/CKobuki.h similarity index 100% rename from src/C++/Driver/src/CKobuki.h rename to src/C++/Driver/src/KobukiDriver/CKobuki.h diff --git a/src/C++/Driver/src/KobukiParser.cpp b/src/C++/Driver/src/KobukiDriver/KobukiParser.cpp similarity index 100% rename from src/C++/Driver/src/KobukiParser.cpp rename to src/C++/Driver/src/KobukiDriver/KobukiParser.cpp diff --git a/src/C++/Driver/src/KobukiParser.h b/src/C++/Driver/src/KobukiDriver/KobukiParser.h similarity index 100% rename from src/C++/Driver/src/KobukiParser.h rename to src/C++/Driver/src/KobukiDriver/KobukiParser.h diff --git a/src/C++/Driver/src/graph.h b/src/C++/Driver/src/KobukiDriver/graph.h similarity index 100% rename from src/C++/Driver/src/graph.h rename to src/C++/Driver/src/KobukiDriver/graph.h diff --git a/src/C++/Driver/src/MQTT/main.cpp b/src/C++/Driver/src/MQTT/example.cpp similarity index 100% rename from src/C++/Driver/src/MQTT/main.cpp rename to src/C++/Driver/src/MQTT/example.cpp diff --git a/src/C++/Driver/src/main.cpp b/src/C++/Driver/src/main.cpp index 62d4cec..71fefcf 100644 --- a/src/C++/Driver/src/main.cpp +++ b/src/C++/Driver/src/main.cpp @@ -1,18 +1,28 @@ -#include "CKobuki.h" #include #include #include -#include "graph.h" +#include "KobukiDriver/graph.h" +#include "MQTT/MqttClient.h" +#include "KobukiDriver/CKobuki.h" + using namespace std; CKobuki robot; int movement(); int checkCenterCliff(); -int main() -{ +void setup(){ unsigned char *null_ptr(0); robot.startCommunication("/dev/ttyUSB0", true, null_ptr); + MqttClient client("mqtt://localhost:1883", "raspberry_pi_client", "ishak", "kobuki"); + client.connect(); + client.subscribe("home/commands"); + +} + +int main() +{ + // thread mv(movement); // mv.join(); //only exit once thread one is done running From c2b4a5418bc3bdf5c98edf033381cea7861c1aea Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Thu, 24 Oct 2024 12:45:32 +0200 Subject: [PATCH 70/79] remove debug prints in mqtt class --- src/C++/Driver/src/MQTT/MqttClient.cpp | 18 ++++++++++++------ src/C++/Driver/src/MQTT/MqttClient.h | 10 +++++++++- src/C++/Driver/src/main.cpp | 24 ++++++++++++++---------- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/C++/Driver/src/MQTT/MqttClient.cpp b/src/C++/Driver/src/MQTT/MqttClient.cpp index c2b2fc9..7923822 100644 --- a/src/C++/Driver/src/MQTT/MqttClient.cpp +++ b/src/C++/Driver/src/MQTT/MqttClient.cpp @@ -1,11 +1,11 @@ #include "MqttClient.h" MqttClient::MqttClient(const std::string& address, const std::string& clientId, const std::string& username, const std::string& password) - : client_(address, clientId), username_(username), password_(password) { + : client_(address, clientId), username_(username), password_(password), callback_(*this) { client_.set_callback(callback_); connOpts_.set_clean_session(true); connOpts_.set_mqtt_version(MQTTVERSION_3_1_1); // For MQTT 3.1.1 - if (!username_.empty() && !password_.empty()) { //if username and password are not empty also set those otherwise log in anonymously + if (!username_.empty() && !password_.empty()) { connOpts_.set_user_name(username_); connOpts_.set_password(password_); } @@ -32,7 +32,7 @@ void MqttClient::subscribe(const std::string& topic, int qos) { } } -/// @brief only needed if program doesnt loop itself +/// @brief Only needed when program doesnt keep itself alive void MqttClient::run() { // Keep the client running to receive messages while (true) { @@ -41,9 +41,8 @@ void MqttClient::run() { } void MqttClient::Callback::message_arrived(mqtt::const_message_ptr msg) { - std::cout << "Received message: '" << msg->get_topic() - << "' : " << msg->to_string() << std::endl; - // Do something with the message, e.g., trigger a GPIO action + std::lock_guard lock(client_.messageMutex_); + client_.lastMessage_ = msg->to_string(); } void MqttClient::Callback::connection_lost(const std::string& cause) { @@ -52,4 +51,11 @@ void MqttClient::Callback::connection_lost(const std::string& cause) { void MqttClient::Callback::delivery_complete(mqtt::delivery_token_ptr token) { std::cout << "Message delivered!" << std::endl; +} + +/// @brief Get the last message received from the MQTT broker +/// @return The last message received in a string +std::string MqttClient::getLastMessage() { + std::lock_guard lock(messageMutex_); + return lastMessage_; } \ No newline at end of file diff --git a/src/C++/Driver/src/MQTT/MqttClient.h b/src/C++/Driver/src/MQTT/MqttClient.h index 3f11986..0cae258 100644 --- a/src/C++/Driver/src/MQTT/MqttClient.h +++ b/src/C++/Driver/src/MQTT/MqttClient.h @@ -3,6 +3,7 @@ #include #include +#include #include class MqttClient { @@ -11,13 +12,18 @@ public: void connect(); void subscribe(const std::string& topic, int qos = 1); void run(); + std::string getLastMessage(); private: class Callback : public virtual mqtt::callback { public: - void message_arrived(mqtt::const_message_ptr msg) override; //overide the main functions in the original class + Callback(MqttClient& client) : client_(client) {} + void message_arrived(mqtt::const_message_ptr msg) override; void connection_lost(const std::string& cause) override; void delivery_complete(mqtt::delivery_token_ptr token) override; + + private: + MqttClient& client_; }; mqtt::async_client client_; @@ -25,6 +31,8 @@ private: Callback callback_; std::string username_; std::string password_; + std::string lastMessage_; + std::mutex messageMutex_; }; #endif // MQTTCLIENT_H \ No newline at end of file diff --git a/src/C++/Driver/src/main.cpp b/src/C++/Driver/src/main.cpp index 71fefcf..9763535 100644 --- a/src/C++/Driver/src/main.cpp +++ b/src/C++/Driver/src/main.cpp @@ -9,12 +9,12 @@ using namespace std; CKobuki robot; int movement(); -int checkCenterCliff(); +std::string ReadMQTT() void setup(){ unsigned char *null_ptr(0); robot.startCommunication("/dev/ttyUSB0", true, null_ptr); - MqttClient client("mqtt://localhost:1883", "raspberry_pi_client", "ishak", "kobuki"); + MqttClient client("mqtt://localhost:1883", "KobukiRPI", "ishak", "kobuki"); client.connect(); client.subscribe("home/commands"); @@ -23,19 +23,23 @@ void setup(){ int main() { - // thread mv(movement); - // mv.join(); //only exit once thread one is done running - - checkCenterCliff(); +readMQTT(); return 0; } -int checkCenterCliff() +std::string ReadMQTT() { - while(true){ - std::cout << robot.parser.data.CliffSensorCenter << endl; - } + while (true) { + std::string message = client.getLastMessage(); + if (!message.empty()) { + std::cout << "MQTT Message: " << message << std::endl; + } + + // Add a small delay to avoid busy-waiting + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + return message; + } } From 990d064766328a8f4bfeeacbde6595160b306e78 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Thu, 24 Oct 2024 12:48:23 +0200 Subject: [PATCH 71/79] edited cmakelists --- src/C++/Driver/CMakeLists.txt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/C++/Driver/CMakeLists.txt b/src/C++/Driver/CMakeLists.txt index 7bb90d4..ced9869 100644 --- a/src/C++/Driver/CMakeLists.txt +++ b/src/C++/Driver/CMakeLists.txt @@ -2,11 +2,13 @@ cmake_minimum_required(VERSION 3.9) project(kobuki_control) set(SOURCE_FILES - src/KobukiParser.cpp - src/KobukiParser.h - src/CKobuki.cpp - src/CKobuki.h - src/test.cpp) + src/KobukiDriver/KobukiParser.cpp + src/KobukiDriver/KobukiParser.h + src/KobukiDriver/CKobuki.cpp + src/KobukiDriver/CKobuki.h + src/MQTT/MqttClient.cpp + src/MQTT/MqttClient.h + src/main.cpp) add_executable(kobuki_control ${SOURCE_FILES}) #target_link_libraries(kobuki_control ) \ No newline at end of file From 294af308ec2786adfdea7933bb3b21391cd69e74 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Thu, 24 Oct 2024 12:52:37 +0200 Subject: [PATCH 72/79] bugfixes --- src/C++/Driver/src/main.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/C++/Driver/src/main.cpp b/src/C++/Driver/src/main.cpp index 9763535..fd7b1ae 100644 --- a/src/C++/Driver/src/main.cpp +++ b/src/C++/Driver/src/main.cpp @@ -9,18 +9,20 @@ using namespace std; CKobuki robot; int movement(); -std::string ReadMQTT() +std::string ReadMQTT(); +MqttClient client("mqtt://localhost:1883", "KobukiRPI", "ishak", "kobuki"); + void setup(){ unsigned char *null_ptr(0); robot.startCommunication("/dev/ttyUSB0", true, null_ptr); - MqttClient client("mqtt://localhost:1883", "KobukiRPI", "ishak", "kobuki"); client.connect(); client.subscribe("home/commands"); } int main() + setup(); { readMQTT(); From 80771dc7402fa3625759d35a41f797ce81d861ee Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Thu, 24 Oct 2024 13:23:37 +0200 Subject: [PATCH 73/79] started with fetch --- src/Python/flask/web/static/script.js | 32 +++++++++-------------- src/Python/flask/web/templates/index.html | 2 +- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/Python/flask/web/static/script.js b/src/Python/flask/web/static/script.js index 1e1f33c..2499630 100644 --- a/src/Python/flask/web/static/script.js +++ b/src/Python/flask/web/static/script.js @@ -1,19 +1,13 @@ -document.querySelectorAll('button').forEach(button => { - button.addEventListener('click', function() { - const direction = this.value; - fetch('/move', { - method: 'POST', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - body: new URLSearchParams({ direction: direction }), - }) - .then(response => response.json()) - .then(data => { - document.getElementById('response').innerText = data.message; - }) - .catch(error => { - document.getElementById('response').innerText = 'Er is een fout opgetreden: ' + error; - }); - }); -}); \ No newline at end of file +window.onload = function () { + const form = document.getElementById("form"); + form.onclick = function (event) { + event.preventDefault(); + fetch("/move", { + method: "GET", + }) + .then((response) => {}) + .then(() => { + fetch + }); + }; +}; diff --git a/src/Python/flask/web/templates/index.html b/src/Python/flask/web/templates/index.html index eb6d459..705c2ed 100644 --- a/src/Python/flask/web/templates/index.html +++ b/src/Python/flask/web/templates/index.html @@ -12,7 +12,7 @@ Kobuki Robot
- + From 152ba37cd512d0c18982ee4e68686550079a6f11 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Thu, 24 Oct 2024 13:28:21 +0200 Subject: [PATCH 74/79] edited cmakelists --- src/C++/Driver/CMakeLists.txt | 25 +++++++++++++++++-------- src/C++/Driver/src/MQTT/CMakeLists.txt | 1 - src/C++/Driver/src/main.cpp | 12 ++++-------- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/C++/Driver/CMakeLists.txt b/src/C++/Driver/CMakeLists.txt index ced9869..aea8ac1 100644 --- a/src/C++/Driver/CMakeLists.txt +++ b/src/C++/Driver/CMakeLists.txt @@ -1,14 +1,23 @@ cmake_minimum_required(VERSION 3.9) project(kobuki_control) +set(CMAKE_CXX_STANDARD 23) + +# Find the Paho MQTT C++ library (static) +find_library(PAHO_MQTTPP_LIBRARY_STATIC paho-mqttpp3.a PATHS /usr/local/lib) +find_library(PAHO_MQTT_LIBRARY_STATIC paho-mqtt3a.a PATHS /usr/local/lib) + +include_directories(/usr/local/include) set(SOURCE_FILES - src/KobukiDriver/KobukiParser.cpp - src/KobukiDriver/KobukiParser.h - src/KobukiDriver/CKobuki.cpp - src/KobukiDriver/CKobuki.h - src/MQTT/MqttClient.cpp - src/MQTT/MqttClient.h - src/main.cpp) + src/KobukiDriver/KobukiParser.cpp + src/KobukiDriver/KobukiParser.h + src/KobukiDriver/CKobuki.cpp + src/KobukiDriver/CKobuki.h + src/MQTT/MqttClient.cpp + src/MQTT/MqttClient.h + src/main.cpp) add_executable(kobuki_control ${SOURCE_FILES}) -#target_link_libraries(kobuki_control ) \ No newline at end of file + +# Link the static libraries +target_link_libraries(kobuki_control ${PAHO_MQTTPP_LIBRARY_STATIC} ${PAHO_MQTT_LIBRARY_STATIC} pthread) \ No newline at end of file diff --git a/src/C++/Driver/src/MQTT/CMakeLists.txt b/src/C++/Driver/src/MQTT/CMakeLists.txt index ad70666..ef88b41 100644 --- a/src/C++/Driver/src/MQTT/CMakeLists.txt +++ b/src/C++/Driver/src/MQTT/CMakeLists.txt @@ -22,7 +22,6 @@ set(SOURCE_FILES add_executable(mqtt_receiver ${SOURCE_FILES}) # Link the libraries -target_link_libraries(mqtt_receiver ${PAHO_MQTTPP_LIBRARY} ${PAHO_MQTT_LIBRARY}) # Include directories for headers target_include_directories(mqtt_receiver PRIVATE) diff --git a/src/C++/Driver/src/main.cpp b/src/C++/Driver/src/main.cpp index fd7b1ae..0208a9d 100644 --- a/src/C++/Driver/src/main.cpp +++ b/src/C++/Driver/src/main.cpp @@ -9,7 +9,7 @@ using namespace std; CKobuki robot; int movement(); -std::string ReadMQTT(); +std::string readMQTT(); MqttClient client("mqtt://localhost:1883", "KobukiRPI", "ishak", "kobuki"); @@ -21,16 +21,12 @@ void setup(){ } -int main() +int main(){ setup(); -{ - -readMQTT(); - - return 0; + readMQTT(); } -std::string ReadMQTT() +std::string readMQTT() { while (true) { std::string message = client.getLastMessage(); From 0bfe04e67eba7de509460a49b8339401886119f7 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Thu, 24 Oct 2024 13:29:48 +0200 Subject: [PATCH 75/79] small fix --- src/C++/Driver/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/C++/Driver/CMakeLists.txt b/src/C++/Driver/CMakeLists.txt index aea8ac1..e6c35e2 100644 --- a/src/C++/Driver/CMakeLists.txt +++ b/src/C++/Driver/CMakeLists.txt @@ -3,8 +3,8 @@ project(kobuki_control) set(CMAKE_CXX_STANDARD 23) # Find the Paho MQTT C++ library (static) -find_library(PAHO_MQTTPP_LIBRARY_STATIC paho-mqttpp3.a PATHS /usr/local/lib) -find_library(PAHO_MQTT_LIBRARY_STATIC paho-mqtt3a.a PATHS /usr/local/lib) +find_library(PAHO_MQTTPP_LIBRARY paho-mqttpp3 PATHS /usr/local/lib) +find_library(PAHO_MQTT_LIBRARY paho-mqtt3a PATHS /usr/local/lib) include_directories(/usr/local/include) @@ -20,4 +20,4 @@ set(SOURCE_FILES add_executable(kobuki_control ${SOURCE_FILES}) # Link the static libraries -target_link_libraries(kobuki_control ${PAHO_MQTTPP_LIBRARY_STATIC} ${PAHO_MQTT_LIBRARY_STATIC} pthread) \ No newline at end of file +target_link_libraries(kobuki_control ${PAHO_MQTTPP_LIBRARY} ${PAHO_MQTT_LIBRARY} pthread) \ No newline at end of file From dfb1415940b85c50a2521ac34e181fb6f8539927 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Thu, 24 Oct 2024 13:30:59 +0200 Subject: [PATCH 76/79] added so program doesnt instandly quit --- src/C++/Driver/src/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/C++/Driver/src/main.cpp b/src/C++/Driver/src/main.cpp index 0208a9d..5a6cf7c 100644 --- a/src/C++/Driver/src/main.cpp +++ b/src/C++/Driver/src/main.cpp @@ -24,6 +24,8 @@ void setup(){ int main(){ setup(); readMQTT(); + client.run(); + return 0; } std::string readMQTT() From edf1cabdf3b62551f5488a0c9aaa85e7e27b44d4 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Thu, 24 Oct 2024 13:33:28 +0200 Subject: [PATCH 77/79] testing cpp --- src/C++/Driver/src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/C++/Driver/src/main.cpp b/src/C++/Driver/src/main.cpp index 5a6cf7c..25b6edb 100644 --- a/src/C++/Driver/src/main.cpp +++ b/src/C++/Driver/src/main.cpp @@ -23,14 +23,15 @@ void setup(){ int main(){ setup(); + while(true){ readMQTT(); + } client.run(); return 0; } std::string readMQTT() { - while (true) { std::string message = client.getLastMessage(); if (!message.empty()) { std::cout << "MQTT Message: " << message << std::endl; @@ -39,7 +40,6 @@ std::string readMQTT() // Add a small delay to avoid busy-waiting std::this_thread::sleep_for(std::chrono::milliseconds(100)); return message; - } } From dd49de9d8c7808bde2a524cfad5647b822493608 Mon Sep 17 00:00:00 2001 From: "ishak jmilou.ishak" Date: Mon, 28 Oct 2024 16:57:53 +0100 Subject: [PATCH 78/79] wrote some small comments --- docs/Ishak/smartleerdoel.md | 49 +++++++++++++++++++++++++++++++++++ docs/Ishak/smartleerdoel.pdf | Bin 0 -> 41622 bytes src/Python/flask/web/app.py | 11 +++++--- 3 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 docs/Ishak/smartleerdoel.md create mode 100644 docs/Ishak/smartleerdoel.pdf diff --git a/docs/Ishak/smartleerdoel.md b/docs/Ishak/smartleerdoel.md new file mode 100644 index 0000000..1a81a9c --- /dev/null +++ b/docs/Ishak/smartleerdoel.md @@ -0,0 +1,49 @@ +# Smart leerdoelen + +Na de retrospective die ik heb gedaan, heb ik besloten om de volgende smart leerdoelen te stellen: + +1 **Ik wil in de volgende blok meer gaan opletten op mijn teamgenoten om zo goed te weten waar iedereen mee bezig is.** + +**specifiek:** + +ik heb in onze groep de taak als voorzitter alleen merk ik op dit moment dat ik niet goed weet waar iedereen mee bezig is. Dat is niet handig omdat ik dan als voorzitter niet goed kan inschatten of iedereen op schema ligt. + +**meetbaar:** + +Ik wil dat ik aan het einde van de blok meer contact heb gehad met mijn teamgenoten en dat ik weet waar iedereen mee bezig is. Dit zorgt ervoor dat ik beter kan inschatten of iedereen op schema ligt en of ik moet ingrijpen. + +**acceptabel:** + +Dit is acceptabel omdat ik als voorzitter de taak heb om te zorgen dat iedereen op schema ligt en dat iedereen weet wat hij/zij moet doen. Zonder deze informatie kan ik niet goed mijn taak uitvoeren waardoor de teamgenoten niet goed kunnen werken. + +**realistisch:** + +Dit is realistisch omdat ik als voorzitter de taak heb om te zorgen dat iedereen op schema ligt en dat iedereen weet wat hij/zij moet doen. + +**tijdgebonden:** + +Ik wil dit doel behalen aan het einde van de blok. Dit is een realistische tijd omdat ik dan genoeg tijd heb om dit doel te behalen. Ik kan mij later ook nog tijdens de opleiding verbeteren op dit punt. + +--- + +2 **Ik wil in de volgende blok meer gaan opletten op mijn eigen documentatie.** + +**specifiek:** + +In tegen stelling tot vorig jaar hou ik nu mijn documentatie niet goed bij. Dit is niet handig omdat ik dan niet goed kan zien wat ik daadwerkelijk heb gedaan en wat ik allemaal heb geleerd. Ook is het fijn dat ik dan kan terug kijken op mijn werk als ik het later nodig heb. Ik wil daarom minimaal 2 keer per week mijn documentatie bijwerken. + +**meetbaar:** + +Ik wil dat ik aan het einde van de blok mijn documentatie goed heb bijgehouden. Dit zorgt ervoor dat ik kan zien wat ik heb gedaan en wat ik allemaal heb geleerd. Ook kan ik dan terug kijken op mijn werk als ik het later nodig heb. + +**acceptabel:** + +Dit is acceptabel omdat ik dan toekomst gericht kan werken. Ik kan dan terug kijken op mijn werk als ik het later nodig heb. Ook kan ik dan zien wat ik heb gedaan en wat ik allemaal heb geleerd. + +**realistisch:** + +Dit is realistisch omdat ik dit vorig jaar ook heb gedaan. Ik weet hoe ik mijn documentatie moet bijhouden en wat ik allemaal moet opschrijven. Mijn eis van 2 keer per week is ook realistisch omdat ik dan genoeg tijd heb om mijn documentatie bij te werken. + +**tijdgebonden:** + +Ik wil dit doel behalen aan het einde van de blok. Dit is een realistische tijd omdat ik dan genoeg tijd heb om mijn documentatie bij te werken. \ No newline at end of file diff --git a/docs/Ishak/smartleerdoel.pdf b/docs/Ishak/smartleerdoel.pdf new file mode 100644 index 0000000000000000000000000000000000000000..88161f19dc18339346dba08d68298e512339f015 GIT binary patch literal 41622 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 dpMPHlh@+#EiG$Pkn*+=bf Date: Thu, 31 Oct 2024 16:19:06 +0100 Subject: [PATCH 79/79] added a newline at the end of script.js --- .../flask/web/__pycache__/app.cpython-311.pyc | Bin 914 -> 1862 bytes src/Python/flask/web/static/script.js | 1 + 2 files changed, 1 insertion(+) diff --git a/src/Python/flask/web/__pycache__/app.cpython-311.pyc b/src/Python/flask/web/__pycache__/app.cpython-311.pyc index ddfe8666509599b9c069ef91b551c7d5fc7aed8e..47f94fb584dc7e4dbf2762c9fc3decf3672601d7 100644 GIT binary patch literal 1862 zcmah|&1)M+6rWkGR+42|a&2tOF7c*miq{1B&_ieth1T&$T$`2I_l(7oI?-&1A5GHB?K`8g+R%{Hx;)RU)q_KrAl@~A3JYm-n@DH z-tYb9$4F!dP$~Q}yZyHhfZy4sEB>>^$pHl51yF$sbzs0WG`KWp_|iUuPxFx3Io)pv z3I~A^NDB~f06`RFw+`v(NIFEVLc#kRvmDTI*g2v)9Y*2$aBthUP<<+Yz)@d1IsyUp zjdXYYv+7p`HE=-dIHaQ^p7%(1*FO(tK>b4XX#aV4tp?T5HheiWn1veNJ6}WWoe_rr zGeYD-gi#b!M~Yshc#1}QubV^vtVUnP2C=0*;8Na@Mvs}R#1sFrF55*C!0164*$#wuq{*D+Fd7p&Cbh3A{4D$xu}tlZYi>!w`@nd9{}JuNdun31;TIK zPHjq%1PtWlE!9@~lVW(YaUxRn0yw?C1In7gY*Rqu)+<9AP3N0L-Z69uVn(%}zzNmh zG`V;qvwH6{(JHA}R`L!qGuW~!nr4>EIZeC%Nyf%XW@DEoVP>{im6?Yqmyt`QL}`~6 z!{TCw9OIK6qpAwthNo-EMtH6jo^$y*%#0QPf?@5Tfhu@v_o`^p1+9YWt`vF|sW9F( zg2%vNch02F?p_d;djtl#^B6vYh2A}<_a^8&6uQ^XSTN@Fagx0S?Hrn_e~b41oR@IH zE5N*@;5rGZ8b*qvS!N}Yw+ytPScV~+s?GXp+wwN5T>2bgjRG&)Wko^uj-`v+s8r7B znt~8kk6+OoD_54SvLoiSf|y5+cy>xTCho|lnCk@4{-mHuLCi`e{Fa3c5;h(VboXvH_0{6yQYwWRA`*wkSquRqyR17ldm*BTN4>bL zi}(^U5bT<-z9TA%mu|E5=)QBWokz{qbEr8(2-tG@K zTjNqQAh`kQx9CJI;SjCAB7I=nw5#bCN8qbss zl+6+!r8N;2J-qM~^NE&iguTo-cii%~Lw54Q7x2#guc4X`jKc?+L-ZSv9AwFC- zG2@b#u?O90Flkt7Sx2AZYxIB-+`dM2+Xo>$0yo_M`;Ne@`;PC85U!&A)o-mmtLmdb zN2mAIXT|S~XGS%A1j4VuOcTu1R_b3jK%xZ_E=YLRu_hRM{zZMfjvHXU1?F8a@7X7s zV4?x0T42frQ*R*uH2x&M|8Z@i7Och_@Nx@YZgUVyZ9vr@KEQp@vj~9md*0V;_iC%m z`)UhbZF6C`0o#CS=Ks;Zw)X))ykBYh;;t`##0Q?PJXv}EVRfa!Pqz3;xBInyfS;xw H9-99EI=!uk literal 914 zcmZ`$J8K(35Z=9q?xeG^2?j+b7#AsYDdfV1i4lPih+H`ag%sl8IBD0G@IA!d9kErN zjle3?*`+Im#Qrf-P+_hTgapzls1qqNd$Np_$FMUyGkp8aV?Qo0XAnr?*{{PV7@@B` zn2B`njK70(i3lRtMh>oEN2mxG35a4UcHz|x=u|2am9FJkG=CFe5lO^0>H^^A0aQu- z_pLQQxtCWFuzm;hK-$|h!IJS-%U-2h2 z28$-eSG&gEyO*0@lQ64R52$M}&ucXrZWvY@jh*L)&uYfOX;AlEG1m>*-id#$mi%vJ#GSEr*(BEW&)T%)Bt5$#4mIEV9u3qx?iIIvxpa`hsPFhqv#4 z1~U>d#&;;+`_~z!w1{^0&b+o4i9;-1_E!)W@jWKX&n&B GihcujnZv{Y diff --git a/src/Python/flask/web/static/script.js b/src/Python/flask/web/static/script.js index 2499630..44a0489 100644 --- a/src/Python/flask/web/static/script.js +++ b/src/Python/flask/web/static/script.js @@ -11,3 +11,4 @@ window.onload = function () { }); }; }; +9 \ No newline at end of file