diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/Exercise.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/Exercise.java
index 18153d7..7444f2b 100644
--- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/Exercise.java
+++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/Exercise.java
@@ -1,12 +1,12 @@
package com.example.fitbot.exercise;
-import com.example.fitbot.util.path.GesturePath;
+import com.example.fitbot.util.path.AnglePath;
public class Exercise {
public final EMuscleGroup muscleGroup;
- public final GesturePath leftPath;
- public final GesturePath rightPath;
+ public final AnglePath leftPath;
+ public final AnglePath rightPath;
public final String name;
public final String shortDescription;
public final String description;
@@ -26,7 +26,10 @@ public class Exercise {
* @param imageUrl The URL of the image.
* @param videoUrl The URL of the video.
*/
- public Exercise(EMuscleGroup muscleGroup, String name,String shortDescription, String description, String imageUrl, String videoUrl, GesturePath leftPath, GesturePath rightPath, float exerciseTimeInSeconds) {
+ public Exercise(EMuscleGroup muscleGroup, String name, String shortDescription,
+ String description, String imageUrl, String videoUrl,
+ AnglePath leftPath, AnglePath rightPath, float exerciseTimeInSeconds) {
+
this.name = name;
this.muscleGroup = muscleGroup;
this.shortDescription = shortDescription;
diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/ExerciseManager.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/ExerciseManager.java
index 0de72d0..b69e4c0 100644
--- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/ExerciseManager.java
+++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/ExerciseManager.java
@@ -1,6 +1,6 @@
package com.example.fitbot.exercise;
-import com.example.fitbot.util.path.GesturePath;
+import com.example.fitbot.util.path.AnglePath;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
@@ -28,9 +28,6 @@ public class ExerciseManager {
private static final String PROPERTY_PATH = "path";
private static final String PROPERTY_NAME = "name";
- // The delimiter used to separate the paths of the sensors.
- public static final String PATH_DELIMITER = ":";
-
public static final int SENSOR_COUNT = 2;
private static final String[] REQUIRED_PROPERTIES = {
@@ -40,8 +37,8 @@ public class ExerciseManager {
};
public static final int DEFAULT_EXERCISE_REPETITIONS = 10;
- public static final float DEFAULT_SEGMENT_SPEED = 1.0f;
public static final float EXERCISE_ERROR_MARGIN = 1.0f;
+ public static final float EXERCISE_TIME_SCALING_FACTOR = 1.0f;
/**
* Function for sending an HTTP request to the server.
@@ -104,9 +101,10 @@ public class ExerciseManager {
// If one wants to add support for more sensors, one will have to adjust the Exercise
// class to support more paths.
System.out.println(content.get(PROPERTY_PATH).getAsString());
- String[] leftRightData = content.get(PROPERTY_PATH).getAsString().split(PATH_DELIMITER);
- if (leftRightData.length != SENSOR_COUNT) {
+ AnglePath[] paths = AnglePath.fromString(content.get(PROPERTY_PATH).getAsString());
+
+ if (paths.length != SENSOR_COUNT) {
System.out.println("Invalid path data.");
return null;
}
@@ -118,9 +116,9 @@ public class ExerciseManager {
content.get(PROPERTY_DESC).getAsString(),
content.get(PROPERTY_IMAGE_URL).getAsString(),
content.get(PROPERTY_VIDEO_URL).getAsString(),
- GesturePath.fromString(leftRightData[0]),
- GesturePath.fromString(leftRightData[1]),
- DEFAULT_SEGMENT_SPEED
+ paths[0],
+ paths[1],
+ content.get(PROPERTY_EXERCISE_DURATION).getAsInt()
);
} catch (Exception e) {
e.printStackTrace();
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
index 9c79a39..48907b2 100644
--- 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
@@ -126,7 +126,7 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall
exerciseStatusElement.post(() -> {
this.fetchExerciseAsync((exercise) -> {
// Acquire paths from the exercise and provide them to the motion processor
- Vector3f[][] vectors = new Vector3f[][]{exercise.leftPath.getVectors(), exercise.rightPath.getVectors()};
+ Vector3f[][] vectors = new Vector3f[][]{exercise.leftPath.getAngleVectors(), exercise.rightPath.getAngleVectors()};
motionProcessor = new InputProcessor(vectors, exercise.exerciseTimeInSeconds, SENSOR_SAMPLE_RATE);
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
index 3aaca38..934a9df 100644
--- 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
@@ -16,6 +16,7 @@ import android.view.WindowManager;
import android.widget.Button;
import com.example.fitbot.R;
+import com.example.fitbot.pepper.Pepper;
import com.example.fitbot.util.NavigationManager;
import java.io.OutputStream;
diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/AnglePath.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/AnglePath.java
new file mode 100644
index 0000000..1eb15e4
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/AnglePath.java
@@ -0,0 +1,67 @@
+package com.example.fitbot.util.path;
+
+import com.example.fitbot.exercise.ExerciseManager;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+import org.joml.Vector3f;
+
+public class AnglePath {
+
+ // The angles
+ private final Vector3f[] angles;
+
+ /**
+ * Create a new gesture path with a given set of vectors and curvature.
+ *
+ * @param angles The vectors that make up the path.
+ */
+ public AnglePath(Vector3f[] angles) {
+ this.angles = angles;
+ }
+
+ /**
+ * Method for retrieving the vectors of the GesturePath.
+ */
+ public Vector3f[] getAngleVectors() {
+ return this.angles;
+ }
+
+ /**
+ * Function for converting a string to a GesturePath object.
+ * This function has been updated to convert Json strings to AnglePath objects.
+ * The JSON must be in the following format:
+ * [
+ * { "deviceId": number, "data": [ [x, y, z], [x, y, z], ... ] },
+ * ]
+ *
+ * @param jsonInput The string to convert
+ * @return The AnglePath object
+ */
+
+ public static AnglePath[] fromString(String jsonInput) {
+ if (jsonInput == null)
+ throw new IllegalArgumentException("Input string cannot be null");
+
+ JsonElement parsed = JsonParser.parseString(jsonInput);
+ if (!parsed.isJsonArray())
+ throw new IllegalArgumentException("Input string must be a JSON array");
+
+ if ( parsed.getAsJsonArray().size() != ExerciseManager.SENSOR_COUNT)
+ throw new IllegalArgumentException("Input string must contain 2 elements");
+
+ Vector3f[][] angles = new Vector3f[ExerciseManager.SENSOR_COUNT][];
+ for ( int dataArrayIdx = 0; dataArrayIdx < parsed.getAsJsonArray().size(); dataArrayIdx++)
+ {
+ JsonArray array = parsed.getAsJsonArray().get(dataArrayIdx).getAsJsonObject().get("data").getAsJsonArray();
+ angles[dataArrayIdx] = new Vector3f[array.size()];
+ for (int i = 0; i < array.size(); i++) {
+ JsonArray vec = array.get(i).getAsJsonArray();
+ angles[dataArrayIdx][i] = new Vector3f(vec.get(0).getAsFloat(), vec.get(1).getAsFloat(), vec.get(2).getAsFloat());
+ }
+ }
+ return new AnglePath[] {new AnglePath(angles[0]), new AnglePath(angles[1])};
+ }
+}
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
deleted file mode 100644
index f3b8cb3..0000000
--- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/GesturePath.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package com.example.fitbot.util.path;
-
-import org.joml.Vector3f;
-
-public class GesturePath {
-
- // The vectors that make up the path.
- private final PathSegment[] segments;
-
- /**
- * Create a new gesture path with a given set of vectors and curvature.
- *
- * @param vectors The vectors that make up the path.
- */
- public GesturePath(Vector3f[] vectors) {
- if (vectors.length < 2) {
- this.segments = new PathSegment[1];
- this.segments[0] = new PathSegment(
- new Vector3f(0, 0, 0),
- new Vector3f(0, 0, 0)
- );
- return;
- }
-
- 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 vectors of the GesturePath.
- */
- public Vector3f[] getVectors() {
- Vector3f[] vectors = new Vector3f[segments.length + 1];
- vectors[0] = segments[0].getStart();
- for (int i = 0; i < segments.length; i++)
- vectors[i + 1] = segments[i].getEnd();
-
- return vectors;
- }
-
- /**
- * 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];
-
- PathSegment closest = segments[0];
- for (int i = 1; i < segments.length; i++)
- closest = PathSegment.closer(closest, segments[i], reference);
-
- return closest;
- }
-
- /**
- * 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.
- }
-
-
- /**
- * Function for converting a string to a GesturePath object.
- * The input string bytes will be directly converted into 3d vectors.
- * Every scalar is composed of 32 bits (4 characters), meaning 96 bits per vector.
- *
- * Note: ASCII to Vector conversion is done in Big Endian format (most significant byte first).
- *
- * @param input The string to convert
- * @return The GesturePath object
- */
-
- public static GesturePath fromString(String input) {
- if (input == null)
- throw new IllegalArgumentException("Input string cannot be null");
- 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 (" + input.length() + " bytes provided - must be a multiple of 12)");
- }
- Vector3f[] vectors = new Vector3f[input.length() / 12];
-
- 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)
- );
- }
- vectors[i / 12] = new Vector3f(xyz[0], xyz[1], xyz[2]);
- }
- return new GesturePath(vectors);
- }
-}
diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/InputProcessor.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/InputProcessor.java
index e95008a..8e358b7 100644
--- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/InputProcessor.java
+++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/InputProcessor.java
@@ -2,12 +2,15 @@ package com.example.fitbot.util.processing;
import android.util.Log;
+import com.aldebaran.qi.sdk.object.geometry.Vector3;
import com.example.fitbot.exercise.Exercise;
import com.example.fitbot.exercise.ExerciseManager;
import com.example.fitbot.util.server.WebServer;
+import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
+import com.google.gson.JsonPrimitive;
import org.jetbrains.annotations.NotNull;
import org.joml.Vector3f;
@@ -17,12 +20,15 @@ import java.util.List;
public class InputProcessor {
- private Vector3f[][] selfRotationVectorPaths; // Relative path of the motion data
+ private List[] selfRotationVectorPaths; // Relative path of the motion data
+ //private Vector3f[][] selfRotationVectorPaths; // Relative path of the motion data
private Vector3f[][] targetRotationVectorPaths; // Target path of the motion data
private final float sampleRate; // The sample rate of the motion sensor
private float exerciseDurationInSeconds;
+ private float exerciseScore = 0.0F;
+
/**
* This field is used to determine if the motion data is being recorded.
* If this is the case, instead of functioning normally, the element
@@ -45,7 +51,7 @@ public class InputProcessor {
private IInputHandler motionDataConsumer;
private static final String[] REQUIRED_SENSOR_JSON_PROPERTIES =
- {"rotationX", "rotationY", "rotationZ", "type", "deviceId"};
+ {"rotationX", "rotationY", "rotationZ", "deviceId"};
// The web server that listens for incoming motion data.
private WebServer server;
@@ -60,7 +66,9 @@ public class InputProcessor {
* @param inputSampleRate The sample rate of the motion sensor.
*/
public InputProcessor(Vector3f[][] paths, float exerciseTime, float inputSampleRate) {
- selfRotationVectorPaths = new Vector3f[paths.length][(int) (exerciseTime * inputSampleRate)];
+ this.selfRotationVectorPaths = new ArrayList[2];
+ this.selfRotationVectorPaths[0] = new ArrayList<>();
+ this.selfRotationVectorPaths[1] = new ArrayList<>();
targetRotationVectorPaths = paths;
this.sampleRate = inputSampleRate;
@@ -78,10 +86,11 @@ public class InputProcessor {
if ( this.recordingMovement )
throw new IllegalStateException("Cannot change exercise while recording movement.");
- this.selfRotationVectorPaths = new Vector3f[2][(int) (exercise.exerciseTimeInSeconds * this.sampleRate)];
- this.targetRotationVectorPaths = new Vector3f[2][exercise.rightPath.getVectors().length];
- this.targetRotationVectorPaths[0] = exercise.leftPath.getVectors();
- this.targetRotationVectorPaths[1] = exercise.rightPath.getVectors();
+ this.selfRotationVectorPaths[0] = new ArrayList<>();
+ this.selfRotationVectorPaths[1] = new ArrayList<>();
+ this.targetRotationVectorPaths = new Vector3f[2][exercise.rightPath.getAngleVectors().length];
+ this.targetRotationVectorPaths[0] = exercise.leftPath.getAngleVectors();
+ this.targetRotationVectorPaths[1] = exercise.rightPath.getAngleVectors();
this.exerciseDurationInSeconds = exercise.exerciseTimeInSeconds;
this.secondsPassed = 0.0D;
this.lastTime = System.currentTimeMillis();
@@ -101,7 +110,8 @@ public class InputProcessor {
if (recording) {
this.secondsPassed = 0.0D;
this.lastTime = System.currentTimeMillis();
- this.selfRotationVectorPaths = new Vector3f[2][(int) (duration * this.sampleRate)];
+ this.selfRotationVectorPaths[0] = new ArrayList<>();
+ this.selfRotationVectorPaths[1] = new ArrayList<>();
}
}
@@ -161,7 +171,8 @@ public class InputProcessor {
try {
Log.i("MotionProcessor", "Time passed: " + this.secondsPassed + "s");
- Log.i("MotionProcessor", "Recording: " + this.recordingMovement + ", " + this.secondsPassed + " / " + this.recordingDurationInSeconds);
+ if ( this.recordingMovement)
+ Log.i("MotionProcessor", this.secondsPassed + " / " + this.recordingDurationInSeconds);
Log.i("MotionProcessor", "Received packet data: " + data);
JsonElement json = JsonParser.parseString(data);
@@ -178,9 +189,11 @@ public class InputProcessor {
}
// Parse the data
- Vector3f rotation = new Vector3f(object.get("rotationX").getAsFloat(), object.get("rotationY").getAsFloat(), object.get("rotationZ").getAsFloat());
+ Vector3f rotation = new Vector3f(
+ object.get("rotationX").getAsFloat(),
+ object.get("rotationY").getAsFloat(),
+ object.get("rotationZ").getAsFloat());
int deviceId = object.get("deviceId").getAsInt();
- String type = object.get("type").getAsString();
// Parse the retrieved data
parseRotationVector(rotation, deviceId);
@@ -203,7 +216,7 @@ public class InputProcessor {
// Supposed index of the current rotation vector in the `rotationVectorPaths` array
- int selfIndex = (int) (secondsPassed * sampleRate);
+ this.selfRotationVectorPaths[deviceId].add(rotation);
if ( this.recordingMovement && this.secondsPassed >= this.recordingDurationInSeconds) {
// Do something with the recorded data.
@@ -217,11 +230,8 @@ public class InputProcessor {
Log.i("MotionProcessor", "Converted data: ");
Log.i("MotionProcessor", converted);
}
- motionDataConsumer.accept(rotation, deviceId);
- if (selfIndex >= selfRotationVectorPaths[deviceId].length || selfIndex < 0)
- return;
- selfRotationVectorPaths[deviceId][selfIndex] = rotation;
+ motionDataConsumer.accept(rotation, deviceId);
}
}
@@ -234,38 +244,36 @@ public class InputProcessor {
*/
private String convertRecordedDataToString()
{
- // First, remove empty entries
- StringBuilder pathBuilder = new StringBuilder();
-
int[] intBits = new int[3];
char[] vectorChars = new char[12]; // 4 bytes per scalar, 12 chars per vector
+ JsonArray jsonArray = new JsonArray();
+ /*
+ * Convert to JSON array in the following format:
+ * [
+ * { "deviceId": number, "data": [ [x, y, z], [x, y, z], ... ] },
+ * ]
+ */
// Iterate over all devices. In the current instance, it's 2.
for ( int deviceId = 0; deviceId < selfRotationVectorPaths.length; deviceId++) {
- for (Vector3f dataPoint : selfRotationVectorPaths[deviceId]) {
- if (dataPoint != null) {
- // Convert float to int bits for conversion to char
- intBits[0] = Float.floatToIntBits(dataPoint.x);
- intBits[1] = Float.floatToIntBits(dataPoint.y);
- intBits[2] = Float.floatToIntBits(dataPoint.z);
+ JsonObject jsonDeviceObject = new JsonObject();
+ jsonDeviceObject.addProperty("deviceId", deviceId);
- // Convert int bits to char, in Big Endian order.
- // This is important for converting back to float later.
- for (int i = 0; i < 3; i++) {
- vectorChars[i * 4] = (char) (intBits[i] >> 24);
- vectorChars[i * 4 + 1] = (char) (intBits[i] >> 16);
- vectorChars[i * 4 + 2] = (char) (intBits[i] >> 8);
- vectorChars[i * 4 + 3] = (char) intBits[i];
- }
+ // Data array
+ JsonArray jsonDeviceDataArray = new JsonArray();
- pathBuilder.append(vectorChars);
- }
+ for ( Vector3f vector : selfRotationVectorPaths[deviceId]) {
+ JsonArray jsonScalarArray = new JsonArray();
+ jsonScalarArray.add(vector.x);
+ jsonScalarArray.add(vector.y);
+ jsonScalarArray.add(vector.z);
+ jsonDeviceDataArray.add(jsonScalarArray);
}
- // Add a separator between devices
- if ( deviceId < selfRotationVectorPaths.length - 1)
- pathBuilder.append(ExerciseManager.PATH_DELIMITER);
+ jsonDeviceObject.add("data", jsonDeviceDataArray);
+
+ jsonArray.add(jsonDeviceObject);
}
- return pathBuilder.toString();
+ return jsonArray.toString();
}
/**
@@ -288,6 +296,13 @@ public class InputProcessor {
this.motionDataConsumer = consumer;
}
+ /**
+ * Function for getting the combined (average) error value of both sensors.
+ public double getCombinedError()
+ {
+
+ }*/
+
/**
* Function for getting the error offsets of the user's path compared to the
* target path at a given point in time.
@@ -300,7 +315,7 @@ public class InputProcessor {
*/
public double getError(int sensorId, float time) {
- // Ensure the sensor ID is within the bounds of the array
+ /*// Ensure the sensor ID is within the bounds of the array
if (sensorId < 0 || sensorId >= selfRotationVectorPaths.length)
return 0.0d;
@@ -316,7 +331,7 @@ public class InputProcessor {
this.targetRotationVectorPaths[sensorId][targetIndex] != null
) {
return this.selfRotationVectorPaths[sensorId][selfIndex].distance(this.targetRotationVectorPaths[sensorId][targetIndex]);
- }
+ }*/
return 0.0d;
}
diff --git a/code/src/Fitbot/app/src/test/java/com/example/fitbot/PathSegmentTest.java b/code/src/Fitbot/app/src/test/java/com/example/fitbot/PathSegmentTest.java
deleted file mode 100644
index 0ab0f1d..0000000
--- a/code/src/Fitbot/app/src/test/java/com/example/fitbot/PathSegmentTest.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.example.fitbot;
-
-import static org.junit.Assert.assertEquals;
-
-import com.example.fitbot.util.path.GesturePath;
-import com.example.fitbot.util.path.PathSegment;
-
-import org.joml.Vector3f;
-import org.junit.Test;
-
-public class PathSegmentTest {
-
- @Test
- public void testPathSegment() {
- // Test the PathSegment class
- Vector3f[] vectors = new Vector3f[2];
- vectors[0] = new Vector3f(0, 0, 0);
- vectors[1] = new Vector3f(1, 1, 1);
- GesturePath path = new GesturePath(vectors);
- PathSegment[] segments = path.getSegments();
- assertEquals(1, segments.length);
- assertEquals(new Vector3f(0, 0, 0), segments[0].getStart());
- assertEquals(new Vector3f(1, 1, 1), segments[0].getEnd());
- assertEquals(new Vector3f(0.5f, 0.5f, 0.5f), segments[0].interpolate(0.5));
- }
-
-
- @Test
- public void test_pathSegmentInterpolation() {
- Vector3f start = new Vector3f(0, 0, 0);
- Vector3f end = new Vector3f(1, 1, 1);
- PathSegment segment = new PathSegment(start, end);
- assertEquals(new Vector3f(0.5f, 0.5f, 0.5f), segment.interpolate(0.5));
- }
-
-
-}
diff --git a/docs/documentation/brainstorm/Infrastructure b/docs/documentation/brainstorm/Infrastructure.md
similarity index 100%
rename from docs/documentation/brainstorm/Infrastructure
rename to docs/documentation/brainstorm/Infrastructure.md
diff --git a/docs/documentation/diagrams/infrastructure.md b/docs/documentation/diagrams/infrastructure.md
index 267cdee..425d4f3 100644
--- a/docs/documentation/diagrams/infrastructure.md
+++ b/docs/documentation/diagrams/infrastructure.md
@@ -20,8 +20,9 @@ classDiagram
Raspberry Pi --> NodeJS
Raspberry Pi --> Database
-NodeJS <--> Android Application : Request exercise data from database
+NodeJS <--> Android Application : Request exercise data from database. Send ip adress to cache
Database <--> NodeJS : Database queries
+NodeJS --> ESP8266 : Get pepper ip
ESP8266 --> Android Application : Send rotation data via WiFi to\n Pepper Web Server
@@ -48,6 +49,7 @@ namespace Server {
class NodeJS {
+MariaDB
+Handle requests
+ +Cache pepper IP
}
}
diff --git a/docs/personal-documentation/Luca/diagram-pepper-abstraction.md b/docs/personal-documentation/Luca/diagram-pepper-abstraction.md
new file mode 100644
index 0000000..c92bbbc
--- /dev/null
+++ b/docs/personal-documentation/Luca/diagram-pepper-abstraction.md
@@ -0,0 +1,88 @@
+## Pepper Abstraction Design
+
+---
+
+### Introduction
+
+The Pepper robot is a complex system that can be controlled by a variety of different actions. To make the system more
+manageable, we've decided implement abstraction and encapsulation in the classes related to Pepper controls.
+This way, we can easily add new action events in the future.
+All these classes inherit from the `AbstractPepperActionEvent` class.
+
+### Problems
+
+1. The Pepper robot functions with a system that only allows one action to be executed at a time, per action category.
+This means that, for example, when two speech actions are executed at the same time, the application will crash due
+to a `RuntimeException` being thrown. Due to this fact, whenever the execution of multiple processes overlap,
+the application will crash.
+
+2. Besides the first problem, for the Pepper robot to be able to execute any actions, it is required to have a
+QiContext available. This context is only provided in a class that extends the `RobotLifecycleCallbacks` class.
+This means, that whenever the class does not extend this class, the robot will be unable to execute any actions.
+
+### Solution
+
+To prevent the application from crashing, we've decided to implement a queue system in the `Pepper` class.
+This system allows us to queue any new actions that need to be executed whenever another action is already
+being executed. This way, we can prevent the application throwing a `RuntimeException` and thus crashing.
+
+To tackle the second problem, we've decided to implement a system where the Pepper class has a global variable, which
+holds the current QiContext. This means, that whenever a user decides to execute an action, and no current QiContext
+is available, the action will be queued until a QiContext is available. This means that we can queue several actions
+at once without any exceptions being thrown.
+
+### Diagrams
+
+#### Class Diagram
+
+```mermaid
+classDiagram
+ class Pepper {
+ -pepperActionEventQueue : ConcurrentLinkedQueue
+ -isAnimating : AtomicBoolean
+ -isSpeaking : AtomicBoolean
+
+ +latestContext : QiContext
+ +addToEventQueue(AbstractPepperActionEvent event)
+ +provideQiContext(QiContext context)
+
+ -processEventQueue()
+ }
+ class AbstractPepperActionEvent {
+ +getAction() EPepperAction
+ }
+ class PepperSpeechEvent {
+ +phrase : String
+ +locale : Locale
+ +PepperSpeechEvent(String phrase, Locale locale)
+ +getSay(QiContext context) Say
+ }
+ class PepperAnimationEvent {
+ +PepperAnimationEvent(String animationName)
+ +PepperAnimationEvent(String animationName, IAnimationCompletedListener listener)
+ +getAnimation(QiContext context) Animate
+ +animationName : String
+ +IAnimationCompletedListener : IAnimationCompletedListener
+ }
+ Pepper <|-- AbstractPepperActionEvent
+ PepperSpeechEvent <|-- AbstractPepperActionEvent
+ PepperAnimationEvent <|-- AbstractPepperActionEvent
+```
+
+#### Queue System in Pepper class
+
+```mermaid
+
+graph LR
+ subgraph "Pepper Class - Action Queue System"
+ speak[say(String phrase)\nPublic\nCreate PepperSpeechEvent] --Call method--> addQueue
+ animate[animate(String animationName)\nPublic\nCreate PepperAnimationEvent] --Call method--> addQueue
+ addQueue[addToEventQueue(AbstractPepperActionEvent event)\nPublic\nAdd provided event to event queue] --Add to queue--> queue[Event Queue\nPrivate\nQueue containing all events that\nneed to be executed]
+
+ addQueue --Call method--> handleQueue[processEventQueue()\nPrivate\nCheck whether there is a context\navailable, and whether an event\nis currently being executed.\nExecutes the next event in the Queue]
+
+ queue <.-> handleQueue
+
+ provideCtx[provideQiContext(QiContext context)\nPublic\nSets global QiContext variable\nto provided context. If the context \nis not null,process the event queue] --Sets global QiContext variable--> handleQueue
+ end
+```
\ No newline at end of file
diff --git a/docs/personal-documentation/Luca/expert-review-tips.md b/docs/personal-documentation/Luca/expert-review-tips.md
deleted file mode 100644
index fb147bc..0000000
--- a/docs/personal-documentation/Luca/expert-review-tips.md
+++ /dev/null
@@ -1,9 +0,0 @@
-
-## Expert review #1
-
-### Document as you go
-Documenteer alle problemen die voorkomen bij het project en noteer de
-oplossingen voor deze problemen. Dit kan bijvoorbeeld d.m.v. een command die
-cache files verwijderd, of op welke manier je een project fixt. Dit kan toekomstige
-problemen voorkomen.
-
diff --git a/docs/personal-documentation/Luca/expert-review.md b/docs/personal-documentation/Luca/expert-review.md
index fa98e9b..cf97502 100644
--- a/docs/personal-documentation/Luca/expert-review.md
+++ b/docs/personal-documentation/Luca/expert-review.md
@@ -12,6 +12,9 @@ Deze classes inheriten `AbstractPepperActionEvent`.
K2: Gebruikers Test
+( Maak een fictief persoon die de applicatie zou kunnen gebruiken, om erachter te komen
+wat ze zouden willen )
+
---
Wij hebben gezamenlijk gecommuniceerd over het plan, echter is alleen
@@ -32,6 +35,14 @@ Zie bestand 'infrastructure.md'
K4 - Ontwerp embedded system
+Documenteer het queue systeem van de Pepper class
+Maak een mermaid graph LR diagram
+
---
Zie '/documentation/hardware/sensors'
+
+K5 - Embedded Software Schrijven
+
+Feedback:
+- Is in principe K1,
diff --git a/docs/personal-documentation/Luca/gebruikers-onderzoek-personage.md b/docs/personal-documentation/Luca/gebruikers-onderzoek-personage.md
new file mode 100644
index 0000000..12b4c35
--- /dev/null
+++ b/docs/personal-documentation/Luca/gebruikers-onderzoek-personage.md
@@ -0,0 +1,72 @@
+### Gebruikersonderzoek Personage
+
+---
+
+Gezien de huidige omstandigheden is het nogal lastig om actuele feedback te verkrijgen
+van onze doelgroep. Dit betekent dat we een fictief karakter moeten ontwikkelen die als onze
+gebruiker functioneert. Hierbij moeten we zo veel mogelijk parameters vaststellen die
+overeen kunnen komen met een potentiele gebruiker.
+
+Om hiermee te beginnen is het noodzakelijk om eerst deze parameters vast te stellen.
+
+Deze zijn als volgt:
+
+- Bedraagt een leeftijd van tussen de 50 en 70 jaar
+- Woont in een verzorgingstehuis
+- Heeft enigzins last van eenzaamheid
+- Heeft moeite met lichamelijke activiteiten
+- Grote kans op slecht zicht
+
+Nu deze parameters vastgesteld zijn kunnen we een fictief personage ontwikkelen die als onze
+gebruiker functioneert. Dit personage zal de naam 'Henk' dragen.
+
+Vervolgens is het handig om de applicatie te introduceren.
+De applicatie zal als volgt geintroduceerd worden:
+
+"Onze applicatie is een interactief programma waarmee u samen fitness activiteiten kunt
+verrichten met een virtuele assistent genaamd Pepper. Pepper zal u begeleiden door de
+verschillende oefeningen en u helpen met het uitvoeren van de oefeningen. Iedere
+oefening zal worden begeleid door een stem die u verteld wat u moet doen en hoe u dit
+moet doen. Daarnaast zal Pepper u ook feedback geven over hoe goed u de oefeningen
+uitvoert."
+
+Een fictieve reactie op alle gestelde voorwaarden kan zijn als volgt:
+
+#### Introductie
+
+Goedendag, ik ben Henk en ik ben 67 jaar oud. Ik woon al een aantal jaar in verzorgingstehuis genaamd Amstelhuis.
+Helaas heb ik de laatste tijd wat meer last van mijn gezondheid, waardoor ik minder goed kan bewegen. Hierdoor voel ik
+me soms wat eenzaam en verveel ik me wel eens.
+
+Ik ben altijd erg actief geweest, dus toen ik hoorde over de Pepper FitBot app was ik meteen enthousiast. De
+verpleegster vertelde me dat de Pepper app misschien wel kan helpen om mijn conditie op peil te houden en om me minder
+eenzaam te voelen. Dus ik ben erg benieuwd wat de FitBot app allemaal kan!
+
+#### Gebruikservaring
+
+Eerste indruk: Toen ik de FitBot app voor het eerst gebruikte, vond ik het erg leuk dat Pepper me begeleidde door de
+oefeningen. Hij is duidelijk en behulpzaam, en hij maakt er een gezellige sfeer van.
+
+##### Gebruiksgemak
+De FitBot app is erg gebruiksvriendelijk. De app is eenvoudig te bedienen en de instructies zijn
+duidelijk. Ook vind ik het fijn dat de app mijn voortgang bijhoudt.
+
+##### Functionaliteit
+De FitBot app heeft veel leuke en nuttige functies. Ik vind het vooral leuk dat er verschillende
+oefeningen zijn voor verschillende niveaus.
+
+##### Motivatie
+Pepper is een geweldige motivator. Hij moedigt me aan om door te gaan en hij geeft me complimenten als ik
+goed bezig ben. Hierdoor ben ik gemotiveerder om te blijven sporten.
+
+##### Verbeterpunten
+
+- Het zou leuk zijn als er meer oefeningen aan de app worden toegevoegd. Zo zou ik graag meer oefeningen willen doen voor
+mijn spierkracht en lenigheid.
+- De uitleg van de oefeningen is soms een beetje kort. Het zou fijn zijn als deze wat uitgebreider zou zijn.
+- Het zou leuk zijn als er de mogelijkheid was om samen met anderen te sporten via de app. Zo zou ik bijvoorbeeld met
+mijn kleinkinderen kunnen videobellen terwijl we allebei dezelfde oefeningen doen.
+
+Al met al ben ik erg tevreden over de FitBot app. Het is een leuke en effectieve manier om te sporten. Pepper is een
+fijne motivator en de app heeft veel nuttige functies. Ik zou de FitBot app zeker aanbevelen aan andere mensen in het
+verzorgingstehuis.
\ No newline at end of file
diff --git a/docs/personal-documentation/Luca/infrastructure-design.md b/docs/personal-documentation/Luca/infrastructure-design.md
new file mode 100644
index 0000000..b2d3e89
--- /dev/null
+++ b/docs/personal-documentation/Luca/infrastructure-design.md
@@ -0,0 +1,61 @@
+### Infrastructure Design
+
+---
+
+As for our project, we've made the following design choices for our infrastructure.
+We've decided to implement a NodeJS server on a Raspberry Pi, which will handle the requests for retrieving exercises.
+This server will communicate with a MariaDB database, which contains the exercise data.
+The Pepper robot will host a web server, which will handle the incoming rotational data from an ESP8266.
+This data will then be processed by a motion processor class, `InputProcessor`, which will compare the rotational data
+to the data of the current exercise and show how well the user is performing.
+
+Down below is a visual representation of how this infrastructure will look like.
+
+### General Infrastructure Diagram
+```mermaid
+
+graph TB
+ subgraph "Raspberry Pi"
+ server[NodeJS Server\n\nHandles requests for\nretrieving exercises]
+ db[Database - MariaDB\n\nContains exercise data]
+ server --Fetch database entry--> db
+ db --Return retrieved entry--> server
+
+ end
+
+ subgraph "Pepper Robot"
+ webServer[Web Server\n\nHandles incoming rotational data\nfrom ESP8266]
+ motionProcessor[Motion Processor\n\nProcesses rotational data,\ncompares it to the current exercise\nand shows the statistics on the screen]
+ ui[User Interface\n\nShows the current exercise,\nhow to perform it and the\nstatistics of the user's performance]
+ motionProcessor --Send HTTP GET for Exercise--> server
+ server --Send exercise data\nin JSON format--> motionProcessor
+ webServer --Process rotational data--> motionProcessor
+ motionProcessor --Show statistics\non the UI--> ui
+ end
+
+ subgraph "Motion Sensing Device"
+ esp[ESP8266\n\nMeasures sensor data\nand sends it to the web server]
+ gyro[Gyroscope\n\nMeasures rotational data\n(Rx, Ry, Rz)]
+ esp --Send rotational data\nto Pepper Web Server--> webServer
+ gyro <---> esp
+ end
+
+```
+
+### Database Diagram
+
+For the design of our database, we've decided to only add a single table named `Exercise`.
+This table contains all the information needed for the exercises.
+```mermaid
+classDiagram
+ class Exercise {
+ +ExerciseId : INT
+ +Name : VARCHAR
+ +Description : VARCHAR
+ +ShortDescription : VARCHAR
+ +ImageURL : VARCHAR
+ +VideoURL : VARCHAR
+ +MuscleGroup : VARCHAR
+ +Path : VARCHAR
+ }
+```
\ No newline at end of file