Compare commits

...
79 Commits
Author SHA1 Message Date
zeunerti74726 3dea00a8d1 Too big too handle 2023-03-03 19:48:03 +01:00
zeunerti74726 960b05e76f Testfahrten 2023-03-03 18:57:35 +01:00
zeunerti74726 94e9c4ba7a Faster! 2023-03-03 18:47:41 +01:00
zeunerti74726 6da9bfff54 Bugs found during tests 2023-03-03 18:46:31 +01:00
zeunerti74726 c40b69ebe2 Save video 2023-03-03 18:45:03 +01:00
zeunerti74726 397e6fe331 Let signals to stop always pass 2023-02-23 20:39:28 +01:00
zeunerti74726 60fbc8758d fabs instead of abs 2023-02-23 20:38:18 +01:00
zeunerti74726 fe4af52380 Merge branch 'master' of https://git.efi.th-nuernberg.de/gitea/yasarba71520/Line-Following-Robot 2023-02-23 11:12:40 +01:00
zeunerti74726 426f57798e uint -> int; max send rate; 2023-02-22 14:45:50 +01:00
zeunerti74726 9d896df965 Index error 2023-02-22 14:42:09 +01:00
bockva71868 ce6ca27490 Error Handling 2023-02-08 12:13:18 +01:00
zeunerti74726 bc3484acae Implement correct interface for manual mode. 2023-02-07 21:32:19 +01:00
zeunerti74726 1f172a8b7a start stop token 2023-02-07 21:29:24 +01:00
zeunerti74726 6577c39a1b Merge branch 'master' of https://git.efi.th-nuernberg.de/gitea/yasarba71520/Line-Following-Robot 2023-02-07 21:26:06 +01:00
zeunerti74726 9a80ec1410 SChneller 2023-02-07 21:25:38 +01:00
zeunerti74726 366b3db8f9 Merge branch 'master' of https://git.efi.th-nuernberg.de/gitea/yasarba71520/Line-Following-Robot 2023-02-07 21:21:03 +01:00
zeunerti74726 65516babfc Use buffer for zerstückelte Messages 2023-02-07 21:20:49 +01:00
zeunerti74726 a920aefa54 Debug Messages 2023-02-07 21:20:10 +01:00
bockva71868 a34657dc1a Error handling 2023-02-07 19:54:14 +01:00
zeunerti74726 8cda9e8c0f Add start and end signal to telegram 2023-02-07 16:07:17 +01:00
zeunerti74726 e9114fdfe5 Wait for 250ms before sending again 2023-02-07 15:27:28 +01:00
zeunerti74726 a8e8ccbbe1 call asynctask through mainactivity 2023-02-07 14:57:29 +01:00
zeunerti74726 ffb38996e8 connectToWifi in Future 2023-02-07 14:56:44 +01:00
bockva71868 e248dc3e0c Threadsave socket 2023-02-07 13:48:59 +01:00
bockva71868 8831c130cd Threadsave socket 2023-02-07 13:46:04 +01:00
zeunerti74726 b361fad52d Dont use AsyncTask 2023-02-06 10:53:38 +01:00
yasarba71520 2ee3603229 App: Socket in Async Task 2023-02-05 15:24:43 +01:00
yasarba71520 cd6973efbb App: Sending data in Async Task 2023-02-05 15:24:09 +01:00
zeunerti74726 60e19a8968 Adjust telegramm 2023-02-03 20:38:52 +01:00
zeunerti74726 a929bbebed missing , 2023-02-02 09:25:34 +01:00
yasarba71520 6a55bda519 Merge branch 'master' of https://git.efi.th-nuernberg.de/gitea/yasarba71520/Line-Following-Robot 2023-02-01 20:10:17 +01:00
yasarba71520 53c37e03c1 App: Telegramm with wheel datas/Turn directions 2023-02-01 20:10:12 +01:00
zeunerti74726 7814f64873 Allow neg. angle 2023-02-01 17:35:52 +01:00
zeunerti74726 6692a2fcda combine rotation and translation 2023-02-01 17:26:35 +01:00
yasarba71520 ed730bc438 App: Minor changes 2023-01-31 23:33:07 +01:00
yasarba71520 1c245e9b43 Merge branch 'master' of https://git.efi.th-nuernberg.de/gitea/yasarba71520/Line-Following-Robot 2023-01-31 23:12:11 +01:00
yasarba71520 ce8d424f95 App: Abzweigungsliste erstellt 2023-01-31 23:12:05 +01:00
zeunerti74726 f6d346a3c1 Deeskalation bei den Pfeilspitzen 2023-01-31 22:06:00 +01:00
zeunerti74726 0f5c2e3f42 P-Controller Concept 2023-01-31 22:03:25 +01:00
zeunerti74726 2af8bfa536 Merge branch 'master' of https://git.efi.th-nuernberg.de/gitea/yasarba71520/Line-Following-Robot 2023-01-31 22:02:17 +01:00
zeunerti74726 be7b35f668 New angle calculation concept 2023-01-31 22:01:25 +01:00
yasarba71520 ea33e0b065 Merge branch 'master' of https://git.efi.th-nuernberg.de/gitea/yasarba71520/Line-Following-Robot 2023-01-31 21:48:21 +01:00
yasarba71520 9709f4c0aa Minor changes App 2023-01-31 21:48:14 +01:00
yasarba71520 cb388a769d Interactive Joystick and shared preferences 2023-01-31 21:37:59 +01:00
zeunerti74726 d7fc54cfd0 rad->deg; use predefined pi 2023-01-31 21:18:53 +01:00
zeunerti74726 722898da6d motor float->double, angle int->double 2023-01-31 21:05:04 +01:00
zeunerti74726 0aa939db39 Introduce angle calculation 2023-01-31 21:03:51 +01:00
zeunerti74726 a9a24e5d72 Compile Utils as .lib instead of .dll 2023-01-31 20:36:19 +01:00
zeunerti74726 450bb76d7d Introduce maxSpeed 2023-01-31 12:45:08 +01:00
zeunerti74726 59ce30a828 Start Autonomous via socket; redirect signals to uart 2023-01-29 22:42:33 +01:00
zeunerti74726 b3d0037952 Log Uart communication 2023-01-16 06:38:09 +01:00
zeunerti74726 75e1391017 Redirect telegram to uart 2023-01-16 06:37:39 +01:00
zeunerti74726 e5fc3f9f38 Move initialisation in state machine 2023-01-16 03:57:23 +01:00
zeunerti74726 e7e40ef3b6 separate states from state machine 2023-01-16 03:34:25 +01:00
zeunerti74726 7c8dc41063 Start state machine 2023-01-16 03:04:40 +01:00
zeunerti74726 7411bdc628 Add State Machine 2023-01-16 03:04:15 +01:00
zeunerti74726 8812ecfda1 Docu 2023-01-16 03:03:45 +01:00
zeunerti74726 6e4500d932 lfr_central 2023-01-15 22:40:40 +01:00
zeunerti74726 3149466a37 Main method in separate file; Better cmake; Bugfix for calling destructor; Handle closing connections, reconnecting and refusing multiple connections 2023-01-15 22:39:52 +01:00
zeunerti74726 0218391ea0 Better cmake; separate main method in own file 2023-01-15 22:37:21 +01:00
zeunerti74726 bbc154efe2 Bugfix when calling destructor without a running thread 2023-01-15 22:36:27 +01:00
zeunerti74726 1fd6853245 include_directories->target_include_directories 2023-01-15 22:34:56 +01:00
zeunerti74726 b1a8673617 async socket 2023-01-14 17:03:59 +01:00
yasarba71520 0b90a6b5ae Merge branch 'master' of https://git.efi.th-nuernberg.de/gitea/yasarba71520/Line-Following-Robot 2023-01-12 09:32:32 +01:00
yasarba71520 ff7cc62f6a IP-Adresse etc. in der app 2023-01-12 09:32:27 +01:00
yasarba71520 208728662d Android App nach Ändeurngen mit Vanessa 2023-01-12 09:32:00 +01:00
zeunerti74726 e30f7c80c9 added Socket Project 2023-01-11 16:21:09 +01:00
yasarba71520 4d800c36fe Android App starten 2023-01-08 18:30:55 +01:00
yasarba71520 1f66795bb1 Merge remote-tracking branch 'origin/master' 2023-01-08 18:29:53 +01:00
yasarba71520 3368c2586f Android App starten 2023-01-08 18:21:04 +01:00
zeunerti74726 ff7634e0b0 Check for valid lane 2023-01-05 10:39:48 +01:00
zeunerti74726 7175b68abe motor signals in the loop 2023-01-04 21:50:59 +01:00
zeunerti74726 747053f132 input threadsafe 2023-01-04 21:50:02 +01:00
zeunerti74726 8150850bb6 float mistakes 2023-01-04 21:47:54 +01:00
zeunerti74726 f55ebb6b3f exception handling 2023-01-04 16:52:42 +01:00
zeunerti74726 7fe6850da4 No idea why this worked on the pi 2023-01-04 16:08:38 +01:00
zeunerti74726 4c9435dbee nvm the c++ 20 thing 2023-01-04 16:06:11 +01:00
zeunerti74726 b5811dbbcb Ressource guarding multithreading 2022-12-22 23:13:53 +01:00
zeunerti74726 b46898a506 cmake standard to cpp 20 2022-12-22 23:12:21 +01:00
195 changed files with 4935 additions and 251 deletions
+19 -24
View File
@@ -9,23 +9,6 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package( OpenCV REQUIRED )
find_package(Threads REQUIRED)
include_directories( ${OpenCV_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/Input
${CMAKE_CURRENT_SOURCE_DIR}/Processing
${CMAKE_CURRENT_SOURCE_DIR}/ControlModule
${CMAKE_CURRENT_SOURCE_DIR}/Interpreter
${CMAKE_CURRENT_SOURCE_DIR}/IntersectionHandler
${CMAKE_CURRENT_SOURCE_DIR}/Utils
)
link_directories( ${Input_SOURCE_DIRS}
${Processing_SOURCE_DIRS}
${ControlModule_SOURCE_DIRS}
${Interpreter_SOURCE_DIRS}
${IntersectionHandler_SOURCE_DIRS}
${Utils_SOURCE_DIRS}
)
add_subdirectory(Input)
add_subdirectory(Processing)
add_subdirectory(ControlModule)
@@ -34,16 +17,28 @@ add_subdirectory(IntersectionHandler)
add_subdirectory(Utils)
add_subdirectory(Spielwiese)
target_include_directories(Input PRIVATE .)
target_include_directories(Processing PRIVATE .)
target_include_directories(ControlModule PRIVATE .)
target_include_directories(Interpreter PRIVATE .)
target_include_directories(IntersectionHandler PRIVATE .)
target_include_directories(Utils PRIVATE .)
add_executable(lfr_image_processing lfr.cpp autonomous_mode_main.cpp)
add_library(lfr_image_processing_lib lfr.cpp)
target_include_directories(lfr_image_processing PUBLIC ${OpenCV_INCLUDE_DIRS})
target_include_directories(lfr_image_processing PUBLIC ${Input_SOURCE_DIRS})
target_include_directories(lfr_image_processing PUBLIC ${Processing_SOURCE_DIRS})
target_include_directories(lfr_image_processing PUBLIC ${ControlModule_SOURCE_DIRS})
target_include_directories(lfr_image_processing PUBLIC ${Interpreter_SOURCE_DIRS})
target_include_directories(lfr_image_processing PUBLIC ${IntersectionHandler_SOURCE_DIRS})
target_include_directories(lfr_image_processing PUBLIC ${Utils_SOURCE_DIRS})
target_include_directories(lfr_image_processing PUBLIC .)
target_include_directories(lfr_image_processing_lib PUBLIC ${OpenCV_INCLUDE_DIRS})
target_include_directories(lfr_image_processing_lib PUBLIC ${Input_SOURCE_DIRS})
target_include_directories(lfr_image_processing_lib PUBLIC ${Processing_SOURCE_DIRS})
target_include_directories(lfr_image_processing_lib PUBLIC ${ControlModule_SOURCE_DIRS})
target_include_directories(lfr_image_processing_lib PUBLIC ${Interpreter_SOURCE_DIRS})
target_include_directories(lfr_image_processing_lib PUBLIC ${IntersectionHandler_SOURCE_DIRS})
target_include_directories(lfr_image_processing_lib PUBLIC .)
target_link_libraries( lfr_image_processing ${OpenCV_LIBS} Input Processing ControlModule Interpreter IntersectionHandler Utils Threads::Threads)
target_link_libraries( lfr_image_processing_lib ${OpenCV_LIBS} Input Processing ControlModule Interpreter IntersectionHandler Utils Threads::Threads)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
+2 -4
View File
@@ -1,10 +1,8 @@
include_directories( ${Utils_SOURCE_DIRS})
link_directories(${Utils_SOURCE_DIRS})
add_library(ControlModule control_module.cpp)
set_target_properties(ControlModule PROPERTIES VERSION ${PROJECT_VERSION})
target_include_directories(ControlModule PRIVATE .)
target_include_directories(ControlModule PRIVATE ${Utils_SOURCE_DIRS})
target_include_directories(ControlModule PUBLIC .)
target_link_libraries( ControlModule Utils)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
+87 -20
View File
@@ -1,11 +1,16 @@
#include "control_module.h"
ControlModule::ControlModule(){
ControlModule::ControlModule(): ControlModule(0.0, 1.0, 1.0)
{
}
ControlModule::ControlModule(float forwardSpeed, float rotateSpeed, float moveSideSpeed)
ControlModule::ControlModule(double maxSpeed, double rotateSpeed, double moveSideSpeed)
{
this->forwardSpeed = forwardSpeed;
motors[0] = 0.0;
motors[1] = 0.0;
motors[2] = 0.0;
motors[3] = 0.0;
this->maxSpeed = maxSpeed;
this->rotateSpeed = rotateSpeed;
this->moveSideSpeed = moveSideSpeed;
}
@@ -14,42 +19,104 @@ ControlModule::~ControlModule()
{
}
void ControlModule::moveForward(){
for(int i = 0; i <= sizeof(motors)/sizeof(int); i++){
motors[i] += forwardSpeed;
void ControlModule::adjustSpeed(){
double factor = 0.0;
if(maxSpeed > 1.0)
{
factor = 1.0;
}
else if(maxSpeed < -1.0)
{
factor = -1.0;
}
else
{
factor = maxSpeed;
}
for(int i = 0; i < 4; i++)
{
motors[i] *= factor;
}
};
void ControlModule::moveSide(int imageColumsMiddle, int contourColumsMiddle){
float speed = moveSideSpeed * (contourColumsMiddle - imageColumsMiddle)/imageColumsMiddle;
double speed = moveSideSpeed * static_cast<double>(contourColumsMiddle - imageColumsMiddle)/static_cast<double>(imageColumsMiddle);
motors[0] += speed;
motors[1] -= speed;
motors[2] -= speed;
motors[3] += speed;
}
void ControlModule::rotate(int angle){
float speed = rotateSpeed * (angle + 90)/90;
motors[0] += speed;
motors[1] -= speed;
motors[2] += speed;
motors[3] -= speed;
void ControlModule::drive(double ratio)
{
motors[0] += ratio;
motors[1] += ratio;
motors[2] += ratio;
motors[3] += ratio;
}
void ControlModule::rotate(double ratio)
{
motors[0] += ratio;
motors[1] -= ratio;
motors[2] += ratio;
motors[3] -= ratio;
}
void ControlModule::unit(){
float max = 10E-12;
double max = 1.0E-6;
for(int i = 0; i <= sizeof(motors)/sizeof(int); i++){
if(motors[i] > max)
max = motors[i];
}
for(int i = 0; i <= sizeof(motors)/sizeof(int); i++){
motors[i] /= max;
//Avoid dividing by zero
if (max > 0.001)
{
for(int i = 0; i < 4; i++){
motors[i] /= max;
}
}
}
void ControlModule::calcSpeeds(int imageColumsMiddle, int contourColumsMiddle, int angle){
moveForward();
moveSide(imageColumsMiddle, contourColumsMiddle);
rotate(angle);
void ControlModule::calcSpeeds(int imageColumsMiddle, int contourColumsMiddle, double angle){
std::unique_lock<std::mutex> lock(mtx);
double rotationRatio = ratio(angle);
rotate(rotationRatio);
drive(1.0-std::fabs(rotationRatio));
unit();
adjustSpeed();
}
std::vector<double> ControlModule::readMotors()
{
std::unique_lock<std::mutex> lock(mtx);
return std::vector<double> {motors[0], motors[1], motors[2], motors[3]};
}
double ControlModule::ratio(double angle)
{
double minAngularSpeed = -1.0;
double maxAngularSpeed = 1.0;
double speedRange = maxAngularSpeed - minAngularSpeed;
double minAngle = -20.0;
double maxAngle = 20.0;
double angularRange = maxAngle - minAngle;
if(angle < minAngle)
{
angle = minAngle;
}
if(angle > maxAngle)
{
angle = maxAngle;
}
double progress = angle - minAngle;
double progressPercent = progress/angularRange;
double speed = minAngularSpeed + progressPercent*speedRange;
return speed;
}
+16 -8
View File
@@ -1,20 +1,28 @@
#pragma once
#include <mutex>
#include <vector>
#include <iostream>
#include <cmath>
class ControlModule
{
private:
float motors[4]; //LeftFront; RightFront; LeftBack; RightBack
float forwardSpeed;
float rotateSpeed;
float moveSideSpeed;
mutable std::mutex mtx;
double motors[4]; //LeftFront; RightFront; LeftBack; RightBack
double maxSpeed;
double rotateSpeed;
double moveSideSpeed;
public:
ControlModule(/* args */);
ControlModule(float forwardSpeed, float rotateSpeed, float moveSideSpeed);
ControlModule(double maxSpeed, double rotateSpeed, double moveSideSpeed);
~ControlModule();
void moveForward();
void adjustSpeed();
void moveSide(int imageColumsMiddle, int contourColumsMiddle);
void rotate(int angle);
void rotate(double ratio);
void drive(double ratio);
void unit(); //Brings the max Value to 1.0
double ratio(double angle);
void calcSpeeds(int imageColumsMiddle, int contourColumsMiddle, int angle); //Funktion to be called
void calcSpeeds(int imageColumsMiddle, int contourColumsMiddle, double angle); //Funktion to be called
std::vector<double> readMotors();
};
+2 -4
View File
@@ -1,12 +1,10 @@
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} ${Utils_SOURCE_DIRS})
link_directories(${Utils_SOURCE_DIRS})
add_library(Input input.cpp)
set_target_properties(Input PROPERTIES VERSION ${PROJECT_VERSION})
target_include_directories(Input PRIVATE .)
target_include_directories(Input PRIVATE ${OpenCV_INCLUDE_DIRS} ${Utils_SOURCE_DIRS})
target_include_directories(Input PUBLIC .)
target_link_libraries( Input ${OpenCV_LIBS} Utils)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
+18 -10
View File
@@ -1,9 +1,10 @@
#include "input.h"
// TODO: Wenn ihr in die Zeile den Pfad zum Testvideo statt der 0 packt, benmutzt er das Testvideo.
Input::Input(int videoHeight, int videoWidth) : cap("C:\\Line-Following-Robot\\AutonomousMode\\Test_data\\video1.h264"), videoHeight(videoHeight), videoWidth(videoWidth)
Input::Input(int videoHeight, int videoWidth) : cap("C:\\Line-Following-Robot\\AutonomousMode\\Test_data\\video1.h264"), videoHeight(videoHeight), videoWidth(videoWidth)//Input::Input(int videoHeight, int videoWidth) : cap(0), videoHeight(videoHeight), videoWidth(videoWidth)
//Input::Input(int videoHeight, int videoWidth) : cap(0), videoHeight(videoHeight), videoWidth(videoWidth)
{
std::unique_lock<std::mutex> lock(mtx);
this->cap.set(CAP_PROP_FRAME_HEIGHT, videoHeight);
this->cap.set(CAP_PROP_FRAME_WIDTH, videoWidth);
}
@@ -15,22 +16,25 @@ Input::~Input()
Mat Input::readFile(String filePath)
{
std::srand(std::time(0));
std::unique_lock<std::mutex> lock(mtx);
std::srand(static_cast<unsigned int>(std::time(0)));
// Read all .jpg files from the specified folder
cv::String folder = filePath;
std::vector<cv::String> filenames;
cv::glob(folder, filenames);
// Random shuffle
std::random_shuffle(filenames.begin(), filenames.end());
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(filenames.begin(), filenames.end(), g);
Mat image = imread(filePath, IMREAD_COLOR);
if(image.empty())
{
std::cout << "Could not read the image: " << filePath << std::endl;
return Mat();
//To do:Exception handeling
stringstream sstream;
sstream << "Could not read the image: " << filePath << std::endl;
throw std::runtime_error(sstream.str());
}
resize(image, image, Size(this->videoWidth, this->videoHeight));
return image;
@@ -38,16 +42,19 @@ Mat Input::readFile(String filePath)
Mat Input::readWebcam()
{
std::unique_lock<std::mutex> lock(mtx);
Mat image;
if(!cap.isOpened()) {
cout << "Video capture not opened" << std::endl;
return Mat();
stringstream sstream;
sstream << "Video capture not opened" << std::endl;
throw std::runtime_error(sstream.str());
}
if(!cap.grab()) {
cout << "Could not grab frame from camera" << std::endl;
return Mat();
stringstream sstream;
sstream << "Could not grab frame from camera" << std::endl;
throw std::runtime_error(sstream.str());
}
cap.retrieve(image);
return image;
@@ -55,5 +62,6 @@ Mat Input::readWebcam()
void Input::freeWebcam()
{
std::unique_lock<std::mutex> lock(mtx);
this->cap.release();
}
+2 -1
View File
@@ -4,6 +4,7 @@
#include <vector>
#include <string>
#include <algorithm>
#include <random>
#include <opencv2/opencv.hpp>
#include <opencv2/core/utils/logger.hpp>
@@ -15,7 +16,7 @@ class Input
{
private:
VideoCapture cap;
mutable std::mutex mtx;
public:
int videoHeight;
int videoWidth;
+2 -4
View File
@@ -1,10 +1,8 @@
include_directories( ${Utils_SOURCE_DIRS})
link_directories(${Utils_SOURCE_DIRS})
add_library(Interpreter interpreter.cpp)
set_target_properties(Interpreter PROPERTIES VERSION ${PROJECT_VERSION})
target_include_directories(Interpreter PRIVATE .)
target_include_directories(Interpreter PRIVATE ${Utils_SOURCE_DIRS})
target_include_directories(Interpreter PUBLIC .)
target_link_libraries( Interpreter Utils)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
@@ -1,10 +1,9 @@
include_directories( ${Utils_SOURCE_DIRS})
link_directories(${Utils_SOURCE_DIRS})
add_library(IntersectionHandler intersection_handler.cpp)
set_target_properties(IntersectionHandler PROPERTIES VERSION ${PROJECT_VERSION})
target_include_directories(IntersectionHandler PRIVATE .)
#target_include_directories(IntersectionHandler PRIVATE ${Utils_SOURCE_DIRS})
target_include_directories(IntersectionHandler PRIVATE ${Utils_SOURCE_DIRS})
target_include_directories(IntersectionHandler PUBLIC .)
target_link_libraries( IntersectionHandler Utils)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
@@ -6,4 +6,14 @@ IntersectionHandler::IntersectionHandler(/* args */)
IntersectionHandler::~IntersectionHandler()
{
}
const bool IntersectionHandler::foundLane(const FrameData& data)
{
return data.boundingBoxes.size();
}
const bool IntersectionHandler::foundIntersection(const FrameData& data)
{
return data.boundingBoxes.size()>1;
}
@@ -1,11 +1,14 @@
#pragma once
#include <utils.h>
class IntersectionHandler
{
private:
/* data */
public:
IntersectionHandler(/* args */);
~IntersectionHandler();
const bool foundLane(const FrameData& data);
const bool foundIntersection(const FrameData& data);
};
+3 -5
View File
@@ -1,13 +1,11 @@
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
include_directories( ${Utils_SOURCE_DIRS})
link_directories(${Utils_SOURCE_DIRS})
add_library(Processing processing.cpp)
set_target_properties(Processing PROPERTIES VERSION ${PROJECT_VERSION})
target_include_directories(Processing PRIVATE .)
target_include_directories(Processing PRIVATE ${Utils_INCLUDE_DIRS})
target_include_directories(Processing PRIVATE ${OpenCV_INCLUDE_DIRS})
target_include_directories(Processing PUBLIC .)
target_link_libraries( Processing ${OpenCV_LIBS} Utils)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
+60 -46
View File
@@ -82,58 +82,72 @@ void Processing::calcAngles(FrameData &data, int imageColums, int imageRows, boo
if(data.contours.size() > 0)
{
int angle = 0;
int index;
if(turnLeft){
// get the most left/right contour
int leftmostEdge = imageColums;
for (int i = 0; i < data.leftEdges.size(); i++)
{
int edge = data.leftEdges[i].x;
if (edge <= leftmostEdge)
{
leftmostEdge = edge;
index = i;
}
}
}else
int index;
// get the most left/right contour
int leftmostEdge = imageColums;
int rightmostEdge = 0;
for (int i = 0; i < data.leftEdges.size(); i++)
{
int edge = data.leftEdges[i].x;
if (edge <= leftmostEdge && turnLeft)
{
int rightmostEdge = 0;
for (int i = 0; i < data.leftEdges.size(); i++)
{
int edge = data.leftEdges[i].x;
if (edge >= rightmostEdge)
{
rightmostEdge = edge;
index = i;
}
}
}
// Find the Top-Left and Buttom-Left Point of the Contour
std::vector<cv::Point> leftMostContour = data.contours[index];
int xleftButtom = imageColums;
int xleftTop = imageColums;
int yButtom = data.boundingBoxes[index].y;
int yTop = data.boundingBoxes[index].height;
for (int i = 0; i < leftMostContour.size(); i++){
if(leftMostContour[i].y == 0 && leftMostContour[i].x < xleftButtom)
{
xleftButtom = leftMostContour[i].x;
}else if(leftMostContour[i].y > yTop -4 && leftMostContour[i].x < xleftTop){
xleftTop = leftMostContour[i].x;
}
leftmostEdge = edge;
index = i;
}
else if(edge >= rightmostEdge && !turnLeft)
{
rightmostEdge = edge;
index = i;
}
}
// Find the Top-Left and Bottom-Left Point of the Contour
std::vector<cv::Point> leftMostContour = data.contours[index];
/*
Not going to dive into that part to fix it.
Trying to use centroid instead.
int xleftBottom = imageColums;
int xleftTop = imageColums;
int yBottom = data.boundingBoxes[index].y;
int yTop = data.boundingBoxes[index].height;
for (int i = 0; i < leftMostContour.size(); i++)
{
if(leftMostContour[i].y == 0 && leftMostContour[i].x < xleftBottom)
{
xleftBottom = leftMostContour[i].x;
}
else if(leftMostContour[i].y > yTop -4 && leftMostContour[i].x < xleftTop)
{
xleftTop = leftMostContour[i].x;
}
}
// calculate angle
int deltaX = abs(xleftButtom - xleftTop);
int deltaX = abs(xleftBottom - xleftTop);
int deltaY = yTop;
angle = Calcs::calcAngle(deltaX, deltaY);
*/
//Get the contours center using moments:
cv::Moments moments=cv::moments(leftMostContour);
LFRPoint contourCenter(moments.m10/moments.m00, moments.m01/moments.m00);
LFRPoint imageCenter(double(imageColums)/2.0, double(imageRows)/2.0);
LFRPoint focusPoint(imageCenter.x, imageCenter.y+1000.0);
LFRVector a(imageCenter-focusPoint);
LFRVector b(contourCenter-focusPoint);
double angle = a.angle(b);
if (b.x < 0.0)
{
angle *= -1.0;
}
//Write to Data
data.angle = angle;
+3 -2
View File
@@ -1,12 +1,13 @@
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_library(Utils utils.cpp)
set_target_properties(Utils PROPERTIES VERSION ${PROJECT_VERSION})
target_include_directories(Utils PRIVATE .)
target_include_directories(Utils PRIVATE ${OpenCV_INCLUDE_DIRS})
target_include_directories(Utils PUBLIC .)
target_link_libraries( Utils ${OpenCV_LIBS} )
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
set (UTILS_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR})
include(CPack)
+17 -3
View File
@@ -1,7 +1,5 @@
#include "utils.h"
#define PI 3.14159265359
LFRPoint::LFRPoint(/* args */) : x(0.0), y(0.0)
{
}
@@ -31,6 +29,22 @@ LFRVector::~LFRVector()
{
}
double LFRVector::angle(const LFRVector& other) const
{
return acos(dot(other)/(this->norm()*other.norm())) * (180.0/M_PI);
}
double LFRVector::dot(const LFRVector& other) const
{
return x*other.x + y*other.y;
}
double LFRVector::norm() const
{
return sqrt(x*x+y*y);
}
LFRLine::LFRLine(/* args */) : start(), dir()
{
}
@@ -55,7 +69,7 @@ int Calcs::calcAngle(int deltaX, int deltaY){
int refAngle = 0;
if(deltaX > 10E-12){
refAngle = (int)((atan(deltaY/deltaX) * 180.0/PI) + 0.5 - (refAngle<0)); //Here 0.5 (or -0.5) is added to round a float number to int right
refAngle = (int)((atan(deltaY/deltaX) * 180.0/M_PI) + 0.5 - (refAngle<0)); //Here 0.5 (or -0.5) is added to round a float number to int right
// convert from img coordinates to regbot coordinates
refAngle = -(refAngle);
+8 -1
View File
@@ -1,6 +1,9 @@
#pragma once
#include <opencv2/opencv.hpp>
#include <cmath>
#define _USE_MATH_DEFINES
#include <math.h>
using namespace cv;
using namespace std;
@@ -30,6 +33,10 @@ public:
LFRVector(const LFRPoint& pt);
~LFRVector();
double angle(const LFRVector& other) const;
double dot(const LFRVector& other) const;
double norm() const;
};
class LFRLine
@@ -60,7 +67,7 @@ public:
std::vector<cv::Rect> boundingBoxes;
std::vector<cv::Point> leftEdges;
std::vector<cv::Point> middlePoints;
int angle; //Angle of the contour the robot has to follow to
double angle; //Angle of the contour the robot has to follow to
int index; //Index of the contour the robot has to follow to
FrameData(): contours(), boundingBoxes(), leftEdges(), middlePoints() {}
+53 -8
View File
@@ -4,19 +4,64 @@
int main(void)
{
//Disable opencv logging messages
cv::utils::logging::setLogLevel(cv::utils::logging::LOG_LEVEL_WARNING);
//cv::utils::logging::setLogLevel(cv::utils::logging::LOG_LEVEL_WARNING);
const int thresholdBinary = 140;
const int videoHeight = 720;
const int videoWidth = 1280;
const int gaussKernelSize = 11;
const double maxSpeed = 0.5;
std::mutex mutex;
LFR lfr(videoHeight, videoWidth, thresholdBinary, gaussKernelSize, maxSpeed, [&](std::exception const &ex)
{
std::unique_lock<std::mutex> lock(mutex);
std::cerr<<"camera exception:"<<ex.what()<<std::endl;
return false;
});
//To calculate the frame rate
std::chrono::milliseconds last = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
std::chrono::milliseconds now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
cv::Mat img;
lfr.addListener([&](LFR_Result result)
{
std::unique_lock<std::mutex> lock(mutex);
if (!result.rawImage.empty())
{
img = result.rawImage;
//Resize to minimize latency using raspi over ssh
//cv::resize(result.rawImage, img, cv::Size(128, 64+32));
//Calculate frame rate
now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
unsigned int deltaMs = static_cast<unsigned int>((now-last).count());
double delta = static_cast<double>(deltaMs) / 1000.0;
double frameRate = 1.0 / static_cast<double>(delta);
if (result.validLane)
{
std::cout << "Frame rate: " << frameRate << " angle: " << result.data.angle
<< " motor 1: " << result.motorSignals[0] << " motor 2: " << result.motorSignals[1]
<< " motor 3: " << result.motorSignals[2] << " motor 4: " << result.motorSignals[3] <<std::endl;
}
else
{
std::cout << "No lane found." << std::endl;;
}
last = now;
}
}, &mutex);
LFR lfr(videoHeight, videoWidth, thresholdBinary, gaussKernelSize);
lfr.saveOutputFlag = false;
lfr.videoFlag = true;
lfr.startLoop();
//To end the video stream, write any char in the console.
char a;
std::cin >> a;
lfr.endLoop();
for(int finished = false; finished != 'q';){
finished = std::tolower(cv::waitKey(1));
std::unique_lock<std::mutex> lock(mutex);
if(!img.empty()){
cv::imshow("frame", img);
}
}
}
+103 -48
View File
@@ -3,63 +3,126 @@
#define right false
#define left true
LFR::LFR(int videoHeight, int videoWidth, int thresholdBinary, int gaussKernelSize)
: iAmLooping(false), input(videoHeight, videoWidth), processing(), controlModule(), interpreter(), intersectionHandler()
LFR::LFR(int videoHeight, int videoWidth, int thresholdBinary, int gaussKernelSize, double maxSpeed, ExceptionCallback cb):
stop(false),
input(videoHeight, videoWidth),
processing(),
controlModule(maxSpeed, 1.0, 1.0),
interpreter(),
intersectionHandler(),
cb(cb)
{
this->iAmLooping = false;
this->thresholdBinary = thresholdBinary;
this->gaussKernelSize = gaussKernelSize;
this->videoFlag = false;
this->saveOutputFlag = false;
this->outputFileName = "";
}
LFR::~LFR()
{
if(iAmLooping)
endLoop();
if(thread)
{
this->endLoop();
thread->join();
}
}
void LFR::loop()
void LFR::removeListener(LFR::ListenerKey key)
{
if(this->videoFlag) {namedWindow("Display window");}
while(iAmLooping)
std::lock_guard<std::mutex> lock(mutex);
auto it = std::find_if(std::begin(listeners), std::end(listeners), [&](auto const &val){
return val.first == key;
});
if(it != std::end(listeners))
{
Mat originalImage = input.readWebcam();
Point roiOrigin(0, int(originalImage.rows*(3.25/6.0)));
Rect roi(roiOrigin.x, roiOrigin.y, originalImage.cols, originalImage.rows/6);
//Mat processedImage = originalImage(roi);
Mat processedImage = originalImage;
processing.processImage(processedImage, this->thresholdBinary, this->gaussKernelSize);
//processedImage = processedImage(roi);
FrameData data = processing.calculateLineSegments(processedImage, roi);
processing.filterReflections(data);
processing.calcAngles(data, originalImage.cols, originalImage.rows, left);
this->provideOutput(originalImage, processedImage, data, roi);
listeners.erase(it);
}
if(this->videoFlag) {destroyWindow("Display window");}
input.freeWebcam();
}
void LFR::addListener(LFR::ListenerCallback cb, LFR::ListenerKey key)
{
std::lock_guard<std::mutex> lock(mutex);
listeners.emplace_back(key, std::move(cb));
}
void LFR::setStop(bool val)
{
std::lock_guard<std::mutex> lock(mutex);
stop = val;
}
void LFR::createThread()
{
thread = std::make_unique<std::thread>([this](){
while(true)
{
LFR_Result result;
if(!stop && !listeners.empty())
{
try
{
std::lock_guard<std::mutex> lock(mutex);
Mat originalImage = input.readWebcam();
Point roiOrigin(0, int(originalImage.rows*(3.25/6.0)));
Rect roi(roiOrigin.x, roiOrigin.y, originalImage.cols, originalImage.rows/6);
Mat processedImage = originalImage;
processing.processImage(processedImage, this->thresholdBinary, this->gaussKernelSize);
FrameData data = processing.calculateLineSegments(processedImage, roi);
processing.filterReflections(data);
processing.calcAngles(data, originalImage.cols, originalImage.rows, left);
result.validLane = intersectionHandler.foundLane(data);
if (result.validLane)
{
controlModule.calcSpeeds(1,1, data.angle);
processedImage = provideOutput(originalImage, processedImage, data, roi);
}
result.rawImage = originalImage;
result.processedImage = processedImage;
result.data = data;
result.motorSignals = controlModule.readMotors();
}
catch(std::exception const &ex)
{
if(!cb(ex))
{
//callback returned false -> exception not handled -> exit
exit(EXIT_FAILURE);
}
}
//Invoke the callback method (ListenerPair second -> ListenerCallback)
for(auto &val : listeners)
{
val.second(result);
}
}
else
{
break;
}
}
});
}
void LFR::startLoop()
{
iAmLooping = true;
this->loopThread=thread(&LFR::loop, this);
if(thread)
{
//Restart thread if it is running
setStop(true);
thread->join();
setStop(false);
}
createThread();
}
void LFR::endLoop()
{
iAmLooping = false;
this->loopThread.join();
return;
setStop(true);
}
void LFR::provideOutput(Mat originalImage, Mat processedImage, const FrameData& frameData, const Rect& roi)
cv::Mat LFR::provideOutput(Mat originalImage, Mat processedImage, const FrameData& frameData, const Rect& roi)
{
for(int i = 0; i < frameData.contours.size(); i++)
{
@@ -76,21 +139,13 @@ void LFR::provideOutput(Mat originalImage, Mat processedImage, const FrameData&
{
//Draw the Arrow for the check of the angle
int length = 100;
Point P1 = frameData.middlePoints[frameData.index];
Point P2;
P2.x = (int)round(P1.x + length * cos(frameData.angle * CV_PI / 180.0));
P2.y = (int)round(P1.y + length * sin(frameData.angle * CV_PI / 180.0));
cv::arrowedLine(originalImage, P1, P2, Scalar(0,0,255), 2, 8);
}
if(this->videoFlag)
{
imshow("Display window", originalImage);
imshow("processed:", processedImage);
char c = (char)waitKey(25);
}
if (this->saveOutputFlag && !(this->outputFileName.empty()))
{
imwrite(this->outputFileName, originalImage);
Point contourCenter = frameData.middlePoints[frameData.index];
Point imageCenter = Point(originalImage.size().width/2.0, originalImage.size().height/2.0);
Point focalPoint = Point(imageCenter.x, imageCenter.y+1000.0);
cv::arrowedLine(originalImage, focalPoint, contourCenter, Scalar(0,0,255), 2, 8, 0, 0.03);
cv::arrowedLine(originalImage, focalPoint, imageCenter, Scalar(0,0,255), 2, 8, 0, 0.03);
}
return originalImage;
}
+34 -13
View File
@@ -3,6 +3,7 @@
#include <iostream>
#include <future>
#include <thread>
#include <functional>
#include <opencv2/opencv.hpp>
@@ -15,34 +16,54 @@
using namespace cv;
struct LFR_Result
{
bool validLane;
cv::Mat rawImage;
cv::Mat processedImage;
FrameData data;
std::vector<double> motorSignals;
};
class LFR
{
public:
using ListenerKey = void const*;
using ExceptionCallback = std::function<bool(std::exception const &ex)>;
using ListenerCallback = std::function<void(LFR_Result)>;
private:
using ListenerPair = std::pair<ListenerKey, ListenerCallback>;
using ListenerVector = std::vector<ListenerPair>;
Input input;
Processing processing;
ControlModule controlModule;
Interpreter interpreter;
IntersectionHandler intersectionHandler;
volatile bool iAmLooping;
void loop();
thread loopThread;
int thresholdBinary;
int gaussKernelSize;
void provideOutput(Mat originalImage, Mat processedImage, const FrameData& frameData, const Rect& roi);
ListenerVector listeners;
ExceptionCallback cb;
bool stop;
std::unique_ptr<std::thread> thread;
mutable std::mutex mutex;
//void provideOutput(Mat originalImage, Mat processedImage, const FrameData& frameData, const Rect& roi);
void createThread();
void setStop(bool val);
public:
LFR() = delete;
LFR(int videoHeight, int videoWidth, int thresholdBinary, int gaussKernelSize);
LFR(int videoHeight, int videoWidth, int thresholdBinary, int gaussKernelSize, double maxSpeed, ExceptionCallback cb);
~LFR();
void startLoop();
void endLoop();
bool videoFlag;
bool saveOutputFlag;
std::string outputFileName;
void addListener(ListenerCallback cv, ListenerKey key);
void removeListener(ListenerKey key);
void isStopped() const noexcept;
Mat provideOutput(Mat originalImage, Mat processedImage, const FrameData& frameData, const Rect& roi);
};
+24
View File
@@ -0,0 +1,24 @@
cmake_minimum_required(VERSION 3.1.0)
project(lfr_central VERSION 0.1.0)
include(CTest)
enable_testing()
set(THREADS_PREFER_PTHREAD_FLAG ON)
add_subdirectory(AutonomousMode)
add_subdirectory(Communication)
add_subdirectory(Socket)
add_executable(lfr_central main.cpp lfr_state_machine.cpp lfr_states.cpp)
target_include_directories(lfr_central PRIVATE ${lfr_image_processing_SOURCE_DIRS})
target_include_directories(lfr_central PRIVATE ${lfr_uart_SOURCE_DIRS})
target_include_directories(lfr_central PRIVATE ${lfr_socket_SOURCE_DIRS})
target_link_libraries( lfr_central lfr_image_processing_lib lfr_uart_lib lfr_socket_lib)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
+6 -1
View File
@@ -8,9 +8,14 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
add_executable(lfr_uart uart_communication.cpp)
add_executable(lfr_uart uart_communication.cpp uart_communication_main.cpp)
add_library(lfr_uart_lib uart_communication.cpp)
target_link_libraries( lfr_uart Threads::Threads)
target_link_libraries( lfr_uart_lib Threads::Threads)
target_include_directories(lfr_uart PUBLIC .)
target_include_directories(lfr_uart_lib PUBLIC .)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
+38 -40
View File
@@ -2,6 +2,7 @@
LFR_UART::LFR_UART() : fileDescriptor(-1) {
this->last =std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
this->openSerialPort();
this->configureSerialPort();
}
@@ -13,11 +14,13 @@ void LFR_UART::openFile(const char *fileName) {
this->fileDescriptor = open(fileName, O_RDWR | O_NONBLOCK);
}
int LFR_UART::writeDataToFile(uint8_t *buff, uint32_t bufferLength) {
int LFR_UART::writeDataToFile(int8_t *buff, uint32_t bufferLength) {
//std::cout << "Sending uart: " << std::bitset<8>(buff[0]) << std::endl;
std::cout << "Sending Uart: " << std::bitset<8>(buff[0]) << ", " << std::bitset<8>(buff[1]) << ", " << std::bitset<8>(buff[2]) << ", " << std::bitset<8>(buff[3]) << " csum: " << std::bitset<8>(buff[4]) << std::endl;
return write(this->fileDescriptor, buff, bufferLength);
}
int LFR_UART::readFromFile(uint8_t *buff, uint32_t bufferLength) {
int LFR_UART::readFromFile(int8_t *buff, uint32_t bufferLength) {
return read(this->fileDescriptor, buff, bufferLength);
}
@@ -25,37 +28,32 @@ int LFR_UART::closeFile() {
return close(this->fileDescriptor);
}
uint8_t LFR_UART::doubleToByte(double in){
int8_t LFR_UART::doubleToByte(double in){
/*
* Map the range of -1.0 to 1.0 as double to the range of a byte.
*
* -1 -> 0
* 0.0 -> 127
* 1.0 -> 254
* Not using the full range upto 254 to hit the 0.0
* Map the range of -1.0 to 1.0 as double to the range of a byte. (int8 range)
*/
double minDouble = -1.0;
double maxDouble = 1.0;
double rangeDouble = maxDouble - minDouble;
double minByte = 0.0;
double maxByte = 255.0;
double minByte = -128.0;
double maxByte = 127.0;
double rangeByte = maxByte - minByte;
double progress = in - minDouble;
double progressPercent = progress/rangeDouble;
double inputInByteRange = minByte + progressPercent*rangeByte;
return uint8_t(inputInByteRange);
return int8_t(inputInByteRange);
}
double LFR_UART::byteToDouble(uint8_t in){
double LFR_UART::byteToDouble(int8_t in){
double minDouble = -1.0;
double maxDouble = 1.0;
double rangeDouble = maxDouble - minDouble;
double minByte = 0.0;
double maxByte = 255.0;
double minByte = -128.0;
double maxByte = 127.0;
double rangeByte = maxByte - minByte;
double progress = double(in) - minByte;
@@ -66,27 +64,43 @@ double LFR_UART::byteToDouble(uint8_t in){
}
void LFR_UART::sendTelegram(double wheel1, double wheel2, double wheel3, double wheel4){
std::chrono::milliseconds now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
unsigned int deltaMs = static_cast<unsigned int>((now-last).count());
if (deltaMs < 50 && (std::fabs(wheel1)+std::fabs(wheel2)+std::fabs(wheel3)+std::fabs(wheel4)) > 0.0005)
{
std::cout << "Too fast" << std::endl;
return;
}
last = now;
if(wheel1 > 1.0 || wheel2 > 1.0 || wheel3 > 1.0 || wheel4 > 1.0){
throw CommunicatorException("Wheel value must not be greater than 1.0");
}
if(wheel1 < -1.0 || wheel2 < -1.0 || wheel3 < -1.0 || wheel4 < -1.0){
throw CommunicatorException("Wheel value must not be smaller than -1.0");
}
// Discrepancy between the numbering of the wheels in App/Pi and the µc
// Our - their
// 1 - 4
// 2 - 2
// 3 - 3
// 4 - 1
int8_t wheel1B = this->doubleToByte(wheel4);
//int8_t wheel1B = this->doubleToByte(wheel1);
int8_t wheel2B = this->doubleToByte(wheel2);
int8_t wheel3B = this->doubleToByte(wheel3);
int8_t wheel4B = this->doubleToByte(wheel1);
//int8_t wheel4B = this->doubleToByte(wheel4);
uint8_t wheel1B = this->doubleToByte(wheel1);
uint8_t wheel2B = this->doubleToByte(wheel2);
uint8_t wheel3B = this->doubleToByte(wheel3);
uint8_t wheel4B = this->doubleToByte(wheel4);
int8_t checksum = wheel1B^wheel2B^wheel3B^wheel4B;
uint8_t checksum = wheel1B^wheel2B^wheel3B^wheel4B;
uint8_t telegram_buffer[5] = {wheel1B, wheel2B, wheel3B, wheel4B, checksum};
int8_t telegram_buffer[5] = {wheel1B, wheel2B, wheel3B, wheel4B, checksum};
uint32_t telegram_length = 5;
this->writeDataToFile(telegram_buffer, telegram_length);
}
bool LFR_UART::readTelegram(double* buffer){
uint8_t tmp_buffer[5] = {0, 0, 0, 0, 0};
int8_t tmp_buffer[5] = {0, 0, 0, 0, 0};
uint32_t telegram_length = 5;
this->readFromFile(tmp_buffer, telegram_length);
@@ -133,20 +147,4 @@ void LFR_UART::closeSerialPort() {
this->closeFile();
}
int main(void) {
printf("Starting the loopback application...\r\n");
LFR_UART uartCommunicator;
uartCommunicator.sendTelegram(-1.0, -0.99, 0.99, 1.0);
double buffer[4] = {0.0, 0.0, 0.0, 0.0};
sleep(1);
if(uartCommunicator.readTelegram(buffer)){
for(int i = 0; i < 4; i++) {
std::cout << buffer[i] << " ";
}
}
else {
std::cout<<"ne";
}
return 0;
}
+10 -4
View File
@@ -10,12 +10,17 @@
#include <termios.h>
#include <iostream>
#include <exception>
#include <iostream>
#include <chrono>
#include <cmath>
#include <bitset>
class LFR_UART
{
public:
std::chrono::milliseconds last;
int fileDescriptor;
const char* serialPortPath = "/dev/ttyS0";
@@ -28,13 +33,14 @@ class LFR_UART
void configureSerialPort();
void closeSerialPort();
int writeDataToFile(uint8_t *buff, uint32_t bufferLength);
int readFromFile(uint8_t *buff, uint32_t bufferLength);
int writeDataToFile(int8_t *buff, uint32_t bufferLength);
int readFromFile(int8_t *buff, uint32_t bufferLength);
public:
uint8_t doubleToByte(double in);
double byteToDouble(uint8_t in);
int8_t doubleToByte(double in);
double byteToDouble(int8_t in);
void sendTelegram(double wheel1, double wheel2, double wheel3, double wheel4);
bool readTelegram(double* buffer);
+26
View File
@@ -0,0 +1,26 @@
#include "uart_communication.h"
/*
* Usage: telnet [ip] [port]
* eg.: telnet 192.158.4.1 8080
* To quit: ctrl + +
* q
*/
int main(void) {
printf("Starting the loopback application...\r\n");
LFR_UART uartCommunicator;
uartCommunicator.sendTelegram(-1.0, -0.99, 0.99, 1.0);
double buffer[4] = {0.0, 0.0, 0.0, 0.0};
sleep(1);
if(uartCommunicator.readTelegram(buffer)){
for(int i = 0; i < 4; i++) {
std::cout << buffer[i] << " ";
}
}
else {
std::cout<<"ne";
}
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
+3
View File
@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml
+1
View File
@@ -0,0 +1 @@
LFRMobileApp
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" />
</component>
</project>
+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<targetSelectedWithDropDown>
<Target>
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="C:\Users\baran\.android\avd\Pixel_2_API_R.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-01-12T21:16:30.648959800Z" />
</component>
</project>
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/virtual-joystick-android-master/virtualjoystick" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>
+34
View File
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DesignSurface">
<option name="filePathToZoomLevelMap">
<map>
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/drawable-anydpi/manuell.xml" value="0.1" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/drawable-v24/ic_launcher_foreground.xml" value="0.1" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/drawable/ic_baseline_rotate_left_24.xml" value="0.1" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/drawable/ic_dashboard_black_24dp.xml" value="0.1" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/drawable/ic_home_black_24dp.xml" value="0.1" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/drawable/ic_launcher_background.xml" value="0.1" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/drawable/ic_notifications_black_24dp.xml" value="0.1" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/drawable/my_btn_toggle.xml" value="0.1" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/drawable/vorwarts.xml" value="0.1" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/layout/activity_main.xml" value="0.16666666666666666" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/layout/fragment_automatik.xml" value="0.14666666666666667" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/layout/fragment_dashboard.xml" value="0.14666666666666667" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/layout/fragment_einstellungen.xml" value="0.25" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/layout/fragment_home.xml" value="0.16666666666666666" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/layout/fragment_manuell.xml" value="0.22" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/layout/fragment_notifications.xml" value="0.16666666666666666" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/menu/bottom_nav_menu.xml" value="0.16666666666666666" />
<entry key="..\:/Line-Following-Robot/MobileApp/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.1" />
<entry key="..\:/Users/baran/.gradle/caches/transforms-3/2518aadee33334bef1598ce32f2dbd8e/transformed/material-1.7.0/res/drawable-v21/material_cursor_drawable.xml" value="0.1" />
</map>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>
Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

+1
View File
@@ -0,0 +1 @@
/build
+45
View File
@@ -0,0 +1,45 @@
plugins {
id 'com.android.application'
}
android {
compileSdk 32
defaultConfig {
applicationId "com.example.lfrmobileapp"
minSdk 22
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildFeatures {
viewBinding true
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
implementation 'androidx.navigation:navigation-fragment:2.5.3'
implementation 'androidx.navigation:navigation-ui:2.5.3'
implementation project(path: ':virtualjoystick')
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}
+21
View File
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
@@ -0,0 +1,26 @@
package com.example.lfrmobileapp;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.example.lfrmobileapp", appContext.getPackageName());
}
}
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.lfrmobileapp">
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.LFRMobileApp"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
@@ -0,0 +1,51 @@
package com.example.lfrmobileapp;
import android.accounts.NetworkErrorException;
import android.util.Log;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Objects;
public class Communication {
public String telegram(int[] wheels, int strenght){
String tel = "aa";
tel += "0"; //Manuel mode
for(int i = 0; i < wheels.length; i++){
if(wheels[i] == 1){
tel += ";" + Float.toString(((float)strenght)/100) ;
}else if(wheels[i] == -1)
tel += ";" + Float.toString(((float)-strenght)/100);
else{
tel += ";0.00";
}
}
tel += "zz";
return tel;
}
public String telegram(boolean startStop, ArrayList<String> list){
String tel = "aa";
tel += "1"; //Autonomous mode
if(startStop){
tel += ";1";
}else{
return "aa0;0.0;0.0;0.0;0.0zz";
}
for (String i : list) {
if(i.equals("Links")){
tel += ";0";
}else if (i.equals("Rechts")){
tel += ";1";
}
}
tel += "zz";
return tel;
}
}
@@ -0,0 +1,49 @@
package com.example.lfrmobileapp;
import android.os.AsyncTask;
import android.util.Log;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class DataTransferAsyncTask extends AsyncTask<Void, Void, Void> {
private static final double sendRatePerSecond = 4.0;
private boolean connected;
private final ExtendedSocket socket;
private BlockingQueue<String> blockingQueue;
public DataTransferAsyncTask(ExtendedSocket socket) {
this.socket = socket;
this.connected = true;
this.blockingQueue = new LinkedBlockingQueue<>();
}
public void writeTelegram(String telegram) {
// Schau mal hier bei Fehler
blockingQueue.offer(telegram);
}
@Override
protected Void doInBackground(Void... params) {
while(!isCancelled() && connected) {
try {
synchronized (socket) {
String message = blockingQueue.poll((long) (1000.0/sendRatePerSecond), TimeUnit.MILLISECONDS);
if(message != null){
Log.v("TAG", message + "\n");
socket.sendMessage(message);
}
}
} catch (Exception e) {
e.printStackTrace();
connected = false;
}
}
return null;
}
}
@@ -0,0 +1,25 @@
package com.example.lfrmobileapp;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class ExtendedSocket {
private final Socket socket;
public ExtendedSocket(Socket socket) {
this.socket = socket;
}
public void sendMessage(String message) throws IOException {
synchronized (socket){
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
outputStream.writeBytes(message);
outputStream.flush();
}
}
public void closeSocket() throws IOException {
this.socket.close();
}
}
@@ -0,0 +1,91 @@
package com.example.lfrmobileapp;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.Toast;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import com.example.lfrmobileapp.databinding.ActivityMainBinding;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private ExtendedSocket socket;
private DataTransferAsyncTask dataTransferAsyncTask;
public Boolean connected = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_main);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(binding.navView, navController);
}
public boolean connectToWifi(String ipAddress, int port){
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Boolean> future = executor.submit(() -> {
Socket tempSocket = new Socket();
tempSocket.connect(new InetSocketAddress(ipAddress, port), 1000);
try {
socket = new ExtendedSocket(tempSocket);
socket.sendMessage("Verbindung aufbauen");
} catch (Exception e) {
socket.closeSocket();
return false;
}
return true;
});
try {
connected = future.get();
} catch (InterruptedException e) {
System.err.println("InterruptedException: " + e.getMessage());
} catch (ExecutionException e) {
System.err.println("ExecutionException: " + e.getCause().getMessage());
}
executor.shutdown();
if(connected){
dataTransferAsyncTask = new DataTransferAsyncTask(socket);
dataTransferAsyncTask.execute();
return true;
}else{
return false;
}
}
public void sendTelegram(String telegram)
{
this.dataTransferAsyncTask.writeTelegram(telegram);
}
}
@@ -0,0 +1,182 @@
package com.example.lfrmobileapp.ui.dashboard;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.ListView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import com.example.lfrmobileapp.Communication;
import com.example.lfrmobileapp.DataTransferAsyncTask;
import com.example.lfrmobileapp.MainActivity;
import com.example.lfrmobileapp.R;
import com.example.lfrmobileapp.databinding.FragmentAutomatikBinding;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import kotlin.collections.UArraySortingKt;
// Autonomous Mode
public class DashboardFragment extends Fragment {
Communication com = new Communication();
private FragmentAutomatikBinding binding;
MainActivity mainActivity;
//Keys for Shared Preferences
String listKey = "listkey";
@Override
public void onAttach(Context context) {
super.onAttach(context);
mainActivity = (MainActivity) context;
}
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
DashboardViewModel dashboardViewModel =
new ViewModelProvider(this).get(DashboardViewModel.class);
binding = FragmentAutomatikBinding.inflate(inflater, container, false);
View root = binding.getRoot();
final TextView textView = binding.textDashboard;
dashboardViewModel.getText().observe(getViewLifecycleOwner(), textView::setText);
//Shared Preferences
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
//Get Arraylist from Shared Preferences String
ArrayList<String> autoList = stringToArraylist(sharedPref.getString(listKey, ""));
binding.startAutomatic.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (mainActivity.connected){
if(isChecked){
mainActivity.sendTelegram(com.telegram(true, autoList));
}else{
mainActivity.sendTelegram(com.telegram(false, autoList));
}
}
}
});
// on the below line we are initializing the adapter for our list view.
ArrayAdapter<String> adapter = new ArrayAdapter<String>(root.getContext(), android.R.layout.simple_list_item_1, autoList){
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view =super.getView(position, convertView, parent);
TextView textView=(TextView) view.findViewById(android.R.id.text1);
//Set Color to black
textView.setTextColor(Color.BLACK);
return view;
}
@Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
//Save Arraylist in Shared Preferences as String
editor.putString(listKey, listToString(autoList));
editor.apply();
}
};
// on below line we are setting adapter for our list view.
binding.automaticList.setAdapter(adapter);
// on below line we are adding click listener for our button.
binding.addLeft.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// on below line we are getting text from edit text
String item = "Links";
Boolean automaticOn = binding.startAutomatic.isChecked();
// on below line we are checking if item is not empty
if (!item.isEmpty() && !automaticOn) {
// on below line we are adding item to our list.
autoList.add(item);
// on below line we are notifying adapter
// that data in list is updated to
// update our list view.
adapter.notifyDataSetChanged();
}
}
});
// on below line we are adding click listener for our button.
binding.addRight.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// on below line we are getting text from edit text
String item = "Rechts";
Boolean automaticOn = binding.startAutomatic.isChecked();
// on below line we are checking if item is not empty
if (!item.isEmpty() && !automaticOn) {
// on below line we are adding item to our list.
autoList.add(item);
// on below line we are notifying adapter
// that data in list is updated to
// update our list view.
adapter.notifyDataSetChanged();
}
}
});
//Deleting element in ListView
binding.automaticList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Boolean automaticOn = binding.startAutomatic.isChecked();
if(!automaticOn) {
autoList.remove(position);
adapter.notifyDataSetChanged();
}
}
});
return root;
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
public String listToString(ArrayList<String> list){
String result = "";
if(!list.isEmpty()) {
for (String s : list) {
result += s + ";";
}
}
return result;
}
public ArrayList<String> stringToArraylist(String str){
ArrayList<String> list = null;
String[] stringArray = str.split(";");
list = new ArrayList<String>(Arrays.asList(stringArray));
return list;
}
}
@@ -0,0 +1,19 @@
package com.example.lfrmobileapp.ui.dashboard;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class DashboardViewModel extends ViewModel {
private final MutableLiveData<String> mText;
public DashboardViewModel() {
mText = new MutableLiveData<>();
mText.setValue("");
}
public LiveData<String> getText() {
return mText;
}
}
@@ -0,0 +1,170 @@
package com.example.lfrmobileapp.ui.home;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import com.example.lfrmobileapp.Communication;
import com.example.lfrmobileapp.DataTransferAsyncTask;
import com.example.lfrmobileapp.MainActivity;
import com.example.lfrmobileapp.R;
import com.example.lfrmobileapp.databinding.FragmentManuellBinding;
import com.example.lfrmobileapp.ui.notifications.NotificationsFragment;
import io.github.controlwear.virtual.joystick.android.JoystickView;
public class HomeFragment extends Fragment {
//Keys for Shared Preferences
String ipKey = "ipkey";
String portKey = "portkey";
//Default Ip-Address and Port
String ipAddress = "192.168.0.1";
int port = 8000;
MainActivity mainActivity;
Communication com = new Communication();
long lastOnMoveCall = System.currentTimeMillis();
private FragmentManuellBinding binding;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mainActivity = (MainActivity) context;
}
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
HomeViewModel homeViewModel =
new ViewModelProvider(this).get(HomeViewModel.class);
binding = FragmentManuellBinding.inflate(inflater, container, false);
View root = binding.getRoot();
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
//Get saved Ip-Adress and Port from Shared Preferences
ipAddress = sharedPref.getString(ipKey, "");
port = sharedPref.getInt(portKey, 0);
//Set text from Textview
final TextView textView = binding.textHome;
homeViewModel.getText().observe(getViewLifecycleOwner(), textView::setText);
binding.rotateLeft.setOnTouchListener(new View.OnTouchListener(){
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
if (mainActivity.connected) {
if (event.getAction() == MotionEvent.ACTION_UP) {
binding.rotateLeft.performClick();
mainActivity.sendTelegram(com.telegram(new int[]{0, 0, 0, 0}, 0));
return true;
} else {
mainActivity.sendTelegram(com.telegram(new int[]{-1, 1, -1, 1}, 50));
}
}
return false;
}
});
binding.rotateRight.setOnTouchListener(new View.OnTouchListener(){
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
if (mainActivity.connected){
if(event.getAction() == MotionEvent.ACTION_UP){
binding.rotateRight.performClick();
mainActivity.sendTelegram(com.telegram(new int[]{0, 0, 0, 0}, 0));
return true;
}else{
mainActivity.sendTelegram(com.telegram(new int[]{1, -1, 1, -1}, 50));
}
}
return false;
}
});
JoystickView joystick = (JoystickView) binding.joystick;
joystick.setOnMoveListener(new JoystickView.OnMoveListener() {
@Override
public void onMove(int angle, int strength) {
boolean send = false;
if (System.currentTimeMillis() - lastOnMoveCall > 250){
send = true;
lastOnMoveCall = System.currentTimeMillis();
}
String telegram = "";
homeViewModel.setText(Integer.toString(angle), Integer.toString(strength));
//8 segments of the joystick
if((angle >= 338 || angle < 22) && strength != 0){
joystick.setBackgroundResource(R.mipmap.right);
telegram = com.telegram(new int[]{1, -1, -1, 1}, strength);
}else if((angle >= 22 && angle < 67) && strength != 0){
joystick.setBackgroundResource(R.mipmap.right_forward);
telegram = com.telegram(new int[]{1, 0, 0, 1}, strength);
}else if((angle >=67 && angle < 112) && strength != 0){
joystick.setBackgroundResource(R.mipmap.forward);
telegram = com.telegram(new int[]{1, 1, 1, 1}, strength);
}else if((angle >=112 && angle < 157) && strength != 0){
joystick.setBackgroundResource(R.mipmap.left_forward);
telegram = com.telegram(new int[]{0, 1, 1, 0}, strength);
}else if((angle >=157 && angle < 202) && strength != 0){
joystick.setBackgroundResource(R.mipmap.left);
telegram = com.telegram(new int[]{-1, 1, 1, -1}, strength);
}else if((angle >=202 && angle < 247) && strength != 0){
joystick.setBackgroundResource(R.mipmap.left_back);
telegram = com.telegram(new int[]{-1, 0, 0, -1}, strength);
}else if((angle >=247 && angle < 292) && strength != 0){
joystick.setBackgroundResource(R.mipmap.back);
telegram = com.telegram(new int[]{-1, -1, -1, -1}, strength);
}else if((angle >=292 && angle < 337) && strength != 0){
joystick.setBackgroundResource(R.mipmap.right_back);
telegram = com.telegram(new int[]{0, -1, -1, 0}, strength);
}
else{
joystick.setBackgroundResource(R.mipmap.blank);
telegram = com.telegram(new int[]{0, 0, 0, 0}, strength);
send=true;
}
if (send && mainActivity.connected)
{
mainActivity.sendTelegram(telegram);
// Log.v("TAG", telegram + "\n");
}
}
});
return root;
}
@Override
public void onDestroyView() {
super.onDestroyView();
// dataTransferAsyncTask.cancel(false);
binding = null;
}
}
@@ -0,0 +1,24 @@
package com.example.lfrmobileapp.ui.home;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class HomeViewModel extends ViewModel {
private final MutableLiveData<String> mText;
public HomeViewModel() {
mText = new MutableLiveData<>();
mText.setValue("Bewege den Punkt zum steuern des Roboters");
}
public LiveData<String>setText(String angle, String strength){
mText.setValue("Winkel: "+ angle + " Verstärkung: " + strength);
return mText;
};
public LiveData<String> getText() {
return mText;
}
}
@@ -0,0 +1,135 @@
package com.example.lfrmobileapp.ui.notifications;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import com.example.lfrmobileapp.Communication;
import com.example.lfrmobileapp.DataTransferAsyncTask;
import com.example.lfrmobileapp.MainActivity;
import com.example.lfrmobileapp.databinding.FragmentEinstellungenBinding;
import java.io.DataOutputStream;
import java.net.Socket;
/*class NetworkThread extends Thread {
String ip;
int port;
boolean connected;
NetworkThread(String ip, int port) {
this.ip = ip;
this.port = port;
this.connected = false;
}
public void run() {
try {
Socket socket = new Socket(ip, port);
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
outputStream.writeBytes("Verbindung aufbauen");
outputStream.flush();
socket.close();
connected = true;
} catch (Exception e) {
e.printStackTrace();
connected = false;
}
}
}*/
public class NotificationsFragment extends Fragment {
Boolean connected = false;
MainActivity mainActivity;
String ipKey = "ipkey";
String portKey = "portkey";
String connectionFailed = "Verbindung fehlgeschlagen.";
String connectionSuccessful = "Verbindung erfolgreich.";
String ipAddress = "192.168.4.1";
int port = 8080;
int duration = Toast.LENGTH_LONG;
DataTransferAsyncTask dataTransferAsyncTask;
private FragmentEinstellungenBinding binding;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mainActivity = (MainActivity) context;
}
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
NotificationsViewModel notificationsViewModel =
new ViewModelProvider(this).get(NotificationsViewModel.class);
binding = FragmentEinstellungenBinding.inflate(inflater, container, false);
View root = binding.getRoot();
Communication com = new Communication();
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
ipAddress = sharedPref.getString(ipKey, "");
binding.ipAdress.setText(ipAddress);
port = sharedPref.getInt(portKey, -1);
if(port != -1){
binding.port.setText(Integer.toString(port));
}else{
binding.port.setText("");
}
// dataTransferAsyncTask = new DataTransferAsyncTask(ipAddress, port);
final Button button = binding.connect;
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try {
ipAddress = String.valueOf(binding.ipAdress.getText());
port = Integer.parseInt(String.valueOf(binding.port.getText()));
} catch (Exception e){
System.err.println("Parse Exception: " + e.getMessage());
}
connected = mainActivity.connectToWifi(ipAddress, port);
if(connected){
editor.putString(ipKey, ipAddress);
editor.putInt(portKey, port);
editor.apply();
Toast toast = Toast.makeText(v.getContext(), connectionSuccessful, duration);
toast.show();
}else{
Toast toast = Toast.makeText(v.getContext(), connectionFailed, duration);
toast.show();
// dataTransferAsyncTask.cancel(true);
}
}
});
return root;
}
@Override
public void onDestroyView() {
super.onDestroyView();
// dataTransferAsyncTask.cancel(true);
binding = null;
}
}
@@ -0,0 +1,19 @@
package com.example.lfrmobileapp.ui.notifications;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class NotificationsViewModel extends ViewModel {
private final MutableLiveData<String> mText;
public NotificationsViewModel() {
mText = new MutableLiveData<>();
mText.setValue("");
}
public LiveData<String> getText() {
return mText;
}
}
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#333333"
android:alpha="0.6">
<path
android:fillColor="@android:color/white"
android:pathData="M17,16l-4,-4V8.82C14.16,8.4 15,7.3 15,6c0,-1.66 -1.34,-3 -3,-3S9,4.34 9,6c0,1.3 0.84,2.4 2,2.82V12l-4,4H3v5h5v-3.05l4,-4.2 4,4.2V21h5v-5h-4z"/>
</vector>
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#333333"
android:alpha="0.6">
<path
android:fillColor="@android:color/white"
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
</vector>
@@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#333333"
android:alpha="0.6">
<path
android:fillColor="@android:color/white"
android:pathData="M15.54,5.54L13.77,7.3 12,5.54 10.23,7.3 8.46,5.54 12,2zM18.46,15.54l-1.76,-1.77L18.46,12l-1.76,-1.77 1.76,-1.77L22,12zM8.46,18.46l1.77,-1.76L12,18.46l1.77,-1.76 1.77,1.76L12,22zM5.54,8.46l1.76,1.77L5.54,12l1.76,1.77 -1.76,1.77L2,12z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M12,12m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
</vector>
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#333333"
android:alpha="0.6">
<path
android:fillColor="@android:color/white"
android:pathData="M4,12l1.41,1.41L11,7.83V20h2V7.83l5.58,5.59L20,12l-8,-8 -8,8z"/>
</vector>
Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
Binary file not shown.

After

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 928 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 750 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 475 B

@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#3C3F41"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M7.11,8.53L5.7,7.11C4.8,8.27 4.24,9.61 4.07,11h2.02c0.14,-0.87 0.49,-1.72 1.02,-2.47zM6.09,13L4.07,13c0.17,1.39 0.72,2.73 1.62,3.89l1.41,-1.42c-0.52,-0.75 -0.87,-1.59 -1.01,-2.47zM7.1,18.32c1.16,0.9 2.51,1.44 3.9,1.61L11,17.9c-0.87,-0.15 -1.71,-0.49 -2.46,-1.03L7.1,18.32zM13,4.07L13,1L8.45,5.55 13,10L13,6.09c2.84,0.48 5,2.94 5,5.91s-2.16,5.43 -5,5.91v2.02c3.95,-0.49 7,-3.85 7,-7.93s-3.05,-7.44 -7,-7.93z"/>
</vector>
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#3C3F41"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M15.55,5.55L11,1v3.07C7.06,4.56 4,7.92 4,12s3.05,7.44 7,7.93v-2.02c-2.84,-0.48 -5,-2.94 -5,-5.91s2.16,-5.43 5,-5.91L11,10l4.55,-4.45zM19.93,11c-0.17,-1.39 -0.72,-2.73 -1.62,-3.89l-1.42,1.42c0.54,0.75 0.88,1.6 1.02,2.47h2.02zM13,17.9v2.02c1.39,-0.17 2.74,-0.71 3.9,-1.61l-1.44,-1.44c-0.75,0.54 -1.59,0.89 -2.46,1.03zM16.89,15.48l1.42,1.41c0.9,-1.16 1.45,-2.5 1.62,-3.89h-2.02c-0.14,0.87 -0.48,1.72 -1.02,2.48z"/>
</vector>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M3,13h8L11,3L3,3v10zM3,21h8v-6L3,15v6zM13,21h8L21,11h-8v10zM13,3v6h8L21,3h-8z" />
</vector>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z" />
</vector>
@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2z" />
</vector>
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M4,12l1.41,1.41L11,7.83V20h2V7.83l5.58,5.59L20,12l-8,-8 -8,8z"/>
</vector>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/bottom_nav_menu" />
<fragment
android:id="@+id/nav_host_fragment_activity_main"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:defaultNavHost="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/mobile_navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.dashboard.DashboardFragment">
<Switch
android:id="@+id/startAutomatic"
android:layout_width="224dp"
android:layout_height="38dp"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:checked="false"
android:fontFamily="sans-serif-medium"
android:text="Roboter losfahren "
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.147"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text_dashboard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.946" />
<TextView
android:id="@+id/textTurnLeftRight"
android:layout_width="137dp"
android:layout_height="39dp"
android:layout_marginStart="8dp"
android:layout_marginTop="64dp"
android:layout_marginEnd="8dp"
android:fontFamily="sans-serif-medium"
android:text="Abzweigung hinzufügen:"
android:textColor="#000000"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.089"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/addLeft"
android:layout_width="105dp"
android:layout_height="40dp"
android:layout_marginTop="64dp"
android:layout_marginEnd="16dp"
android:fontFamily="sans-serif-medium"
android:text="Links"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.613"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/addRight"
android:layout_width="105dp"
android:layout_height="40dp"
android:layout_marginTop="64dp"
android:layout_marginEnd="16dp"
android:fontFamily="sans-serif-medium"
android:text="Rechts"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ListView
android:id="@+id/automaticList"
android:layout_width="match_parent"
android:layout_height="470dp"
android:layout_marginTop="110dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/startAutomatic" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.notifications.NotificationsFragment">
<EditText
android:id="@+id/ipAdress"
android:layout_width="269dp"
android:layout_height="wrap_content"
android:layout_marginTop="60dp"
android:hint="IP-Adresse"
android:digits="0123456789."
android:textColor="#000000"
android:inputType="number|numberDecimal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/port"
android:layout_width="269dp"
android:layout_height="wrap_content"
android:layout_marginTop="120dp"
android:ems="10"
android:hint="Port"
android:digits="0123456789"
android:textColor="#000000"
android:inputType="number|numberDecimal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/connect"
android:layout_width="269dp"
android:layout_height="wrap_content"
android:layout_marginTop="180dp"
android:text="Verbinden"
android:background="@color/THblue"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"></Button>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.home.HomeFragment">
<io.github.controlwear.virtual.joystick.android.JoystickView
android:id="@+id/joystick"
android:layout_width="308dp"
android:layout_height="317dp"
android:layout_marginTop="68dp"
android:background="@mipmap/blank"
app:JV_buttonColor="#FFFFFF"
app:JV_buttonSizeRatio="11%"
app:JV_fixedCenter="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text_home"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:textSize="15sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<Button
android:id="@+id/rotateLeft"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_marginTop="350dp"
android:background="@drawable/ic_baseline_rotate_left_24"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.150"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"></Button>
<Button
android:id="@+id/rotateRight"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_marginTop="350dp"
android:background="@drawable/ic_baseline_rotate_right_24"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.85"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"></Button>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/navigation_home"
android:icon="@drawable/manuell"
android:title="@string/title_home" />
<item
android:id="@+id/navigation_dashboard"
android:icon="@drawable/automatik"
android:title="@string/title_dashboard" />
<item
android:id="@+id/navigation_notifications"
android:icon="@drawable/einstellungen"
android:title="@string/title_notifications" />
</menu>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Some files were not shown because too many files have changed in this diff Show More