diff --git a/code/arduino/Movement-sensor-code/Connectivity.cpp b/code/arduino/Movement-sensor-code/Connectivity.cpp index bfc3c04..955d7d0 100644 --- a/code/arduino/Movement-sensor-code/Connectivity.cpp +++ b/code/arduino/Movement-sensor-code/Connectivity.cpp @@ -21,9 +21,9 @@ void Connectivity::connectWiFi(char* ssid, char* pass){ // } const char* getServerURL = "http://145.92.8.132:443/get-ip"; -String ipAddress = ""; +char* ipAddress = ""; -String Connectivity::fetchIPAddress() { +const char* Connectivity::fetchIPAddress() { if (WiFi.status() == WL_CONNECTED) { HTTPClient http; WiFiClient client; @@ -32,7 +32,7 @@ String Connectivity::fetchIPAddress() { int httpCode = http.GET(); if (httpCode > 0) { if (httpCode == HTTP_CODE_OK) { - ipAddress = http.getString(); + ipAddress = strdup(http.getString().c_str()); } } else { Serial.printf("GET request failed, error: %s\n", http.errorToString(httpCode).c_str()); diff --git a/code/arduino/Movement-sensor-code/Connectivity.h b/code/arduino/Movement-sensor-code/Connectivity.h index 6de0109..37d528b 100644 --- a/code/arduino/Movement-sensor-code/Connectivity.h +++ b/code/arduino/Movement-sensor-code/Connectivity.h @@ -19,7 +19,7 @@ public: 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); - String fetchIPAddress(); + const char* fetchIPAddress(); private: ESP8266WiFiMulti wifi; diff --git a/code/arduino/Movement-sensor-code/Movement-sensor-code.ino b/code/arduino/Movement-sensor-code/Movement-sensor-code.ino index 061f12d..6540384 100644 --- a/code/arduino/Movement-sensor-code/Movement-sensor-code.ino +++ b/code/arduino/Movement-sensor-code/Movement-sensor-code.ino @@ -7,8 +7,6 @@ void setup() { Serial.begin(9600); } -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(); @@ -19,6 +17,11 @@ struct acceleration { float z = 9; } accelData; + if (!ipAquired) { + serverIp = connectivity.fetchIPAddress(); + 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 memset(buffer, 0, BUFFER_SIZE); @@ -34,10 +37,10 @@ struct acceleration { accelData.z, "data"); // %d = int, %f = floatation, %s = string - connectivity.httpPost(connectivity.fetchIPAddress(), "/", 3445, buffer, strlen(buffer), "application/json"); + connectivity.httpPost(serverIp, "/", 3445, buffer, strlen(buffer), "application/json"); lastTime = currentTime; } } //acceleration.X //acceleration.Y -//acceleration.Z +//acceleration.Z \ 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 8e3480e..bd6639b 100644 --- a/code/arduino/Movement-sensor-code/headerFIle.h +++ b/code/arduino/Movement-sensor-code/headerFIle.h @@ -15,3 +15,5 @@ WebSocketsClient webSocket; #define IP_ADDRESS "192.168.137.12" 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/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/app/src/main/java/com/example/fitbot/exercise/Exercise.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/Exercise.java index 331d356..f0a1e7a 100644 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/Exercise.java +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/Exercise.java @@ -7,7 +7,7 @@ public class Exercise { public final EMuscleGroup muscleGroup; public final GesturePath leftPath; public final GesturePath rightPath; - public final String title; + public final String name; public final String description; public final String imageUrl; public final String videoUrl; @@ -19,14 +19,14 @@ public class Exercise { * @param muscleGroup The muscle group of the exercise. * @param leftPath The path of the left hand. * @param rightPath The path of the right hand. - * @param title The title of the exercise. + * @param name The title of the exercise. * @param description The description of the exercise. * @param imageUrl The URL of the image. * @param videoUrl The URL of the video. */ - public Exercise(EMuscleGroup muscleGroup, String title, String description, String imageUrl, String videoUrl, GesturePath leftPath, GesturePath rightPath, float exerciseTimeInSeconds) { + public Exercise(EMuscleGroup muscleGroup, String name, String description, String imageUrl, String videoUrl, GesturePath leftPath, GesturePath rightPath, float exerciseTimeInSeconds) { + this.name = name; this.muscleGroup = muscleGroup; - this.title = title; this.description = description; this.leftPath = leftPath; this.rightPath = rightPath; diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/ExerciseManager.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/ExerciseManager.java index dc045e5..613eb36 100644 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/ExerciseManager.java +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/ExerciseManager.java @@ -13,7 +13,7 @@ import java.net.URLConnection; public class ExerciseManager { - private static final String HOST_ADDRESS = "http://145.92.8.132:443/"; + private static final String HOST_ADDRESS = "http://145.92.8.132:443"; // The value of these property variables must be equivalent of // the JSON data that the database sends back. @@ -85,11 +85,12 @@ public class ExerciseManager { */ public static Exercise fetchExerciseFromDatabase() { String response = sendHTTP( - HOST_ADDRESS, "POST", "application/json", null + HOST_ADDRESS, "POST", "application/json", "{}" ); // Validate the response if (response != null) { try { + System.out.println(response); JsonObject content = JsonParser.parseString(response).getAsJsonObject(); // Ensure all required properties are present 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 81f020d..1d74427 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 @@ -6,6 +6,7 @@ import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.os.Bundle; import android.util.Log; +import android.widget.TextView; import android.view.View; import android.view.WindowManager; import android.widget.Button; @@ -29,9 +30,10 @@ import org.joml.Vector3f; public class FitnessActivity extends RobotActivity implements RobotLifecycleCallbacks { // Private fields for the FitnessActivity class. - private ExerciseStatusElement personalMotionPreviewElement; + private ExerciseStatusElement exerciseStatusElement; private InputProcessor motionProcessor; private Exercise currentExercise; + private TextView exerciseNameTextView; // Some nice little messages for the user private static final String[] EXERCISE_NOT_FOUND_MESSAGES = new String[]{ @@ -56,6 +58,7 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall // Remove the ugly ass bar on top of the view setSpeechBarDisplayStrategy(SpeechBarDisplayStrategy.IMMERSIVE); + this.exerciseNameTextView = findViewById(R.id.textViewFitnessTitle); // Find the VideoView by its ID VideoView videoView = findViewById(R.id.videoView); @@ -82,22 +85,23 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall // Provide the context so that all queued actions can be performed. Pepper.provideContext(qiContext, this.getClass()); - personalMotionPreviewElement = findViewById(R.id.personalMotionPreviewElement); + exerciseStatusElement = findViewById(R.id.personalMotionPreviewElement); // 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(() -> { + exerciseStatusElement.post(() -> { this.fetchExerciseAsync((exercise) -> { // Acquire paths from the exercise and provide them to the motion processor Vector3f[][] vectors = new Vector3f[][]{exercise.leftPath.getVectors(), exercise.rightPath.getVectors()}; motionProcessor = new InputProcessor(vectors, exercise.exerciseTimeInSeconds, SENSOR_SAMPLE_RATE); - personalMotionPreviewElement.initialize(exercise, motionProcessor, EXERCISE_COUNT); - + exerciseStatusElement.initialize(exercise, motionProcessor, EXERCISE_COUNT); + motionProcessor.useExercise(exercise); + /* TODO: Remove if not needed */motionProcessor.setRecording(true, 10); motionProcessor.startListening(); - motionProcessor.setInputHandler(personalMotionPreviewElement); + motionProcessor.setInputHandler(exerciseStatusElement); }, (n) -> { int randomMessageIndex = (int) Math.floor(Math.random() * EXERCISE_NOT_FOUND_MESSAGES.length); @@ -123,6 +127,7 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall if (exercise == null) { onFailedFetch.handle(null); } else { + exerciseNameTextView.setText(exercise.name); onSuccessfulFetch.handle(exercise); } })).start(); diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/components/ExerciseStatusElement.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/components/ExerciseStatusElement.java index 606321b..c8b112b 100644 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/components/ExerciseStatusElement.java +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/components/ExerciseStatusElement.java @@ -38,16 +38,6 @@ public class ExerciseStatusElement extends View implements IInputHandler { private final Paint borderPaint = new Paint(); private final Paint backgroundPaint = new Paint(); - // TODO: Remove - private final Matrix4f viewMatrix = new Matrix4f(); // The view matrix for the 3D to 2D transformation. - private final 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 final 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!", @@ -93,16 +83,6 @@ public class ExerciseStatusElement extends View implements IInputHandler { 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()) - }; - Pepper.say(STARTING_PHRASES[(int) Math.floor(Math.random() * STARTING_PHRASES.length)]); // Handler that is called every time the motion processor receives new data. @@ -111,6 +91,10 @@ public class ExerciseStatusElement extends View implements IInputHandler { Log.i("MotionProcessor", "Rotation vector received: " + rotationVector); Log.i("MotionProcessor", "Last error offset:" + this.motionProcessor.getError(deviceId, this.motionProcessor.secondsPassed())); + // Check whether the current exercise has been completed. + // This is determined by the duration of the exercise, and the amount of time that has passed. + // The duration of the exercise originates from the database, and is stored in seconds. + // Whenever 'useExercise' is called, the timer resets and this method will be called again. if (this.motionProcessor.hasFinished()) { // If for some reason the parent activity is not defined, // move back to the main screen. @@ -124,6 +108,8 @@ public class ExerciseStatusElement extends View implements IInputHandler { this.exerciseCount--; this.parentActivity.fetchExerciseAsync((newExercise) -> { this.motionProcessor.useExercise(newExercise); + + // Whenever the database retrieval failed, we return to the main screen. }, (failed) -> { // Move to main screen NavigationManager.navigateToActivity(parentActivity, MainActivity.class); @@ -131,21 +117,8 @@ public class ExerciseStatusElement extends View implements IInputHandler { } else { // Finish the exercise. NavigationManager.navigateToActivity(parentActivity, EndScreenActivity.class); - return; } } - - /* TODO: Use raw vector */ - vectors.add(projectVertex(rotationVector, this.getWidth(), this.getHeight())); - - /* TODO: Remove */ - Vector2f parsed = projectVertex(rotationVector, this.getWidth(), this.getHeight()); - - this.vectors.add(parsed /* TODO: Add regular vertex once exercise data is stored in DB*/); - - // Remove the first element if the array is too big - if (this.vectors.size() > 100) - this.vectors.poll(); }); } @@ -159,50 +132,12 @@ public class ExerciseStatusElement extends View implements IInputHandler { 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;*/ - - - /* TODO: Remove */ - 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; 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 c78bd89..66c6d94 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 @@ -80,6 +80,8 @@ public class InputProcessor { this.selfRotationVectorPaths = new Vector3f[2][(int) (exercise.exerciseTimeInSeconds * this.sampleRate)]; this.targetRotationVectorPaths = new Vector3f[2][exercise.rightPath.getVectors().length]; + this.targetRotationVectorPaths[0] = exercise.leftPath.getVectors(); + this.targetRotationVectorPaths[1] = exercise.rightPath.getVectors(); this.exerciseDurationInSeconds = exercise.exerciseTimeInSeconds; this.secondsPassed = 0.0D; this.lastTime = System.currentTimeMillis(); @@ -99,7 +101,6 @@ public class InputProcessor { if (recording) { this.secondsPassed = 0.0D; this.lastTime = System.currentTimeMillis(); - } } 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 4f5d387..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 @@ -14,7 +14,7 @@ public class DatabaseFetchingTest { 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);