diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 2585ec5..d0a4004 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -15,6 +15,10 @@ + + + + + @@ -81,6 +90,22 @@ + { + "keyToString": { + "RunOnceActivity.OpenProjectViewOnStart": "true", + "RunOnceActivity.ShowReadmeOnStart": "true", + "git-widget-placeholder": "main", + "kotlin-language-version-configured": "true", + "last_opened_file_path": "/Users/lucawarm/Jetbrains/Android Studio/muupooviixee66", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "nodejs_package_manager_path": "npm", + "settings.editor.selected.configurable": "preferences.pluginManager", + "vue.rearranger.settings.migration": "true" + } +} @@ -144,6 +169,13 @@ + + + + + + @@ -157,6 +189,12 @@ + + + + + + 1713528225837 @@ -210,7 +248,47 @@ - @@ -237,6 +315,11 @@ - \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c5f3f6b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "interactive" +} \ No newline at end of file diff --git a/code/arduino/Movement-sensor-code/Connectivity.cpp b/code/arduino/Movement-sensor-code/Connectivity.cpp new file mode 100644 index 0000000..dc24184 --- /dev/null +++ b/code/arduino/Movement-sensor-code/Connectivity.cpp @@ -0,0 +1,23 @@ +#include "Connectivity.h" + +void Connectivity::connectWiFi(char* ssid, char* pass){ + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, pass); + while (WiFi.status() != WL_CONNECTED) { + Serial.println("connecting to wifi"); + delay(1000); + } + Serial.println(WiFi.localIP()); +} + +void Connectivity::websocketSetup(char* ip, uint16_t port, char* adress){ + //ws server address, port and URL + webSocket.begin(ip , port, adress); + // try every 500 again if connection has failed + webSocket.setReconnectInterval(500); +} + +void Connectivity::sendData(float roll, float pitch, float yaw){ + String message = "{\"Sensor\": 1, \"roll\":\"" + String(roll) + "\",\"pitch\":\"" + String(pitch) + "\",\"yaw\":\"" + String(yaw) + "\"}"; + webSocket.sendTXT(message); +} \ No newline at end of file diff --git a/code/arduino/Movement-sensor-code/Connectivity.h b/code/arduino/Movement-sensor-code/Connectivity.h new file mode 100644 index 0000000..be2a9a2 --- /dev/null +++ b/code/arduino/Movement-sensor-code/Connectivity.h @@ -0,0 +1,30 @@ +#ifndef Connectivity_h +#define Connectivity_h + +#include "Arduino.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Connectivity { +public: + void connectWiFi(char* ssid, char* pass); + void websocketSetup(char* ip, uint16_t port, char* adress); + void sendData(float roll, float pitch, float yaw); + +private: + ESP8266WiFiMulti wifi; + WebSocketsClient webSocket; +}; + +#endif \ No newline at end of file diff --git a/code/arduino/Movement-sensor-code/Movement-sensor-code.ino b/code/arduino/Movement-sensor-code/Movement-sensor-code.ino index f889f39..932d32d 100644 --- a/code/arduino/Movement-sensor-code/Movement-sensor-code.ino +++ b/code/arduino/Movement-sensor-code/Movement-sensor-code.ino @@ -1,22 +1,29 @@ #include "headerFile.h" -SensorManager sensorManager; -ESP8266WiFiMulti wifi; -WebSocketsClient webSocket; -#define USE_SERIAL Serial +SensorManager::Rotation offset; void setup() { Serial.begin(9600); Serial.println("startup"); - delay(5000); - connectWiFi(); + + connectivity.connectWiFi(ssid, pass); sensorManager.sensorSetup(); - websocketSetup(); + + //ws server address, port and URL + webSocket.begin("145.3.245.22", 8001, ""); + // try every 500 again if connection has failed + webSocket.setReconnectInterval(500); } void loop() { SensorManager::Rotation rotation = sensorManager.readLoop(); + // Subtract offset + rotation.i -= offset.i; + rotation.j -= offset.j; + rotation.k -= offset.k; + rotation.w -= offset.w; + // Convert quaternion to Euler angles in radians float roll = atan2(2.0f * (rotation.w * rotation.i + rotation.j * rotation.k), 1.0f - 2.0f * (rotation.i * rotation.i + rotation.j * rotation.j)); float pitch = asin(2.0f * (rotation.w * rotation.j - rotation.k * rotation.i)); @@ -36,27 +43,17 @@ void loop() { Serial.println(); webSocket.loop(); -} - -void connectWiFi(){ - - WiFi.mode(WIFI_STA); - wifi.addAP(ssid, pass); - WiFi.begin(); - while (WiFi.status() != WL_CONNECTED) { - Serial.println("connecting to wifi"); - delay(1000); + if (Serial.available()) { + String command = Serial.readStringUntil('\n'); + command.trim(); // remove any trailing whitespace + if (command == "setZeroPoint") { + setZeroPoint(); + } } - Serial.println(WiFi.localIP()); - } - -void websocketSetup(){ - //ws server address, port and URL - webSocket.begin("192.168.178.118", 8001, ""); - // try every 500 again if connection has failed - webSocket.setReconnectInterval(500); +void setZeroPoint() { + offset = sensorManager.readLoop(); } void sendData(float roll, float pitch, float yaw){ diff --git a/code/arduino/Movement-sensor-code/SensorManager.cpp b/code/arduino/Movement-sensor-code/SensorManager.cpp index 4ca3d62..063f0da 100644 --- a/code/arduino/Movement-sensor-code/SensorManager.cpp +++ b/code/arduino/Movement-sensor-code/SensorManager.cpp @@ -1,6 +1,7 @@ #include "SensorManager.h" #include + SensorManager::SensorManager() {} void SensorManager::sensorSetup() { diff --git a/code/arduino/Movement-sensor-code/headerFIle.h b/code/arduino/Movement-sensor-code/headerFIle.h index cd3f6ae..b7b8220 100644 --- a/code/arduino/Movement-sensor-code/headerFIle.h +++ b/code/arduino/Movement-sensor-code/headerFIle.h @@ -1,20 +1,13 @@ -#include +//classes +#include "SensorManager.h" +#include "Connectivity.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +//define +SensorManager sensorManager; +Connectivity connectivity; +WebSocketsClient webSocket; +#define USE_SERIAL Serial -#define ssid "ObsidianAmstelveen" -#define pass "drijversstraatmaastricht" -//custom classes -#include "SensorManager.h" \ No newline at end of file +#define ssid "1235678i" +#define pass "12345678" diff --git a/code/src/Fitbot/app/build.gradle b/code/src/Fitbot/app/build.gradle index 38cf8be..6494462 100644 --- a/code/src/Fitbot/app/build.gradle +++ b/code/src/Fitbot/app/build.gradle @@ -34,7 +34,12 @@ dependencies { implementation 'com.android.support.constraint:constraint-layout:2.0.4' implementation 'com.android.support:cardview-v7:28.0.0' implementation 'com.android.support:design:28.0.0' + implementation 'org.joml:joml:1.10.5' + implementation 'com.google.code.gson:gson:2.8.6' testImplementation 'junit:junit:4.13.2' + testImplementation 'org.junit.jupiter:junit-jupiter' + testImplementation 'org.junit.jupiter:junit-jupiter' + testImplementation 'org.junit.jupiter:junit-jupiter' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation 'com.aldebaran:qisdk:1.7.5' diff --git a/code/src/Fitbot/app/src/main/AndroidManifest.xml b/code/src/Fitbot/app/src/main/AndroidManifest.xml index 1388b7a..c664f73 100644 --- a/code/src/Fitbot/app/src/main/AndroidManifest.xml +++ b/code/src/Fitbot/app/src/main/AndroidManifest.xml @@ -4,6 +4,10 @@ + + + + + diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/MainActivity.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/MainActivity.java deleted file mode 100644 index 14e8445..0000000 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/MainActivity.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.example.fitbot; - -import android.os.Bundle; - -import com.aldebaran.qi.sdk.QiContext; -import com.aldebaran.qi.sdk.QiSDK; -import com.aldebaran.qi.sdk.RobotLifecycleCallbacks; -import com.aldebaran.qi.sdk.design.activity.RobotActivity; - -public class MainActivity extends RobotActivity implements RobotLifecycleCallbacks { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // Register the RobotLifecycleCallbacks to this Activity. - - QiSDK.register(this, this); - - } - - @Override - protected void onDestroy() { - // Unregister the RobotLifecycleCallbacks for this Activity. - QiSDK.unregister(this, this); - super.onDestroy(); - } - - @Override - public void onRobotFocusGained(QiContext qiContext) { - // TODO: - // Add start screen. - } - - - @Override - public void onRobotFocusLost() { - // Nothing here. - } - - @Override - public void onRobotFocusRefused(String reason) { - // The robot focus is refused. - } -} \ No newline at end of file diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/AbstractExercise.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/AbstractExercise.java new file mode 100644 index 0000000..daf7d8b --- /dev/null +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/AbstractExercise.java @@ -0,0 +1,104 @@ +package com.example.fitbot.exercise; + +import android.util.Log; + +import com.example.fitbot.util.path.GesturePath; +import com.example.fitbot.util.server.IWebSocketHandler; +import com.example.fitbot.util.server.WebSocket; + +import java.util.Objects; + +public abstract class AbstractExercise implements IWebSocketHandler { + + private EMuscleGroup muscleGroup; + private GesturePath path; + + // Static fields. + private static WebSocket webSocket; + private static AbstractExercise currentExercise = null; + + + /** + * Constructor for the AbstractExercise class. + * + * @param muscleGroup The muscle group of the exercise. + * @param path The path of the exercise. + */ + public AbstractExercise(EMuscleGroup muscleGroup, GesturePath path) { + this.muscleGroup = muscleGroup; + this.path = path; + } + + /** + * Start the exercise. + * This method starts a WebSocket server + */ + public final void startExercise() { + + // Ensure no other exercise is active. + if (currentExercise != null && currentExercise != this) { + currentExercise.__stopExercise(); + Log.i("Exercises", "Another exercise was started when another was still running."); + } + + // If a WebSocket server is already running, change the event handler to be this class. + if (webSocket != null && webSocket.isConnected()) { + webSocket.setEventHandler(this); + } + + try { + webSocket = WebSocket.createServer(); + Objects.requireNonNull(webSocket, "WebSocket server could not be created."); + + webSocket.startListening(); + webSocket.setEventHandler(this); + currentExercise = this; + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Method for ending this exercise and returning the grade of the performance + * of this activity. + */ + public final double finishExercise() { + this.__stopExercise(); + + // TODO: Implement grade calculation + return 0.0; + } + + /** + * Stop the exercise. + * This method stops the WebSocket server. + */ + private void __stopExercise() { + if (webSocket != null && webSocket.isConnected()) { + webSocket.stop(); + webSocket = null; + } + currentExercise = null; + } + + /** + * Check if the current exercise is the current activity. + */ + public final boolean isCurrentActivity() { + return currentExercise == this; + } + + /** + * Get the muscle group of the exercise. + */ + public EMuscleGroup getMuscleGroup() { + return muscleGroup; + } + + /** + * Get the path of the exercise. + */ + public GesturePath getPath() { + return path; + } +} diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/EMuscleGroup.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/EMuscleGroup.java new file mode 100644 index 0000000..27ff244 --- /dev/null +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/EMuscleGroup.java @@ -0,0 +1,30 @@ +package com.example.fitbot.exercise; + +public enum EMuscleGroup { + // TODO: Implement + + TORSO(0), + ARMS(1), + LEGS(2), + BALANCE(3); + + int muscleGroupIdentifier; + + EMuscleGroup(int identifier) { + this.muscleGroupIdentifier = identifier; + } + + public int getIdentifier() { + return this.muscleGroupIdentifier; + } + + public static EMuscleGroup parse(int identifier) { + for (EMuscleGroup muscleGroup : EMuscleGroup.values()) { + if (muscleGroup.getIdentifier() == identifier) { + return muscleGroup; + } + } + return null; + } + +} diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/ExerciseUser.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/ExerciseUser.java new file mode 100644 index 0000000..bcf3320 --- /dev/null +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/ExerciseUser.java @@ -0,0 +1,53 @@ +package com.example.fitbot.exercise; + + +/** + * The ExerciseUser class represents a user of the exercise application. + * This contains all necessary information of the current user. + */ +public class ExerciseUser { + + public float upperArmLength; + public float lowerArmLength; + public float upperLegLength; + public float lowerLegLength; + public float height; + + /** + * Constructor for the ExerciseUser class. + * @param upperArmLength The length of the upper arm. + * @param lowerArmLength The length of the lower arm. + * @param height The height of the user. + * @param upperLegLength The length of the upper leg. + * @param lowerLegLength The length of the lower leg. + */ + public ExerciseUser(float upperArmLength, float lowerArmLength, float height, float upperLegLength, float lowerLegLength) { + this.upperArmLength = upperArmLength; + this.lowerArmLength = lowerArmLength; + this.upperLegLength = upperLegLength; + this.lowerLegLength = lowerLegLength; + this.height = height; + } + + /** + * Constructor for the ExerciseUser class. + * @param height The height of the user. + */ + public ExerciseUser(float height) { + this.height = height; + this.upperArmLength = height * 0.2f; + this.lowerArmLength = height * 0.2f; + this.upperLegLength = height * 0.3f; + this.lowerLegLength = height * 0.3f; + } + + /** + * Default constructor for the ExerciseUser class. + * This sets the default height to 180.0f. (1.80m) + */ + public ExerciseUser() { + this(180.0f); + } + + +} diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/FitnessManager.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/FitnessManager.java new file mode 100644 index 0000000..ada8292 --- /dev/null +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/FitnessManager.java @@ -0,0 +1,113 @@ +package com.example.fitbot.exercise; + +import com.example.fitbot.util.path.GesturePath; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import org.joml.Vector3f; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Constructor; +import java.net.URL; +import java.net.URLConnection; + +public class FitnessManager { + + private static final String HOST_ADDRESS = "http://145.92.8.132"; + + private static final String PROPERTY_DESC = "description"; + private static final String PROPERTY_VECTORS = "vector_data"; + private static final String PROPERTY_NAME = "name"; + private static final String PROPERTY_MUSCLE_GROUP = "muscle_group"; + + private static String sendHTTP(String url, String method, String contentType, String body) { + try { + URLConnection connection = new URL(url).openConnection(); + connection.addRequestProperty("Content-Type", contentType); + connection.addRequestProperty("Request-Method", method); + connection.getOutputStream().write(body.getBytes()); + connection.connect(); + InputStream stream = connection.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); + StringBuilder builder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + builder.append(line); + } + return builder.toString(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + /** + * Function for retrieving an exercise from the Raspberry Pi Database. + * + * @param uniqueIdentifier The unique identifier of the exercise + * @return The exercise, if it exists on the server. Otherwise null. + */ + public static AbstractExercise acquireExercise(String uniqueIdentifier, Class referenceClass) { + String response = sendHTTP( + HOST_ADDRESS + "/acquire", "GET", "application/json", "{\"kind\":\"" + uniqueIdentifier + "\"}" + ); + // Validate the response + if (response != null) { + try { + JsonObject content = JsonParser.parseString(response).getAsJsonObject(); + Constructor constructor = referenceClass.getConstructor(referenceClass); + T instance = null; + try { + instance = constructor.newInstance( + EMuscleGroup.parse(content.get(PROPERTY_MUSCLE_GROUP).getAsInt()), + gesturePathFromString(content.get(PROPERTY_VECTORS).getAsString()) + ); + } catch (Exception e) { + e.printStackTrace(); + } + return instance; + } catch (Exception e) { + e.printStackTrace(); + } + } + return null; + } + + /** + * Function for converting a string to a GesturePath object. + * The input string bytes will be directly converted into 3d vectors. + * Every coordinate is composed of 32 bits, so four characters per coordinate. + * + * @param input The string to convert + * @return The GesturePath object + */ + private static GesturePath gesturePathFromString(String input) { + byte[] bytes = input.getBytes(); + + // Check if the input string contains a valid amount of bytes (12 bytes per vector) + if (input.length() % 12 != 0) { + throw new IllegalArgumentException("Invalid input string length"); + } + GesturePath.Builder builder = new GesturePath.Builder(); + + float[] xyz = new float[3]; + for (int i = 0; i < bytes.length; i += 12) { + for (int j = 0; j < 3; j++) { + xyz[j] = Float.intBitsToFloat( + (bytes[i + j * 4] & 0xFF) << 24 | + (bytes[i + j * 4 + 1] & 0xFF) << 16 | + (bytes[i + j * 4 + 2] & 0xFF) << 8 | + (bytes[i + j * 4 + 3] & 0xFF) + ); + } + builder.addVector(new Vector3f( + xyz[0], xyz[1], xyz[2] + )); + } + return builder.build(); + } + +} diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/sports/ESportType.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/sports/ESportType.java deleted file mode 100644 index 4ea7606..0000000 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/sports/ESportType.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.example.fitbot.sports; - -public enum ESportType { - - FITNESS("Fitness"), - POWER("Krachttrening"); - - private final String name; - - ESportType(String name) { - this.name = name; - } - - public String getName() { - return name; - } - -} diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/SportPreviewActivity.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/SportPreviewActivity.java deleted file mode 100644 index ce952bc..0000000 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/SportPreviewActivity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.example.fitbot.ui; - -import com.aldebaran.qi.sdk.QiContext; -import com.aldebaran.qi.sdk.RobotLifecycleCallbacks; -import com.aldebaran.qi.sdk.design.activity.RobotActivity; - -public class SportPreviewActivity extends RobotActivity implements RobotLifecycleCallbacks { - - - @Override - public void onRobotFocusGained(QiContext qiContext) { - - } - - @Override - public void onRobotFocusLost() { - - } - - @Override - public void onRobotFocusRefused(String reason) { - - } -} diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/CompletionActivity.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/CompletionActivity.java new file mode 100644 index 0000000..8cc269b --- /dev/null +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/CompletionActivity.java @@ -0,0 +1,4 @@ +package com.example.fitbot.ui.activities; + +public class CompletionActivity { +} diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/FitnessActivity.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/FitnessActivity.java new file mode 100644 index 0000000..196a65b --- /dev/null +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/FitnessActivity.java @@ -0,0 +1,29 @@ +package com.example.fitbot.ui.activities; + +import android.os.Bundle; +import com.aldebaran.qi.sdk.QiContext; +import com.aldebaran.qi.sdk.RobotLifecycleCallbacks; +import com.aldebaran.qi.sdk.design.activity.RobotActivity; + +public class FitnessActivity extends RobotActivity implements RobotLifecycleCallbacks { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public void onRobotFocusGained(QiContext qiContext) { + // Implement your logic when the robot focus is gained + } + + @Override + public void onRobotFocusLost() { + // Implement your logic when the robot focus is lost + } + + @Override + public void onRobotFocusRefused(String reason) { + // Implement your logic when the robot focus is refused + } +} diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/MainActivity.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/MainActivity.java new file mode 100644 index 0000000..949e2b0 --- /dev/null +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/MainActivity.java @@ -0,0 +1,53 @@ +package com.example.fitbot.ui.activities; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.support.design.widget.NavigationView; +import android.support.v4.view.GravityCompat; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBarDrawerToggle; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; + +import com.example.fitbot.R; + +public class MainActivity extends AppCompatActivity { + + //Variables + DrawerLayout drawerLayout; + NavigationView navigationView; + Toolbar toolbar; + + @SuppressLint("WrongViewCast") + @Override + protected void onCreate (Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + /*---Hooks---*/ + drawerLayout = findViewById(R.id.drawer_layout); + navigationView = findViewById(R.id.nav_view); + toolbar = findViewById(R.id.toolbar); + + /*---Tool Bar---*/ +// setSupportActionBar(toolbar); + + /*---Navigation Drawer Menu---*/ + navigationView.bringToFront(); + + ActionBarDrawerToggle toggle=new + ActionBarDrawerToggle(this,drawerLayout,toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); + drawerLayout.addDrawerListener(toggle); + toggle.syncState(); + } + + @Override + public void onBackPressed(){ + if(drawerLayout.isDrawerOpen(GravityCompat.START)){ + drawerLayout.closeDrawer(GravityCompat.START); + } + else + {super.onBackPressed(); + } + } +} diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/components/PersonalMotionPreviewElement.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/components/PersonalMotionPreviewElement.java index b5161d8..32631ee 100644 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/components/PersonalMotionPreviewElement.java +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/components/PersonalMotionPreviewElement.java @@ -2,42 +2,164 @@ package com.example.fitbot.ui.components; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.Path; import android.view.View; -import com.example.fitbot.util.processing.GesturePath; +import com.example.fitbot.util.path.GesturePath; +import com.example.fitbot.util.path.PathSegment; import com.example.fitbot.util.processing.MotionData; import com.example.fitbot.util.processing.MotionProcessor; -import com.example.fitbot.util.processing.Vector3; + +import org.joml.Matrix4f; +import org.joml.Vector2f; +import org.joml.Vector3f; +import org.joml.Vector4f; public class PersonalMotionPreviewElement extends View { private GesturePath path; private double pathTime = 0.0D; // The timestamp at which the path is currently at. private MotionProcessor motionProcessor; - private Path targetPath, personalPath; + private Path referencePath, performingPath; + private Paint referencePaint, performingPaint; /** - * Method that calculates the path that will be drawn on the - * canvas. This method will be called every time new motion data is received. + * Constants for the preview path projection. */ - private void calculateDrawingPath(Vector3 transformedVector, MotionData motionData, int sampleIndex, double sampleRate) { - - } - + private final float FOV = 70.0f; // The field of view of the preview path + private final float Z_NEAR = 0.1f; // The near clipping plane + private final float Z_FAR = 1000.0f; // The far clipping plane + private Vector3f cameraPosition = new Vector3f(0.0f, 0.0f, 0.0f); // The position of the camera + private Vector2f screenDimensions = new Vector2f(); // Width and height dimensions of the screen + private Vector2f rotation = new Vector2f(); // Rotation vector (yaw, pitch) + /** + * Constructor for the PersonalMotionPreviewElement class. + * + * @param context The context in which this element is created. + * @param path The gesture path that will be drawn on the canvas. + */ public PersonalMotionPreviewElement(Context context, GesturePath path) { super(context); this.path = path; this.motionProcessor = new MotionProcessor(); this.motionProcessor.startListening(); - this.motionProcessor.setMotionDataEventHandler(this::calculateDrawingPath); - this.targetPath = new Path(); - this.personalPath = new Path(); + this.motionProcessor.setMotionDataEventHandler((processed, preprocessed, sampleIndex, sampleRate) -> { + // TODO: Implement the calculation of the `performingPath` based on the motion data + }); + + this.referencePath = getDrawablePath(path.getSegments()); + this.performingPath = new Path(); + + this.referencePaint = new Paint(); + this.referencePaint.setColor(-1); // White + this.referencePaint.setStyle(Paint.Style.STROKE); + this.referencePaint.setStrokeWidth(5.0f); + this.performingPaint = new Paint(); + this.performingPaint.setColor(0xFF0000FF); // Blue + this.performingPaint.setStyle(Paint.Style.STROKE); + this.performingPaint.setStrokeWidth(5.0f); } + /** + * Method that calculates the path that will be drawn on the + * canvas. This method will be called every time new motion data is received. + */ + private void calculateDrawingPath(Vector3f transformedVector, MotionData motionData, int sampleIndex, double sampleRate) { + // Recalculate the personal path based on the new motion data + + } + + /** + * Method for setting the gesture path that will be drawn on the canvas. + * + * @param path The gesture path to draw. + */ + public void setGesturePath(GesturePath path) { + this.path = path; + this.referencePath = getDrawablePath(path.getSegments()); + } + + /** + * Method for setting the rotation of the preview path. + * + * @param yaw The yaw rotation of the preview path. + * @param pitch The pitch rotation of the preview path. + */ + public void setRotation(float yaw, float pitch) { + this.rotation.set(Math.toRadians(yaw), Math.toRadians(pitch)); + } + + /** + * Method for projecting a 3D point onto the screen. + * This method converts the 3D point to 2D space using a Model-View-Projection matrix transformation. + * + * @param point The point to cast to the screen. + * @param virtualWidth The width of the virtual screen. + * This is used to normalize the screen coordinates. + * @param virtualHeight The height of the virtual screen. + * @return The transformed vector in screen coordinates ranging from (0, 0) to (virtualWidth, virtualHeight). + */ + private Vector2f projectVertex(Vector3f point, int virtualWidth, int virtualHeight) { + + Matrix4f modelViewMatrix = new Matrix4f() + .rotateX((float) Math.toRadians(rotation.x)) + .rotateY((float) Math.toRadians(rotation.y)) + .translate(cameraPosition); + + Matrix4f projectionMatrix = new Matrix4f() + .perspective((float) Math.toRadians(FOV), (float) virtualWidth / virtualHeight, Z_NEAR, Z_FAR); + + // Calculate Model-View-Projection matrix + Matrix4f MVP = new Matrix4f() + .set(projectionMatrix) + .mul(modelViewMatrix); + + // Convert to screen coordinates + Vector4f screenCoordinates = new Vector4f(point, 1.0f) + .mul(MVP); + + // Normalize screen coordinates from (-1, 1) to (0, virtualWidth) and (0, virtualHeight) + float normalizedX = (screenCoordinates.x / screenCoordinates.w + 1.0f) * 0.5f * virtualWidth; + float normalizedY = (1.0f - screenCoordinates.y / screenCoordinates.w) * 0.5f * virtualHeight; + + return new Vector2f(normalizedX, normalizedY); + } + + /** + * Method that converts a sequence of vectors to a Path object. + * This path is a set of bezier curves that will be drawn on the canvas. + * + * @param segments The path segments in the path. + * These segments will be connected by bezier curves, which + * all have unique curvature values. + * @return The generated path object. + */ + private Path getDrawablePath(PathSegment... segments) { + + Path calculatedPath = new Path(); + + // Starting point + Vector2f origin = projectVertex(segments[0].getStart(), getWidth(), getHeight()); + calculatedPath.moveTo(origin.x, origin.y); + + // Draw the path segments + for (PathSegment segment : segments) { + Vector2f startProjected = projectVertex(segment.getStart(), getWidth()/2, getHeight()); + Vector2f endProjected = projectVertex(segment.getEnd(), getWidth()/2, getHeight()); + calculatedPath.lineTo(startProjected.x, startProjected.y); + calculatedPath.lineTo(endProjected.x, endProjected.y); + } + + return calculatedPath; + } + + @Override public void onDraw(Canvas canvas) { // Draw the sport preview canvas + canvas.drawPath(referencePath, referencePaint); + canvas.drawPath(performingPath, performingPaint); } } diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/GesturePath.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/GesturePath.java new file mode 100644 index 0000000..88c41ad --- /dev/null +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/GesturePath.java @@ -0,0 +1,121 @@ +package com.example.fitbot.util.path; + +import org.joml.Vector3f; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class GesturePath { + + // The vectors that make up the path. + private final PathSegment[] segments; + + public GesturePath(Vector3f[] vectors) { + this(vectors, 0.0D); + } + + /** + * Create a new gesture path with a given set of vectors and curvature. + * + * @param vectors The vectors that make up the path. + * @param curvature The curvature of the path. + */ + public GesturePath(Vector3f[] vectors, double curvature) + { + if ( vectors.length < 2) + throw new IllegalArgumentException("A path must have at least two points."); + + this.segments = new PathSegment[vectors.length - 1]; + for ( int i = 0; i < vectors.length - 1; i++) + segments[i] = new PathSegment(vectors[i], vectors[i + 1]); + } + + /** + * Constructor for a GesturePath with provided PathSegments. + * @param segments The PathSegments to initialize the path with. + */ + public GesturePath(PathSegment... segments) { + this.segments = segments; + } + + /** + * Getter method for retrieving the path segments of this GesturePath. + * + * @return The path segments. + */ + public PathSegment[] getSegments() { + return segments; + } + + /** + * Method for retrieving the closest path segment to a reference point. + * + * @param reference The reference point to find the closest path segment to. + * @return The closest path segment to the reference point. + */ + public PathSegment closest(Vector3f reference) { + // If there's only one segment, return that one. + if ( segments.length == 1) + return segments[0]; + + return Arrays + .stream(segments) + .reduce(segments[0], (a, b) -> PathSegment.closer(a, b, reference)); + } + + /** + * Get the error between an arbitrary path segment and the reference point. + * + * @param referencePoint The reference point to calculate the error of. + * @return The error offset between the path and the reference point. + */ + public double getError(Vector3f referencePoint) { + return closest(referencePoint).difference(referencePoint); // Get the closest segment and calculate the error. + } + + // Builder class for the GesturePath object. + public static class Builder { + + // List of vectors to add to the GesturePath object. + private final List vectors; + + /** + * Constructor for the Builder object. + * + * @param vectors The list of vectors to add. + */ + public Builder(List vectors) { + this.vectors = vectors; + } + + /** + * Default constructor for the Builder object. + */ + public Builder() { + this.vectors = new ArrayList<>(); + } + + /** + * Adds a vector to the GesturePath object. + * + * @param vector The vector to add. + * @return The Builder object. + */ + public Builder addVector(Vector3f vector) { + vectors.add(vector); + return this; + } + + /** + * Builds the GesturePath object. + * + * @return The GesturePath object. + */ + public GesturePath build() { + return new GesturePath(vectors.toArray(new Vector3f[0])); + } + + } + +} diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/PathSegment.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/PathSegment.java new file mode 100644 index 0000000..11183ca --- /dev/null +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/PathSegment.java @@ -0,0 +1,105 @@ +package com.example.fitbot.util.path; + +import org.joml.Vector3f; + +public class PathSegment { + + private final Vector3f start, end; + private final double distance; + + /** + * Constructor for creating a PathSegment of two lines, with the normal vector + * pointing straight upwards relative to the line, with a curvature of 0.0. + * + * @param start The starting point of the line segment + * @param end The end point of the line segment. + */ + public PathSegment(Vector3f start, Vector3f end) { + this.start = start; + this.end = end; + this.distance = start.distance(end); + } + + /** + * Method that interpolates between the start and end points of the path segment, + * depending on the curvature of the curve. If the curvature is unset, or set to 0 + * then this method will use linear interpolation. Otherwise, it will use a curve. + * + * @param t The interpolation value between 0 and 1. + */ + public Vector3f interpolate(double t) { + return new Vector3f(this.start) + .lerp(this.end, (float) Math.min(1.0F, Math.max(0.0F, t))); + } + + /** + * Method for calculating the difference between the provided vector and the + * path segment, depending on the normal vector and the curvature. + * If the provided vector does not lie on the path segment, this method will return + * the linear distance to the path. + * + * @param other The vector to calculate the difference to. + * @return The difference between the vector and the path segment. + */ + public double difference(Vector3f other) { + + if (this.distance == 0) + return this.start.distance(other); + + double t = ((other.x - this.start.x) * (this.end.x - this.start.x) + + (other.y - this.start.y) * (this.end.y - this.start.y) + + (other.z - this.start.z) * (this.end.z - this.start.z)) / distance; + + t = Math.max(0, Math.min(1, t)); + + return other.distance(new Vector3f( + (float) (this.start.x + t * (this.end.x - this.start.x)), + (float) (this.start.y + t * (this.end.y - this.start.y)), + (float) (this.start.z + t * (this.end.z - this.start.z)) + )); + } + + /** + * Get the normal vector of the path segment. + * + * @return The normal vector of the path segment. + */ + public Vector3f getStart() { + return start; + } + + /** + * Get the end point of the path segment. + * + * @return The end point of the path segment. + */ + public Vector3f getEnd() { + return end; + } + + /** + * Method for returning the distance to the closest point on the path segment. + * + * @param reference The reference point to calculate the distance to. + * @return The distance to the closest point on the path segment. + */ + public double distance(Vector3f reference) { + if ( this.start.distanceSquared(reference) > this.end.distanceSquared(reference)) + return this.end.distance(reference); + return this.start.distance(reference); + } + + /** + * Function for returning the closest path segment to a reference point. + * + * @param first The first path segment to compare. + * @param second The second path segment to compare. + * @param referencePoint The reference point to compare to. + * @return The closest path segment to the reference point. + */ + public static PathSegment closer(PathSegment first, PathSegment second, Vector3f referencePoint) { + if (first.distance(referencePoint) < second.distance(referencePoint)) + return first; + return second; + } +} diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/GesturePath.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/GesturePath.java deleted file mode 100644 index 451de9d..0000000 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/GesturePath.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.example.fitbot.util.processing; - -import java.util.ArrayList; -import java.util.List; - -public class GesturePath { - - // The vectors that make up the path. - private final Vector3[] vectors; - - public GesturePath(Vector3[] vectors) { - this.vectors = vectors; - } - - /** - * Get the error between an arbitrary path segment and the reference point. - * - * @param referencePoint The reference point to calculate the error of. - * @return The error offset between the path and the reference point. - */ - public double getError(Vector3 referencePoint) { - // If there are no vectors, return 0. - if ( vectors.length == 0) - return 0; - - // If there's only one vector, return the distance to that vector. - if ( vectors.length == 1) - return vectors[0].distance(referencePoint); - - double distance = Double.MAX_VALUE; - double currentDistSq, nextDistSq; - int closestVectorIdx = 0; - - // Acquire two closest points to the reference point. - for ( int i = 0; i < vectors.length - 1; i++) { - currentDistSq = vectors[i].distanceSq(referencePoint); - nextDistSq = vectors[i + 1].distanceSq(referencePoint); - - if ( currentDistSq < distance) { - distance = currentDistSq; - closestVectorIdx = i; - } else if ( nextDistSq < distance) { - distance = nextDistSq; - closestVectorIdx = i + 1; - i++; // Skip the next iteration; this point is already closer. - } - } - - // Calculate the error between the two closest points. - Vector3 pointB = (closestVectorIdx == vectors.length - 1) ? - vectors[closestVectorIdx - 1] : // If the closest point is the last point, use the 1 to last one - (closestVectorIdx > 0 && // Find the closer point between the surrounding points. - (vectors[closestVectorIdx - 1].distanceSq(referencePoint) < vectors[closestVectorIdx + 1].distanceSq(referencePoint))) ? - vectors[closestVectorIdx - 1] : - vectors[closestVectorIdx + 1]; - - return referencePoint.distanceToLine(vectors[closestVectorIdx], pointB); - } - - // Builder class for the GesturePath object. - public static class Builder { - - // List of vectors to add to the GesturePath object. - private final List vectors; - - /** - * Constructor for the Builder object. - * - * @param vectors The list of vectors to add. - */ - public Builder(List vectors) { - this.vectors = vectors; - } - - /** - * Default constructor for the Builder object. - */ - public Builder() { - this.vectors = new ArrayList<>(); - } - - /** - * Adds a vector to the GesturePath object. - * - * @param vector The vector to add. - * @return The Builder object. - */ - public Builder addVector(Vector3 vector) { - vectors.add(vector); - return this; - } - - /** - * Builds the GesturePath object. - * - * @return The GesturePath object. - */ - public GesturePath build() { - return new GesturePath(vectors.toArray(new Vector3[0])); - } - - } - -} diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/IMotionDataConsumer.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/IMotionDataConsumer.java new file mode 100644 index 0000000..b09726d --- /dev/null +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/IMotionDataConsumer.java @@ -0,0 +1,16 @@ +package com.example.fitbot.util.processing; + +import org.joml.Vector3f; + +public interface IMotionDataConsumer { + + /** + * Function for accepting motion data and the transformed vector. + * @param transformedVector The transformed vector. + * @param motionData The input motion data. + * @param sampleIndex The index of the current sample + * @param sampleRate The sample rate. + */ + void accept(Vector3f transformedVector, MotionData motionData, int sampleIndex, double sampleRate); + +} \ No newline at end of file diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionData.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionData.java index 2c10030..37e016f 100644 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionData.java +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionData.java @@ -1,11 +1,13 @@ package com.example.fitbot.util.processing; +import org.joml.Vector3f; + import java.util.Objects; public class MotionData { // Data of the motion sensor - public Vector3 acceleration, rotation; + public Vector3f acceleration, rotation; // Delimiter for the data received from the motion sensor private static final String DATA_DELIMITER = ";"; @@ -20,9 +22,9 @@ public class MotionData { * @param rotationY The rotation in the Y axis in degrees. * @param rotationZ The rotation in the Z axis in degrees. */ - public MotionData(double accelerationX, double accelerationY, double accelerationZ, double rotationX, double rotationY, double rotationZ) { - this.acceleration = new Vector3(accelerationX, accelerationY, accelerationZ); - this.rotation = new Vector3(rotationX, rotationY, rotationZ); + public MotionData(float accelerationX, float accelerationY, float accelerationZ, float rotationX, float rotationY, float rotationZ) { + this.acceleration = new Vector3f(accelerationX, accelerationY, accelerationZ); + this.rotation = new Vector3f(rotationX, rotationY, rotationZ); } /** @@ -31,7 +33,7 @@ public class MotionData { * @param acceleration The acceleration vector in m/s^2. * @param rotation The rotation vector in degrees. */ - public MotionData(Vector3 acceleration, Vector3 rotation) { + public MotionData(Vector3f acceleration, Vector3f rotation) { this.acceleration = acceleration; this.rotation = rotation; } @@ -52,12 +54,12 @@ public class MotionData { return null; return new MotionData( - Double.parseDouble(parts[0]), - Double.parseDouble(parts[1]), - Double.parseDouble(parts[2]), - Double.parseDouble(parts[3]), - Double.parseDouble(parts[4]), - Double.parseDouble(parts[5]) + Float.parseFloat(parts[0]), + Float.parseFloat(parts[1]), + Float.parseFloat(parts[2]), + Float.parseFloat(parts[3]), + Float.parseFloat(parts[4]), + Float.parseFloat(parts[5]) ); } } diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionProcessor.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionProcessor.java index 43539ba..9a04461 100644 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionProcessor.java +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionProcessor.java @@ -2,10 +2,12 @@ package com.example.fitbot.util.processing; import android.util.Log; +import com.example.fitbot.util.path.GesturePath; import com.example.fitbot.util.server.IWebSocketHandler; import com.example.fitbot.util.server.WebSocket; import org.jetbrains.annotations.NotNull; +import org.joml.Vector3f; import java.util.ArrayList; import java.util.List; @@ -16,10 +18,11 @@ public class MotionProcessor { public static final String DELIMITER = ";"; private final List preprocessedData = new ArrayList<>(); // Preprocessed motion data - private final List relativePath = new ArrayList<>(); // Relative path of the motion data - private Vector3 ZERO = new Vector3(0, 0, 0); - private double sampleRate = 1.0D; // samples/second - private DataConsumer motionDataConsumer = (p1, p2, p3, p4) -> {}; + private final List relativePath = new ArrayList<>(); // Relative path of the motion data + private Vector3f ZERO = new Vector3f(0, 0, 0); + + private float sampleRate = 1.0F; // samples/second + private IMotionDataConsumer motionDataConsumer = (p1, p2, p3, p4) -> {}; private GesturePath path; private WebSocket socket; @@ -77,14 +80,14 @@ public class MotionProcessor { // Otherwise check if it starts with 'calibrate', this is the ZERO point. } else if ( data.startsWith("zero")) { // message to calibrate device String[] vectorData = data.split(" ")[1].split(DELIMITER); - ZERO = new Vector3( + ZERO = new Vector3f( Float.parseFloat(vectorData[0]), Float.parseFloat(vectorData[1]), Float.parseFloat(vectorData[2]) ); Log.i("MotionProcessor", "Device calibrated at " + ZERO.toString()); } else if ( data.startsWith("sampleRate")) { - this.sampleRate = Double.parseDouble(data.split(" ")[1]); + this.sampleRate = Float.parseFloat(data.split(" ")[1]); } } @@ -104,8 +107,8 @@ public class MotionProcessor { */ public void addMotionData(MotionData data) { preprocessedData.add(data); - Vector3 previous = this.relativePath.isEmpty() ? ZERO : this.relativePath.get(this.relativePath.size() - 1); - Vector3 relativeVector = getRelativeVector(data).add(previous); + Vector3f previous = this.relativePath.isEmpty() ? ZERO : this.relativePath.get(this.relativePath.size() - 1); + Vector3f relativeVector = getRelativeVector(data).add(previous); this.relativePath.add(relativeVector); motionDataConsumer.accept(relativeVector, data, this.relativePath.size(), this.sampleRate); } @@ -115,7 +118,7 @@ public class MotionProcessor { * * @param relativePath The new relative path. */ - public void setRelativePath(List relativePath) { + public void setRelativePath(List relativePath) { this.relativePath.clear(); this.relativePath.addAll(relativePath); } @@ -124,7 +127,7 @@ public class MotionProcessor { * Function for setting the motion data receiver. * @param consumer The consumer to set. */ - public void setMotionDataEventHandler(DataConsumer consumer) { + public void setMotionDataEventHandler(IMotionDataConsumer consumer) { if ( consumer != null) this.motionDataConsumer = consumer; } @@ -138,15 +141,17 @@ public class MotionProcessor { * @param motionData The motion data to calculate the relative vector for. * @return The relative vector of the motion data. */ - public Vector3 getRelativeVector(MotionData motionData) { + public Vector3f getRelativeVector(MotionData motionData) { // Rotate the acceleration vector back by the rotation vector to make it // perpendicular to the gravity vector, then apply double integration to get the relative position. // s = 1/2 * a * t^2 return motionData.acceleration - .rotate(motionData.rotation.negate()) - .divide(2) - .multiply(sampleRate * sampleRate); + .rotateX(-motionData.rotation.x) + .rotateY(-motionData.rotation.y) + .rotateZ(-motionData.rotation.z) + .div(2) + .mul(sampleRate * sampleRate); } /** @@ -185,7 +190,7 @@ public class MotionProcessor { * @param referencePoint The reference point to compare the motion data to. * @return The error of the motion data compared to the reference path. */ - public double getError(GesturePath path, Vector3 referencePoint) + public double getError(GesturePath path, Vector3f referencePoint) { return path.getError(referencePoint); } @@ -197,7 +202,7 @@ public class MotionProcessor { * @param referencePoint The reference point to compare the path data to. * @return The error of the motion data compared to the reference path. */ - public double getError(Vector3 referencePoint) { + public double getError(Vector3f referencePoint) { if ( path == null) return 0; return path.getError(referencePoint); @@ -241,19 +246,4 @@ public class MotionProcessor { Log.i("MotionProcessor", "Sample rate: " + sampleRate); Log.i("MotionProcessor", "Calibration point: " + ZERO.toString()); } - - /** - * Interface that accepts motion data and the transformed vector. - */ - public interface DataConsumer { - - /** - * Function for accepting motion data and the transformed vector. - * @param transformedVector The transformed vector. - * @param motionData The input motion data. - * @param sampleIndex The index of the current sample - * @param sampleRate The sample rate. - */ - void accept(Vector3 transformedVector, MotionData motionData, int sampleIndex, double sampleRate); - } } diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/Vector3.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/Vector3.java deleted file mode 100644 index 47c251c..0000000 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/Vector3.java +++ /dev/null @@ -1,258 +0,0 @@ -package com.example.fitbot.util.processing; - -import java.util.Arrays; -import java.util.Comparator; - -public class Vector3 { - - public double x, y, z; - - /** - * Constructor for creating a new vector. - * - * @param x The X component of the vector. - * @param y The Y component of the vector. - * @param z The Z component of the vector. - */ - public Vector3(double x, double y, double z) { - this.x = x; - this.y = y; - this.z = z; - } - - /** - * Copy the vector. - * - * @return A new vector with the same values. - */ - public Vector3 copy() { - return new Vector3(this.x, this.y, this.z); - } - - /** - * Get the zero vector. - * - * @return The zero vector. - */ - public static Vector3 zero() { - return new Vector3(0, 0, 0); - } - - /** - * Get the magnitude of the vector. - * - * @return The magnitude of the vector. - */ - public double magnitude() { - return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); - } - - /** - * Normalize the vector. - * - * @return The normalized vector. - */ - public Vector3 normalize() { - double mag = this.magnitude(); - if (mag == 0) throw new IllegalArgumentException("Cannot normalize the zero vector."); - return new Vector3(this.x / mag, this.y / mag, this.z / mag); - } - - /** - * Subtract the vector from another vector. - * - * @param other The other vector to subtract. - * @return The new vector. - */ - public Vector3 subtract(Vector3 other) { - return new Vector3(this.x - other.x, this.y - other.y, this.z - other.z); - } - - /** - * Add the vector to another vector. - * - * @param other The other vector to add. - * @return The new vector. - */ - public Vector3 add(Vector3 other) { - return new Vector3(this.x + other.x, this.y + other.y, this.z + other.z); - } - - /** - * Multiply the vector by a scalar. - * - * @param scalar The scalar to multiply by. - * @return The multiplied vector. - */ - public Vector3 multiply(double scalar) { - return new Vector3(this.x * scalar, this.y * scalar, this.z * scalar); - } - - /** - * Divide the vector by a scalar. - * - * @param scalar The scalar to divide by. - * @return The divided vector. - */ - public Vector3 divide(double scalar) { - if (scalar == 0) throw new IllegalArgumentException("Cannot divide by zero."); - return new Vector3(this.x / scalar, this.y / scalar, this.z / scalar); - } - - /** - * Negate the vector. - * - * @return The negated vector. - */ - public Vector3 negate() { - return new Vector3(-this.x, -this.y, -this.z); - } - - /** - * Rotate the vector around the X, Y, and Z axes. - * - * @param radX Rotation around the X axis in radians. - * @param radY Rotation around the Y axis in radians. - * @param radZ Rotation around the Z axis in radians. - * @return The rotated vector. - */ - public Vector3 rotate(double radX, double radY, double radZ) { - double cosX = Math.cos(radX); - double cosY = Math.cos(radY); - double cosZ = Math.cos(radZ); - double sinX = Math.sin(radX); - double sinY = Math.sin(radY); - double sinZ = Math.sin(radZ); - double newX = x * cosY * cosZ + y * cosY * sinZ - z * sinY; - double newY = x * (sinX * sinY * cosZ - cosX * sinZ) + y * (sinX * sinY * sinZ + cosX * cosZ) + z * sinX * cosY; - double newZ = x * (cosX * sinY * cosZ + sinX * sinZ) + y * (cosX * sinY * sinZ - sinX * cosZ) + z * cosX * cosY; - return new Vector3(newX, newY, newZ); - } - - /** - * Rotate the vector around the X, Y, and Z axes. - * - * @param rotation The rotation vector. - * @return The rotated vector. - */ - public Vector3 rotate(Vector3 rotation) { - return rotate(rotation.x, rotation.y, rotation.z); - } - - /** - * Rotate the vector around the X axis. - * - * @param angle Rotation around the X axis in radians. - * @return The rotated vector. - */ - public Vector3 rotateX(double angle) { - double sinTheta = Math.sin(angle); - double cosTheta = Math.cos(angle); - return new Vector3( - x, - y * cosTheta - z * sinTheta, - y * sinTheta + z * cosTheta - ); - } - - /** - * Rotate the vector around the Y axis. - * - * @param angle Rotation around the Y axis in radians. - * @return The rotated vector. - */ - public Vector3 rotateY(double angle) { - double sinTheta = Math.sin(angle); - double cosTheta = Math.cos(angle); - return new Vector3( - x * cosTheta + z * sinTheta, - y, - -x * sinTheta + z * cosTheta - ); - } - - /** - * Rotate the vector around the Z axis. - * - * @param angle Rotation around the Z axis in radians. - * @return The rotated vector. - */ - public Vector3 rotateZ(double angle) { - double sinTheta = Math.sin(angle); - double cosTheta = Math.cos(angle); - return new Vector3( - x * cosTheta - y * sinTheta, - x * sinTheta + y * cosTheta, - z - ); - } - - /** - * Get the squared distance between this vector and another vector. - * - * @param compare The other vector. - * @return The squared distance between the two vectors. - */ - public double distanceSq(Vector3 compare) { - return Math.pow(compare.x - x, 2) + Math.pow(compare.y - y, 2) + Math.pow(compare.z - z, 2); - } - - /** - * Get the distance between this vector and another vector. - * - * @param compare The other vector. - * @return The distance between the two vectors. - */ - public double distance(Vector3 compare) { - return Math.sqrt(distanceSq(compare)); - } - - /** - * Calculate the distance to a line defined by two points. - * - * @param lineStart The starting point of the line. - * @param lineEnd The ending point of the line. - * @return The distance to the line. - */ - public double distanceToLine(Vector3 lineStart, Vector3 lineEnd) { - double lineDistance = lineStart.distanceSq(lineEnd); - if (lineDistance == 0) - return this.distanceSq(lineStart); - - double t = ((this.x - lineStart.x) * (lineEnd.x - lineStart.x) + - (this.y - lineStart.y) * (lineEnd.y - lineStart.y) + - (this.z - lineStart.z) * (lineEnd.z - lineStart.z)) / lineDistance; - - t = Math.max(0, Math.min(1, t)); - - return this.distanceSq(new Vector3( - lineStart.x + t * (lineEnd.x - lineStart.x), - lineStart.y + t * (lineEnd.y - lineStart.y), - lineStart.z + t * (lineEnd.z - lineStart.z)) - ); - } - - /** - * Retrieve the closest vector to this one given a list of vectors. - * - * @param vectors The list of vectors to compare. - * @return The closest vector. - */ - public Vector3 closest(Vector3 ... vectors) { - return Arrays.stream(vectors).min(Comparator.comparingDouble(this::distanceSq)).orElse(null); - } - - public Vector3 map(VectorMapFunction function) { - return function.apply(this); - } - - public interface VectorMapFunction { - Vector3 apply(Vector3 vector); - } - - @Override - public String toString() - { - return "Vector3(" + this.x + ", " + this.y + ", " + this.z + ")"; - } -} diff --git a/code/src/Fitbot/app/src/main/res/layout/activity_fitness.xml b/code/src/Fitbot/app/src/main/res/layout/activity_fitness.xml new file mode 100644 index 0000000..35990c8 --- /dev/null +++ b/code/src/Fitbot/app/src/main/res/layout/activity_fitness.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/code/src/Fitbot/app/src/main/res/layout/activity_main.xml b/code/src/Fitbot/app/src/main/res/layout/activity_main.xml index 2baee25..901a002 100644 --- a/code/src/Fitbot/app/src/main/res/layout/activity_main.xml +++ b/code/src/Fitbot/app/src/main/res/layout/activity_main.xml @@ -6,7 +6,7 @@ android:layout_height="match_parent" android:background="#232323" android:fitsSystemWindows="true" - tools:context=".MainActivity" + tools:context=".ui.activities.MainActivity" tools:openDrawer="start"> b[class] --> c[Class name] +``` + +## Constructor +A constructor in Java is a special method that is used to initialize objects. The constructor is called when an object of a class is created. It can be used to set initial values for object attributes. + +The constructor Method is the first method that is called when a class is created. It has the same name as the class and no return type. It is automaticly called when a class is created. + +### Methods +A method is a block of code which only runs when it is called. You can pass data, known as parameters, into a method. Methods are used to perform certain actions, and they are also known as functions. + +Methods are build like this +```mermaid +flowchart +A[Access Modifiers] --> B[Method Modifier] --> C[Return Type] --> D[Method Name] --> E[Parameters] --> F[Method Body] +``` + + +Example: +```java +public class MyClass { + // Method + static void myMethod() { + // print Hello World! + System.out.println("Hello World!"); + } + // Main method + //access modifier, Method Modifier, return type, method name, parameters, method body + public static void main(String[] args) { + // Call the method + myMethod(); + } +} +``` + + +### Atributes +Attributes are variables within a class. When an object is created from a class, the object will have these attributes. + +Example: +```java +public class MyClass { + int x = 5; +} +``` + +## Classes +### Class modifiers + +#### Non-access modifiers +| Modifier | Description | | | | +|---|---|---|---|---| +| final | The class cannot be inherited by other classes (You will learn more about inheritance in the Inheritance chapter) | | | | +| abstract | The class cannot be used to create objects (To access an abstract class, it must be inherited from another class. You will learn more about inheritance and abstraction in the Inheritance and Abstraction chapters) | | | | +|||| + +#### Access modifiers +| Modifier | Description | | | | +|---|---|---|---|---| +| public | The code is accessible for all classes | | | | +| private | The code is only accessible within the declared class | | | | +| default | The code is only accessible in the same package. This is used when you don't specify a modifier. You will learn more about packages in the Packages chapter | | | | +| protected | The code is accessible in the same package and subclasses. You will learn more about subclasses and superclasses in the Inheritance chapter | | | | +| | | | | | + + +## Methods and attributes +#### non access modifiers +| Modifier | Description | | | | +|---|---|---|---|---| +| final | Attributes and methods cannot be overridden/modified | | | | +| static | Attributes and methods belongs to the class, rather than an object. You don't really wanna use this one. | | | | +| abstract | Can only be used in an abstract class, and can only be used on methods. The method does not have a body, for example abstract void run();. The body is provided by the subclass (inherited from). You will learn more about inheritance and abstraction in the Inheritance and Abstraction chapters | | | | +| transient | Attributes and methods are skipped when serializing the object containing them | | | | +| synchronized | Methods can only be accessed by one thread at a time | | | | +| volatile | The value of an attribute is not cached thread-locally, and is always read from the "main memory" | | | | +|||| + +#### Access modifiers +| Modifier | Description | | | | +|---|---|---|---|---| +| public | The code is accessible for all classes | | | | +| private | The code is only accessible within the declared class | | | | +| default | The code is only accessible in the same package. This is used when you don't specify a modifier. You will learn more about packages in the Packages chapter | | | | +| protected | The code is accessible in the same package and subclasses. You will learn more about subclasses and superclasses in the Inheritance chapter | | | | +| | | | | | + + +## Sources + +* https://www.w3schools.com/java/java_modifiers.asp diff --git a/docs/documentation/assets/math-expression-acceleration-vector.png b/docs/documentation/assets/math-expression-acceleration-vector.png new file mode 100644 index 0000000..a818694 Binary files /dev/null and b/docs/documentation/assets/math-expression-acceleration-vector.png differ diff --git a/docs/documentation/assets/motion-path-example-path-error.png b/docs/documentation/assets/motion-path-example-path-error.png new file mode 100644 index 0000000..a92c0aa Binary files /dev/null and b/docs/documentation/assets/motion-path-example-path-error.png differ diff --git a/docs/documentation/assets/motion-path-example-vertices.png b/docs/documentation/assets/motion-path-example-vertices.png new file mode 100644 index 0000000..8505cfb Binary files /dev/null and b/docs/documentation/assets/motion-path-example-vertices.png differ diff --git a/docs/documentation/diagrams/assets/.$appDiagram.png.dtmp b/docs/documentation/diagrams/assets/.$appDiagram.png.dtmp deleted file mode 100644 index cc2914b..0000000 --- a/docs/documentation/diagrams/assets/.$appDiagram.png.dtmp +++ /dev/null @@ -1,181 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/documentation/diagrams/assets/appDiagram.png b/docs/documentation/diagrams/assets/appDiagram.png index 41ba8b7..5816953 100644 Binary files a/docs/documentation/diagrams/assets/appDiagram.png and b/docs/documentation/diagrams/assets/appDiagram.png differ diff --git a/docs/documentation/raspberryPi/apache/apache.md b/docs/documentation/raspberry-pi/apache/apache.md similarity index 100% rename from docs/documentation/raspberryPi/apache/apache.md rename to docs/documentation/raspberry-pi/apache/apache.md diff --git a/docs/documentation/raspberryPi/apache/apacheSetup.md b/docs/documentation/raspberry-pi/apache/apacheSetup.md similarity index 100% rename from docs/documentation/raspberryPi/apache/apacheSetup.md rename to docs/documentation/raspberry-pi/apache/apacheSetup.md diff --git a/docs/documentation/raspberryPi/mariaDB/mariaDB.md b/docs/documentation/raspberry-pi/mariaDB/mariaDB.md similarity index 100% rename from docs/documentation/raspberryPi/mariaDB/mariaDB.md rename to docs/documentation/raspberry-pi/mariaDB/mariaDB.md diff --git a/docs/documentation/raspberryPi/mariaDB/mariaDBSetup.md b/docs/documentation/raspberry-pi/mariaDB/mariaDBSetup.md similarity index 100% rename from docs/documentation/raspberryPi/mariaDB/mariaDBSetup.md rename to docs/documentation/raspberry-pi/mariaDB/mariaDBSetup.md diff --git a/docs/documentation/raspberryPi/nodeJs/nodeJs.md b/docs/documentation/raspberry-pi/nodeJs/nodeJs.md similarity index 100% rename from docs/documentation/raspberryPi/nodeJs/nodeJs.md rename to docs/documentation/raspberry-pi/nodeJs/nodeJs.md diff --git a/docs/documentation/raspberryPi/nodeJs/nodeJsSetup.md b/docs/documentation/raspberry-pi/nodeJs/nodeJsSetup.md similarity index 100% rename from docs/documentation/raspberryPi/nodeJs/nodeJsSetup.md rename to docs/documentation/raspberry-pi/nodeJs/nodeJsSetup.md diff --git a/docs/documentation/raspberryPi/phpMyAdmin/phpMyAdmin.md b/docs/documentation/raspberry-pi/phpMyAdmin/phpMyAdmin.md similarity index 100% rename from docs/documentation/raspberryPi/phpMyAdmin/phpMyAdmin.md rename to docs/documentation/raspberry-pi/phpMyAdmin/phpMyAdmin.md diff --git a/docs/documentation/raspberryPi/phpMyAdmin/phpMyAdminSetup.md b/docs/documentation/raspberry-pi/phpMyAdmin/phpMyAdminSetup.md similarity index 100% rename from docs/documentation/raspberryPi/phpMyAdmin/phpMyAdminSetup.md rename to docs/documentation/raspberry-pi/phpMyAdmin/phpMyAdminSetup.md diff --git a/docs/documentation/raspberryPi/raspberryPiSetup.md b/docs/documentation/raspberry-pi/raspberryPiSetup.md similarity index 100% rename from docs/documentation/raspberryPi/raspberryPiSetup.md rename to docs/documentation/raspberry-pi/raspberryPiSetup.md diff --git a/docs/documentation/research-questions/motion-tracking-system-analysis.md b/docs/documentation/research-questions/motion-tracking-system-analysis.md new file mode 100644 index 0000000..9a349ea --- /dev/null +++ b/docs/documentation/research-questions/motion-tracking-system-analysis.md @@ -0,0 +1,50 @@ +## Analysis for Motion Tracking System on the Pepper Robot. + +--- + +For our project, we want our users to be able to see the movement they're making, so they can +see whether they're executing the fitness task correctly. For a tracking system as such, we'll need to use quite +some mathematics. + +Our current approach is defining the required path by a set of vertices; points in 3d space. +These points define along which path the user has to move their limbs to, depending on what the activity is +and where they've placed the tracking devices. + +A path can look like the following + +Path Point Example + +To be able to measure the position of our tracking device, we'll have to use sensors that allow us +to retrieve useful information that can provide us with either position or velocity. The device will have +to be calibrated initially, of course, due to position being relative. + +To acquire our measurements, we've chosen for the following configuration for the tracking device: + +- ESP8266 (Wi-Fi only) +- Accelerometer / Gyroscope combination (BNO085) + +We've chosen for this configuration due to the fact that it delivers all of our needs, with the smallest form factor, +whilst also delivering quality measurements. +This sadly does come at the cost that the ESP8266 does not have a dedicated Bluetooth chip, therefore making +connectivity to our robot a little more complicated. + +The calculations behind the tracking system will be done in the following steps: + +1. Acquire calibration point (zero point) +2. Convert relative acceleration and rotation to position, relative to the calibration point +3. Generate a path object that can be compared to the correct one +4. Calculate the difference of the path at every measurement sample + +At first, to get the calibration point, the user will have to stand still for a moment without moving. +This can be sensed by the device, which will then be sent to the Pepper robot. +We've decided to send this data using Wi-Fi using a HTTP WebSocket connection, due to the fact that our +ESP8266 does not have a Bluetooth chip present, and due to the fact that a WebSocket connection allows us +for a both fast and secure data transfer. + +Second, to convert our relative acceleration rotation to a useful position, we'll have to first convert the +acceleration vector `A(x, y, z)` and rotation vector `R(x, y, z)` to an acceleration vector that is +perpendicular to the normal vector of the earth. This is because the acceleration vector of the device +is relative to its own axes, and not to the earth's normal vector. +To convert this, we'll have to multiply the acceleration vector `A(x, y, z)` by the rotation matrix +with negative angles, to rotate it back to be perpendicular with the normal of the earth. +After this transformation \ No newline at end of file diff --git a/docs/documentation/research-questions/position-tracking-research.md b/docs/documentation/research-questions/position-tracking-research.md new file mode 100644 index 0000000..f9edfa8 --- /dev/null +++ b/docs/documentation/research-questions/position-tracking-research.md @@ -0,0 +1,89 @@ +# Position Tracking with Embedded Systems + +## Introduction + +For this project we want to design an embedded system that can track a users position. We want to track their current position on the ground and see how they are shifting their weight. This system will be used to track their position to determine if a user is doing the exercises correctly. + +## Objectives + +- Design an embedded system that can track user position. +- Develop an algorithm to process the data from the Wii Fit Board and determine the user's position. + +## Research and Analysis + +### Choosing the Wii Fit Board + +For this project we have chosen the Wii Fit Board as our primary sensor. The Wii Fit Board is a balance board that can measure a user's weight and center of balance. It is a low-cost sensor that is easy to interface with a microcontroller. The Wii Fit Board communicates over Bluetooth, which makes it easy to connect to a microcontroller with Bluetooth capabilities. + +### Alternative Solutions + +There are other sensors that can be used for position tracking, such as pressure sensors or accelerometers. However, these sensors are more expensive and may require additional processing to determine the user's position. The Wii Fit Board provides a simple and cost-effective solution for position tracking. + +Example of other sensors that can be used for position tracking: + +Pressure sensors: + - Description: Pressure sensors can be used to measure the force applied by the user on the ground. By measuring the pressure distribution, the user's position can be determined. + - Pros: High accuracy, can measure force applied by the user. + - Cons: Expensive, will require additional hardware for data transfer. + - Cost: ~ 33 euros (https://www.antratek.nl/flexiforce-a401-sensor-25lbs?gad_source=1&gclid=CjwKCAjwupGyBhBBEiwA0UcqaMMrIXGafsF2oE-15JaTPT5tDhfCyDHz2D2gSghyPvg11okv_QIFThoCw5oQAvD_BwE) + +Accelerometers: + - Description: Accelerometers can be used to measure the user's acceleration and orientation. By integrating the acceleration data, the user's position can be determined. + - Pros: Can measure acceleration and orientation, cheap. + - Cons: Will require additional hardware for data transfer. + - Cost: ~ 5 euros (https://www.amazon.nl/versnellingsmeter-gyroscoop-versnellingssensor-converter-gegevensuitgang/dp/B07BVXN2GP/ref=asc_df_B07BVXN2GP/?tag=nlshogostdde-21&linkCode=df0&hvadid=430548884871&hvpos=&hvnetw=g&hvrand=5187253011954678898&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1010543&hvtargid=pla-928293154057&psc=1&mcid=43bf111afa7b3ba593f4a49321683352) + +### System Requirements + +To be added + +## System Design + +### Hardware + +The hardware of the system will consist of the following components: + - Wii Fit Board: The primary sensor for position tracking. + - Pepper: The controller that will process the data from the Wii Fit Board. + +### Software + +The software of the system will consist of the following: + - Wiiboard-simple: A library that will be used to transfer data from the Wii Fit Board to pepper. + - Position Tracking Algorithm: An algorithm that will process the sensor data and determine the user's position. + +### Integration + +The Wii Fit Board will be connected to Pepper using the Wiiboard-simple library. The library will be used to read the sensor data from the Wii Fit Board and transfer it to Pepper. The position tracking algorithm will process the sensor data and determine the user's position. + +Challenge: + - Connecting to the wii fit board. It is not possible to connect directly to the Wii Fit Board, it is necessary to use a library that can interpret the data sent by the Wii Fit Board. + - The Wii Fit Balance Board sends data in a specific format. To interpret this data, it's necessary to understand the format and how to convert it to a usable format. + - The Wii Fit Balance Board uses Bluetooth 2.0 to communicate. Pepper uses Bluetooth 4.0 this means that there might be compatibility issues/latancy issues. + +## Implementation + +### Prototyping + +To start the implementation of the system, we will create a prototype that will read the sensor data from the Wii Fit Board and send it to your computer. Once we have the data, we will develop the position tracking algorithm to determine the user's position. After that, the algorithm will be integrated with pepper. + +### Testing and Validation + +Tests: + - Test the prototype to ensure that it can read the sensor data from the Wii Fit Board. + - Test the position tracking algorithm to ensure that it can determine the user's position accurately. + - Test the integrated system to ensure that it can track the user's position in real-time. + +## Conclusion + +To be added + +## References + +[Wiiboard lib](https://code.google.com/archive/p/wiiboard-simple/wikis/Documentation.wiki) +https://advanti-lab.sb.dfki.de/?page_id=64 +https://github.com/paulburton/fitscales +https://github.com/micromu/WiiRemoteJ + +## Appendices + +To be added \ No newline at end of file diff --git a/docs/personalDocs/Luca/expert-review-tips.md b/docs/personal-documentation/Luca/expert-review-tips.md similarity index 100% rename from docs/personalDocs/Luca/expert-review-tips.md rename to docs/personal-documentation/Luca/expert-review-tips.md diff --git a/docs/personalDocs/Luca/literatuuronderzoek/onderzoek-formulier.md b/docs/personal-documentation/Luca/literatuuronderzoek/onderzoek-formulier.md similarity index 100% rename from docs/personalDocs/Luca/literatuuronderzoek/onderzoek-formulier.md rename to docs/personal-documentation/Luca/literatuuronderzoek/onderzoek-formulier.md diff --git a/docs/personal-documentation/Luca/literatuuronderzoek/onderzoek-voorbeeld.md b/docs/personal-documentation/Luca/literatuuronderzoek/onderzoek-voorbeeld.md new file mode 100644 index 0000000..fb20ae4 --- /dev/null +++ b/docs/personal-documentation/Luca/literatuuronderzoek/onderzoek-voorbeeld.md @@ -0,0 +1,68 @@ +# Literatuuronderzoek Luca Warmenhoven + +## Hoe kunnen we voorkomen dat de privacy van ouderen wordt geschonden bij het inzetten van kunstmatige intelligentie om eenzaamheid te bestrijden? + +--- + +### Inhoudsopgave + +1. [Inleiding](#inleiding) +2. [Hoe ontstaat eenzaamheid onder ouderen?](#hoe-ontstaat-eenzaamheid-onder-ouderen) +3. [Kan kunstmatige intelligentie ingezet worden om dit te verhelpen?](#op-welke-manier-kunnen-we-kunstmatige-intelligentie-inzetten-om-eenzaamheid-onder-ouderen-te-bestrijden) +4. [Hoe kunnen we ervoor zorgen dat de privacy van ouderen niet wordt geschonden?](#hoe-kunnen-we-ervoor-zorgen-dat-dit-gedaan-kan-worden-zonder-de-privacy-van-ouderen-te-schenden) +5. [Conclusie](#conclusie) +6. [Bronnen](#bronnen) + +--- + +### Inleiding + +Door de vergrijzing van de bevolking neemt het aantal ouderen in Nederland toe. Dit zorgt ervoor dat er steeds meer ouderen terecht komen in de verzorgingstehuizen. +Met een stijgende hoeveelheid ouderen in de verzorgingstehuizen zou je denken dat de eenzaamheid onder hen afneemt, maar dit is echter niet het geval. +Een manier om dit probleem op te lossen is door het inzetten van robots. Om deze robots nog capabeler te maken wordt er tegenwoordig ook gebruik gemaakt van kunstmatige +intelligentie. Dit komt echter ook met nadelen, zo kan het dat er informatie gedeeld wordt met de makers van de robots. +In dit onderzoek zal er gekeken worden of het mogelijk is om kunstmatige intelligentie toe te passen zonder dat dit ten koste gaat van de privacy van de ouderen. + +### Wat zijn de belangrijkste factoren die bijdragen aan eenzaamheid onder ouderen? + +Om te begrijpen hoe we eenzaamheid kunnen aanpakken is het noodzakelijk om te begrijpen waar het vandaan komt. Hierbij is het belangrijk om te kijken +naar wat voor factoren er meespelen in de levens van de ouderen die hieraan kunnen bijdragen. Eenzaamheid kan zowel fysiek als mentaal zijn, dit betekent +dat hoewel het persoon omringt kan zijn met mensen, hij/zij nog steeds gevoelens van eenzaamheid kan ervaren. De oorzaak van emotionele eenzaamheid verschilt +per persoon, en valt niet zo gemakkelijk te verklaren, als te verhelpen. Bij fysieke eenzaamheid is het echter makkelijker om te zien waar het vandaan komt. +Hierbij kunnen er andere omgevingsfactoren meespelen die ervoor zorgen dat het persoon zich eenzaam voelt, +denk hierbij aan het verlies van een partner of vrienden, familieproblematiek of acute verandering van levensstijl ([1. SCP 2018](#bronnen)). +Door dit soort veranderingen kan het zijn dat het persoon in een depressie raakt, wat er weer voor kan zorgen dat het persoon zich eenzaam voelt, +en dat het persoon zich nog meer terugtrekt van de buitenwereld. Dit is een vicieuze cirkel die moeilijk te doorbreken is. +Daarom is het belangrijk om te kijken of er ook methoden zijn om hierbij te helpen, zowel binnen als buitenhuis. + +Doordat robots de laatste decennia steeds geavanceerder zijn geworden, is het mogelijk om te overwegen deze toe te passen +in de ouderenzorg om te helpen bij het eenzaamheidsprobleem. Robots worden de afgelopen jaren al steeds meer ingezet om ouderen te helpen +bij bepaalde dagelijkse problemen, zoals het wassen van ouderen in het bad, of het helpen bij eten consumeren ([3. University of Japan, 2017](#bronnen)). +Door de verbeteringen van technologie over de afgelopen jaren heeft K.I. ook een drastische verbetering ondergaan. Hierdoor valt er te overwegen +om deze toe te passen om te helpen met het eenzaamheidsprobleem bij ouderen. + + +### Op welke manier kunnen we kunstmatige intelligentie inzetten om eenzaamheid onder ouderen te bestrijden? + +Zoals al eerder was vermeld worden robots al langer gebruikt bij het helpen van ouderen met huishoudelijke taken die voor hen te zwaar zijn. +Daarom valt het idee ook te overwegen om robots in te zetten om ouderen te helpen met het bestrijden van eenzaamheid. Hiervoor kan er +gebruik gemaakt worden van kunstmatige intelligentie. Kunstmatige intelligentie kan gebruikt worden om de robot te leren hoe het om moet gaan met +de gebruiker, om zowel te horen wat de gebruiker zegt, inhoudelijke reacties te geven op de gebruiker of om de gebruiker te helpen met bepaalde taken als ernaar +gevraagd wordt. Dit kan ervoor zorgen dat de ouderen zich minder eenzaam voelen, en dat ze zich meer op hun gemak voelen in hun eigen huis. + + +### Hoe kunnen we ervoor zorgen dat dit gedaan kan worden zonder de privacy van ouderen te schenden? + + +### Conclusie + + +### Bronnen + +1. [Eenzaamheid ouderen](https://repository.scp.nl/bitstream/handle/publications/393/Kwetsbaar%20en%20eenzaam.pdf?sequence=1&isAllowed=y) +2. [Cijfers eenzaamheid onder ouderen](https://www.cbs.nl/nl-nl/nieuws/2023/38/bijna-70-procent-van-ouderen-heeft-minstens-elke-week-contact-met-de-buren) +3. [Inzetten robots in de ouderenzorg](https://digitcult.lim.di.unimi.it/index.php/dc/article/view/54) +4. [Effectiviteit robots in de ouderenzorg](https://essay.utwente.nl/92446/1/Watford-Spence_MA_Behavioural%2C%20Management%20and%20Social%20sciences.pdf) +5. [AI, Privacy and Security](https://www.frontiersin.org/articles/10.3389/frai.2022.826737/full) +6. [Problematic Interactions between AI and Health Privacy](https://heinonline.org/HOL/LandingPage?handle=hein.journals/utahlr2021&div=25&id=&page=) + diff --git a/docs/personalDocs/Luca/literatuuronderzoek/onderzoek.md b/docs/personal-documentation/Luca/literatuuronderzoek/onderzoek.md similarity index 100% rename from docs/personalDocs/Luca/literatuuronderzoek/onderzoek.md rename to docs/personal-documentation/Luca/literatuuronderzoek/onderzoek.md diff --git a/docs/personalDocs/Luca/weekly-reports/sprint-1-week-1.md b/docs/personal-documentation/Luca/weekly-reports/sprint-1-week-1.md similarity index 100% rename from docs/personalDocs/Luca/weekly-reports/sprint-1-week-1.md rename to docs/personal-documentation/Luca/weekly-reports/sprint-1-week-1.md diff --git a/docs/personalDocs/Luca/weekly-reports/sprint-1-week-2.md b/docs/personal-documentation/Luca/weekly-reports/sprint-1-week-2.md similarity index 100% rename from docs/personalDocs/Luca/weekly-reports/sprint-1-week-2.md rename to docs/personal-documentation/Luca/weekly-reports/sprint-1-week-2.md diff --git a/docs/personal-documentation/Niels/Onderzoeks verslag/betoog opdrachten.md b/docs/personal-documentation/Niels/Onderzoeks verslag/betoog opdrachten.md new file mode 100644 index 0000000..d5771c1 --- /dev/null +++ b/docs/personal-documentation/Niels/Onderzoeks verslag/betoog opdrachten.md @@ -0,0 +1,91 @@ +**A. ONDERWERP – Het thema/vraagstuk van het onderzoek is:** + +Ethiek binnen de ICT bij ouderenzorg + +**B. AANLEIDING – De aanleiding en/of context van het thema/vraagstuk is:** + +omdat wij niet weten hoe we met nieuwe technologie om moeten gaan. Dit kan voor veel problemen zorgen als er niet goed over wordt nagedacht. Er is nu nog veel onduidelijkheid over dit onderwerp + +**C. AFBAKENING – Binnen dit thema beperk ik mij tot het aspect:** + +Ouderenzorg en Robotica + +**D. DOELSTELLING – Het onderzoek levert het volgende op (bijv. kennis die er nu nog niet is in de vorm van een voorstel/ontwerp, of een diagnose van het probleem):** + +Ik wil weten of de opdracht waarmee we bezig zijn een ethisch probleem kan vormen. + +**C. ETHISCH/MAATSCHAPPELIJK ISSUE – Het voor mijn publiek interessante issue dat op het gebied van het afgebakende thema speelt is:** + +Is het wel ethisch verantwoord om ouderen in contact te brengen met robots + +**G. VRAAGSTELLING 1 - De Hoofdvraag van mijn onderzoek is:** + +Welke ethische dilemma's kunnen er vormen bij het gebruik van robotica in de ouderenzorg. + +**H. BEGRIPSOMSCHRIJVING – De volgende begrippen uit mijn vraagstelling definieer ik als:** + +**I. VRAAGSTELLING 2 - De deelvragen van mijn onderzoek zijn:** + + +# Hoofdvraag + +Welke ethische dilemma's kunnen er vormen bij het gebruik van robotica in de ouderenzorg. + +# Deelvragen + + +Wat zijn de mogelijke effecten van robots op het emotionele en sociale welzijn van ouderen? + + Kan het gebruik van robots in de ouderenzorg leiden tot een gevoel van dehumanisering of verminderde menselijke interactie voor ouderen? + +Welke risico's zijn er op het gebied van veiligheid en privacy voor ouderen bij het gebruik van robots in de zorg? + +# Bronnen +Design issues for assistive robotics for the elderly +https://www.sciencedirect.com/science/article/abs/pii/S1474034605000923 +| +Socially Assistive Robots in Elderly Care: A Systematic Review into Effects and Effectiveness +https://www.sciencedirect.com/science/article/abs/pii/S1525861010003476 + +Older adults’ experiences with and perceptions of the use of socially assistive robots in aged care: A systematic review of quantitative evidence +https://www.sciencedirect.com/science/article/abs/pii/S0167494321000613 + +The ethical issues of social assistive robotics: A critical literature review +https://www.sciencedirect.com/science/article/pii/S0160791X21002013 + +Enabling Security Services in Socially Assistive Robot Scenarios for Healthcare Applications +https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8541011/ + +The concept of social dignity as a yardstick to delimit ethical use of robotic assistance in the care of older persons +https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8614079/ + +Socially facilitative robots for older adults to alleviate social isolation: A participatory design workshop approach in the US and Japan +https://www.frontiersin.org/journals/psychology/articles/10.3389/fpsyg.2022.904019/full + +Ethical Design and Use of Robotic Care of the Elderly +https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8936033/ + +# inleiding + +De vergrijzing van de samenleving zet druk op de ouderenzorg. Er is een tekort aan zorgverleners, terwijl de vraag naar zorg toeneemt. Robotica wordt gezien als een mogelijke oplossing om dit probleem optelossen. Robots kunnen taken overnemen van verpleegsters, zoals medicatie toedienen, lichaamsverzorging en gezelschap bieden. Maar de inzet van robots in de ouderenzorg roept ook ethische dilemma's op. Ik ga onderzoeken welke etische dillemas er kunnen ontstaan in de zorg. Om dit doel te bereiken, zullen we de volgende deelvragen beantwoorden: + +- Wat zijn de mogelijke effecten van het gebruik van robots op het emotionele en sociale welzijn van ouderen? + +- Leidt robotisering in de ouderenzorg tot onpersoonlijke en mechanische zorg? + +- Welke risico's zijn er over de veiligheid en privacy voor ouderen bij het gebruik van robots in de zorg? + +Deze vragen behandelen allerei verschillende aspecten van robotica in de ouderzorg. na het beantwoorden van de deelvragen kunnen wij een concusie trekken en kijken naar welke dillemas er kunnen ontstaan. + +## Wat zijn de mogelijke effecten van het gebruik van robots op het emotionele en sociale welzijn van ouderen? + +Het sociale welzijn van ouderen is een belangrijk onderwerp. Ouderen kunnen zich vaak enzaam of afgesloten voelen van de samenleving. Dit is een groot probleem binnen in de ouderzorg omdat je niet wilt dat ouderen zich nog eenzamer gaan voelen nadat zij worden verzorgd door een robot. Daarom wil ik weten wat de effecten zijn van het gebruik van robotica in de ouderzorg, Zodat ik daaruit kan bepalen wat voor een dillema het met zich mee zou brengen. + +Er zijn al veel onderzoeken geweest naar dit onderwerp. Onderzoek wijst uit dat robots zowel positieve als negatieve effecten kunnen hebben. Een postief effect ervan is dat ouderen zich minder eenzaam voelen. 17 onderzoeken met 4 verschillende type robots wijsen erop dat Uit de meeste onderzoeken bleek dat gezelschapsrobots een positieve invloed hadden op (socio)psychologische (bijv. humeur, eenzaamheid, sociale connecties en communicatie) en fysiologische (bijv. stressverlaging) variabelen. De methodologische kwaliteit van de studies was over het algemeen laag.[1] Dit laat zien dat het helpt om eenzaamheid bij ouderen tegentegaan. Ze kunnen ook worden gebruikt om ouderen te helpen in contact te blijven met vrienden en familie. Dit is handig iets omdat ouderen dan dichter bij hun familie zijn wat voor de meeste ouderen heel belangrijk is om eenzaamheid tegen te gaan. Bovendien kunnen robots worden gebruikt om ouderen te motiveren om actief en betrokken te blijven bij hun leven. Fitness is niet alleen iets om fit te blijven maar brengt ook socialen aspecten met zich mee. Ik ben nu persoonlijk bezig met een project waarmee wij ouderen willen stimuleren meer te bewegen zodat zij ook wat vaker naar buiten kunnen en potentieel ook samen workouts kunnen doen. + +Over het algemeen zijn de mogelijke effecten van robots op het emotionele en sociale welzijn van ouderen complex. Er zijn zowel mogelijke Voordelen en nadelen, en de impact van robots zal waarschijnlijk van persoon tot persoon verschillen. Het is belangrijk om deze factoren zorgvuldig af te wegen bij het beslissen of robots wel of niet in de ouderzorg te implementeren. + +## Kan het gebruik van robots in de ouderenzorg leiden tot een gevoel van dehumanisering of verminderde menselijke interactie voor ouderen? + + +(Socially Assistive Robots in Elderly Care: A Systematic Review into Effects and Effectiveness https://www.sciencedirect.com/science/article/abs/pii/S1525861010003476)[1] diff --git a/docs/personalDocs/Sam/Betoog.md b/docs/personal-documentation/Sam/Betoog.md similarity index 100% rename from docs/personalDocs/Sam/Betoog.md rename to docs/personal-documentation/Sam/Betoog.md diff --git a/docs/personalDocs/Sam/Formulier Probleembeschrijving en Hoofd en Deelvragen copy.md b/docs/personal-documentation/Sam/Formulier Probleembeschrijving en Hoofd en Deelvragen copy.md similarity index 100% rename from docs/personalDocs/Sam/Formulier Probleembeschrijving en Hoofd en Deelvragen copy.md rename to docs/personal-documentation/Sam/Formulier Probleembeschrijving en Hoofd en Deelvragen copy.md diff --git a/docs/personalDocs/Sam/Formulier Probleembeschrijving en Hoofd en DeelvragenV2.md b/docs/personal-documentation/Sam/Formulier Probleembeschrijving en Hoofd en DeelvragenV2.md similarity index 100% rename from docs/personalDocs/Sam/Formulier Probleembeschrijving en Hoofd en DeelvragenV2.md rename to docs/personal-documentation/Sam/Formulier Probleembeschrijving en Hoofd en DeelvragenV2.md diff --git a/docs/personalDocs/Sam/Hoofd-deelvragen.md b/docs/personal-documentation/Sam/Hoofd-deelvragen.md similarity index 100% rename from docs/personalDocs/Sam/Hoofd-deelvragen.md rename to docs/personal-documentation/Sam/Hoofd-deelvragen.md diff --git a/docs/personalDocs/sebas/dailyUpdates.md b/docs/personal-documentation/sebas/dailyUpdates.md similarity index 100% rename from docs/personalDocs/sebas/dailyUpdates.md rename to docs/personal-documentation/sebas/dailyUpdates.md diff --git a/docs/personalDocs/sebas/expertReview/expert1sprint1.md b/docs/personal-documentation/sebas/expertReview/expert1sprint1.md similarity index 100% rename from docs/personalDocs/sebas/expertReview/expert1sprint1.md rename to docs/personal-documentation/sebas/expertReview/expert1sprint1.md diff --git a/docs/personalDocs/sebas/expertReview/expert2sprint2.md b/docs/personal-documentation/sebas/expertReview/expert2sprint2.md similarity index 100% rename from docs/personalDocs/sebas/expertReview/expert2sprint2.md rename to docs/personal-documentation/sebas/expertReview/expert2sprint2.md diff --git a/docs/personalDocs/sebas/onderzoekEthiek/Formulier Probleembeschrijving en Hoofd en Deelvragen.docx b/docs/personal-documentation/sebas/onderzoekEthiek/Formulier Probleembeschrijving en Hoofd en Deelvragen.docx similarity index 100% rename from docs/personalDocs/sebas/onderzoekEthiek/Formulier Probleembeschrijving en Hoofd en Deelvragen.docx rename to docs/personal-documentation/sebas/onderzoekEthiek/Formulier Probleembeschrijving en Hoofd en Deelvragen.docx diff --git a/docs/personalDocs/sebas/onderzoekEthiek/deelvragen.md b/docs/personal-documentation/sebas/onderzoekEthiek/deelvragen.md similarity index 100% rename from docs/personalDocs/sebas/onderzoekEthiek/deelvragen.md rename to docs/personal-documentation/sebas/onderzoekEthiek/deelvragen.md diff --git a/docs/personalDocs/sebas/onderzoekEthiek/formulier.md b/docs/personal-documentation/sebas/onderzoekEthiek/formulier.md similarity index 100% rename from docs/personalDocs/sebas/onderzoekEthiek/formulier.md rename to docs/personal-documentation/sebas/onderzoekEthiek/formulier.md diff --git a/docs/personalDocs/sebas/onderzoekEthiek/onderzoekEthiek.md b/docs/personal-documentation/sebas/onderzoekEthiek/onderzoekEthiek.md similarity index 100% rename from docs/personalDocs/sebas/onderzoekEthiek/onderzoekEthiek.md rename to docs/personal-documentation/sebas/onderzoekEthiek/onderzoekEthiek.md diff --git a/docs/personalDocs/Niels/Onderzoeks verslag/betoog opdrachten.md b/docs/personalDocs/Niels/Onderzoeks verslag/betoog opdrachten.md deleted file mode 100644 index d23fe15..0000000 --- a/docs/personalDocs/Niels/Onderzoeks verslag/betoog opdrachten.md +++ /dev/null @@ -1,62 +0,0 @@ -**A. ONDERWERP – Het thema/vraagstuk van het onderzoek is:** - -Ethiek binnen de ICT bij ouderenzorg - -**B. AANLEIDING – De aanleiding en/of context van het thema/vraagstuk is:** - -omdat wij niet weten hoe we met nieuwe technologie om moeten gaan. Dit kan voor veel problemen zorgen als er niet goed over wordt nagedacht. Er is nu nog veel onduidelijkheid over dit onderwerp - -**C. AFBAKENING – Binnen dit thema beperk ik mij tot het aspect:** - -Ouderenzorg en Robotica - -**D. DOELSTELLING – Het onderzoek levert het volgende op (bijv. kennis die er nu nog niet is in de vorm van een voorstel/ontwerp, of een diagnose van het probleem):** - -Ik wil weten of de opdracht waarmee we bezig zijn een ethisch probleem kan vormen. - -**C. ETHISCH/MAATSCHAPPELIJK ISSUE – Het voor mijn publiek interessante issue dat op het gebied van het afgebakende thema speelt is:** - -Is het wel ethisch verantwoord om ouderen in contact te brengen met robots - -**G. VRAAGSTELLING 1 - De Hoofdvraag van mijn onderzoek is:** - -Welke ethische dilemma's kunnen er vormen bij het gebruik van robotica in de ouderenzorg. - -**H. BEGRIPSOMSCHRIJVING – De volgende begrippen uit mijn vraagstelling definieer ik als:** - -**I. VRAAGSTELLING 2 - De deelvragen van mijn onderzoek zijn:** - - -# Deelvragen - - -Wat is de impact van robots op de emotionele en sociale welzijn van ouderen? - -Kan het gebruik van robots in de ouderezorg ervoor zorgen dat de zorg minder menselijk wordt? - -Hoe worden de veiligheid en persoonlijke gegevens van ouderen Beschermd bij het gebruik van robots? - -# Bronnen -Design issues for assistive robotics for the elderly -https://www.sciencedirect.com/science/article/abs/pii/S1474034605000923 -| -Socially Assistive Robots in Elderly Care: A Systematic Review into Effects and Effectiveness -https://www.sciencedirect.com/science/article/abs/pii/S1525861010003476 - -Older adults’ experiences with and perceptions of the use of socially assistive robots in aged care: A systematic review of quantitative evidence -https://www.sciencedirect.com/science/article/abs/pii/S0167494321000613 - -The ethical issues of social assistive robotics: A critical literature review -https://www.sciencedirect.com/science/article/pii/S0160791X21002013 - -Enabling Security Services in Socially Assistive Robot Scenarios for Healthcare Applications -https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8541011/ - -The concept of social dignity as a yardstick to delimit ethical use of robotic assistance in the care of older persons -https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8614079/ - -Socially facilitative robots for older adults to alleviate social isolation: A participatory design workshop approach in the US and Japan -https://www.frontiersin.org/journals/psychology/articles/10.3389/fpsyg.2022.904019/full - -Ethical Design and Use of Robotic Care of the Elderly -https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8936033/ \ No newline at end of file diff --git a/docs/teamdocumentatie/sprint-reports/sprint-report-s1.md b/docs/teamdocumentatie/sprint-reports/sprint-report-s1.md index a9120f1..61889f5 100644 --- a/docs/teamdocumentatie/sprint-reports/sprint-report-s1.md +++ b/docs/teamdocumentatie/sprint-reports/sprint-report-s1.md @@ -80,6 +80,6 @@ Wat moet er beter? Wat ging er goed? Welke SMART leerdoelen hebben jullie voor d We zijn samen gaan zitten voor de retrospective, hier uit is het volgende voort gekomen (we hebben gebruik gemaakt van the 4 L's): -![alt text](Sprint1Retro.png) +![Retro](Sprint1Retro.png) De leerdoelen zet iedereen in zijn eigen scorion formulier. \ No newline at end of file