diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 4020532..25b05d8 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -14,10 +14,9 @@
-
-
+
-
+
@@ -210,7 +209,11 @@
-
+
+
+
+
+ 1713528225837
@@ -384,7 +387,23 @@
1716891155110
-
+
+
+ 1716977853269
+
+
+
+ 1716977853269
+
+
+
+ 1716988959836
+
+
+
+ 1716988959836
+
+
@@ -424,6 +443,8 @@
-
+
+
+
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index c5f3f6b..0e14d8e 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,3 @@
{
- "java.configuration.updateBuildConfiguration": "interactive"
+ "java.configuration.updateBuildConfiguration": "disabled"
}
\ No newline at end of file
diff --git a/code/arduino/Movement-sensor-code/Connectivity.cpp b/code/arduino/Movement-sensor-code/Connectivity.cpp
index 6e96ca3..d4c5837 100644
--- a/code/arduino/Movement-sensor-code/Connectivity.cpp
+++ b/code/arduino/Movement-sensor-code/Connectivity.cpp
@@ -8,23 +8,56 @@ void Connectivity::connectWiFi(char* ssid, char* pass){
}
}
-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::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);
+// 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);
+// }
+
+const char* getServerURL = "http://145.92.8.132:443/get-ip";
+String ipAddress = ""; // string that will hold the server's IP address
+
+/** Fetch the IP address of pepper from the server */
+const char* Connectivity::fetchIPAddress() {
+ char* ipAddress = NULL; // Declare ipAddress as a char*
+ if (WiFi.status() == WL_CONNECTED) {
+ HTTPClient http;
+ WiFiClient client;
+ http.begin(client, getServerURL);
+
+ int httpCode = http.GET();
+ if (httpCode > 0) {
+ if (httpCode == HTTP_CODE_OK) {
+ // If successful (code 200), read the response body and parse the IP address
+ String response = http.getString();
+ StaticJsonDocument<200> doc;
+ deserializeJson(doc, response);
+ const char* ip = doc["ip"]; // Extract the IP address
+ ipAddress = strdup(ip);
+ }
+ } else {
+ Serial.printf("GET request failed, error: %s\n", http.errorToString(httpCode).c_str());
+ }
+
+ http.end();
+ } else {
+ Serial.println("WiFi not connected");
+ }
+ return ipAddress;
}
/** Send a POST request to a server with provided data */
int Connectivity::httpPost(const char *serverAddress, const char *serverSubPath, const unsigned short serverPort,
const char *data, const size_t dataLength, const char *contentType)
{
- if ( wifi_client.connect(serverAddress, serverPort)) {
+ WiFiClient wifi_client; // Ensure WiFiClient is declared and initialized
+ if (wifi_client.connect(serverAddress, serverPort)) {
wifi_client.printf("POST %s HTTP/1.1\r\n", serverSubPath);
wifi_client.printf("Content-Type: %s\r\n", contentType);
wifi_client.printf("Content-Length: %d\r\n", dataLength);
@@ -35,4 +68,4 @@ int Connectivity::httpPost(const char *serverAddress, const char *serverSubPath,
}
return 1;
-}
\ No newline at end of file
+}
diff --git a/code/arduino/Movement-sensor-code/Connectivity.h b/code/arduino/Movement-sensor-code/Connectivity.h
index 90742aa..ae711e7 100644
--- a/code/arduino/Movement-sensor-code/Connectivity.h
+++ b/code/arduino/Movement-sensor-code/Connectivity.h
@@ -1,30 +1,33 @@
-#ifndef Connectivity_h
-#define Connectivity_h
+#ifndef MOVEMENTSENSORCODE_CONNECTIVITY_h
+#define MOVEMENTSENSORCODE_CONNECTIVITY_h
#include "Arduino.h"
#include
#include
#include
+#include
#include
#include
#include
#include
#include
+#include
-class Connectivity {
+// declare the class Connectivity with all functions
+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);
int httpPost(const char *serverAddress, const char *serverSubPath, const unsigned short serverPort, const char *data, const size_t dataLength, const char *contentType);
-
+ const char* fetchIPAddress();
private:
ESP8266WiFiMulti wifi;
WiFiClient wifi_client;
- WebSocketsClient webSocket;
+ // WebSocketsClient webSocket;
};
-#endif
\ No newline at end of file
+#endif // MOVEMENTSENSORCODE_CONNECTIVITY_h
\ 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 3bb3e92..4b57532 100644
--- a/code/arduino/Movement-sensor-code/Movement-sensor-code.ino
+++ b/code/arduino/Movement-sensor-code/Movement-sensor-code.ino
@@ -6,38 +6,42 @@ void setup() {
sensorManager.sensorSetup();
}
-unsigned long lastTime = 0; // will store the last time the code was run
-
void loop() {
- SensorManager::eulerAngles eulerRotation = sensorManager.getEulerAngles();
- // SensorManager::acceleration rotationAcceleration = sensorManager.getAcelleration();
-
+ //get data from sensor
+ SensorManager::eulerAngles Rotation = sensorManager.getEulerAngles();
+//static structure
+// TODO: redo json for esp8266 and in android studio
struct acceleration {
float x = 9;
float y = 9;
float z = 9;
} accelData;
+ if (!ipAquired) {
+ serverIp = connectivity.fetchIPAddress(); //Fetch pepper ip address
+ ipAquired = true;
+ }
+
+ unsigned long lastTime = 0; // will store the last time the code was run
unsigned long currentTime = millis();
- if (currentTime - lastTime >= 100) { // 100 ms has passed
+ if (currentTime - lastTime >= 100) { // do everything inside every 100 ms
memset(buffer, 0, BUFFER_SIZE);
+ //convert string to char*
sprintf(
buffer,
"{\"deviceId\": %d, \"rotationX\": %f, \"rotationY\": %f, \"rotationZ\": %f, \"accelerationX\": %f, \"accelerationY\": %f, \"accelerationZ\": %f, \"type\": %s}",
DEVICE_ID,
- eulerRotation.roll,
- eulerRotation.pitch,
- eulerRotation.yaw,
+ Rotation.roll,
+ Rotation.pitch,
+ Rotation.yaw,
accelData.x,
accelData.y,
accelData.z,
"data");
// %d = int, %f = floatation, %s = string
- connectivity.httpPost("192.168.137.243", "/", 3445, buffer, strlen(buffer), "application/json");
+ //send data to pepper
+ connectivity.httpPost(serverIp, "/", 3445, buffer, strlen(buffer), "application/json");
lastTime = currentTime;
}
}
-//acceleration.X
-//acceleration.Y
-//acceleration.Z
diff --git a/code/arduino/Movement-sensor-code/SensorManager.cpp b/code/arduino/Movement-sensor-code/SensorManager.cpp
index 7fee39d..ab2216f 100644
--- a/code/arduino/Movement-sensor-code/SensorManager.cpp
+++ b/code/arduino/Movement-sensor-code/SensorManager.cpp
@@ -17,14 +17,14 @@ void SensorManager::sensorSetup() {
// myIMU.enableStepCounter(500); //Send data update every 500ms
}
//get sensordata
-SensorManager::RotationQuintillions SensorManager::getQuintillions() {
+SensorManager::RotationQuaternions SensorManager::getQuaternions() {
if (myIMU.dataAvailable() == true) {
float i = myIMU.getQuatI();
float j = myIMU.getQuatJ();
float k = myIMU.getQuatK();
float w = myIMU.getQuatReal();
- RotationQuintillions rotation = { i, j, k, w };
+ RotationQuaternions rotation = { i, j, k, w };
return rotation;
} else {
float i = myIMU.getQuatI();
@@ -32,13 +32,13 @@ SensorManager::RotationQuintillions SensorManager::getQuintillions() {
float k = myIMU.getQuatK();
float w = myIMU.getQuatReal();
- RotationQuintillions rotation = { i, j, k, w };
+ RotationQuaternions rotation = { i, j, k, w };
return rotation;
}
}
-//calculate Quintillions to Euler angles from -1π to +1π
+//calculate Quaternions to Euler angles from -1π to +1π
SensorManager::eulerAngles SensorManager::getEulerAngles() {
- SensorManager::RotationQuintillions rotation = getQuintillions();
+ SensorManager::RotationQuaternions rotation = getQuaternions();
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));
float yaw = atan2(2.0f * (rotation.w * rotation.k + rotation.i * rotation.j), 1.0f - 2.0f * (rotation.j * rotation.j + rotation.k * rotation.k));
diff --git a/code/arduino/Movement-sensor-code/SensorManager.h b/code/arduino/Movement-sensor-code/SensorManager.h
index aaf4d71..41f800f 100644
--- a/code/arduino/Movement-sensor-code/SensorManager.h
+++ b/code/arduino/Movement-sensor-code/SensorManager.h
@@ -1,9 +1,10 @@
-#ifndef SensorManager_h
-#define SensorManager_h
+#ifndef MOVEMENTSENSORCODE_SENSORMANAGER_H
+#define MOVEMENTSENSORCODE_SENSORMANAGER_H
#include "Arduino.h"
#include "SparkFun_BNO080_Arduino_Library.h"
+// declare the class SensorManager with all functions
class SensorManager {
public:
SensorManager();
@@ -18,19 +19,22 @@ public:
float y;
float z;
};
-
+// void sendData(float roll, float pitch, float yaw);
eulerAngles getEulerAngles();
acceleration getAcelleration();
bool sensorTap();
+
private:
- struct RotationQuintillions {
+
+ struct RotationQuaternions {
float i;
float j;
float k;
float w;
};
- RotationQuintillions getQuintillions();
+ RotationQuaternions getQuaternions(); // get the quaternions from the sensor
+
BNO080 myIMU;
};
-#endif
\ No newline at end of file
+#endif // MOVEMENTSENSORCODE_SENSORMANAGER_H
\ No newline at end of file
diff --git a/code/arduino/Movement-sensor-code/headerFIle.h b/code/arduino/Movement-sensor-code/headerFIle.h
index b065b3e..1c21dcb 100644
--- a/code/arduino/Movement-sensor-code/headerFIle.h
+++ b/code/arduino/Movement-sensor-code/headerFIle.h
@@ -11,5 +11,8 @@ WebSocketsClient webSocket;
#define ssid "1235678i"
#define pass "12345678"
#define BUFFER_SIZE 1024
-#define DEVICE_ID 1
+#define DEVICE_ID 0
+
char *buffer = (char *)malloc(sizeof(char) * BUFFER_SIZE);
+const char* serverIp = NULL; // Declare serverIp here
+bool ipAquired = false;
\ No newline at end of file
diff --git a/code/arduino/bluetoothEsp/bluetoothEsp.ino b/code/arduino/bluetoothEsp/bluetoothEsp.ino
deleted file mode 100644
index 0e0eaaf..0000000
--- a/code/arduino/bluetoothEsp/bluetoothEsp.ino
+++ /dev/null
@@ -1,33 +0,0 @@
-#include
-#include
-
-// Define the service UUID
-#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
-
-// Define the characteristic UUID
-#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
-
-void setup() {
- // Create a BLE server
- BLEServer *pServer = BLEDevice::createServer();
-
- // Create a BLE service
- BLEService *pService = pServer->createService(SERVICE_UUID);
-
- // Create a BLE characteristic
- BLECharacteristic *pCharacteristic = pService->createCharacteristic(
- CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ);
-
- // Set the characteristic value
- pCharacteristic->setValue("Hello, Bluetooth!");
-
- // Start the service
- pService->start();
-
- // Start advertising the service
- pServer->getAdvertising()->start();
-}
-
-void loop() {
- // Nothing to do here
-}
\ No newline at end of file
diff --git a/code/web/incoming_request_handlers.js b/code/server/incoming_request_handlers.js
similarity index 57%
rename from code/web/incoming_request_handlers.js
rename to code/server/incoming_request_handlers.js
index 6049b3b..9d23366 100644
--- a/code/web/incoming_request_handlers.js
+++ b/code/server/incoming_request_handlers.js
@@ -1,3 +1,5 @@
+const databaseQuery = 'SELECT * FROM `Exercise` WHERE ExerciseID = 1';
+// const databaseQueryRand = 'SELECT * FROM `Exercise` ORDER BY RAND() LIMIT 1';
/**
*
@@ -9,41 +11,33 @@
function handleIncoming(request, response, app, pool)
{
- let query = 'SELECT * FROM Exercise WHERE ExerciseID = ?';
- let parameters = [];
-
- if (!request.hasOwnProperty('uid') || typeof request.uid !== 'number')
- {
- query = 'SELECT * FROM Exercise';
- } else parameters.push(request.uid);
-
// Acquire database connection
pool.getConnection()
.then(conn => {
- conn.query(query, parameters)
+ conn.query(
+ databaseQuery)
.then(rows => {
if (rows.length === 0)
{
response
.status(404)
- .send(JSON.stringify({error: 'Exercise not found'}));
+ .send(JSON.stringify({error: 'No exercises found in the database.'}));
}
else
{
- // Send back the data in the right format
- let converted = rows.map(row => {
- return {
- name: row.Name,
- description: row.Description,
- muscleGroup: row.MuscleGroup,
- imageUrl: row.ImageURL,
- videoUrl: row.VideoURL
- };
- });
-
- response
- .status(200)
- .send(JSON.stringify(converted));
+ let row = rows[0];
+ response.status(200)
+ .send(JSON.stringify({
+ exerciseId: row['ExerciseID'],
+ name: row['Name'],
+ muscleGroup: row['MuscleGroup'],
+ shortDescription: row['ShortDescription'],
+ description: row['Description'],
+ imageUrl: row['ImageURL'],
+ videoUrl: row['VideoURL'],
+ path: row['Path'],
+ duration: row['Duration']
+ }))
}
})
.catch(error => {
diff --git a/code/server/ipSender/index.js b/code/server/ipSender/index.js
new file mode 100644
index 0000000..dc68c2d
--- /dev/null
+++ b/code/server/ipSender/index.js
@@ -0,0 +1,22 @@
+const express = require('express');
+const app = express();
+
+app.use(express.json()); // for parsing application/json
+
+let ipAddress = ''; // to store the received IP address
+
+// endpoint to receive an IP address from an external source
+app.post('/set-ip', (req, res) => {
+ ipAddress = req.body.ip;
+ console.log('IP address received:', ipAddress);
+});
+
+// endpoint for the ESP32 to fetch the IP address
+app.get('/get-ip', (req, res) => {
+ res.json({ ip: ipAddress });
+ console.log('IP address sent to ESP32');
+});
+
+app.listen(42069, () => {
+ console.log('Server is running on port 42069');
+});
\ No newline at end of file
diff --git a/code/web/server.js b/code/server/server.js
similarity index 61%
rename from code/web/server.js
rename to code/server/server.js
index 886846e..c31eded 100644
--- a/code/web/server.js
+++ b/code/server/server.js
@@ -21,6 +21,20 @@ const pool = mariadb.createPool(databaseCredentials);
// Register incoming HTTP request handlers
require('./incoming_request_handlers')(app, pool);
+let ipAddress = ''; // to store the received IP address
+
+// endpoint to receive an IP address from an external source
+app.post('/set-ip', (req, res) => {
+ ipAddress = req.body.ip;
+ console.log('IP address received:', ipAddress);
+});
+
+// endpoint for the ESP32 to fetch the IP address
+app.get('/get-ip', (req, res) => {
+ res.json({ ip: ipAddress });
+ console.log('IP address sent to ESP32');
+});
+
// Start server
app.listen(serverPort, () => {
console.log(`Server running on port ${serverPort}`);
diff --git a/code/server/test/config.js b/code/server/test/config.js
new file mode 100644
index 0000000..87c69b0
--- /dev/null
+++ b/code/server/test/config.js
@@ -0,0 +1,8 @@
+// config.js
+module.exports = {
+ host: '127.0.0.1',
+ user: 'fitbot',
+ password: 'fitbot123',
+ database: 'fitbot',
+ port: 3306, // Default MariaDB port
+ };
diff --git a/code/server/test/testConnection.js b/code/server/test/testConnection.js
new file mode 100644
index 0000000..4eb953a
--- /dev/null
+++ b/code/server/test/testConnection.js
@@ -0,0 +1,35 @@
+const express = require('express');
+const mariadb = require('mariadb');
+const config = require('./config');
+
+const app = express();
+const port = 443; // Use port 443
+
+const pool = mariadb.createPool({
+ host: config.host,
+ user: config.user,
+ password: config.password,
+ database: config.database,
+ connectionLimit: 5,
+ acquireTimeout: 30000, // Increase timeout to 30 seconds
+});
+
+app.get('/', async (req, res) => {
+ let conn;
+ try {
+ conn = await pool.getConnection();
+ console.log("Connected to MariaDB!");
+ const rows = await conn.query("SELECT * FROM Exercise ORDER BY RAND() LIMIT 1");
+ console.log(rows); // [{val: 1}]
+ res.json(rows); // Send the result as JSON response
+ } catch (err) {
+ console.error("Unable to connect to MariaDB:", err);
+ res.status(500).send("Unable to connect to MariaDB");
+ } finally {
+ if (conn) conn.release(); // Release the connection back to the pool
+ }
+});
+
+app.listen(port, '145.92.8.132', () => {
+ console.log(`Server is listening on http://145.92.8.132:${port}`);
+});
diff --git a/code/src/Fitbot/.gitignore b/code/src/Fitbot/.gitignore
index 732c947..203dde6 100644
--- a/code/src/Fitbot/.gitignore
+++ b/code/src/Fitbot/.gitignore
@@ -14,4 +14,5 @@
.cxx
local.properties
.idea
-.vscode
\ No newline at end of file
+.vscode
+/.idea/
diff --git a/code/src/Fitbot/.idea/misc.xml b/code/src/Fitbot/.idea/misc.xml
index a647bf6..c23d507 100644
--- a/code/src/Fitbot/.idea/misc.xml
+++ b/code/src/Fitbot/.idea/misc.xml
@@ -16,33 +16,45 @@
+
+
+
+
+
+
+
+
+
-
+
+
+
+
diff --git a/code/src/Fitbot/app/src/main/AndroidManifest.xml b/code/src/Fitbot/app/src/main/AndroidManifest.xml
index 326887c..32bdaaf 100644
--- a/code/src/Fitbot/app/src/main/AndroidManifest.xml
+++ b/code/src/Fitbot/app/src/main/AndroidManifest.xml
@@ -10,19 +10,21 @@
+
+
+
+
-
-
+ * Before any of the functions in this class can be used, the Pepper class needs a QiContext to be
+ * set. This is retrieved in the `onRobotFocusGained` method of the RobotLifecycleCallbacks
+ * interface, and can then provided using the `provideContext` method.
+ *
+ */
+public class Pepper {
+
+ // Queue containing all Pepper actions that need to be executed
+ // This is to prevent the app from crashing when attempting to perform multiple actions at once
+ private static final ConcurrentLinkedQueue pepperActionEventQueue =
+ new ConcurrentLinkedQueue<>();
+
+ private static final AtomicBoolean isAnimating = new AtomicBoolean(false);
+ private static final AtomicBoolean isSpeaking = new AtomicBoolean(false);
+
+ private static final Locale DEFAULT_LOCALE = new Locale(Language.DUTCH, Region.NETHERLANDS);
+
+ /**
+ * The latest QiContext used by Pepper.
+ * This can be publicly accessed to get the latest QiContext used by Pepper.
+ */
+ public static QiContext latestContext = null;
+
+ /**
+ * Make the Pepper robot speak a phrase.
+ * This function adds a SpeechEvent to the event queue,
+ * and will speak the phrase once Pepper is ready to process it.
+ *
+ * @param phrase The phrase to speak
+ */
+ public static void say(String phrase) {
+ addToEventQueue(new PepperSpeechEvent(phrase, DEFAULT_LOCALE));
+ }
+
+ /**
+ * Make the Pepper robot perform an animation.
+ * This function adds an AnimationEvent to the event queue,
+ * and will perform the animation once Pepper is ready to process it.
+ *
+ * @param animationName The name of the animation to play
+ */
+ public static void animate(String animationName) {
+ addToEventQueue(new PepperAnimationEvent(animationName));
+ }
+
+ /**
+ * Add an event to the event queue.
+ * The event will be executed once Pepper is ready to process it.
+ *
+ * @param event The event to add to the queue
+ */
+ public static void addToEventQueue(AbstractPepperActionEvent event) {
+ pepperActionEventQueue.add(event);
+ processEventQueue();
+ }
+
+ /**
+ * Process the event queue.
+ * This method will process the next event in the queue if Pepper is not currently
+ * speaking or animating.
+ * This prevents multiple actions from being executed at the same time, which can
+ * cause the application to crash.
+ */
+ private static synchronized void processEventQueue() {
+ if (!pepperActionEventQueue.isEmpty()) {
+ AbstractPepperActionEvent event = pepperActionEventQueue.poll();
+
+ // Prevent null pointer exceptions
+ if (event == null || latestContext == null)
+ return;
+
+ switch (event.getAction()) {
+ /* Event for speaking a phrase **/
+ case ACTION_SPEAK:
+ if (!(event instanceof PepperSpeechEvent) || isSpeaking.get())
+ break;
+
+ PepperSpeechEvent speechEvent = (PepperSpeechEvent) event;
+ isSpeaking.set(true);
+ speechEvent
+ .getSay(latestContext)
+ .async()
+ .run()
+ .andThenConsume(future -> {
+ isSpeaking.set(false);
+ processEventQueue();
+ });
+ break;
+
+ /* Event for animating the robot **/
+ case ACTION_ANIMATE:
+ if (!(event instanceof PepperAnimationEvent) || isAnimating.get())
+ break;
+
+ PepperAnimationEvent animationEvent = (PepperAnimationEvent) event;
+ animationEvent
+ .getAnimation(latestContext)
+ .async()
+ .run()
+ .andThenConsume(future -> {
+ isAnimating.set(false);
+ processEventQueue();
+ });
+ break;
+ default:
+ // Do nothing
+ break;
+ }
+ }
+ }
+
+ /**
+ * Function for providing the latest QiContext to Pepper.
+ *
+ * @param context The QiContext to use.
+ * This can be null if the context is not available.
+ * @param origin The origin of the context.
+ * This parameter is to prevent other classes from
+ * unnecessarily providing a context, or setting
+ * the context to null.
+ */
+ public static void provideContext(QiContext context, Class extends RobotLifecycleCallbacks> origin) {
+ latestContext = context;
+ if (context != null) {
+ processEventQueue();
+ }
+ }
+
+}
diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/pepper/PepperAnimationEvent.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/pepper/PepperAnimationEvent.java
new file mode 100644
index 0000000..0bebc4f
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/pepper/PepperAnimationEvent.java
@@ -0,0 +1,65 @@
+package com.example.fitbot.pepper;
+
+import com.aldebaran.qi.sdk.QiContext;
+import com.aldebaran.qi.sdk.builder.AnimateBuilder;
+import com.aldebaran.qi.sdk.builder.AnimationBuilder;
+import com.aldebaran.qi.sdk.object.actuation.Animate;
+import com.aldebaran.qi.sdk.object.actuation.Animation;
+
+public class PepperAnimationEvent extends AbstractPepperActionEvent {
+
+ public final String animationName;
+ private final IAnimationCompletedListener onLabelReachedListener;
+
+
+ /**
+ * Constructor for PepperAnimationEvent
+ *
+ * @param animationName The name of the animation to play
+ * @param onLabelReachedListener The listener to call when the animation is completed
+ */
+ public PepperAnimationEvent(String animationName, IAnimationCompletedListener onLabelReachedListener) {
+ this.animationName = animationName;
+ this.onLabelReachedListener = onLabelReachedListener;
+ }
+
+ /**
+ * Constructor for PepperAnimationEvent
+ *
+ * @param animationName The name of the animation to play
+ */
+ public PepperAnimationEvent(String animationName) {
+ this(animationName, null);
+ }
+
+ @Override
+ public EPepperAction getAction() {
+ return EPepperAction.ACTION_ANIMATE;
+ }
+
+ /**
+ * Returns an animation object, which can be used to play the animation
+ * in the Pepper class.
+ */
+ public Animate getAnimation(QiContext context) {
+ Animation animation = AnimationBuilder.with(context)
+ .withResources(context.getResources().getIdentifier(animationName, "raw", context.getPackageName()))
+ .build();
+
+ Animate animate = AnimateBuilder.with(context)
+ .withAnimation(animation)
+ .build();
+
+ // Add a listener for when a label is reached
+ animate.addOnLabelReachedListener((label, time) -> {
+ if (onLabelReachedListener != null && "end".equals(label)) {
+ onLabelReachedListener.onComplete();
+ }
+ });
+ return animate;
+ }
+
+ public interface IAnimationCompletedListener {
+ void onComplete();
+ }
+}
diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/pepper/PepperSpeechEvent.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/pepper/PepperSpeechEvent.java
new file mode 100644
index 0000000..ecf8eab
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/pepper/PepperSpeechEvent.java
@@ -0,0 +1,32 @@
+package com.example.fitbot.pepper;
+
+import com.aldebaran.qi.sdk.QiContext;
+import com.aldebaran.qi.sdk.builder.SayBuilder;
+import com.aldebaran.qi.sdk.object.conversation.Say;
+import com.aldebaran.qi.sdk.object.locale.Locale;
+
+public class PepperSpeechEvent extends AbstractPepperActionEvent {
+
+ public final String phrase;
+ public final Locale locale;
+
+ public PepperSpeechEvent(String phrase, Locale locale) {
+ this.locale = locale;
+ this.phrase = phrase;
+ }
+
+ @Override
+ public EPepperAction getAction() {
+ return EPepperAction.ACTION_SPEAK;
+ }
+
+ /**
+ * Returns a Say object, which can then be executed.
+ */
+ public Say getSay(QiContext context) {
+ return SayBuilder.with(context)
+ .withText(this.phrase)
+ .withLocale(this.locale)
+ .build();
+ }
+}
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
deleted file mode 100644
index 8cc269b..0000000
--- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/CompletionActivity.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.example.fitbot.ui.activities;
-
-public class CompletionActivity {
-}
diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/EndScreenActivity.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/EndScreenActivity.java
index 703c53b..e2286ee 100644
--- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/EndScreenActivity.java
+++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/EndScreenActivity.java
@@ -4,8 +4,7 @@ import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.example.fitbot.R;
-import com.example.fitbot.ui.activities.FitnessActivity;
-import com.example.fitbot.ui.activities.MainActivity;
+import com.example.fitbot.util.NavigationManager;
public class EndScreenActivity extends AppCompatActivity {
@@ -14,7 +13,8 @@ public class EndScreenActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_end_screen);
- com.example.fitbot.util.ButtonNavigation.setupButtonNavigation(this, R.id.homeButtonEndScreen, MainActivity.class);
- com.example.fitbot.util.ButtonNavigation.setupButtonNavigation(this, R.id.startButtonEndScreen, FitnessActivity.class);
+ NavigationManager.hideSystemUI(this);
+
+ NavigationManager.setupButtonNavigation(this, R.id.homeButtonEndScreen, MainActivity.class);
}
}
\ No newline at end of file
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 5d2d6dd..5b681fc 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
@@ -1,8 +1,23 @@
package com.example.fitbot.ui.activities;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.media.MediaPlayer;
+import android.net.Uri;
import android.os.Bundle;
+import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.View;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.TextView;
import android.widget.VideoView;
import com.aldebaran.qi.sdk.QiContext;
@@ -10,123 +25,275 @@ import com.aldebaran.qi.sdk.QiSDK;
import com.aldebaran.qi.sdk.RobotLifecycleCallbacks;
import com.aldebaran.qi.sdk.design.activity.RobotActivity;
import com.aldebaran.qi.sdk.design.activity.conversationstatus.SpeechBarDisplayStrategy;
+import com.aldebaran.qi.sdk.object.actuation.Animate;
import com.example.fitbot.R;
import com.example.fitbot.exercise.Exercise;
import com.example.fitbot.exercise.ExerciseManager;
-import com.example.fitbot.ui.components.PersonalMotionPreviewElement;
-import com.example.fitbot.util.ButtonNavigation;
-import com.example.fitbot.util.FitnessCycle;
+import com.example.fitbot.pepper.Pepper;
+import com.example.fitbot.util.NavigationManager;
import com.example.fitbot.util.processing.InputProcessor;
-import org.joml.Vector3f;
-
public class FitnessActivity extends RobotActivity implements RobotLifecycleCallbacks {
// Private fields for the FitnessActivity class.
- private PersonalMotionPreviewElement personalMotionPreviewElement;
private InputProcessor motionProcessor;
private Exercise currentExercise;
+ // Progress circle for the exercises
+ private ProgressBar progressCircle;
+ private TextView progressText;
+ private int progress = 1;
+ private final int maxProgress = 10;
+
+ // Exercise status element data
+ private TextView exerciseMuscleGroupTextView;
+ private TextView exerciseNameTextView;
+ private TextView exerciseShortDescriptionTextView;
+ //private TextView exerciseDescriptionTextView;
+ private static String exerciseVideoUrl;
+ private Animate animate;
+ private VideoView videoView;
private QiContext qiContext;
+ private final Object lock = new Object();
+
// Some nice little messages for the user
- private static final String[] EXERCISE_NOT_FOUND_MESSAGES = new String[] {
+ private static final String[] EXERCISE_NOT_FOUND_MESSAGES = new String[]{
"Ik heb momenteel helaas wat moeite met het ophalen van oefeningen, sorry.",
"Het lijkt erop dat de oefeningen op een misterieus avontuur zijn. Even wachten tot ze terug zijn.",
- "Ssst, de oefeningen slapen nog, probeer het later nog eens."
+ ", de oefeningen slapen nog, probeer het later nog eens."
};
private static final String EXERCISE_NOT_FOUND_SEEK_HELP_MESSAGE =
"Indien dit probleem zich voortzet, neem contact op met de ontwikkelaar.";
private static final float SENSOR_SAMPLE_RATE = 10.0f;
- private static final int EXERCISE_COUNT = 5;
+ private static final int EXERCISE_COUNT = 5;
+ private static int EXERCISE_VIDEO_REPETITION = 1;
private static final float EXERCISE_SPEED_MULTIPLIER = 1.0f;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
QiSDK.register(this, this);
-
setContentView(R.layout.activity_fitness);
+ videoView = findViewById(R.id.videoView);
- // Remove the ugly ass bar on top of the view
+ // Fill empty objects with exercise data
+ this.exerciseNameTextView = findViewById(R.id.textViewFitnessTitle);
+ this.exerciseShortDescriptionTextView = findViewById(R.id.textViewFitnessShortDescription);
+ //this.exerciseDescriptionTextView = findViewById(R.id.textViewDialogDescription);
+
+ // Set the repetition count for the exercise
+ EXERCISE_VIDEO_REPETITION = 1;
+
+ progressCircle = findViewById(R.id.progressCircle);
+ progressText = findViewById(R.id.progressText);
+ progressCircle.setMax(maxProgress);
+
+ // Set color of loading circle
+ ProgressBar loadingCircle = findViewById(R.id.loadingCircle);
+ loadingCircle.setIndeterminateTintList(ColorStateList.valueOf(Color.RED));
+
+ // Navigation Buttons
+ NavigationManager.setupButtonNavigation(this, R.id.homeButtonFitness, MainActivity.class);
+ NavigationManager.setupButtonNavigation(this, R.id.skipButtonFitness, MainActivity.class); //Needs to skip exercises once those are implemented
+
+ // Hide system UI
+ NavigationManager.hideSystemUI(this);
setSpeechBarDisplayStrategy(SpeechBarDisplayStrategy.IMMERSIVE);
- // Find the VideoView by its ID
- VideoView videoView = findViewById(R.id.videoView);
- FitnessCycle.playVideo(videoView, this);
- ButtonNavigation.setupButtonNavigation(this, R.id.homeButtonFitness, MainActivity.class);
- // Implement your logic when the robot focus is gained
-
+ // Initiate info button
+ Button infoButtonFitness = findViewById(R.id.infoButtonFitness);
+ infoButtonFitness.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showInfoDialog();
+ }
+ });
}
@Override
public void onRobotFocusGained(QiContext qiContext) {
- this.qiContext = qiContext;
- // Find the VideoView by its ID
-// CompletableFuture.runAsync(() -> FitnessCycle.executeMovement("bicepcurl", 10, qiContext));
- personalMotionPreviewElement = findViewById(R.id.personalMotionPreviewElement);
+ // Provide the context so that all queued actions can be performed.
+ Pepper.provideContext(qiContext, this.getClass());
// Initialize the element whenever it has been added to the screen.
// This will provide the element with the appropriate dimensions for drawing
// the canvas properly.
- personalMotionPreviewElement.post(() -> {
- Exercise exercise = this.acquireExercise();
- if ( exercise == null) {
- return;
- }
+ 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()};
+ motionProcessor = new InputProcessor(this);
+ motionProcessor.useExercise(exercise);
- motionProcessor = new InputProcessor(vectors, exercise.exerciseTimeInSeconds, SENSOR_SAMPLE_RATE);
-
- personalMotionPreviewElement.provideQiContext(qiContext);
- personalMotionPreviewElement.initialize(exercise, motionProcessor, EXERCISE_COUNT);
-
- motionProcessor.startListening();
- motionProcessor.setInputHandler(personalMotionPreviewElement);
+ }, (n) -> {
+ int randomMessageIndex = (int) Math.floor(Math.random() * EXERCISE_NOT_FOUND_MESSAGES.length);
+ Pepper.say(EXERCISE_NOT_FOUND_MESSAGES[randomMessageIndex]);
+ Pepper.say(EXERCISE_NOT_FOUND_SEEK_HELP_MESSAGE);
+ // Run on main thread to prevent crashes (wack)
+ this.runOnUiThread(() -> NavigationManager.navigateToActivity(this, EndScreenActivity.class));
});
- personalMotionPreviewElement.provideQiContext(qiContext);
-
- // FitnessCycle.playVideo(qiContext, videoView, this);
}
/**
* Acquire an exercise from the ExerciseManager.
* Whenever the retrieval failed, it will have the robot say something to the user
* to inform them about the issue.
- *
- * @return The acquired exercise, or null if the exercise could not be retrieved.
*/
- public Exercise acquireExercise() {
- Exercise exercise = ExerciseManager.retrieveExercise();
- if ( exercise == null && this.qiContext != null)
- {
- int randomMessageIndex = (int)Math.floor(Math.random() * EXERCISE_NOT_FOUND_MESSAGES.length);
- FitnessCycle.say(EXERCISE_NOT_FOUND_MESSAGES[randomMessageIndex], qiContext);
- FitnessCycle.say(EXERCISE_NOT_FOUND_SEEK_HELP_MESSAGE, qiContext);
+ public void fetchExerciseAsync(Exercise.ExerciseFetchHandler onSuccessfulFetch, Exercise.ExerciseFetchHandler onFailedFetch) {
+ // For some stupid reason we cannot perform network operations on the main thread.
+ Log.e("fetchvideo", "video fetched");
+ // therefore we'll have to do it like this...
+ new Thread(() -> {
+ Exercise exercise = ExerciseManager.fetchExerciseFromDatabase();
+ if (exercise == null) {
+ onFailedFetch.handle(null);
+
+ // Main thread stuff
+ runOnUiThread(() -> NavigationManager.navigateToActivity(this, MainActivity.class));
+ } else {
+ onSuccessfulFetch.handle(exercise);
+ runOnUiThread(() -> {
+
+ exerciseNameTextView.setText(exercise.name);
+ exerciseShortDescriptionTextView.setText(exercise.shortDescription);
+ // exerciseDescriptionTextView.setText(exercise.description);
+ exerciseVideoUrl = exercise.videoUrl;
+
+ // Play the video
+ playVideo(videoView, this);
+
+ // When the video has started playing remove the loading circle
+ videoView.setOnInfoListener((mp, what, extra) -> {
+ if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
+ ProgressBar loadingCircle = findViewById(R.id.loadingCircle);
+ loadingCircle.setVisibility(View.GONE);
+
+
+ //Pepper.animate("armraise");
+
+ // Start checking for user movement once the video has loaded
+ this.motionProcessor.startListening();
+ this.motionProcessor.startCheckingUserMovement();
+ this.motionProcessor.setRecording(true, 3.f);
+
+ return true;
+ }
+ return false;
+ });
+
+ videoView.setOnCompletionListener(mp -> {
+ if (EXERCISE_VIDEO_REPETITION < ExerciseManager.DEFAULT_EXERCISE_REPETITIONS) {
+ videoView.start(); // start the video again
+ EXERCISE_VIDEO_REPETITION++;
+ if (progress >= 10) {
+ runOnUiThread(() -> NavigationManager.navigateToActivity(this, EndScreenActivity.class));
+ }
+ }
+ });
+ });
+ }
+ }).start();
+ }
+
+ /**
+ * Function for playing a video in a VideoView
+ *
+ * @param videoView The VideoView to play the video in
+ * @param context The context to use
+ */
+ public void playVideo(VideoView videoView, Context context) {
+ // Set up the video player
+ if (videoView != null) {
+ videoView.setVideoURI(Uri.parse("android.resource://" + context.getPackageName() + "/" + R.raw.arm_raises));
+ videoView.start();
+ } else {
+ Log.e("FitnessActivity", "VideoView is null. Check your layout XML.");
}
- return exercise;
}
@Override
public void onRobotFocusLost() {
- // Implement your logic when the robot focus is lost
+ QiSDK.unregister(this, this);
+ Pepper.provideContext(null, this.getClass()); // Remove the context (unavailable)
+
+ // Go to the main screen
+// NavigationManager.navigateToActivity(this, MainActivity.class);
}
@Override
public void onRobotFocusRefused(String reason) {
- // Implement your logic when the robot focus is refused
}
@Override
protected void onDestroy() {
- super.onDestroy();
+ if (this.motionProcessor != null) {
+ this.motionProcessor.stopListening();
+ this.motionProcessor = null;
+ }
QiSDK.unregister(this, this);
- this.motionProcessor.stopListening();
- this.motionProcessor = null;
- this.personalMotionPreviewElement.destroy();
+ Pepper.provideContext(null, this.getClass());
+
+ super.onDestroy();
+ }
+
+ private void showInfoDialog() {
+ final Dialog dialog = new Dialog(this);
+ dialog.setContentView(R.layout.dialog_info);
+
+ // Hide the system UI
+ NavigationManager.hideSystemUI(this);
+
+ // Set the dialog options
+ dialog.getWindow().setDimAmount(0.5f);
+ dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
+ dialog.setCancelable(true);
+
+ // Close button for dialog
+ Button closeButton = dialog.findViewById(R.id.closeButtonDialog);
+ closeButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ dialog.dismiss();
+ }
+ });
+ dialog.show();
+ }
+
+ public void incrementProgress() {
+ if (progress++ < maxProgress) {
+ triggerColorBurst(true);
+ updateProgress();
+ }
+ }
+
+ private void updateProgress() {
+ progressCircle.setProgress(progress);
+ progressText.setText(progress + "/" + maxProgress);
+ }
+
+ public void triggerColorBurst(boolean isGoodRep) {
+
+ Log.i("InputProcessor", "Color Burst");
+
+ try {
+ int circleId = isGoodRep ? R.drawable.progress_circle_good : R.drawable.progress_circle_bad;
+ int soundId = isGoodRep ? R.raw.good_sound : R.raw.wrong_sound;
+ progressCircle.setProgressDrawable(ContextCompat.getDrawable(this, circleId));
+ // MediaPlayer.create(this, soundId).start();
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(progressCircle, "alpha", 1f, 0f, 1f);
+ animator.setDuration(700); // Burst duration
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ progressCircle.setProgressDrawable(ContextCompat.getDrawable(FitnessActivity.this, R.drawable.progress_circle));
+ }
+ });
+ animator.start();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
}
}
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/HelpActivity.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/HelpActivity.java
index cbc714c..7dab65d 100644
--- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/HelpActivity.java
+++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/HelpActivity.java
@@ -1,11 +1,11 @@
package com.example.fitbot.ui.activities;
-import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
-import android.view.View;
+import android.support.v7.app.AppCompatActivity;
import com.example.fitbot.R;
-import com.example.fitbot.util.ButtonNavigation;
+import com.example.fitbot.pepper.Pepper;
+import com.example.fitbot.util.NavigationManager;
public class HelpActivity extends AppCompatActivity {
@@ -14,18 +14,12 @@ public class HelpActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_help);
- ButtonNavigation.setupButtonNavigation(this, R.id.homeButtonHelp, MainActivity.class);
+ Pepper.say("Welkom bij FitBot. De robot die helpt om fit te blijven. Druk op Start om de oefening te beginnen. Ga terug naar het begin scherm door op het huisje te klikken");
- // Hide system UI
- hideSystemUI();
- }
- private void hideSystemUI() {
- View decorView = getWindow().getDecorView();
- // Hide the status bar and navigation bar
- int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
- decorView.setSystemUiVisibility(uiOptions);
+
+ NavigationManager.setupButtonNavigation(this, R.id.homeButtonHelp, MainActivity.class);
+
+ NavigationManager.hideSystemUI(this);
}
}
\ No newline at end of file
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 4edfa2e..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
@@ -1,5 +1,6 @@
package com.example.fitbot.ui.activities;
+import static com.example.fitbot.util.Networking.sendIpAddress;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.Uri;
@@ -10,13 +11,17 @@ 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 android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import com.example.fitbot.R;
-import com.example.fitbot.util.ButtonNavigation;
+import com.example.fitbot.pepper.Pepper;
+import com.example.fitbot.util.NavigationManager;
+
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
public class MainActivity extends AppCompatActivity {
@@ -31,7 +36,6 @@ public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
-
// Set full screen mode to hide status bar
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
@@ -49,7 +53,8 @@ public class MainActivity extends AppCompatActivity {
setUpUi();
// Hide system UI
- hideSystemUI();
+ NavigationManager.hideSystemUI(this);
+ sendIpAddress(this);
}
private void setUpUi() {
@@ -63,8 +68,8 @@ public class MainActivity extends AppCompatActivity {
if (getSupportActionBar() != null) {
getSupportActionBar().hide();
}
- ButtonNavigation.setupButtonNavigation(this, R.id.startButtonMain, FitnessActivity.class);
- ButtonNavigation.setupButtonNavigation(this, R.id.helpButtonMain, HelpActivity.class);
+ NavigationManager.setupButtonNavigation(this, R.id.startButtonMain, FitnessActivity.class);
+ NavigationManager.setupButtonNavigation(this, R.id.helpButtonMain, HelpActivity.class);
/*---Tool Bar---*/
setSupportActionBar(toolbar); // Make the toolbar act as the action bar
@@ -80,33 +85,22 @@ public class MainActivity extends AppCompatActivity {
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
- hideSystemUI();
}
@Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
- hideSystemUI();
}
};
drawerLayout.addDrawerListener(toggle);
toggle.syncState(); // Synchronize the state of the navigation drawer
}
- private void hideSystemUI() {
- View decorView = getWindow().getDecorView();
- // Hide the status bar and navigation bar
- int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
- decorView.setSystemUiVisibility(uiOptions);
- }
-
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
- hideSystemUI();
+ NavigationManager.hideSystemUI(this);
}
}
@@ -118,4 +112,8 @@ public class MainActivity extends AppCompatActivity {
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
deleted file mode 100644
index 92f4831..0000000
--- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/components/PersonalMotionPreviewElement.java
+++ /dev/null
@@ -1,254 +0,0 @@
-package com.example.fitbot.ui.components;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.support.annotation.Nullable;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-
-import com.aldebaran.qi.sdk.QiContext;
-import com.example.fitbot.exercise.Exercise;
-import com.example.fitbot.ui.activities.EndScreenActivity;
-import com.example.fitbot.ui.activities.FitnessActivity;
-import com.example.fitbot.ui.activities.MainActivity;
-import com.example.fitbot.util.FitnessCycle;
-import com.example.fitbot.util.processing.IInputHandler;
-import com.example.fitbot.util.processing.InputProcessor;
-
-import org.joml.Matrix4f;
-import org.joml.Vector2f;
-import org.joml.Vector3f;
-import org.joml.Vector4f;
-
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-public class PersonalMotionPreviewElement extends View implements IInputHandler {
-
- // Fields regarding Exercise and speech handling.
- private InputProcessor motionProcessor;
- private Exercise exercise;
- private QiContext qiContext;
- private int exerciseCount;
-
- private FitnessActivity parentActivity;
-
- private final Paint userProgressPaint = new Paint();
- private final Paint borderPaint = new Paint();
- private final Paint backgroundPaint = new Paint();
-
- // TODO: Remove
- private Matrix4f viewMatrix = new Matrix4f(); // The view matrix for the 3D to 2D transformation.
- private Matrix4f projectionMatrix = new Matrix4f(); // The projection matrix for the 3D to 2D transformation.
- private final Vector4f objectPosition = new Vector4f(0, 0, 0, 1); // The location of the object in 3D space.
- private ConcurrentLinkedQueue vectors = new ConcurrentLinkedQueue<>();
-
- // TODO: Remove
- private Vector2f[] axisVectors = new Vector2f[0];
-
-
- private static final String[] STARTING_PHRASES = {
- "Veel success met de oefening!",
- "Je kan het!",
- "Veel plezier!"
- };
-
-
- public PersonalMotionPreviewElement(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- if ( context instanceof Activity)
- {
- this.parentActivity = (FitnessActivity) context;
- }
-
- this.userProgressPaint.setColor(0xFFFF0000); // Red
- this.userProgressPaint.setStyle(Paint.Style.FILL);
- this.userProgressPaint.setStrokeWidth(5.0f);
- this.userProgressPaint.setAntiAlias(true);
-
- // Target paint is the filling of the target path.
- this.borderPaint.setColor(-1);
- this.borderPaint.setStyle(Paint.Style.STROKE);
- this.borderPaint.setStrokeWidth(5.0f);
- this.borderPaint.setAntiAlias(true);
-
- this.backgroundPaint.setColor(0xFF000000); // Black
- }
-
- /**
- * Method for initializing the PersonalMotionPreviewElement.
- * This method has to be called with a "post" function when the element has been
- * created, otherwise the dimensions of the element aren't initialized yet, which
- * will cause the vertex projections to fail (0 width and height).
- *
- * @param exercise The exercise that the user is currently performing.
- * @param motionProcessor The motion processor that will be used to process the user's motion.
- * @param exerciseCount The total amount of exercises that the user has to perform.
- */
- public void initialize(@Nullable Exercise exercise, InputProcessor motionProcessor, int exerciseCount) {
- Log.i("PersonalMotionPreviewElement", "Creating new PersonalMotionPreviewElement.");
-
- this.motionProcessor = motionProcessor;
- this.exercise = exercise;
- this.exerciseCount = exerciseCount;
-
- // TODO: Remove
- this.axisVectors = new Vector2f[] {
- projectVertex(new Vector3f(-5.0f, 0, 0), getWidth(), getHeight()),
- projectVertex(new Vector3f(5.0f, 0, 0), getWidth(), getHeight()),
- projectVertex(new Vector3f(0, -5.0f, 0), getWidth(), getHeight()),
- projectVertex(new Vector3f(0, 5.0f, 0), getWidth(), getHeight()),
- projectVertex(new Vector3f(0, 0, -5.0f), getWidth(), getHeight()),
- projectVertex(new Vector3f(0, 0, 5.0f), getWidth(), getHeight())
- };
- }
-
- public void destroy()
- {
- if ( this.motionProcessor != null )
- this.motionProcessor.stopListening();
-
- this.motionProcessor = null;
- }
-
- /**
- * Function for providing a QiContext to the PersonalMotionPreviewElement.
- * This function will be called by the parent activity when the QiContext is available.
- * Also say something nice to the user :)
- *
- * @param context The QiContext to provide.
- */
- public void provideQiContext(QiContext context) {
- this.qiContext = context;
-
- // Handler that is called every time the motion processor receives new data.
- this.motionProcessor.setInputHandler((rotationVector, deviceId) -> {
-
- Log.i("MotionProcessor", "Rotation vector received: " + rotationVector);
- Log.i("MotionProcessor", "Last error offset:" + this.motionProcessor.getError(deviceId, this.motionProcessor.secondsPassed()));
-
- if ( this.motionProcessor.hasFinished())
- {
- if ( this.parentActivity == null)
- {
- // Move to main screen
- this.destroy();
- Intent intent = new Intent(getContext(), MainActivity.class);
- getContext().startActivity(intent);
- return;
- }
- // Move on to the next exercise, or finish.
- if ( this.exerciseCount > 0 )
- {
- this.exerciseCount--;
- this.exercise = this.parentActivity.acquireExercise();
- this.motionProcessor.useExercise(this.exercise);
- }
- else
- {
- // Finish the exercise.
- this.destroy();
- Intent intent = new Intent(getContext(), EndScreenActivity.class);
- getContext().startActivity(intent);
- return;
- }
- }
-
- // TODO: Adjust / remove
- vectors.add(projectVertex(rotationVector, this.getWidth(), this.getHeight()));
- Log.i("MotionProcessor", "Rotation vector received: " + rotationVector);
- Vector2f parsed = projectVertex(rotationVector, this.getWidth(), this.getHeight());
-
- this.vectors.add(parsed);
- // Remove the first element if the array is too big
- if (this.vectors.size() > 100)
- this.vectors.poll();
- });
-
- if (this.qiContext == null)
- return;
-
- FitnessCycle.say(STARTING_PHRASES[(int) Math.floor(Math.random() * STARTING_PHRASES.length)], this.qiContext);
- }
-
- /**
- * Method for setting the gesture path that will be drawn on the canvas.
- *
- * @param exercise The exercise that the user is currently performing.
- */
- public void setExercise(Exercise exercise) {
- this.motionProcessor.useExercise(exercise);
- this.exercise = exercise;
- }
-
-
- private Vector2f projectVertex(Vector3f point, int virtualWidth, int virtualHeight) {
- viewMatrix
- .identity()
- .lookAt(new Vector3f(0, 0, -2), new Vector3f(0, 0, 0), new Vector3f(0, 1, 0));
-
- // Transform the projection matrix to a perspective projection matrix
- // Perspective transformation conserves the depth of the object
- projectionMatrix
- .identity()
- .perspective((float) Math.toRadians(70), (float) virtualWidth / virtualHeight, .01f, 1000.0f);
-
- // Convert world coordinates to screen-space using MVP matrix
- Vector4f screenCoordinates = new Vector4f(point, 1.0f)
- .mul(this.viewMatrix)
- .mul(this.projectionMatrix);
-
- // 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);
- }
-
-
-
- @Override
- public void onDraw(Canvas canvas) {
- canvas.drawRect(0, 0, getWidth(), getHeight(), backgroundPaint);
- this.setBackgroundColor(0xFF000000); // Black
- /*if (this.exercise == null)
- return;*/
-
- for (int i = 0, startX, endX, startY, endY; i < axisVectors.length/2; i++)
- {
- startX = (int)Math.max(0, Math.min(this.getWidth(), (int)axisVectors[i*2].x));
- endX = (int)Math.max(0, Math.min(this.getWidth(), (int)axisVectors[i*2+1].x));
- startY = (int)Math.max(0, Math.min(this.getHeight(), (int)axisVectors[i*2].y));
- endY = (int)Math.max(0, Math.min(this.getHeight(), (int)axisVectors[i*2+1].y));
- canvas.drawLine(startX, startY, endX, endY, this.borderPaint);
- }
-
- for ( Vector2f point : this.vectors)
- {
- canvas.drawRect(point.x, point.y, point.x + 5, point.y + 5, this.userProgressPaint);
- }
-/*
- // Draw target circle
- float targetRadius = (this.screenDimensions.x + this.screenDimensions.y) / 5.0f;
- canvas.drawCircle(this.screenDimensions.x / 2, this.screenDimensions.y / 2, targetRadius, this.targetPaint);
- canvas.drawCircle(this.screenDimensions.x / 2, this.screenDimensions.y / 2, (targetRadius * exerciseProgress.get()/1000.0f), this.referencePaint);
- referencePaint.setColor(
- Color.argb(
- 255,
- (int)(255 * (1.0 - exerciseProgress.get()/1000.0f)),
- (int)(255 * exerciseProgress.get()/1000.0f),
- 0
- )
- );*/
-
- this.invalidate();
- }
-
- @Override
- public void accept(Vector3f rotationVector, int sensorId) {
-
- }
-}
diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/Animations.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/Animations.java
index 01444f4..6d243c1 100644
--- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/Animations.java
+++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/Animations.java
@@ -11,8 +11,7 @@ import com.aldebaran.qi.sdk.object.actuation.Animation;
public class Animations {
- public static void Animate(String AnimationFile, QiContext ctx)
- {
+ public static void Animate(String AnimationFile, QiContext ctx) {
int resId = ctx.getResources().getIdentifier(AnimationFile, "raw", ctx.getPackageName());
Animation animation = AnimationBuilder.with(ctx)
diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/ButtonNavigation.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/ButtonNavigation.java
deleted file mode 100644
index b239b35..0000000
--- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/ButtonNavigation.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.example.fitbot.util;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.view.View;
-import android.widget.Button;
-
-public class ButtonNavigation {
-
- /**
- * Sets up a button to navigate to a different activity when clicked.
- *
- * @param currentActivity The activity that contains the button
- * @param buttonId The ID of the button
- * @param targetActivity The activity to navigate to
- */
- public static void setupButtonNavigation(Activity currentActivity, int buttonId, Class extends Activity> targetActivity) {
- Button button = currentActivity.findViewById(buttonId);
- button.setOnClickListener(v -> {
- Intent intent = new Intent(currentActivity, targetActivity);
- currentActivity.startActivity(intent);
- currentActivity.finish();
- });
- }
-}
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/FitnessCycle.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/FitnessCycle.java
deleted file mode 100644
index a55b445..0000000
--- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/FitnessCycle.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package com.example.fitbot.util;
-
-import android.content.Context;
-import android.net.Uri;
-import android.support.v7.app.AppCompatActivity;
-import android.util.Log;
-import android.widget.VideoView;
-
-import com.aldebaran.qi.sdk.builder.SayBuilder;
-import com.aldebaran.qi.sdk.object.locale.Language;
-import com.aldebaran.qi.sdk.object.locale.Locale;
-import com.aldebaran.qi.sdk.object.locale.Region;
-import com.example.fitbot.R;
-import com.aldebaran.qi.sdk.QiContext;
-import com.aldebaran.qi.sdk.builder.AnimateBuilder;
-import com.aldebaran.qi.sdk.builder.AnimationBuilder;
-import com.aldebaran.qi.sdk.object.actuation.Animate;
-import com.aldebaran.qi.sdk.object.actuation.Animation;
-
-import java.util.concurrent.atomic.AtomicInteger;
-
-public class FitnessCycle extends AppCompatActivity {
-
- private static final Locale DUTCH_LOCALE = new Locale(Language.DUTCH, Region.NETHERLANDS);
-
-
- /**
- * Function for executing a movement animation a certain number of times
- * on the robot
- *
- * @param Exercise The name of the exercise to perform
- * @param Reps The number of repetitions to perform
- * @param qiContext The QiContext to use
- */
- public static void executeMovement(String Exercise, int Reps, QiContext qiContext) {
- AtomicInteger repCount = new AtomicInteger(0);
-
- Animation animation = AnimationBuilder.with(qiContext)
- .withResources(qiContext.getResources().getIdentifier(Exercise, "raw", qiContext.getPackageName()))
- .build();
-
- Animate animate = AnimateBuilder.with(qiContext)
- .withAnimation(animation)
- .build();
-
- // Add a listener for when a label is reached
- animate.addOnLabelReachedListener((label, time) -> {
- // Increment repCount when the end of a repetition is reached
- if ("end".equals(label)) {
- repCount.incrementAndGet();
- }
- });
-
- // Run the animation the desired number of times
- for (int i = 0; i < Reps; i++) {
- animate.run();
- }
- }
-
- /**
- * Function for making the robot say something with DUTCH_LOCALE as locale
- * @param phrase The phrase to make the robot say
- * @param ctx The QiContext to use
- */
- public static void say(String phrase, QiContext ctx)
- {
- say(phrase, ctx, DUTCH_LOCALE);
- }
-
- /**
- * Function for making the robot say something with a specific locale
- * @param phrase The phrase to make the robot say
- * @param ctx The QiContext to use
- * @param locale The locale to use
- */
- public static void say(String phrase, QiContext ctx, Locale locale)
- {
- SayBuilder
- .with(ctx)
- .withLocale(locale)
- .withText(phrase)
- .build()
- .run();
- }
-
- /**
- * Function for playing a video in a VideoView
- *
- * @param videoView The VideoView to play the video in
- * @param context The context to use
- */
- public static void playVideo(VideoView videoView, Context context) {
- // Set up the video player
- if (videoView != null) {
- Uri videoUri = Uri.parse("android.resource://" + context.getPackageName() + "/" + R.raw.bicepvideo);
- videoView.setVideoURI(videoUri);
-
- videoView.setOnCompletionListener(mp -> {
- // Repeat the video when it finishes playing
- videoView.start();
- });
-
- videoView.start();
- } else {
- Log.e("FitnessActivity", "VideoView is null. Check your layout XML.");
- }
- }
-}
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/NavigationManager.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/NavigationManager.java
new file mode 100644
index 0000000..a906b53
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/NavigationManager.java
@@ -0,0 +1,60 @@
+package com.example.fitbot.util;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.view.View;
+import android.widget.Button;
+
+public class NavigationManager {
+
+ /**
+ * Sets up a button to navigate to a different activity when clicked.
+ *
+ * @param currentActivity The activity that contains the button
+ * @param buttonId The ID of the button
+ * @param targetActivity The activity to navigate to
+ */
+ public static void setupButtonNavigation(Activity currentActivity, int buttonId, Class extends Activity> targetActivity) {
+ Button button = currentActivity.findViewById(buttonId);
+ if (button == null) {
+ throw new IllegalArgumentException("Button with ID " + buttonId + " not found in " + currentActivity.getClass().getSimpleName());
+ }
+ button.setOnClickListener(v -> NavigationManager.navigateToActivity(currentActivity, targetActivity));
+ }
+
+ /**
+ * Navigates to the target activity.
+ *
+ * @param currentActivity The current activity
+ * @param targetActivity The target activity
+ */
+ public static void navigateToActivity(Activity currentActivity, Class extends Activity> targetActivity) {
+ Intent intent = new Intent(currentActivity, targetActivity);
+ // Close previous activity
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ currentActivity.startActivity(intent);
+ currentActivity.finish();
+ }
+
+ /**
+ * Navigates to the target activity.
+ *
+ * @param context The context
+ * @param targetActivity The target activity
+ */
+ public static void navigateToActivity(Context context, Class extends Activity> targetActivity) {
+ Intent intent = new Intent(context, targetActivity);
+ context.startActivity(intent);
+ }
+
+ public static void hideSystemUI(Activity currentActivity) {
+ View decorView = currentActivity.getWindow().getDecorView();
+ // Hide the status bar and navigation bar
+ int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+ decorView.setSystemUiVisibility(uiOptions);
+ }
+
+}
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/Networking.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/Networking.java
new file mode 100644
index 0000000..db0e6f2
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/Networking.java
@@ -0,0 +1,76 @@
+package com.example.fitbot.util;
+
+import android.content.Context;
+import android.net.wifi.WifiManager;
+import android.os.AsyncTask;
+import android.util.Log;
+
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.nio.ByteOrder;
+import java.nio.charset.StandardCharsets;
+
+public class Networking {
+
+ public static void sendIpAddress(final Context context) {
+ new AsyncTask() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ String ipAddress = getIPAddress(context);
+ String jsonInputString = "{\"ip\":\"" +
+ ipAddress +
+ "\"}";
+
+ byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8);
+ HttpURLConnection conn = null;
+ try {
+ URL url = new URL("http://145.92.8.132:443/set-ip"); // Replace with your Node server URL
+ conn = (HttpURLConnection) url.openConnection();
+ conn.setRequestMethod("POST");
+ conn.setRequestProperty("Content-Type", "application/json");
+ conn.setDoOutput(true);
+
+ OutputStream os = conn.getOutputStream();
+ os.write(input, 0, input.length);
+ os.close();
+
+ int responseCode = conn.getResponseCode();
+ Log.i("NetworkUtils", "Response Code: " + responseCode);
+ } catch (Exception e) {
+ Log.e("NetworkUtils", "Error sending IP address", e);
+ } finally {
+ if (conn != null) {
+ conn.disconnect();
+ }
+ }
+ return null;
+ }
+ }.execute();
+ }
+
+
+ private static String getIPAddress(Context context) {
+ WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
+ int ipAddress = wifiManager.getConnectionInfo().getIpAddress();
+
+ // Convert little-endian to big-endian if needed
+ if (ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN)) {
+ ipAddress = Integer.reverseBytes(ipAddress);
+ }
+
+ byte[] ipByteArray = BigInteger.valueOf(ipAddress).toByteArray();
+
+ String ip = "";
+ try {
+ ip = InetAddress.getByAddress(ipByteArray).getHostAddress();
+ } catch (UnknownHostException ex) {
+ Log.e("WIFIIP", "Unable to get host address.");
+ }
+
+ return ip;
+ }
+}
\ No newline at end of file
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..e9b1bf4
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/AnglePath.java
@@ -0,0 +1,69 @@
+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();
+ int deviceIdx = parsed.getAsJsonArray().get(dataArrayIdx).getAsJsonObject().get("deviceId").getAsInt();
+ angles[deviceIdx] = new Vector3f[array.size()];
+ for (int i = 0; i < array.size(); i++) {
+ JsonArray vec = array.get(i).getAsJsonArray();
+ angles[deviceIdx][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 79b7eaf..0000000
--- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/GesturePath.java
+++ /dev/null
@@ -1,123 +0,0 @@
-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;
-
- /**
- * 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)
- 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 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) {
- 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");
- }
- 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/path/PathSegment.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/PathSegment.java
index 11183ca..4fc9984 100644
--- 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
@@ -12,7 +12,7 @@ public class PathSegment {
* 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.
+ * @param end The end point of the line segment.
*/
public PathSegment(Vector3f start, Vector3f end) {
this.start = start;
@@ -25,7 +25,7 @@ public class PathSegment {
* 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.
+ * @param t The interpolation value between 0 and 1.
*/
public Vector3f interpolate(double t) {
return new Vector3f(this.start)
@@ -56,7 +56,7 @@ public class PathSegment {
(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))
- ));
+ ));
}
/**
@@ -84,7 +84,7 @@ public class PathSegment {
* @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))
+ if (this.start.distanceSquared(reference) > this.end.distanceSquared(reference))
return this.end.distance(reference);
return this.start.distance(reference);
}
@@ -92,8 +92,8 @@ public class PathSegment {
/**
* 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 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.
*/
diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/IInputHandler.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/IInputHandler.java
index 12cb7db..9d265fd 100644
--- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/IInputHandler.java
+++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/IInputHandler.java
@@ -4,11 +4,12 @@ import org.joml.Vector3f;
public interface IInputHandler {
- /**
- * Function for accepting motion data and the transformed vector.
- * @param rotationVector The rotation vector of the motion data.
- * @param sensorId The sensor ID of the motion data.
- */
- void accept(Vector3f rotationVector, int sensorId);
+ /**
+ * Function for accepting motion data and the transformed vector.
+ *
+ * @param rotationVector The rotation vector of the motion data.
+ * @param sensorId The sensor ID of the motion data.
+ */
+ void accept(Vector3f rotationVector, int sensorId);
}
\ No newline at end of file
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 dbca4df..c3fc778 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
@@ -1,70 +1,232 @@
package com.example.fitbot.util.processing;
+import android.app.ActivityManager;
import android.util.Log;
import com.example.fitbot.exercise.Exercise;
+import com.example.fitbot.exercise.ExerciseManager;
+import com.example.fitbot.pepper.Pepper;
+import com.example.fitbot.ui.activities.EndScreenActivity;
+import com.example.fitbot.ui.activities.FitnessActivity;
+import com.example.fitbot.ui.activities.MainActivity;
+import com.example.fitbot.util.NavigationManager;
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 org.jetbrains.annotations.NotNull;
import org.joml.Vector3f;
+import org.json.JSONArray;
+
+import java.util.ArrayList;
+import java.util.List;
public class InputProcessor {
- private Vector3f[][] selfRotationVectorPaths; // Relative path of the motion data
+ private List[] selfRotationVectorPaths = null; // 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 exerciseDuration;
+ private float exerciseRepetitionDurationInSeconds = 0.0f;
+ private int exercisesRemaining = 1;
+
+ private float errorCheckInterval_s;
+ private int checksPerformed = 0;
+ private int totalChecks = 0;
+
+ private final FitnessActivity parentActivity;
+
+ /**
+ * The phrases that are said by the robot whenever the exercise starts.
+ */
+ private static final String[] STARTING_PHRASES = {
+ "Veel success met de oefening!",
+ "Je kan het!",
+ "Veel plezier!"
+ };
+
+ /**
+ * This field is used to determine if the motion data is being recorded.
+ * If this is the case, instead of functioning normally, the element
+ * will record the movement that the user makes, store it in the
+ * `selfRotationVectorPaths` field and send it to the server.
+ */
+ private boolean recordingMovement = false;
+
+ /**
+ * Represents the duration of the recording in seconds.
+ * This field only has effect when the `recordingMovement` field is set to true.
+ */
+ private float recordingDurationInSeconds = 0.0f;
// How many seconds have passed since the start of the exercise.
// The exercise starts whenever the `startListening` function is called.
private double secondsPassed = 0.0D;
private long lastTime;
- private IInputHandler motionDataConsumer = (rotationVector, deviceId) -> {
- };
+ private static final String[] REQUIRED_SENSOR_JSON_PROPERTIES =
+ {"rotationX", "rotationY", "rotationZ", "deviceId"};
+
+ // The web server that listens for incoming motion data.
private WebServer server;
/**
* Constructor for the motion processor.
- *
- * @param paths The target paths of the motion data.
- * The length of this array must be equal to the
- * amount of sensors available.
- * @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)];
- targetRotationVectorPaths = paths;
-
- this.sampleRate = inputSampleRate;
- this.exerciseDuration = exerciseTime;
+ public InputProcessor(FitnessActivity parentActivity) {
+ this.parentActivity = parentActivity;
}
/**
* Function for setting the exercise to use.
* This updates the user and target path and the
* duration of the exercise.
+ *
+ * This function is only initially used to select the starting exercise;
+ * the exercises that follow are determined by a private method 'nextExercise'
+ *
* @param exercise The exercise to use the paths for.
*/
public void useExercise(Exercise exercise) {
- this.selfRotationVectorPaths = new Vector3f[2][(int) (exercise.exerciseTimeInSeconds * this.sampleRate)];
- this.targetRotationVectorPaths = new Vector3f[2][exercise.rightPath.getVectors().length];
- this.exerciseDuration = exercise.exerciseTimeInSeconds;
- this.secondsPassed = 0.0D;
- this.lastTime = System.currentTimeMillis();
+ if (this.recordingMovement)
+ throw new IllegalStateException("Cannot change exercise while recording movement.");
+
+ this.exercisesRemaining = 1;
+ this.nextExercise(exercise);
+ Pepper.say(STARTING_PHRASES[(int) Math.floor(Math.random() * STARTING_PHRASES.length)]);
}
/**
- * Function for checking if the exercise has finished.
- * @return True if the exercise has finished, false otherwise.
+ * Function that starts checking for user movement.
+ * This function will start a thread that will check for user movement
+ * and compare the last rotation vectors to the target rotation vectors.
+ */
+ public void startCheckingUserMovement() {
+ // Error checking thread.
+ (new Thread(() -> {
+ Log.i("InputProcessor", "Movement Checking Thread started");
+
+ while (this.exercisesRemaining > 0) {
+
+ if ( this.totalChecks == 0 || this.selfRotationVectorPaths == null
+ || this.selfRotationVectorPaths.length == 0
+ || this.selfRotationVectorPaths[0].size() == 0
+ || this.selfRotationVectorPaths[1].size() == 0)
+ continue;
+
+ boolean isFaulty = this.isFaultyMovement();
+
+ Log.i("InputProcessor", "Movement checked: " + (isFaulty ? "Faulty" : "Good"));
+
+ if (isFaulty) {
+ this.onInadequateRepetition();
+ } else this.onAdequateRepetition();
+
+ this.checksPerformed++;
+
+ if (this.checksPerformed >= this.totalChecks)
+ {
+ this.checksPerformed = 0;
+ this.exercisesRemaining--;
+ acquireExercise();
+ }
+
+ try {
+ Thread.sleep((long) (this.errorCheckInterval_s * 1000));
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ })).start();
+ }
+
+ /**
+ * Moves on to the next exercise without changing the remaining exercises.
+ *
+ * @param exercise The exercise to move on to.
+ */
+ private void nextExercise(Exercise exercise) {
+ //TODO: Remove when more than one exercise
+ if (this.exercisesRemaining <= 0) {
+ Log.i("InputProcessor", "Moving to end screen; finished all exercises");
+ // Move to end screen on main activity
+ this.parentActivity.runOnUiThread(() -> NavigationManager.navigateToActivity(this.parentActivity, EndScreenActivity.class));
+ return;
+ }
+
+ Log.i("InputProcessor", "Acquired next exercise: " + exercise.name);
+ ExerciseManager.TOTAL_REPETITIONS_REQUIRED += ExerciseManager.DEFAULT_EXERCISE_REPETITIONS;
+ ExerciseManager.TOTAL_EXERCISES_PREFORMED++;
+
+ this.checksPerformed = 0;
+ this.totalChecks = ExerciseManager.DEFAULT_EXERCISE_REPETITIONS * 6;
+
+ this.selfRotationVectorPaths = new ArrayList[2];
+ 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.exerciseRepetitionDurationInSeconds = exercise.exerciseTimeInSeconds;
+ this.secondsPassed = 0.0D;
+ this.lastTime = System.currentTimeMillis();
+
+ Log.i("InputProcessor", "Repetition time: " + exercise.exerciseTimeInSeconds);
+ this.exerciseRepetitionDurationInSeconds = Math.max(this.exerciseRepetitionDurationInSeconds, 2);
+ this.errorCheckInterval_s = exercise.exerciseTimeInSeconds / 3.0f;
+ Log.i("InputProcessor", "Exercise error checking interval: " + this.errorCheckInterval_s);
+ }
+
+ /**
+ * Method that is called whenever the user performs a good repetition.
+ */
+ public void onAdequateRepetition() {
+ ExerciseManager.TOTAL_REPETITIONS_PERFORMED++;
+ Log.i("InputProcessor", "Adequate repetition performed");
+ this.parentActivity.runOnUiThread(this.parentActivity::incrementProgress);
+ }
+
+ /**
+ * Method that is called whenever the user performs a bad repetition.
+ */
+ public void onInadequateRepetition() {
+ Log.i("InputProcessor", "Inadequate repetition performed");
+ this.parentActivity.runOnUiThread(() -> this.parentActivity.triggerColorBurst(false));
+ }
+
+ /**
+ * Function for setting whether the motion data
+ * should be recorded or not.
+ *
+ * @param recording Whether the motion data should be recorded.
+ * @param duration For how long the motion data should be recorded.
+ * This only has an effect if `recording` is true.
+ */
+ public void setRecording(boolean recording, float duration) {
+ this.recordingMovement = recording;
+ this.recordingDurationInSeconds = duration;
+ if (recording) {
+ this.secondsPassed = 0.0D;
+ this.lastTime = System.currentTimeMillis();
+ this.selfRotationVectorPaths[0] = new ArrayList<>();
+ this.selfRotationVectorPaths[1] = new ArrayList<>();
+ }
+ }
+
+ /**
+ * Function for checking if the exercise or recording has finished.
+ * This function will return true if the execution of the exercise has finished or
+ * if the recording has finished, depending on the state of the `recordingMovement` field.
+ *
+ * @return Whether the exercise or recording has finished.
*/
public boolean hasFinished() {
- return this.secondsPassed >= this.exerciseDuration;
+ return this.recordingMovement ?
+ (this.secondsPassed >= this.recordingDurationInSeconds) :
+ (this.secondsPassed >= this.exerciseRepetitionDurationInSeconds);
}
/**
@@ -88,6 +250,30 @@ public class InputProcessor {
}
}
+ /**
+ * Function for acquiring the next exercise from the database.
+ * Upon successful retrieval, it will call the nextExercise method.
+ */
+ private void acquireExercise() {
+
+ if ( this.exercisesRemaining <= 0)
+ {
+ Log.i("InputProcessor", "Exercises finished");
+ this.parentActivity.runOnUiThread(() -> {
+ NavigationManager.navigateToActivity(this.parentActivity, EndScreenActivity.class);
+ });
+ return;
+ }
+
+ Log.i("MotionProcessor", "Fetching exercise data.");
+
+ this.parentActivity.fetchExerciseAsync(this::nextExercise, (nil) -> {
+
+ Log.i("MotionProcessor", "Failed to fetch exercise data.");
+
+ });
+ }
+
/**
* Function for stopping the listening process
* of the motion sensor. This function will stop
@@ -109,6 +295,9 @@ public class InputProcessor {
try {
+ Log.i("MotionProcessor", "Time passed: " + this.secondsPassed + "s");
+ if (this.recordingMovement)
+ Log.i("MotionProcessor", this.secondsPassed + " / " + this.recordingDurationInSeconds);
Log.i("MotionProcessor", "Received packet data: " + data);
JsonElement json = JsonParser.parseString(data);
@@ -118,23 +307,20 @@ public class InputProcessor {
JsonObject object = json.getAsJsonObject();
- String[] required = {
- "rotationX", "rotationY", "rotationZ",
- "type",
- "deviceId"
- };
-
// Ensure all properties are present in the received JSON object
- for (String s : required) {
+ for (String s : REQUIRED_SENSOR_JSON_PROPERTIES) {
if (!object.has(s))
return;
}
// 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);
} catch (Exception e) {
Log.i("MotionProcessor", "Failed to parse packet data.");
@@ -152,85 +338,112 @@ public class InputProcessor {
// Re-calculate time for index calculation
secondsPassed = (System.currentTimeMillis() - lastTime) / 1000.0d;
- lastTime = System.currentTimeMillis();
+
// Supposed index of the current rotation vector in the `rotationVectorPaths` array
- int selfIndex = (int) (secondsPassed * sampleRate);
+ this.selfRotationVectorPaths[deviceId].add(rotation);
- motionDataConsumer.accept(rotation, deviceId);
- if (selfIndex >= selfRotationVectorPaths[deviceId].length || selfIndex < 0)
- return;
+ if (this.recordingMovement && this.secondsPassed >= this.recordingDurationInSeconds) {
+ // Do something with the recorded data.
+ this.recordingMovement = false;
+ // Convert recorded data from `selfRotationVectorPaths` to string, and
+ // publish to database, or do something else with it.
- selfRotationVectorPaths[deviceId][selfIndex] = rotation;
+ String converted = convertRecordedDataToString();
+ //split string into 4 to print it fully in console
+ final int quarter = converted.length() / 4;
+ String[] parts = {
+ converted.substring(0, quarter),
+ converted.substring(quarter, 2 * quarter),
+ converted.substring(2 * quarter, 3 * quarter),
+ converted.substring(3 * quarter)
+ };
+ Log.i("MotionProcessor", "Converted data: ");
+ Log.i("ProcessedData", parts[0]);
+ Log.i("ProcessedData", parts[1]);
+ Log.i("ProcessedData", parts[2]);
+ Log.i("ProcessedData", parts[3]);
+
+
+ }
+
+ // Do something else with the vector
+ Log.i("MotionProcessor", "Rotation vector: " + rotation.toString() + " from device: " + deviceId);
+
+ // Whenever the exercise has finished and it's not recording,
+ // attempt to move to the next exercise.
+ // If this fails, navigate back to the main activity.
+ if (this.hasFinished() && !this.recordingMovement)
+ acquireExercise();
}
}
/**
- * Method for getting the current progress of the exercise.
- * The return value will range between 0.0 and 1.0.
+ * Function for converting the recorded data to a string.
+ * This function will convert the recorded data to a string
+ * that can be sent to a database or other storage.
*
- * @return The current progress of the exercise.
+ * @return The converted string.
*/
- public double getCurrentProgress()
- {
- return secondsPassed / exerciseDuration;
- }
+ private String convertRecordedDataToString() {
+ 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], ... ] }]
+ */
- /**
- * Function for setting the motion data receiver.
- *
- * @param consumer The consumer to set.
- */
- public void setInputHandler(IInputHandler consumer) {
- if (consumer != null)
- this.motionDataConsumer = consumer;
- }
+ // Iterate over all devices. In the current instance, it's 2.
+ for (int deviceId = 0; deviceId < selfRotationVectorPaths.length; deviceId++) {
+ JsonObject jsonDeviceObject = new JsonObject();
+ jsonDeviceObject.addProperty("deviceId", deviceId);
- /**
- * Function for getting the error offsets of the user's path compared to the
- * target path at a given point in time.
- *
- * @param sensorId The sensor ID to get the error offsets from.
- * @param time The time to get the error offsets from.
- * This value must be >= 0 && <= exerciseTime, otherwise
- * the error will be 0 by default.
- * @return A list of error offsets of the motion data compared to the reference path.
- */
- public double getError(int sensorId, float time) {
+ // Data array
+ JsonArray jsonDeviceDataArray = new JsonArray();
- // Ensure the sensor ID is within the bounds of the array
- if (sensorId < 0 || sensorId >= selfRotationVectorPaths.length)
- return 0.0d;
+ for (Vector3f vector : selfRotationVectorPaths[deviceId]) {
+ JsonArray jsonScalarArray = new JsonArray();
+ jsonScalarArray.add(vector.x);
+ jsonScalarArray.add(vector.y);
+ jsonScalarArray.add(vector.z);
+ jsonDeviceDataArray.add(jsonScalarArray);
+ }
+ jsonDeviceObject.add("data", jsonDeviceDataArray);
- // Index of the current rotation vector
- int targetIndex = (int) ((this.exerciseDuration / this.targetRotationVectorPaths[sensorId].length) * time);
- int selfIndex = (int) (this.selfRotationVectorPaths[sensorId].length / this.sampleRate * time);
-
- // Ensure the indexes are within the bounds of the array
- if (targetIndex >= 0 && targetIndex <= this.targetRotationVectorPaths[sensorId].length - 1 &&
- selfIndex >= 0 && selfIndex <= this.selfRotationVectorPaths[sensorId].length - 1)
- {
- return this.selfRotationVectorPaths[sensorId][selfIndex].distance(this.targetRotationVectorPaths[sensorId][targetIndex]);
+ jsonArray.add(jsonDeviceObject);
}
- return 0.0d;
+ return jsonArray.toString();
}
/**
- * Method for getting the average error of the motion data
- * compared to the reference path.
- *
- * @param sensorId The sensor ID to get the error offsets from.
- * @return The average error of the motion data compared to the reference path.
+ * Function for checking whether the last movement was faulty
*/
- public double getAverageError(int sensorId) {
- double error = 0;
- for (int i = 0; i < this.exerciseDuration; i++) {
- error += getError(sensorId, i);
+ public boolean isFaultyMovement() {
+ boolean upMovementDetected = false;
+ boolean downMovementDetected = false;
+
+ for (List path : selfRotationVectorPaths) {
+ if (path.size() < 2) {
+ continue; // Skip if there are not enough points to compare
+ }
+
+ Vector3f firstPoint = path.get(0);
+ Vector3f lastPoint = path.get(path.size() - 1);
+
+ float y1 = firstPoint.y;
+ float y2 = lastPoint.y;
+
+ if (y2 > y1) {
+ upMovementDetected = true;
+ } else if (y2 < y1) {
+ downMovementDetected = true;
+ }
+
+ if (upMovementDetected && downMovementDetected) {
+ return false; // Return false for faulty movement if both up and down movements are detected
+ }
}
- return error / this.exerciseDuration;
- }
-
- public float secondsPassed() {
- return (float) secondsPassed;
- }
-}
+
+ return true; // Return true for faulty movement if only up or down movement is detected
+ }}
diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/server/IWebServerHandler.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/server/IWebServerHandler.java
index 98739b4..67327cb 100644
--- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/server/IWebServerHandler.java
+++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/server/IWebServerHandler.java
@@ -1,7 +1,5 @@
package com.example.fitbot.util.server;
-import java.net.Socket;
-
/**
* Interface for handling WebSocket events.
*/
diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/server/WebServer.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/server/WebServer.java
index 6eaf4dc..87dc331 100644
--- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/server/WebServer.java
+++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/server/WebServer.java
@@ -10,16 +10,13 @@ import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Consumer;
public class WebServer implements Runnable {
private ServerSocket serverSocket;
- protected IWebServerHandler eventHandler = (input) -> {}; // No-op.
+ protected IWebServerHandler eventHandler = (input) -> {
+ }; // No-op.
private Thread thread;
private final AtomicBoolean forceClose = new AtomicBoolean(false);
@@ -84,7 +81,7 @@ public class WebServer implements Runnable {
String[] data = builder.toString().split("\n\n");
- if ( data.length > 1) { // Check if the data is valid.
+ if (data.length > 1) { // Check if the data is valid.
this.eventHandler.onReceive(data[1]);
}
diff --git a/code/src/Fitbot/app/src/main/res/drawable/help_background.xml b/code/src/Fitbot/app/src/main/res/drawable/border_background.xml
similarity index 77%
rename from code/src/Fitbot/app/src/main/res/drawable/help_background.xml
rename to code/src/Fitbot/app/src/main/res/drawable/border_background.xml
index 7ea69e6..3d0d3c1 100644
--- a/code/src/Fitbot/app/src/main/res/drawable/help_background.xml
+++ b/code/src/Fitbot/app/src/main/res/drawable/border_background.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/main/res/drawable/help2_background.xml b/code/src/Fitbot/app/src/main/res/drawable/border_background_2.xml
similarity index 76%
rename from code/src/Fitbot/app/src/main/res/drawable/help2_background.xml
rename to code/src/Fitbot/app/src/main/res/drawable/border_background_2.xml
index 0fb955b..408d16b 100644
--- a/code/src/Fitbot/app/src/main/res/drawable/help2_background.xml
+++ b/code/src/Fitbot/app/src/main/res/drawable/border_background_2.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/main/res/drawable/border_background_3.xml b/code/src/Fitbot/app/src/main/res/drawable/border_background_3.xml
new file mode 100644
index 0000000..4543b55
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/drawable/border_background_3.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/main/res/drawable/border_background_circle.xml b/code/src/Fitbot/app/src/main/res/drawable/border_background_circle.xml
new file mode 100644
index 0000000..df55912
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/drawable/border_background_circle.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/main/res/drawable/fitbot_launcher_background.xml b/code/src/Fitbot/app/src/main/res/drawable/fitbot_launcher_background.xml
new file mode 100644
index 0000000..071825e
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/drawable/fitbot_launcher_background.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_close_48.xml b/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_close_48.xml
new file mode 100644
index 0000000..72f8573
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_close_48.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_info_24.xml b/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_info_24.xml
new file mode 100644
index 0000000..17255b7
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_info_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_info_40.xml b/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_info_40.xml
new file mode 100644
index 0000000..df12462
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_info_40.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_info_48.xml b/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_info_48.xml
new file mode 100644
index 0000000..15875d1
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_info_48.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_skip_next_48.xml b/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_skip_next_48.xml
new file mode 100644
index 0000000..400f0a5
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_skip_next_48.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/code/src/Fitbot/app/src/main/res/drawable/ic_launcher_background.xml b/code/src/Fitbot/app/src/main/res/drawable/ic_launcher_background.xml
index 3050a42..3a8cd35 100644
--- a/code/src/Fitbot/app/src/main/res/drawable/ic_launcher_background.xml
+++ b/code/src/Fitbot/app/src/main/res/drawable/ic_launcher_background.xml
@@ -1,170 +1,74 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/code/src/Fitbot/app/src/main/res/drawable/progress_circle.xml b/code/src/Fitbot/app/src/main/res/drawable/progress_circle.xml
new file mode 100644
index 0000000..590b046
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/drawable/progress_circle.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/code/src/Fitbot/app/src/main/res/drawable/progress_circle_bad.xml b/code/src/Fitbot/app/src/main/res/drawable/progress_circle_bad.xml
new file mode 100644
index 0000000..b53b748
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/drawable/progress_circle_bad.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/code/src/Fitbot/app/src/main/res/drawable/progress_circle_good.xml b/code/src/Fitbot/app/src/main/res/drawable/progress_circle_good.xml
new file mode 100644
index 0000000..d291a88
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/drawable/progress_circle_good.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/code/src/Fitbot/app/src/main/res/drawable/red_button_gradient.xml b/code/src/Fitbot/app/src/main/res/drawable/red_button_gradient.xml
index 6983a91..a087a43 100644
--- a/code/src/Fitbot/app/src/main/res/drawable/red_button_gradient.xml
+++ b/code/src/Fitbot/app/src/main/res/drawable/red_button_gradient.xml
@@ -2,7 +2,7 @@
@@ -24,10 +25,10 @@
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:layout_marginBottom="40dp"
- android:background="@drawable/help_background"
+ android:background="@drawable/border_background_3"
android:orientation="vertical"
- android:paddingVertical="15dp"
android:paddingHorizontal="20dp"
+ android:paddingVertical="15dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
@@ -40,11 +41,11 @@
-
-
-
-
-
+ android:textAlignment="center" />
@@ -85,8 +66,8 @@
android:id="@+id/homeButtonEndScreen"
android:layout_width="150dp"
android:layout_height="75dp"
- android:layout_marginEnd="280dp"
- android:layout_marginBottom="30dp"
+ android:layout_marginEnd="404dp"
+ android:layout_marginBottom="48dp"
android:background="@drawable/red_button_gradient"
android:drawableTop="@drawable/ic_baseline_home_48"
android:drawableTint="@color/white"
@@ -94,20 +75,4 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
-
-
-
\ No newline at end of file
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
index a619a72..40456d7 100644
--- a/code/src/Fitbot/app/src/main/res/layout/activity_fitness.xml
+++ b/code/src/Fitbot/app/src/main/res/layout/activity_fitness.xml
@@ -1,42 +1,130 @@
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/drawer_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/darkBlue"
+ android:fitsSystemWindows="true"
+ tools:context=".ui.activities.FitnessActivity"
+ tools:openDrawer="start">
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -44,7 +132,7 @@ tools:openDrawer="start">
android:id="@+id/homeButtonFitness"
android:layout_width="150dp"
android:layout_height="75dp"
- android:layout_marginStart="404dp"
+ android:layout_marginStart="175dp"
android:layout_marginBottom="30dp"
android:background="@drawable/red_button_gradient"
android:drawableTop="@drawable/ic_baseline_home_48"
@@ -54,4 +142,18 @@ tools:openDrawer="start">
app:layout_constraintStart_toStartOf="parent"
tools:ignore="SpeakableTextPresentCheck" />
+
+
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/main/res/layout/activity_help.xml b/code/src/Fitbot/app/src/main/res/layout/activity_help.xml
index 369397f..542b353 100644
--- a/code/src/Fitbot/app/src/main/res/layout/activity_help.xml
+++ b/code/src/Fitbot/app/src/main/res/layout/activity_help.xml
@@ -28,7 +28,7 @@
android:layout_height="450dp"
android:layout_marginStart="80dp"
android:layout_marginTop="24dp"
- android:background="@drawable/help2_background"
+ android:background="@drawable/border_background"
android:orientation="vertical"
android:padding="16dp"
app:layout_constraintStart_toStartOf="parent"
@@ -40,10 +40,9 @@
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:layout_marginBottom="40dp"
- android:background="@drawable/help_background"
+ android:padding="16dp"
+ android:background="@drawable/border_background_3"
android:orientation="vertical"
- android:paddingVertical="15dp"
- android:paddingHorizontal="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
@@ -56,11 +55,11 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/main/res/layout/header.xml b/code/src/Fitbot/app/src/main/res/layout/header.xml
index 82ee588..f2bdba6 100644
--- a/code/src/Fitbot/app/src/main/res/layout/header.xml
+++ b/code/src/Fitbot/app/src/main/res/layout/header.xml
@@ -15,6 +15,7 @@
android:layout_marginStart="10dp"
android:layout_marginTop="20dp"
android:src="@drawable/robot_logo"
+ android:tint="@color/white"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -24,7 +25,7 @@
android:layout_marginTop="60dp"
android:text="FitBot"
android:textSize="48sp"
- android:textColor="@color/darkBlue"
+ android:textColor="@color/white"
app:layout_constraintStart_toEndOf="@+id/imageView"
app:layout_constraintTop_toTopOf="parent" />
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-anydpi-v26/fitbot_launcher.xml b/code/src/Fitbot/app/src/main/res/mipmap-anydpi-v26/fitbot_launcher.xml
new file mode 100644
index 0000000..99a3772
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/mipmap-anydpi-v26/fitbot_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-anydpi-v26/fitbot_launcher_round.xml b/code/src/Fitbot/app/src/main/res/mipmap-anydpi-v26/fitbot_launcher_round.xml
new file mode 100644
index 0000000..99a3772
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/mipmap-anydpi-v26/fitbot_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/code/src/Fitbot/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index eca70cf..cad2118 100644
--- a/code/src/Fitbot/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/code/src/Fitbot/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,5 +1,4 @@
-
-
+
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/code/src/Fitbot/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
index eca70cf..cad2118 100644
--- a/code/src/Fitbot/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ b/code/src/Fitbot/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -1,5 +1,4 @@
-
-
+
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-hdpi/fitbot_launcher.png b/code/src/Fitbot/app/src/main/res/mipmap-hdpi/fitbot_launcher.png
new file mode 100644
index 0000000..3093063
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/mipmap-hdpi/fitbot_launcher.png differ
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-hdpi/fitbot_launcher_foreground.png b/code/src/Fitbot/app/src/main/res/mipmap-hdpi/fitbot_launcher_foreground.png
new file mode 100644
index 0000000..5d57314
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/mipmap-hdpi/fitbot_launcher_foreground.png differ
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-hdpi/fitbot_launcher_round.png b/code/src/Fitbot/app/src/main/res/mipmap-hdpi/fitbot_launcher_round.png
new file mode 100644
index 0000000..8b44e8a
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/mipmap-hdpi/fitbot_launcher_round.png differ
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-mdpi/fitbot_launcher.png b/code/src/Fitbot/app/src/main/res/mipmap-mdpi/fitbot_launcher.png
new file mode 100644
index 0000000..f54e67c
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/mipmap-mdpi/fitbot_launcher.png differ
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-mdpi/fitbot_launcher_foreground.png b/code/src/Fitbot/app/src/main/res/mipmap-mdpi/fitbot_launcher_foreground.png
new file mode 100644
index 0000000..a82b6b7
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/mipmap-mdpi/fitbot_launcher_foreground.png differ
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-mdpi/fitbot_launcher_round.png b/code/src/Fitbot/app/src/main/res/mipmap-mdpi/fitbot_launcher_round.png
new file mode 100644
index 0000000..547ad86
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/mipmap-mdpi/fitbot_launcher_round.png differ
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-xhdpi/fitbot_launcher.png b/code/src/Fitbot/app/src/main/res/mipmap-xhdpi/fitbot_launcher.png
new file mode 100644
index 0000000..0d85dfd
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/mipmap-xhdpi/fitbot_launcher.png differ
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-xhdpi/fitbot_launcher_foreground.png b/code/src/Fitbot/app/src/main/res/mipmap-xhdpi/fitbot_launcher_foreground.png
new file mode 100644
index 0000000..e11e0f4
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/mipmap-xhdpi/fitbot_launcher_foreground.png differ
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-xhdpi/fitbot_launcher_round.png b/code/src/Fitbot/app/src/main/res/mipmap-xhdpi/fitbot_launcher_round.png
new file mode 100644
index 0000000..fa4a3c6
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/mipmap-xhdpi/fitbot_launcher_round.png differ
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-xxhdpi/fitbot_launcher.png b/code/src/Fitbot/app/src/main/res/mipmap-xxhdpi/fitbot_launcher.png
new file mode 100644
index 0000000..bf32f32
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/mipmap-xxhdpi/fitbot_launcher.png differ
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-xxhdpi/fitbot_launcher_foreground.png b/code/src/Fitbot/app/src/main/res/mipmap-xxhdpi/fitbot_launcher_foreground.png
new file mode 100644
index 0000000..1d7b0aa
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/mipmap-xxhdpi/fitbot_launcher_foreground.png differ
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-xxhdpi/fitbot_launcher_round.png b/code/src/Fitbot/app/src/main/res/mipmap-xxhdpi/fitbot_launcher_round.png
new file mode 100644
index 0000000..7220e5a
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/mipmap-xxhdpi/fitbot_launcher_round.png differ
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-xxxhdpi/fitbot_launcher.png b/code/src/Fitbot/app/src/main/res/mipmap-xxxhdpi/fitbot_launcher.png
new file mode 100644
index 0000000..8f81dd4
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/mipmap-xxxhdpi/fitbot_launcher.png differ
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-xxxhdpi/fitbot_launcher_foreground.png b/code/src/Fitbot/app/src/main/res/mipmap-xxxhdpi/fitbot_launcher_foreground.png
new file mode 100644
index 0000000..c900079
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/mipmap-xxxhdpi/fitbot_launcher_foreground.png differ
diff --git a/code/src/Fitbot/app/src/main/res/mipmap-xxxhdpi/fitbot_launcher_round.png b/code/src/Fitbot/app/src/main/res/mipmap-xxxhdpi/fitbot_launcher_round.png
new file mode 100644
index 0000000..96cb634
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/mipmap-xxxhdpi/fitbot_launcher_round.png differ
diff --git a/code/src/Fitbot/app/src/main/res/raw/arm_raises.mp4 b/code/src/Fitbot/app/src/main/res/raw/arm_raises.mp4
new file mode 100644
index 0000000..2d3ebe6
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/raw/arm_raises.mp4 differ
diff --git a/code/src/Fitbot/app/src/main/res/raw/armcircle.qianim b/code/src/Fitbot/app/src/main/res/raw/armcircle.qianim
new file mode 100644
index 0000000..2c796e3
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/raw/armcircle.qianim
@@ -0,0 +1,275 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/code/src/Fitbot/app/src/main/res/raw/armraise.qianim b/code/src/Fitbot/app/src/main/res/raw/armraise.qianim
new file mode 100644
index 0000000..052d566
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/raw/armraise.qianim
@@ -0,0 +1,208 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/code/src/Fitbot/app/src/main/res/raw/boxing.qianim b/code/src/Fitbot/app/src/main/res/raw/boxing.qianim
new file mode 100644
index 0000000..f4c9efa
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/raw/boxing.qianim
@@ -0,0 +1 @@
+
diff --git a/code/src/Fitbot/app/src/main/res/raw/chestpress.qianim b/code/src/Fitbot/app/src/main/res/raw/chestpress.qianim
new file mode 100644
index 0000000..56c73b9
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/raw/chestpress.qianim
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/code/src/Fitbot/app/src/main/res/raw/good_sound.mp3 b/code/src/Fitbot/app/src/main/res/raw/good_sound.mp3
new file mode 100644
index 0000000..9fe5526
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/raw/good_sound.mp3 differ
diff --git a/code/src/Fitbot/app/src/main/res/raw/shoulderpress.qianim b/code/src/Fitbot/app/src/main/res/raw/shoulderpress.qianim
new file mode 100644
index 0000000..df2c82e
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/raw/shoulderpress.qianim
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/code/src/Fitbot/app/src/main/res/raw/squat.qianim b/code/src/Fitbot/app/src/main/res/raw/squat.qianim
new file mode 100644
index 0000000..a25766a
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/raw/squat.qianim
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/code/src/Fitbot/app/src/main/res/raw/wrong_sound.wav b/code/src/Fitbot/app/src/main/res/raw/wrong_sound.wav
new file mode 100644
index 0000000..bdd516d
Binary files /dev/null and b/code/src/Fitbot/app/src/main/res/raw/wrong_sound.wav differ
diff --git a/code/src/Fitbot/app/src/main/res/values/colors.xml b/code/src/Fitbot/app/src/main/res/values/colors.xml
index f6ea931..459ed59 100644
--- a/code/src/Fitbot/app/src/main/res/values/colors.xml
+++ b/code/src/Fitbot/app/src/main/res/values/colors.xml
@@ -9,9 +9,13 @@
#FFFFFFFF#1C1C27#24242F
+ #262630#2C2C37#FFFFFF#000000#000000
+ #00000000
+ #EFEFEF
+ #ADADAD
diff --git a/code/src/Fitbot/app/src/main/res/values/ids.xml b/code/src/Fitbot/app/src/main/res/values/ids.xml
new file mode 100644
index 0000000..f37a0c3
--- /dev/null
+++ b/code/src/Fitbot/app/src/main/res/values/ids.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/main/res/values/strings.xml b/code/src/Fitbot/app/src/main/res/values/strings.xml
index cdc20ab..1925160 100644
--- a/code/src/Fitbot/app/src/main/res/values/strings.xml
+++ b/code/src/Fitbot/app/src/main/res/values/strings.xml
@@ -23,4 +23,11 @@
U heeft de oefeningen voltooid! \n Druk op start om nog een sessie te beginnenScore:
+ Title
+
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+ Description
+
+ Exercise description
+ Exercise title
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/main/res/values/styles.xml b/code/src/Fitbot/app/src/main/res/values/styles.xml
index 5da2c49..63e1909 100644
--- a/code/src/Fitbot/app/src/main/res/values/styles.xml
+++ b/code/src/Fitbot/app/src/main/res/values/styles.xml
@@ -25,10 +25,22 @@
6dp
+
+
+
+
+
\ No newline at end of file
diff --git a/code/src/Fitbot/app/src/test/java/com/example/fitbot/DatabaseFetchingTest.java b/code/src/Fitbot/app/src/test/java/com/example/fitbot/DatabaseFetchingTest.java
index 9c824d8..03f2ffe 100644
--- a/code/src/Fitbot/app/src/test/java/com/example/fitbot/DatabaseFetchingTest.java
+++ b/code/src/Fitbot/app/src/test/java/com/example/fitbot/DatabaseFetchingTest.java
@@ -1,6 +1,5 @@
package com.example.fitbot;
-import com.example.fitbot.exercise.EMuscleGroup;
import com.example.fitbot.exercise.Exercise;
import com.example.fitbot.exercise.ExerciseManager;
@@ -11,11 +10,11 @@ public class DatabaseFetchingTest {
@Test
public void testDatabaseFetching() {
- Exercise exercise = ExerciseManager.retrieveExercise();
+ Exercise exercise = ExerciseManager.fetchExerciseFromDatabase();
assert exercise != null;
System.out.println("\n---------------------------------");
System.out.println("Exercise:");
- System.out.println("Name: " + exercise.title);
+ System.out.println("Name: " + exercise.name);
System.out.println("Description: " + exercise.description);
System.out.println("Muscle Group: " + exercise.muscleGroup);
System.out.println("Image URL: " + exercise.imageUrl);
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/code/src/Fitbot/gradle.properties b/code/src/Fitbot/gradle.properties
index c5abf2b..2ab3bb7 100644
--- a/code/src/Fitbot/gradle.properties
+++ b/code/src/Fitbot/gradle.properties
@@ -15,4 +15,3 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
-#android.enableJetifier=true
\ No newline at end of file
diff --git a/code/src/Fitbot/settings.gradle b/code/src/Fitbot/settings.gradle
index ffde70b..885c0be 100644
--- a/code/src/Fitbot/settings.gradle
+++ b/code/src/Fitbot/settings.gradle
@@ -10,9 +10,7 @@ dependencyResolutionManagement {
repositories {
google()
mavenCentral()
- maven {
- url 'https://qisdk.softbankrobotics.com/sdk/maven/'
- }
+ maven { url 'https://qisdk.softbankrobotics.com/sdk/maven/' }
}
}
rootProject.name = "Fitbot"
diff --git a/code/web/pepper_data_test.js b/code/web/pepper_data_test.js
index 674aa18..222a394 100644
--- a/code/web/pepper_data_test.js
+++ b/code/web/pepper_data_test.js
@@ -1,24 +1,22 @@
-const address = 'http://145.92.8.135:3445/';
-
-const data = {
- rotationX: 1,
- rotationY: .4,
- rotationZ: .1,
- accelerationX: 1,
- accelerationY: 2,
- accelerationZ: 4,
- deviceId: 1,
- type: 'data'
-};
-
-for ( let i = 0; i < 10; i++)
+const address = 'http://192.168.137.45:3445';
+const amount = 10;
+for ( let i = 0; i < amount; i++)
{
setTimeout(() => {
console.log("Sending data");
fetch(address, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify(data)
+ body: JSON.stringify({
+ rotationX: 0,
+ rotationY: 0,
+ rotationZ: 0,
+ accelerationX: Math.PI / amount * i,
+ accelerationY: 0,
+ accelerationZ: 0,
+ type: 'data',
+ deviceId: 0
+ })
});
}, i * 1000);
}
\ No newline at end of file
diff --git a/docs/documentation/android/pepper_handling.md b/docs/documentation/android/pepper_handling.md
new file mode 100644
index 0000000..9de544c
--- /dev/null
+++ b/docs/documentation/android/pepper_handling.md
@@ -0,0 +1,37 @@
+## Pepper Handling
+
+---
+
+To make the handling of the Pepper robot easier, we've made some classes
+that can be used to interact with the robot.
+The classes associated with the Pepper robot interaction are located in the
+`com.example.fitbot.pepper` package. To start interacting with the Pepper robot,
+one must assign a `QiContext` first. This can be done by calling `Pepper.provideQiContext(QiContext context)`
+method. This method takes a `QiContext` object as a parameter. This object is used to interact with the robot.
+
+To make the robot talk, one can call the following method:
+```java
+Pepper.say(String text);
+```
+
+To make the robot execute an animation, one can call the following method:
+```java
+Pepper.animate(String animationName);
+```
+
+To make the robot do more sophisticated things, one can call the
+```java
+Pepper.addToEventQueue(AbstractPepperActionEvent event);
+```
+This adds the provided event to the event queue. The event will be executed in the order it was added.
+Whenever there's no valid QiContext available to use, the event will maintain in the queue until one is
+provided.
+
+*Note* All Pepper action events are added to a queue, and executed synchronously. This means
+that if the robot is still busy with a task, adding a new event to the queue will not do anything until
+the robot is done with the current task.
+
+Currently, the only supported actions are:
+
+- `PepperSpeechEvent` - This event makes the robot say something.
+- `PepperAnimationEvent` - This event makes the robot execute an animation.
diff --git a/docs/documentation/android/robot_motion_tracking_system.md b/docs/documentation/android/robot_motion_tracking_system.md
index e222e3d..46ddaae 100644
--- a/docs/documentation/android/robot_motion_tracking_system.md
+++ b/docs/documentation/android/robot_motion_tracking_system.md
@@ -1,108 +1,60 @@
-## Motion Tracking System
+## Motion Tracking System -- Pepper
---
-To capture the user's motion with the sensing devices, we'll need to use a tracking system that calculates the
-path the user makes to be able to determine the user's position and orientation, and therefore whether the movement
-that was made correlates to the provided path.
-This is done by some calculations in the `MotionProcessor` class. To get started, create an instance of the `MotionProcessor` class and call the `processMotion` method with the `MotionData` object as a parameter. This will return a `MotionResult` object that contains the calculated path.
+### Introduction
+The robot motion tracking system is a system that allows the robot to track the user's motion and provide feedback
+based on the user's motion. The system consists of a Web Server, which actively listens for incoming data from the
+two ESP8266 modules. The ESP8266 modules are connected to the robot and are responsible for tracking the user's motion.
+These sensors send rotation data to the Web Server, which can then be parsed and used to provide feedback to the user.
+
+### System Architecture
+
+The system consists of three main components: the Web Server, the ESP8266 modules, and the Pepper robot. The Web Server
+is responsible for receiving data from the ESP8266 modules and processing it. The ESP8266 modules are responsible for
+sending rotation data to the web server, which is then parsed.
+
+### Parsing Data
+
+To parse the data received by the web server, one must utilize the class `InputProcessor`. This class is responsible for
+both starting the server and processing data received by the server. To start parsing data, one can do the following:
```java
-// create the motion processor
-MotionProcessor motionProcessor = new MotionProcessor();
+
+InputProcessor processor = new InputProcessor();
+processor.startListening(); // This starts the web server.
+
```
-To start listening for input, one must call the following method:
-
+To parse data received by the server, one can register an event listener with the `InputProcessor` class. This event listener
+will be called whenever new data is received by the server. To register an event listener, one can do the following:
```java
-// start listening for input
-motionProcessor.startListening();
+
+processor.setInputHandler(new IInputHandler() {
+ @Override
+ public void accept(Vector3f rotationVector, int sensorId) {
+ // Do something with the input.
+ }
+});
+
```
-Calling this function creates a WebSocket server, which the sensing devices can connect to.
-The `MotionProcessor` class will then start listening for a set of messages that start with specified kind of keywords.
-The messages always start with the keyword, separated by a space, and then the data is sent.
-The default data separator is `;`.
-An example of the message format is shown below:
+### Providing Feedback
+
+If one wants to provide feedback to the user, one must first provide an exercise to the `InputProcessor` object.
+This can be done by calling the `setExercise(Exercise exercise)` method. This method takes an `Exercise` object as a parameter.
+This object contains information about the exercise, such as the name of the exercise, the muscle group it targets, and the
+video associated with the exercise. One can then check the status of the current exercise by calling one of the following
+methods:
```java
-// Sending data
-"data accelerationX;accelerationY;accelerationZ;rotationX;rotationY;rotationZ" // all values are floats
+processor.getCurrentProgress(); // Returns the current progress of the exercise as a scalar (0 - 1)
-// Changing the sample rate
-"sampleRate rate" // rate is an integer
+processor.getError(int sensorId, float time); // Get the error offset for a given sensor at a given time
-// Calibrating the zero point
-"zero x;y;z" // x, y, z are floats
-```
+processor.getAverageError(int sensorId); // Get the average error for a given sensor
-To add a custom message received handler, one can simply call the following method:
+processor.secondsPassed(); // Get the number of seconds that have passed since the exercise started
-```java
-// Add a custom message handler
-motionProcessor.setMotionDataEventHandler((Vector3 vector) -> { ... });
-```
-*Note: The message handler provides a vector as a parameter; this vector is already converted from relative acceleration and rotation.*
+processor.hasFinished(); // Check if the exercise has finished
-### Error checking
-
-To check whether the made movements correlate with a given path, one must check for their differences.
-This can be done by a few implemented methods:
-
-***Get the error of a vector compared to a path***
-```java
-GesturePath path = new GesturePath.Builder()
- .addVector(...)
- .build();
-
-Vector3 referencePoint = new Vector3(...);
-double error = motionProcessor.getError(path, referencePoint);
-```
-
-***Get the average error of a computed path to a `GesturePath`***
-```java
-GesturePath path = new GesturePath.Builder()
- .addVector(...)
- .build();
-
-double error = motionProcessor.getAverageError(path);
-```
-
-***Get a list of error values from a computed path to a `GesturePath`***
-```java
-GesturePath path = new GesturePath.Builder()
- .addVector(...)
- .build();
-
-List errorList = motionProcessor.getErrors(path);
-```
-
-### Example
-
-An example of how to use a motion tracking system is shown below:
-
-```java
-
-// create the motion processor
-MotionProcessor motionProcessor = new MotionProcessor();
-
-// Create a gesture path
-GesturePath.Builder pathBuilder = new GesturePath.Builder();
-
-for ( int i = 0; i < 100; i++ )
- pathBuilder.addVector(new Vector3(i, i, i));
-
-GesturePath path = pathBuilder.build();
-
-// Set the path
-for ( int i = 0; i < 100; i++ ) {
- motionProcessor.addMotionData(new MotionData(i, i, i, i, i, i));
-}
-
-// Get error values
-List errorList = motionProcessor.getErrors(path);
-
-// Get average error
-double averageError = motionProcessor.getAverageError(path);
-
-// Now you can do whatever you want with these results.
```
\ No newline at end of file
diff --git a/docs/documentation/assets/Testkaart-wandeling.png b/docs/documentation/assets/Testkaart-wandeling.png
new file mode 100644
index 0000000..e06d8d9
Binary files /dev/null and b/docs/documentation/assets/Testkaart-wandeling.png differ
diff --git a/docs/documentation/assets/knocksensor.png b/docs/documentation/assets/knocksensor.png
new file mode 100644
index 0000000..4a4907f
Binary files /dev/null and b/docs/documentation/assets/knocksensor.png differ
diff --git a/docs/documentation/brainstorm/Dataprotocols.md b/docs/documentation/brainstorm/Dataprotocols.md
new file mode 100644
index 0000000..1b6198f
--- /dev/null
+++ b/docs/documentation/brainstorm/Dataprotocols.md
@@ -0,0 +1,36 @@
+# Dataprotocols
+
+
+
+# different types
+
+### Hypertext Transfer Protocol (HTTP)
+HTTP is the foundation of web communication, permitting the transport of data across the internet using a request-response architecture. It uses TCP/IP and stands out by its statelessness, with each request being independent, increasing the web's scalability and flexibility. While it does not encrypt data which makes it usable with sensible data it still makes an nice easy to use option.
+
+We decided to use this for our project because for communicating with the database it is easy to use and we are not usiong sensible data. If we were to use sensible data that we want to encrypt we can use HTTPS. We are only sending small amounts of data to our app and we are not transfering files to our app. This made HTTP it way more attractive option.
+
+### File Transfer Protocol (FTP)
+FTP is the classic protocol for transferring files between computers. It establishes a connection between two computers and it has 2 modes. Passive mode for recieving files. This leaves a port open on the computer. You also have an active mode. This is were the client opens a port towards an other computer. If you want to encrypt your data you can use FTPS.
+
+When we started the project is thought of this as a option however since we are not only transfering videos but also stuff like titles and dicriptions i thought we were not going to enable it to its fullest potattional. On top of that we are also transfering only small amounts of videos and we switched the way we used videos on our project by hosting the videos on a service like youtube. This made FTP not usefull for our project.
+
+### User Datagram Protocol (UDP)
+UDP is s connectionless protocol that prioritizes speed over reliability. It sends datagrams to a computer without establishing a connection with the reciever. It is not stable so you need to keep in mind that it will not be 100% accurate. However it is really fast so this makes it a suitible option for applications where a tiny amount of dataloss is not an issue.
+
+(to be added)
+
+### Message Queue Telemetry Transport (MQTT)
+MQTT is s lightweight messaging protocol designed for machine-to-machine communication in Internet of Things applications. It uses a publish subscribe model. This is were one device publishes data on a server and the other devices need to subscribe to that publisher to recieve the data. It is commonly used to transmot sensor data to a server.
+
+(to be added)
+
+### Real-time Streaming Protocols (RTSP)
+RTSP is collection of protocols used for streaming media such as videos over networks. However it requires additional software for it to work properly. RTSP shines in controlling live streams allowing features like pause. It's often used in IPTV's and video conferencing applications.
+
+
+Due to its limited support we are not uising it in our project. We were already having issues with other things that are not supported on android or mobile apps and we did not want to risk getting more issues while working on our project since we were already using up our limited time. It is a very interesting option though since it will enable more advanced videos. It also is realy complex which makes it a less atractive option since we are already learning a lot of new things and if we were to want to learn more things we would rather learn something with a low learning curve.
+
+
+# Conclusion
+
+We still used HTTP for its simplicity and because we did not need a fancy data protocol. If i were to make this project again i would still use HTTP because is will make the making of the project easy. If we were to expend our project i would UDP if we were to make it like a game. Then we might be able to make our own wii sports with pepper. Since the loss of some data wont really matter
\ No newline at end of file
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/UML-esp8266.md b/docs/documentation/diagrams/UML-esp8266.md
new file mode 100644
index 0000000..bc7fad5
--- /dev/null
+++ b/docs/documentation/diagrams/UML-esp8266.md
@@ -0,0 +1,61 @@
+# UML esp8266 diagram
+
+```mermaid
+classDiagram
+
+Connectivity --> Movement-sensor-code
+SensorManager --> Movement-sensor-code
+namespace ESP8266 {
+
+ class Movement-sensor-code {
+ + struct RotationQuaternion
+ + PepperIP
+ setup()
+ loop()
+ connectWifi()
+ sensorSetup()
+ getPepperIP()
+ httpPost()
+ }
+
+ class Connectivity {
+ + void connectWiFi(char* ssid, char* pass)
+ + void websocketSetup(char* ip, uint16_t port, char* adress)
+ + void sendData(float roll, float pitch, float yaw);
+ + int httpPost(const char *serverAddress, const char *serverSubPath, const unsigned short serverPort, const + char *data, const size_t dataLength, const char *contentType)
+ + const char* fetchIPAddress()
+
+ -ESP8266WiFiMulti wifi;
+ -WiFiClient wifi_client;
+ }
+
+ class SensorManager {
+ + struct eulerAngles(
+ float roll;
+ float pitch;
+ float yaw;
+ );
+ + struct acceleration (
+ float x;
+ float y;
+ float z;
+ );
+ + eulerAngles getEulerAngles()
+ + acceleration getAcelleration()
+ + bool sensorTap()
+
+
+ - struct RotationQuaternions (
+ float i;
+ float j;
+ float k;
+ float w;
+ );
+ - RotationQuaternions getQuaternions()
+
+ - BNO080 myIMU
+ }
+
+
+}
+```
\ No newline at end of file
diff --git a/docs/documentation/diagrams/assets/positionTracking.png b/docs/documentation/diagrams/assets/positionTracking.png
new file mode 100644
index 0000000..bd712d2
Binary files /dev/null and b/docs/documentation/diagrams/assets/positionTracking.png differ
diff --git a/docs/documentation/diagrams/infrastructure.md b/docs/documentation/diagrams/infrastructure.md
index bbb68a7..425d4f3 100644
--- a/docs/documentation/diagrams/infrastructure.md
+++ b/docs/documentation/diagrams/infrastructure.md
@@ -1,61 +1,75 @@
# Infrastructure UML
+---
+
+The design for our project can be represented by the diagram below.
+
+A simple linguistic representation of the diagram is as follows:
+
+We have a Raspberry Pi, which runs a NodeJS server to handle all incoming requests.
+This server is connected to a MariaDB database, which stores all the exercise data.
+This data can then be received from the application we built for the Pepper robot.
+We also have two ESP8266 modules, which are connected to the Pepper robot's Web Server.
+These modules record angular motion via gyroscopes, and send this data to the web server on the Pepper robot.
+The web server is a requirement to receive incoming data from the sensors, due to the ESP's not having a
+dedicated bluetooth chip to communicate with the Pepper robot.
+The parsed data on the application can then be shown to the user with some feedback regarding their performance.
+
``` mermaid
classDiagram
-Raspberry pi --> NodeJS
-Raspberry pi --> Database
-NodeJS --> Androidapp : getExerciseData (Wifi, Rest API)
+Raspberry Pi --> NodeJS
+Raspberry Pi --> Database
+NodeJS <--> Android Application : Request exercise data from database. Send ip adress to cache
Database <--> NodeJS : Database queries
+NodeJS --> ESP8266 : Get pepper ip
-ESP8266 --> Androidapp : getRotationalData (Wifi)
+ESP8266 --> Android Application : Send rotation data via WiFi to\n Pepper Web Server
namespace Server {
- class Raspberry pi {
+ class Raspberry Pi {
+MariaDB
+Apache2
+NodeJS
- Database()
- Webserver()
-
+ Database
+ Webserver
}
class Database {
+ExerciseID
+ExerciseName
+ +ExerciseShortDesc
+ExerciseDescription
+ExerciseVideo
- +GyroCoordinates
+ +ExerciseImage
+ +GyroVectors
+MuscleGroup
}
class NodeJS {
+MariaDB
- GetRandomExercise()
+ +Handle requests
+ +Cache pepper IP
}
}
namespace Pepper {
- class Androidapp {
+ class Android Application {
+Java
+Android SDK
+QiSDK
- motionProcessing()
- robotMovement()
- showVideo()
- fitnessCycle()
-
-
+ +WebServer
+ +Acquire rotation data from sensors
}
}
namespace Hardware {
class ESP8266{
- +RotationalX
- +RotationalY
- +RotationalZ
- Gyroscope()
+ +RotationX
+ +RotationY
+ +RotationZ
+ Send rotation data to Web Server
}
}
```
diff --git a/docs/documentation/diagrams/positionTracking.fzz b/docs/documentation/diagrams/positionTracking.fzz
new file mode 100644
index 0000000..59ba8cf
Binary files /dev/null and b/docs/documentation/diagrams/positionTracking.fzz differ
diff --git a/docs/documentation/hardware/BOM.md b/docs/documentation/hardware/BOM.md
index 78ebbf3..dd9226f 100644
--- a/docs/documentation/hardware/BOM.md
+++ b/docs/documentation/hardware/BOM.md
@@ -1,2 +1,16 @@
# BOM
+### Embedded hardware
+
+| Part | Amount needed for 1 tracker | Price in Euros | Extra notes | |
+|---|---|---|---|---|
+| - [BNO085](https://shop.slimevr.dev/products/slimevr-imu-module-bno085) (IMU) | 1 | 12 | | |
+| - [Custom PCB](https://github.com/Sorakage033/SlimeVR-CheeseCake/tree/main/002-%E2%80%98%E2%80%99Choco%E2%80%98%E2%80%99SpecialRemake) | 1 | ~5 at 30 pieces | (Use file 8, 9 and 10 and use pcb thickness 1mm | |
+| - [Battery](https://nl.aliexpress.com/item/32583443309.html) (900 mAh) | 1 | ~4 at 20 pieces | | |
+| - [3D print model](https://github.com/Sorakage033/SlimeVR-CheeseCake/blob/main/004-3D%20Print%20Model/001.3-Chocolate-Case_TypeC-Only.stl) | 1 | 0,2 | | |
+| - [Optional Acrylic lid](https://github.com/Sorakage033/SlimeVR-CheeseCake/blob/main/004-3D%20Print%20Model/acryliclid.svg) | 1 | 0,50 | | |
+| | | | | |
+
+#### Extra notes for assembly
+* Watch out when inserting the assembled product into the case. Make sure you put it in at an angle so you don't break the power switch.
+
diff --git a/docs/documentation/hardware/Ideasforfitbord.md b/docs/documentation/hardware/Ideasforfitbord.md
new file mode 100644
index 0000000..b8ec804
--- /dev/null
+++ b/docs/documentation/hardware/Ideasforfitbord.md
@@ -0,0 +1,49 @@
+# Ideas for hardware
+
+# making a balance bord
+
+Since We are not able to connect the wii fit bord we have to come up with a solution. We thought of it for some time and what we want to do with it. Origanlly we wanted to use the balance bord for excersises such as standing on one leg. This is a simple leg excersise we wanted to have. We thaugt of multiple solutions to still have this excersise. However we still needed to think of a design for the frame.
+
+# the frame
+
+We wanted it to have a similar style to the balance bord. howevere since we can make or own we wanted to make it a bit taller. This makes it easier to implement some other excersise such as the step up. This is na excersise that benefits from a taller box than the wii fit box.
+
+## LDR
+
+We can use a LDR to determine if someone is standing on the bord. We will have a small window where light can pass trought to let de LDR read out the light. We need to make clear that the user needs to stand on these points by providing an easy to udnerstand design.
+
+## Knock sensor
+
+A knock sensor is a sensor that detects impact. This could come in handy for us since it could detect impact on our fitbord. If we were to make a fitbord we would love to implement this sensor. We could use it to detect if someone is standing on the fitbord. This will not make the LDR useless since it only will detect one impact. This will be when someone will be standing on the fitbord it will not activate when someone is standing on the fitbord without moving.
+
+We could is it for excersises where u want someone to jog or walk in place. The knock sensor will detect the small impacts from walking. This will greatly expend our excersise pool since walking and running is really important for cardio excersises. We could also make people stamp on the ground. This is a fun and good excersise for your legs.
+
+```C++
+const int knockSensor = A0;
+const int threshold = 200;
+
+int sensorReading = 0;
+
+
+void setup() {
+ Serial.begin(9600);
+}
+
+void loop() {
+
+ sensorReading = analogRead(knockSensor);
+
+ if (sensorReading >= threshold) {
+
+ Serial.println(sensorReading);
+ }
+
+ if (sensorReading >= 500) {
+Serial.println(stamp detected)
+ }
+}
+ delay(10);
+```
+
+
+
\ No newline at end of file
diff --git a/docs/documentation/hardware/Issues.md b/docs/documentation/hardware/Issues.md
index a152afd..18e167d 100644
--- a/docs/documentation/hardware/Issues.md
+++ b/docs/documentation/hardware/Issues.md
@@ -1,4 +1,4 @@
# Issues with hardware
-## Issues with libraries
-The websocket library doesnt work well on the esp8266 d1 mini. It lags out the entire esp and makes it unresponsive.
\ No newline at end of file
+## Issues with programming
+The websocket library doesnt work well on the esp8266 d1 mini. It lags out the entire esp and makes it unresponsive. The solution is to use a different way of communicating.
\ No newline at end of file
diff --git a/docs/documentation/hardware/pcb.md b/docs/documentation/hardware/pcb.md
index 2142df2..80c28a0 100644
--- a/docs/documentation/hardware/pcb.md
+++ b/docs/documentation/hardware/pcb.md
@@ -20,5 +20,9 @@ We chose this pcb because its really small and it has a socket for a sensor and
We are going to rotational data from the sensor and use that to give feedback to the user based on how well they did the exercise.

+## How can i program this ESP?
+
+To program this you need to use the Arduino IDE. You need to install the ESP8266 board in the board manager. You need to go to File -> prefrences -> additional board manager url's. Then you need to add this link `https://arduino.esp8266.com/stable/package_esp8266com_index.json`. Then you can find the LOLIN(WEMOS) D1 mini lite. Thats the board you need to select. When compiling you will see a lot of warnings but you can ignore them.
+
### Sources
* https://github.com/Sorakage033/SlimeVR-CheeseCake
\ No newline at end of file
diff --git a/docs/documentation/hardware/sensors.md b/docs/documentation/hardware/sensors.md
index ea7d2a3..3bc1629 100644
--- a/docs/documentation/hardware/sensors.md
+++ b/docs/documentation/hardware/sensors.md
@@ -21,7 +21,9 @@ There are a lot of different IMU's with a lot of different specifications.
* Bmi160
### Which one are we gonna use?
+
We are going to use the BNO085 because it has the least amount of drift and its very versatile. We can get almost any type of rotational and acceleration data from it.
+
---
diff --git a/docs/documentation/research-questions/position-tracking-research.md b/docs/documentation/research-questions/position-tracking-research.md
index 1d2293d..9d0c428 100644
--- a/docs/documentation/research-questions/position-tracking-research.md
+++ b/docs/documentation/research-questions/position-tracking-research.md
@@ -2,19 +2,18 @@
## 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. This system will be used to track their position to determine if a user is doing the exercises correctly.
+For this project an embedded system that can track a users position is needed. 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 sensor and determine the user's position.
-- Sync the code to the current task for the user.
+- Design an embedded system that can track user position and sent the data to an Android App.
+- Recieve the data from the embedded system in the Android App and sync the data to the current task for the user.
## Research and Analysis
### Choosing the sensor
-For this project we have chosen LDR's as our primary sensor. The LDR's will be placed on the ground in a board and the user will stand on top of the board. The LDR's will be used to track the user's position. The LDR's will be connected to the esp32s3 microcontroller and the data will be processed to determine the user's position.
+For this project we have chosen LDR's as our primary sensor. The LDR's will be placed on the ground in a board and the user will stand on top of the board. The LDR's will be used to track the user's position. The LDR's will be connected to the ESP32 microcontroller and the data will be processed to determine the user's position.
We have chosen this sensor since it's one of the easiest and cheapest solutions to our problem. Other sensors like pressure sensors, accelerometers, and Wii Balance Board are either too expensive, not the most optimal for the task, or hard to integrate with other systems.
@@ -42,9 +41,28 @@ Accelerometers:
- 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
+### Wii Balance Board
-To be added
+The use of a Wii Balance Board was considered for this project. The Wii Balance Board is a balance board that can measure a user's weight and center of balance. The implementation of the board is very similar to the LDR's with an ESP32. The board also had bluetooth which makes it possible to connect to the Android App. However, the Wii Balance Board is very hard to integrate with other systems. The board is not designed to be used with other systems and the documentation is very limited. This makes it very hard to use the board for this project.
+
+#### Problems with the Wii Balance Board
+
+- The Wii Balance Board is not designed to be used with other systems. The documentation is very limited and there is no official SDK available.
+- The Wii Balance Board does not use UUID's for the services and characteristics. This makes it very hard to connect to the board and read the data.
+- When trying to connect to the Wii Balance Board, the board would show up as a device but would ask for a PIN code. The PIN code is not documented anywhere and there is no way to connect to the board without it.
+
+`Bluetooth pairing must be initiated by the host by sending a "Require Authentication" HCI command to its bluetooth device. The bluetooth device will ask the host for a link key, which must be rejected so it will ask for a PIN-Code. The PIN-Code is the binary bluetooth address of the wiimote backwards.`
+
+When trying the solution above the board would reject the PIN code and would not connect to the host.
+
+#### Sources
+
+The following sources have been used to research the Wii Balance Board:
+
+- [Wii Balance Board](https://wiibrew.org/wiki/Wii_Balance_Board#Bluetooth_Communication)
+- [Wii Mote](https://wiibrew.org/wiki/Wiimote#Bluetooth_Communication)
+
+Publicly available projects have been researched aswell nearly all of them dind't use java to connect to the Wii Balance Board. The projects that did use java to connect to the Wii Balance Board were either outdated or didn't work.
## System Design
@@ -52,39 +70,29 @@ To be added
The hardware of the system will consist of the following components:
- LDR: The sensor that will be used to track the user's position based on the light intensity.
- - ESP32S3: The microcontroller that will process the data from the LDR.
- - Pepper: The controller that will recieve the processed data from the ESP32S3 and will sync the data to the current task for the user.
+ - ESP32: The microcontroller that will process the data from the LDR.
+ - Pepper: The controller that will recieve the processed data from the ESP32 and will sync the data to the current task for the user.
#### Connection diagram
-To be added
-
-### Software
-
-To be added
-
-### Integration
-
-To be added
+
## Implementation
### Prototyping
-To be added
+A prototype of the app has been created to test the connection between the ESP32 and the Android App. The app can discover BLE devices and connect to them. The app currently is not able to continously read the data from the ESP32. It can however read the data once.
### Testing and Validation
-To be added
+The prototype of the 'Tracking board' has been tested. The LDR's have were connected to the ESP32 on a breadboard. The ESP32 will emit itself as a GATT server and the Android App will look for the hosts name and connect to it. The Android App will then read the data from the ESP32 once.
## Conclusion
-To be added
+The LDR's with the ESP32 are a good solution for the problem. The LDR's are cheap and easy to use. The ESP32 is a good microcontroller to process the data from the LDR's. The Android App can connect to the ESP32 and read the data from it. The next step is to make the Android App continously read the data from the ESP32 and display it to the user/use it in the app for exercises.
## References
[Bluetooth Discovery](https://developer.android.com/develop/connectivity/bluetooth/find-bluetooth-devices)
-
-## Appendices
-
-To be added
\ No newline at end of file
+[GATT Server Connection](https://developer.android.com/develop/connectivity/bluetooth/ble/connect-gatt-server)
+[ESP32 GATT Server](https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils/tests/BLETests/Arduino/BLE_server)
\ No newline at end of file
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
new file mode 100644
index 0000000..cf97502
--- /dev/null
+++ b/docs/personal-documentation/Luca/expert-review.md
@@ -0,0 +1,48 @@
+K1 - Object-Oriented Programming
+
+---
+
+In alle classen gerelateerd aan de Pepper besturingen wordt er gebruik gemaakt
+van abstractie en encapsulatie.
+Zie:
+- `PepperAnimationEvent`
+- `PepperSpeechEvent`
+
+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
+Niels heengegaan om te communiceren met de gebruikers.
+We hebben om ons heen mede studenten gevraagd om feedback te geven over onze
+applicatie, gezien we helaas te weinig informatie hebben verkregen van de
+actuele gebruiker.
+
+---
+
+K3 - Infrastructure UML
+
+---
+
+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
diff --git a/docs/personal-documentation/Niels/Expertreview3.md b/docs/personal-documentation/Niels/Expertreview3.md
new file mode 100644
index 0000000..63ae69e
--- /dev/null
+++ b/docs/personal-documentation/Niels/Expertreview3.md
@@ -0,0 +1,42 @@
+# K1
+
+Voor k1 heb ik al beschreven wat ik wist van k1 in mijn vorige expert zoals hoe onze database infrastructuur werkt en hoe een android app maken werkt.
+
+### OOP
+
+Ik heb OOP gewerkt met java. Dit komt doordat java een object orianted language is. Ik heb een class gemaakt om makkelijk te kunnen navigeren tussen de menus.
+
+[Navigation Manager](../../../../code/src/Fitbot/app/src/main/java/com/example/fitbot/util/NavigationManager.java)
+
+Ik heb ook een class gemaakt in C++ dit komt doordat ik een class heb gemaakt die het IP get van pepper. hier praat ik verder over in k5
+
+### Database
+
+ik heb de databse ingevuld met data. We hadden eerst alle videos op youtube prive geupload en wilden dat in de database doen. Dat hebben we veranderd naar een google docs. Wij slaan ook andere data op zoals de excersise discription deze wordt verstuurd naar de app en deze wordt dan weergegeven.
+
+# K2
+
+Ik heb voor K2 onderzoeken geschreven over zicht en kleuren bij ouderen. Ook ben ik met de ouderen gaan wandelen en heb ik kleine gesprekken emt hun gevoerd. Ik had de test card al gemaakt in mijn vorige expert en heb nu de learning card gemaakt van mijn ervaring.
+
+
+
+
+
+
+
+
+# K3
+Wij hadden als team vorige sprint al gebrainstormt en besproken hoe wij onze infrastructuur gaan inrichten dit hebben wij met ze alle gedaan en ik in mijn vorige sprint review behandelt welke onderdelen wij gebruiken. Ik ben ook bezig geweest met een onderzoek over datatransfer protocolen. Ik wilde dit odnerzoeken doordat het wij een nieuwe manier van data transfers gebruiken. Ik had voor dit nognooit met fiel transfer gewerkt. Na mijn vorige sprint review kreeg ik als feedback dat het beter was om het met externe linkjes te doen en niet met direct files. Dit heb ik bij mijn team voorgelegt en we hadden het verandert naar youtube linkjes. Nadat wij erachter kwamen dat het niet heel handig is zijn we over gestapt naar google drive.
+
+
+# K4
+Ik had graag willen werken met het wiifit bord helaas werkte dit neit omdat het heel moeilijk te intergreren was in een android app. Daarna wilden wij onze eigen maken maar dit is helaas niet van gekomen omdat onze ESP32 alleen BLE uitzend en dat zorgt ervoor dat de app maar 1 keer de data binnekrijgt. Doordat we weining tijd hebben voor een oplossing ben ik gaan onderzoeken wat voor andere sensoren en oefeningen we kunnen doen met een eigen gemaakte wii fit bord.
+
+[fetchIPAddress](../../documentation/hardware/Ideasforfitbord.md)
+
+# K5
+ik heb een get request gemaakt voor de motion trackers zodat zij het ip kunnen krijgen. Peppers IP is niet static waardoor ze elke keer weer een nieuwe IP nodig hebben. Ik heb ook pepper laten bewegen en ik kan makkelijk meer movement toevoegen. Pepper iets laten zeggen is ook gemakkelijk met de pepper.say command.
+
+[peppermovement](../../../code/src/Fitbot/app/src/main/res/raw/armcircle.qianim)
+
+[fetchIPAddress](../../../code/arduino/Movement-sensor-code/Connectivity.cpp)
\ No newline at end of file
diff --git a/docs/personal-documentation/Niels/assets/Learningcard28.png b/docs/personal-documentation/Niels/assets/Learningcard28.png
new file mode 100644
index 0000000..103d57f
Binary files /dev/null and b/docs/personal-documentation/Niels/assets/Learningcard28.png differ
diff --git a/docs/personal-documentation/Sam/reflectiesOpdracht.md b/docs/personal-documentation/Sam/reflectiesOpdracht.md
index d454f4c..4bc8b26 100644
--- a/docs/personal-documentation/Sam/reflectiesOpdracht.md
+++ b/docs/personal-documentation/Sam/reflectiesOpdracht.md
@@ -1,11 +1,71 @@
# Reflectie 3 blokken
-## Blok 1
+### Blok 1
In blok 1 heb ik de professionele skills Persoonlijk leiderschap en Toekomstgericht organiseren. Ik had veel moeite met documenteren en het scrumboard te gebruiken, omdat ik er nog geen ervaring mee had. Ik had op dat moment al het hele project in blokjes opgedeeld voor mezelf en keer daarna nooit meer naar het scrumboard. Door die manier van werken deed ik ook 5 dingen tegelijk waardoor ik af en toe het overzicht kwijtraakte . Ik had als doel opgesteld om in de volgende blokken meer het scrumboard te gaan gebruiken. Mijn aanpak was proberen zelf wat user story’s te maken, zodat ik ook wat meer betrokken was bij het scrumboard. Uiteindelijk heb ik daardoor wel wat meer gebruik gemaakt van het scrumboard, maar ik ging nog wel veel mijn eigen weg. Ik was niet helemaal tevreden met het resultaat, maar de aanpak werkte wel. Wat ik heb geleerd is als ik veel gebruik van iets wil maken moet ik er zelf ook bij betrokken zijn. Volgende keren zorg ik er voor dat ik betrokken ben bij het scrum board wat nu ook moet, waardoor ik meer het scrumboard gebruik.
-## Blok 2
+### Blok 2
In blok 2 gingen we voor het eerst samenwerken in een duo, waarbij we ook deels onze eigen user story’s moesten maken, dat heeft me ook geholpen om door het hele blok heen het scrumboard meer te gebruiken. Communicatie ging over het algemeen in dat blok redelijk goed. Als we vragen aan elkaar hadden werden die gewoon gesteld en als een van ons vastliep hielpen we elkaar. In sprint 2 werden classes aan ons geïntroduceerd waarbij ik best wat moeite had om dat te begrijpen. Dus ik had maar 1 class gemaakt en verder alles in functies gestopt. Pas eind sprint 2 probeerde ik de feedback te verwerken om alles in classes te stoppen, maar omdat je code uiteindelijk zo complex is. Is het bijna onmogelijk om het in classes te stoppen. Waarbij het resultaat was een heel lastig leesbaar programma. Ik was niet tevreden of over het resultaat aan het einde van het blok. Mijn aanpak was bij het volgende blok. Meteen alles in classes maken. Wat uiteindelijk wel goed heeft gewerkt. Ben daardoor ook achter gekomen hoe handig classes zijn en dat ze enorm veel overzicht geven van wat je aan het maken bent.
-## Blok 3
+### Blok 3
In blok 3 stond doelgericht interacteren en persoonlijke leiderschap centraal. Het groepje in blok 3 was te gezellig waardoor we vaak meer zaten te lollen dan we aan het werk waren. Ik had mezelf de taak gegeven om proberen om meer gefocust te werken zonder dat ik afgeleid raakte door mijn groepje. Mijn aanpak was door mezelf af te schermen met een koptelefoon of eventjes ergens anders te gaan zitten, wat ook goed hielp was even een rondje lopen. Op die manier kon ik de laatste sprint heel efficiënt werken en in blok 4 merk ik ook dat die techniek enorm erg helpt met meer gefocust en productief blijven op een dag. Dit resultaat was eigenlijk een beetje laat het liefst deed ik dit al eind sprint 1, zodat ik heel het blok beter kon doorwerken.
+
+## Sterkte zwakte analyse.
+
+### Toekomstgericht organiseren
+Een van mijn zwakkere punten is organiseren in een team, want ik heb alles heel snel een plan in mijn hoofd maar dat duidelijk op papier zetten is was lastiger. Daardoor kan je ook minder rekening houden met de product owner van wat ze daadwerkelijk willen. Daarbij lukt me het wel beter om andere mogelijkheden en kansen te zien als we bezig zijn met het project waardoor we ons product kunnen verbeteren.
+Ethiek is een van mijn sterkere punten als ik iets maak denk ik wel er bij van wat de slechte gevolgen er van kunnen zijn en of het wel handig is om te maken. Ook ben ik me er van bewust dat er grenzen zijn bij het verzamelen van informatie.
+Procesmanagement is ook een van mijn zwakkere punten maar het is zich langzaam aan het verbeteren. Eerst had ik veel moeite met een planning maken en er voor zorgen dat ik me er aan hield. Nu gaat dat allemaal een stuk beter en merk ik dat ik echt volgens de planning bezig ben. Nu ben ik ook product owner binnen mijn groepje en push ik om een minimal viable product af te hebben voor de sprint 2 review.
+Ik geef mezelf een score van 3. Vanaf het begin van de opleiding is het al stukken verbeterd, maar er is meer ruimte voor verbetering.
+
+### Onderzoekend probleemoplossen
+Een zwak punt van mij is methodische probleemaanpak als het gaat om theoretische vraagstukken. Daarbij heb ik veel moeite met het belangrijkste er uit halen en het onder te verdelen in hoofd en bijzaken. Als het praktisch is gaat het een stuk makkelijker en heb ik heel snel een beeld van de hoofd en bijzaken en welke kennis er nog ontbreekt.
+Met onderzoek heb ik nog wel moeite, over het algemeen heb ik moeite met Nederlands en merk ik zelf dat ik af en toe 3 keer een zin moet lezen totdat ik weet wat er staat. Het onderscheiden van meningen en feiten heb ik minder moeite mee en de betrouwbaarheid van een bron kan ik er redelijk snel uithalen.
+In oplossingen zoeken ben ik redelijk goed in. Ik kan kritisch zijn op mezelf en anderen en geef vaak suggesties over wat beter kan. Of als iets op een andere manier kan. Ook ben ik goed in het bedenken van nieuwe oplossingen op problemen.
+Ik geef mezelf nu een score van 2.5, omdat ik nog niet heel goed ben in teksten en formuleren.
+
+### Persoonlijk leiderschap
+Ik denk dat ondernemend zijn een sterkte punt van mij is. Ik ga snel dingen uit mezelf doen en als iets me niet lukt probeer ik het nog steeds zelf uit te vogelen anders vraag ik om hulp. Bij beslissingen probeer ik instemmingen van het hele groepje er bij te krijgen. Ook als niemand de leiding in het groepje heeft of er gebeurt niks pak ik snel de leiding om nog proberen iets af te kunnen krijgen.
+Persoonlijke ontwikkeling is een sterk punt van mij. Ik weet waar ik goed en slecht in ben en ik reflecteer vaak om mijn acties en wat ik doe en wat misschien beter kon. Ik probeer me mee te leven met anderen en hun ideeën. Ook ben ik mij bewust van de consequenties die mijn acties kunnen hebben.
+Ik heb nog wel moeite met persoonlijke profilering, omdat ik heel snel een rol pak waar ik mij comfortabel bij voel en niet een rol pak dat uitdagender is waarbij ik veel meer leer. Daarentegen weet ik wel heel goed wat ik wil leren en welke kennis ik nog zou willen oppakken. Ook geef ik aan mijn teamgenoten aan waar ik goed en slecht in ben, zodat we makkelijk en beter taken kunnen verdelen als we in tijdnood zitten.
+Over het algemeen geef ik persoonlijke leiderschap 3.6 punten. Ik moet nog werken aan meer uitdaging zoeken, maar verder gaat het goed op dit vlak.
+
+### Doelgericht interacteren
+Ik ben redelijk goed met rekening houden met opdrachtgevers en vraag vaak aan feedback van wat ze willen en laat ze ook zien tussen het project wat we hebben.
+In communiceren ben ik goed en slecht. Ik kan goed actief luisteren en rekening houden met iemands gevoelens. Ook kan ik mijn meningen logisch onderbouwen. Het gedeelte waar ik af en toe nog moeite mee heb ik begrijpelijk kunnen spreken en woord volgorde.
+Met samenwerken ben ik redelijk goed. Ik kan goed afspraken maken en die nakomen, bijvoorbeeld dat we samen eerder naar school komen om iets af te krijgen. We werken samen naar een oplossing en helpen elkaar waar nodig is.
+Ik geef met doelgericht interacteren mezelf 4 punten, omdat het samenwerken elk blok tot nu toe goed is gegaan en ik ook producten naar wens de laatste blokken heb opgeleverd.
+
+
+## SMART Leerdoelen
+### Toekomstgericht organiseren
+Specifiek:
+Ik wil leren hoe ik plannen beter op papier kan zetten, zodat mijn team ook inzicht heeft in mijn ideeën voor het project.
+Meetbaar:
+Ik zal bij de eerste sprint een gestructureerd uitgewerkt plan hebben voor mijn team, zodat ze allemaal op de hoogste zijn van mijn ideeën en zodat we dingen makkelijk kunnen afstemmen.
+Acceptabel:
+Het is realistisch, want ik heb al stappen gezet om het te verbeteren en ik wil kijken hoe goed dit gaat werken.
+Tijdgebonden:
+Ik zal dit doen komend blok, waarbij ik aan het begin van de eerste sprint werk aan een plan die ik kan zien aan mijn teamgenoten waarbij ik mijn visie van het project kan laten zien.
+
+### Onderzoekend probleemoplossen
+Specifiek: Verbeter mijn methodische probleemaanpak bij theoretische vraagstukken en mijn begrip van teksten in het Nederlands.
+Meetbaar: Ik wil mijn vaardigheden verhogen van het huidige niveau naar een hoger niveau waarbij ik complexe vraagstukken gestructureerd en kritisch aanpak.
+Acceptabel: Dit doel is belangerijk voor mijn leerproces en zal me helpen om beter en efficiënter te zijn bij onderzoekend probleem oplossen.
+ Realistisch: Ik zal gerichte inspanningen leveren om mijn vaardigheden te verbeteren, bijvoorbeeld door meer te oefenen met theoretische vraagstukken en actief te werken aan mijn taalvaardigheid.
+Tijdgebonden: Ik wil dit doel bereiken voordat het half jaar project volgend jaar over is.
+
+### Persoonlijk leiderschap
+Specifiek: Binnen zes maanden wil ik mijn persoonlijke leiderschapsvaardigheden versterken door minstens drie keer een uitdagende rol binnen teamprojecten op me te nemen en hierin actief te werken aan nieuwe vaardigheden.
+Meetbaar: Ik zal na elk project een reflectieverslag schrijven en feedback vragen aan ten minste twee teamleden om mijn voortgang te meten. Mijn succescriteria zijn het succesvol voltooien van deze rollen en positieve feedback van teamleden over mijn leiderschapskwaliteiten.
+Acceptabel: Ik ben bereid tijd en moeite te investeren in deze uitdaging omdat het essentieel is voor mijn professionele groei en het behalen van mijn carrièredoelen.
+Realistisch: Met mijn huidige competenties en de beschikbare tijd kan ik deze uitdagende rollen aannemen en succesvol voltooien. Ik heb al bewezen initiatief en leiderschap te kunnen tonen.
+Tijdsgebonden: Ik zal dit doel bereiken door elke twee maanden een nieuw teamproject met een uitdagende rol af te ronden, wat resulteert in drie uitdagende projecten binnen zes maanden.
+
+### Doelgericht interacteren
+Specifiek: Binnen drie maanden wil ik mijn bijdragen aan daily standup-meetings verbeteren door elke dag een duidelijke update te geven over mijn voortgang, obstakels en plannen, en door actief feedback te vragen en te geven.
+Meetbaar: Ik zal elke dag kijken of de daily standup gedaan word. En daarbij elke werkdag mijn bijdrage leveren
+Acceptabel: Dit zorgt er voor dat de samenwerking uiteindelijk beter word en dat iedereen elkaar sneller helpt met dingen
+Realistisch: Dit is realistisch want het is iets kleins van 10 min elke dag.
+Tijdsgebonden: Ik zal dit doel bereiken voor het halfjaar project over is
+
diff --git a/docs/personal-documentation/sebas/dailyUpdates.md b/docs/personal-documentation/sebas/dailyUpdates.md
index 9f6762e..e7edd15 100644
--- a/docs/personal-documentation/sebas/dailyUpdates.md
+++ b/docs/personal-documentation/sebas/dailyUpdates.md
@@ -381,6 +381,136 @@ Done
**31 May**
+To do
+
+ - Expert review
+ - Add Ui for exercises
+
+Done
+
+ - Expert review
+
+**1 June**
+
+- Weekend
+
+**2 June**
+
+- Weekend
+
+**3 June**
+
+To do
+
+ - Add Ui for exercises
+ - Retrieve exercises from database and show them in the app
+
+Done
+
+ - Add Ui for exercises
+
+**4 June**
+
+To do
+
+ -
+
+Done
+
+ -
+
+**5 June**
+
+To do
+
+ -
+
+Done
+
+ -
+
+**6 June**
+
+To do
+
+ -
+
+Done
+
+ -
+
+**7 June**
+
+To do
+
+ -
+
+Done
+
+ -
+
+**8 June**
+
+To do
+
+ -
+
+Done
+
+ -
+
+**9 June**
+
+To do
+
+ -
+
+Done
+
+ -
+
+**10 June**
+
+To do
+
+ -
+
+Done
+
+ -
+
+**11 June**
+
+To do
+
+ -
+
+Done
+
+ -
+
+**12 June**
+
+To do
+
+ -
+
+Done
+
+ -
+
+**13 June**
+
+To do
+
+ -
+
+Done
+
+ -
+
+**14 June**
+
To do
-
diff --git a/docs/personal-documentation/sebas/expertReview/expert3sprint3.md b/docs/personal-documentation/sebas/expertReview/expert3sprint3.md
index 25617d2..48a98a7 100644
--- a/docs/personal-documentation/sebas/expertReview/expert3sprint3.md
+++ b/docs/personal-documentation/sebas/expertReview/expert3sprint3.md
@@ -6,23 +6,52 @@
Voor het bewijs van algemene kennis over K1 zie [Expert review 2 K1](../expertReview/expert2sprint2.md#K1:-Je-hebt-object-georiënteerde-software-gemaakt-die-samenwerkt-met-een-database.).
+### Database connectie
-Deze sprint ben ik bezig geweest met:
+Voor het database gedeelte van K1 ben ik bezig geweest met het maken van een connectie naar de database doormiddel van NodeJs:
-- Functionaliteit van de database
-- Functionaliteit van de server
-- Data ophalen uit de database en weergeven in de app
+[Config](../../../../code/server/test/config.js)
+
+[Connection](../../../../code/server/test/testConnection.js)
+
+### Classes in CPP
+
+Voor het OOP gedeelte van K1 ben ik bezig geweest met het maken en gebruiken van classes in CPP, hierbij heb ik gebruik gemaakt van abstraction en encapsulation:
+
+[CPP Classes](https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-4/muupooviixee66/-/tree/bead6a5a13e5df6658cb9db451c4565250c6a2f6/code/arduino/Position-tracking)
+
+### Java
+
+Omdat wij gebruik maken van java voor het maken van de Android App, is het makkelijk om gebruik te maken van OOP. Java is een object georiënteerde programmeertaal en maakt het makkelijk om gebruik te maken van OOP sinds het een van de belangrijkste concepten is van Java.
+
+In Java heb ik gebruik gemaakt van de volgende OOP concepten:
+
+Abstraction: [Navigation Manager](../../../../code/src/Fitbot/app/src/main/java/com/example/fitbot/util/NavigationManager.java)
+
+In deze class heb ik een public static void gemaakt. Door de void public te maken kan deze functie vanuit elke class worden aangeroepen. Door static te gebruiken kan deze functie worden aangeroepen zonder dat er een object van de class hoeft te worden gemaakt.
+
+De functie is te gebruiker door `NavigationManager.hideSystemUI(this);` aan te roepen. Hierbij is `this` de context van de huidige activity.
---
## K3: Je hebt een infrastructuur ontworpen en gebouwd volgens zelf-gedefinieerde vereisten.
-Feedback verwerkt (diagrammen)
+Voor K3 heb ik de feedback op mijn diagrammen van de vorige sprint verwerkt. Deze sprint heb ik research gedaan naar Reverse Proxy, MariaDB en server hosting.
-Infrastructuur beschreven met problemen en oplossingen [Infrastuctuur](https://muupooviixee66-propedeuse-hbo-ict-onderwijs-2023-178fb5f296aa35.dev.hihva.nl/documentation/database/infrastructure/)
+[Infrastructuur met problemen en oplossingen](https://muupooviixee66-propedeuse-hbo-ict-onderwijs-2023-178fb5f296aa35.dev.hihva.nl/documentation/database/infrastructure/)
---
## K4: Je ontwerpt een embedded systeem op basis van gegeven hardware. & K5: Je kan software schrijven voor een intelligente controller voorzien van actuatoren en sensoren.
-Research naar hardware en software voor de controller
\ No newline at end of file
+Voor K4 ben ik bezig geweest met het onderzoeken van hardware die kan samen werken met pepper om de gebruikers positie te tracken. Aan het begin was het idee om met een Wii Balance Board te werken, maar dit was niet mogelijk. Daarom ben ik gaan kijken naar andere hardware waarmee dit mogelijk zo zijn.
+
+[Research naar hardware en software voor de controller](/docs/documentation/research-questions/position-tracking-research.md)
+
+Voor K5 ben ik bezig geweest met het onderzoeken en schrijven van de software die nodig is om de hardware te laten werken. Hierbij heb ik gekeken naar de software die nodig is om de hardware te laten werken en hoe deze samenwerkt met de software van een Android App. Research naar de software die nodig is voor de controller is te vinden in de link hierboven. De code voor de controller is te vinden in de link hieronder.
+
+Code voor [BLE device scanner](https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-4/muupooviixee66/-/blob/bead6a5a13e5df6658cb9db451c4565250c6a2f6/code/src/Fitbot/app/src/main/java/com/example/fitbot/bluetooth/DeviceScanner.java). Deze code is geschreven voor een android applicatie die BLE devices kan discoveren en connecten.
+
+Code voor de [ESP32](https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-4/muupooviixee66/-/blob/bead6a5a13e5df6658cb9db451c4565250c6a2f6/code/arduino/Position-tracking/test/test.ino). Deze code is geschreven om de ESP32 zich te laten opstellen als GATT server en de data van de LDR sensor te versturen naar de android app.
+
+---
\ No newline at end of file