diff --git a/code/arduino/Movement-sensor-code/Connectivity.cpp b/code/arduino/Movement-sensor-code/Connectivity.cpp index 5bdaa9e..d4c5837 100644 --- a/code/arduino/Movement-sensor-code/Connectivity.cpp +++ b/code/arduino/Movement-sensor-code/Connectivity.cpp @@ -23,6 +23,7 @@ void Connectivity::connectWiFi(char* ssid, char* pass){ 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) { @@ -41,14 +42,14 @@ const char* Connectivity::fetchIPAddress() { ipAddress = strdup(ip); } } else { - Serial.printf("GET request failed, error: %s\n", http.errorToString(httpCode).c_str()); + Serial.printf("GET request failed, error: %s\n", http.errorToString(httpCode).c_str()); } http.end(); } else { Serial.println("WiFi not connected"); } - return ipAddress; // Add this return statement + return ipAddress; } /** Send a POST request to a server with provided data */ diff --git a/code/arduino/Movement-sensor-code/Connectivity.h b/code/arduino/Movement-sensor-code/Connectivity.h index 3df3524..ae711e7 100644 --- a/code/arduino/Movement-sensor-code/Connectivity.h +++ b/code/arduino/Movement-sensor-code/Connectivity.h @@ -14,8 +14,8 @@ #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); diff --git a/code/arduino/Movement-sensor-code/Movement-sensor-code.ino b/code/arduino/Movement-sensor-code/Movement-sensor-code.ino index 6acc498..4b57532 100644 --- a/code/arduino/Movement-sensor-code/Movement-sensor-code.ino +++ b/code/arduino/Movement-sensor-code/Movement-sensor-code.ino @@ -4,11 +4,10 @@ void setup() { //connect to internet and start sensor connectivity.connectWiFi(ssid, pass); sensorManager.sensorSetup(); - Serial.begin(115200); - Serial.println("startup"); } void loop() { + //get data from sensor SensorManager::eulerAngles Rotation = sensorManager.getEulerAngles(); //static structure @@ -28,6 +27,7 @@ struct acceleration { unsigned long currentTime = millis(); 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}", @@ -40,9 +40,8 @@ struct acceleration { accelData.z, "data"); // %d = int, %f = floatation, %s = string + //send data to pepper connectivity.httpPost(serverIp, "/", 3445, buffer, strlen(buffer), "application/json"); - Serial.println(serverIp); - Serial.println(buffer); lastTime = currentTime; } } 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 a4edc9e..6998573 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 @@ -37,7 +37,7 @@ public class ExerciseManager { }; public static final int DEFAULT_EXERCISE_REPETITIONS = 10; - public static final float EXERCISE_ERROR_MARGIN = 1.0f; + public static final float EXERCISE_ERROR_MARGIN = 1.5f; public static final float EXERCISE_TIME_SCALING_FACTOR = 1.0f; // Fields representing the statistics of the user 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 1c36be4..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 @@ -16,6 +16,5 @@ public class EndScreenActivity extends AppCompatActivity { NavigationManager.hideSystemUI(this); NavigationManager.setupButtonNavigation(this, R.id.homeButtonEndScreen, MainActivity.class); - NavigationManager.setupButtonNavigation(this, R.id.startButtonEndScreen, FitnessActivity.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 cac794c..9c9be6b 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 @@ -10,6 +10,7 @@ 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; @@ -19,16 +20,12 @@ import android.widget.ProgressBar; import android.widget.TextView; import android.widget.VideoView; -import com.aldebaran.qi.Future; import com.aldebaran.qi.sdk.QiContext; import com.aldebaran.qi.sdk.QiSDK; import com.aldebaran.qi.sdk.RobotLifecycleCallbacks; -import com.aldebaran.qi.sdk.builder.AnimateBuilder; -import com.aldebaran.qi.sdk.builder.AnimationBuilder; 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.aldebaran.qi.sdk.object.actuation.Animation; import com.example.fitbot.R; import com.example.fitbot.exercise.Exercise; import com.example.fitbot.exercise.ExerciseManager; @@ -45,7 +42,7 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall // Progress circle for the exercises private ProgressBar progressCircle; private TextView progressText; - private int progress = 0; + private int progress = 1; private final int maxProgress = 10; // Exercise status element data @@ -72,7 +69,7 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall private static final float SENSOR_SAMPLE_RATE = 10.0f; private static final int EXERCISE_COUNT = 5; - private static int EXERCISE_REP = 1; + private static int EXERCISE_VIDEO_REPETITION = 1; private static final float EXERCISE_SPEED_MULTIPLIER = 1.0f; @Override @@ -88,7 +85,7 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall //this.exerciseDescriptionTextView = findViewById(R.id.textViewDialogDescription); // Set the repetition count for the exercise - EXERCISE_REP = 1; + EXERCISE_VIDEO_REPETITION = 1; progressCircle = findViewById(R.id.progressCircle); progressText = findViewById(R.id.progressText); @@ -179,6 +176,7 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall // Start checking for user movement once the video has loaded this.motionProcessor.startListening(); this.motionProcessor.startCheckingUserMovement(); +// this.motionProcessor.setRecording(true, 4.f); return true; } @@ -192,9 +190,9 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall } videoView.setOnCompletionListener(mp -> { - if (EXERCISE_REP < EXERCISE_COUNT) { + if (EXERCISE_VIDEO_REPETITION < ExerciseManager.DEFAULT_EXERCISE_REPETITIONS) { videoView.start(); // start the video again - EXERCISE_REP++; + EXERCISE_VIDEO_REPETITION++; } }); }); @@ -211,7 +209,7 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall public void playVideo(VideoView videoView, Context context) { // Set up the video player if (videoView != null) { - videoView.setVideoPath(exerciseVideoUrl); + 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."); @@ -267,8 +265,7 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall } public void incrementProgress() { - if (progress < maxProgress) { - progress++; + if (progress++ < maxProgress) { triggerColorBurst(true); updateProgress(); } @@ -281,19 +278,25 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall public void triggerColorBurst(boolean isGoodRep) { - 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(); + Log.i("InputProcessor", "Color Burst"); - 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(); + 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/util/processing/InputProcessor.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/InputProcessor.java index 15ebf2a..c62aeb8 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 @@ -17,17 +17,18 @@ 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 List[] 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 float exerciseRepetitionDurationInSeconds = 0.0f; - private int exercisesRemaining = 0; + private int exercisesRemaining = 1; private float errorCheckInterval_s; private int checksPerformed = 0; @@ -104,9 +105,20 @@ public class InputProcessor { 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(); @@ -114,7 +126,11 @@ public class InputProcessor { this.checksPerformed++; if (this.checksPerformed >= this.totalChecks) + { + this.checksPerformed = 0; + this.exercisesRemaining--; acquireExercise(); + } try { Thread.sleep((long) (this.errorCheckInterval_s * 1000)); @@ -131,21 +147,21 @@ public class InputProcessor { * @param exercise The exercise to move on to. */ private void nextExercise(Exercise exercise) { - if (this.exercisesRemaining-- <= 0) { - + //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.errorCheckInterval_s = this.exerciseRepetitionDurationInSeconds * ExerciseManager.DEFAULT_EXERCISE_REPETITIONS / 6.0f; - this.selfRotationVectorPaths = new ArrayList[2]; this.selfRotationVectorPaths[0] = new ArrayList<>(); this.selfRotationVectorPaths[1] = new ArrayList<>(); @@ -156,6 +172,11 @@ public class InputProcessor { 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); } /** @@ -163,14 +184,16 @@ public class InputProcessor { */ public void onAdequateRepetition() { ExerciseManager.TOTAL_REPETITIONS_PERFORMED++; - this.parentActivity.incrementProgress(); + 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() { - this.parentActivity.triggerColorBurst(false); + Log.i("InputProcessor", "Inadequate repetition performed"); + this.parentActivity.runOnUiThread(() -> this.parentActivity.triggerColorBurst(false)); } /** @@ -231,7 +254,17 @@ public class InputProcessor { * Upon successful retrieval, it will call the nextExercise method. */ private void acquireExercise() { - this.exercisesRemaining--; + + 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) -> { @@ -386,29 +419,31 @@ public class InputProcessor { * Function for checking whether the last movement was faulty */ public boolean isFaultyMovement() { - - // Calculate the index of the reference rotation vector - // This is done by calculating the closest index of the last received vector - // to the current time. - // i = | (t % T) / T * N | - - int i, referenceIndex; - float distance; - - for (i = 0; i < selfRotationVectorPaths.length; i++) { - referenceIndex = (int) (Math.round( - ((this.secondsPassed % this.exerciseRepetitionDurationInSeconds) / - (this.exerciseRepetitionDurationInSeconds)) * this.targetRotationVectorPaths[i].length)) - % this.targetRotationVectorPaths[i].length; - // If distance is greater than the threshold, return true - distance = this.selfRotationVectorPaths[i].get(this.selfRotationVectorPaths[i].size() - 1).distance( - this.targetRotationVectorPaths[i][referenceIndex]); - - if (distance > ExerciseManager.EXERCISE_ERROR_MARGIN) { - Log.i("MotionProcessor", "Faulty movement detected: " + distance + " > " + ExerciseManager.EXERCISE_ERROR_MARGIN); - return true; + 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 false; + + return true; // Return true for faulty movement if only up or down movement is detected } } diff --git a/code/src/Fitbot/app/src/main/res/layout/activity_end_screen.xml b/code/src/Fitbot/app/src/main/res/layout/activity_end_screen.xml index d8a48fd..c2e3033 100644 --- a/code/src/Fitbot/app/src/main/res/layout/activity_end_screen.xml +++ b/code/src/Fitbot/app/src/main/res/layout/activity_end_screen.xml @@ -8,13 +8,14 @@ tools:context=".ui.activities.HelpActivity"> @@ -26,8 +27,8 @@ android:layout_marginBottom="40dp" 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"> @@ -56,27 +57,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:text="@string/voltooid" - android:textAlignment="center"/> - - - - - + 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" /> -