Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-4/muupooviixee66
This commit is contained in:
@@ -138,7 +138,7 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall
|
|||||||
// the canvas properly.
|
// the canvas properly.
|
||||||
this.fetchExerciseAsync((exercise) -> {
|
this.fetchExerciseAsync((exercise) -> {
|
||||||
// Acquire paths from the exercise and provide them to the motion processor
|
// Acquire paths from the exercise and provide them to the motion processor
|
||||||
motionProcessor = new InputProcessor(SENSOR_SAMPLE_RATE, this);
|
motionProcessor = new InputProcessor(this);
|
||||||
motionProcessor.useExercise(exercise);
|
motionProcessor.useExercise(exercise);
|
||||||
/* TODO: Remove if not needed */
|
/* TODO: Remove if not needed */
|
||||||
motionProcessor.setRecording(true, 10);
|
motionProcessor.setRecording(true, 10);
|
||||||
@@ -166,8 +166,8 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall
|
|||||||
if (exercise == null) {
|
if (exercise == null) {
|
||||||
runOnUiThread(() -> onFailedFetch.handle(null));
|
runOnUiThread(() -> onFailedFetch.handle(null));
|
||||||
} else {
|
} else {
|
||||||
runOnUiThread(() -> {
|
|
||||||
onSuccessfulFetch.handle(exercise);
|
onSuccessfulFetch.handle(exercise);
|
||||||
|
runOnUiThread(() -> {
|
||||||
exerciseNameTextView.setText(exercise.name);
|
exerciseNameTextView.setText(exercise.name);
|
||||||
exerciseShortDescriptionTextView.setText(exercise.shortDescription);
|
exerciseShortDescriptionTextView.setText(exercise.shortDescription);
|
||||||
// exerciseDescriptionTextView.setText(exercise.description);
|
// exerciseDescriptionTextView.setText(exercise.description);
|
||||||
@@ -203,6 +203,9 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall
|
|||||||
Log.e("FitnessActivity", "VideoView is null. Check your layout XML.");
|
Log.e("FitnessActivity", "VideoView is null. Check your layout XML.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start checking for user movement once the video has loaded
|
||||||
|
this.motionProcessor.startCheckingUserMovement();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@@ -24,14 +24,14 @@ import java.util.List;
|
|||||||
public class InputProcessor {
|
public class InputProcessor {
|
||||||
|
|
||||||
private List<Vector3f>[] selfRotationVectorPaths; // Relative path of the motion data
|
private List<Vector3f>[] selfRotationVectorPaths; // Relative path of the motion data
|
||||||
//private Vector3f[][] selfRotationVectorPaths; // Relative path of the motion data
|
|
||||||
private Vector3f[][] targetRotationVectorPaths; // Target path of the motion data
|
private Vector3f[][] targetRotationVectorPaths; // Target path of the motion data
|
||||||
|
|
||||||
private final float sampleRate; // The sample rate of the motion sensor
|
|
||||||
private float exerciseRepetitionDurationInSeconds = 0.0f;
|
private float exerciseRepetitionDurationInSeconds = 0.0f;
|
||||||
private int repetitionsRemaining = 0;
|
|
||||||
private int exercisesRemaining = 0;
|
private int exercisesRemaining = 0;
|
||||||
private float exerciseScore = 0.0F;
|
|
||||||
|
private float errorCheckInterval_s;
|
||||||
|
private int checksPerformed = 0;
|
||||||
|
private int totalChecks = 0;
|
||||||
|
|
||||||
private final FitnessActivity parentActivity;
|
private final FitnessActivity parentActivity;
|
||||||
|
|
||||||
@@ -72,11 +72,8 @@ public class InputProcessor {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for the motion processor.
|
* Constructor for the motion processor.
|
||||||
*
|
|
||||||
* @param inputSampleRate The sample rate of the motion sensor.
|
|
||||||
*/
|
*/
|
||||||
public InputProcessor(float inputSampleRate, FitnessActivity parentActivity) {
|
public InputProcessor(FitnessActivity parentActivity) {
|
||||||
this.sampleRate = inputSampleRate;
|
|
||||||
this.parentActivity = parentActivity;
|
this.parentActivity = parentActivity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,6 +96,37 @@ public class InputProcessor {
|
|||||||
Pepper.say(STARTING_PHRASES[(int) Math.floor(Math.random() * STARTING_PHRASES.length)]);
|
Pepper.say(STARTING_PHRASES[(int) Math.floor(Math.random() * STARTING_PHRASES.length)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(() -> {
|
||||||
|
while (this.exercisesRemaining > 0)
|
||||||
|
{
|
||||||
|
boolean isFaulty = this.isFaultyMovement();
|
||||||
|
|
||||||
|
if ( isFaulty ) {
|
||||||
|
this.onInadequateRepetition();
|
||||||
|
} else this.onAdequateRepetition();
|
||||||
|
|
||||||
|
this.checksPerformed++;
|
||||||
|
|
||||||
|
if ( this.checksPerformed >= this.totalChecks )
|
||||||
|
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.
|
* Moves on to the next exercise without changing the remaining exercises.
|
||||||
*
|
*
|
||||||
@@ -107,17 +135,21 @@ public class InputProcessor {
|
|||||||
private void nextExercise(Exercise exercise) {
|
private void nextExercise(Exercise exercise) {
|
||||||
if (this.exercisesRemaining-- <= 0) {
|
if (this.exercisesRemaining-- <= 0) {
|
||||||
NavigationManager.navigateToActivity(this.parentActivity, EndScreenActivity.class);
|
NavigationManager.navigateToActivity(this.parentActivity, EndScreenActivity.class);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExerciseManager.TOTAL_REPETITIONS_REQUIRED += ExerciseManager.DEFAULT_EXERCISE_REPETITIONS;
|
ExerciseManager.TOTAL_REPETITIONS_REQUIRED += ExerciseManager.DEFAULT_EXERCISE_REPETITIONS;
|
||||||
ExerciseManager.TOTAL_EXERCISES_PREFORMED++;
|
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 = new ArrayList[2];
|
||||||
this.selfRotationVectorPaths[0] = new ArrayList<>();
|
this.selfRotationVectorPaths[0] = new ArrayList<>();
|
||||||
this.selfRotationVectorPaths[1] = new ArrayList<>();
|
this.selfRotationVectorPaths[1] = new ArrayList<>();
|
||||||
|
|
||||||
this.repetitionsRemaining = ExerciseManager.DEFAULT_EXERCISE_REPETITIONS;
|
|
||||||
|
|
||||||
this.targetRotationVectorPaths = new Vector3f[2][exercise.rightPath.getAngleVectors().length];
|
this.targetRotationVectorPaths = new Vector3f[2][exercise.rightPath.getAngleVectors().length];
|
||||||
this.targetRotationVectorPaths[0] = exercise.leftPath.getAngleVectors();
|
this.targetRotationVectorPaths[0] = exercise.leftPath.getAngleVectors();
|
||||||
this.targetRotationVectorPaths[1] = exercise.rightPath.getAngleVectors();
|
this.targetRotationVectorPaths[1] = exercise.rightPath.getAngleVectors();
|
||||||
@@ -194,6 +226,22 @@ public class InputProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function for acquiring the next exercise from the database.
|
||||||
|
* Upon successful retrieval, it will call the nextExercise method.
|
||||||
|
*/
|
||||||
|
private void acquireExercise()
|
||||||
|
{
|
||||||
|
this.exercisesRemaining--;
|
||||||
|
|
||||||
|
this.parentActivity.fetchExerciseAsync(this::nextExercise, (nil) -> {
|
||||||
|
|
||||||
|
Log.i("MotionProcessor", "Failed to fetch exercise data.");
|
||||||
|
NavigationManager.navigateToActivity(this.parentActivity, MainActivity.class);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function for stopping the listening process
|
* Function for stopping the listening process
|
||||||
* of the motion sensor. This function will stop
|
* of the motion sensor. This function will stop
|
||||||
@@ -288,20 +336,13 @@ public class InputProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do something else with the vector
|
// Do something else with the vector
|
||||||
// TODO: Implement !!
|
|
||||||
|
|
||||||
Log.i("MotionProcessor", "Rotation vector: " + rotation.toString() + " from device: " + deviceId);
|
Log.i("MotionProcessor", "Rotation vector: " + rotation.toString() + " from device: " + deviceId);
|
||||||
|
|
||||||
// Whenever the exercise has finished and it's not recording,
|
// Whenever the exercise has finished and it's not recording,
|
||||||
// attempt to move to the next exercise.
|
// attempt to move to the next exercise.
|
||||||
// If this fails, navigate back to the main activity.
|
// If this fails, navigate back to the main activity.
|
||||||
if (this.hasFinished() && !this.recordingMovement) {
|
if (this.hasFinished() && !this.recordingMovement)
|
||||||
this.parentActivity.fetchExerciseAsync(this::nextExercise, (nil) -> {
|
acquireExercise();
|
||||||
Log.i("MotionProcessor", "Failed to fetch exercise data.");
|
|
||||||
NavigationManager.navigateToActivity(this.parentActivity, MainActivity.class);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,9 +359,7 @@ public class InputProcessor {
|
|||||||
JsonArray jsonArray = new JsonArray();
|
JsonArray jsonArray = new JsonArray();
|
||||||
/*
|
/*
|
||||||
* Convert to JSON array in the following format:
|
* Convert to JSON array in the following format:
|
||||||
* [
|
* [ { "deviceId": number, "data": [ [x, y, z], [x, y, z], ... ] }]
|
||||||
* { "deviceId": number, "data": [ [x, y, z], [x, y, z], ... ] },
|
|
||||||
* ]
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Iterate over all devices. In the current instance, it's 2.
|
// Iterate over all devices. In the current instance, it's 2.
|
||||||
@@ -346,20 +385,9 @@ public class InputProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function for getting the combined (average) error value of both sensors.
|
* Function for checking whether the last movement was faulty
|
||||||
public double getCombinedError()
|
|
||||||
{
|
|
||||||
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public boolean isFaultyMovement(int sensorId, float time) {
|
public boolean isFaultyMovement() {
|
||||||
|
|
||||||
// Ensure the sensor ID is within the bounds of the array
|
|
||||||
if (sensorId < 0 || sensorId >= selfRotationVectorPaths.length)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Calculate the index of the reference rotation vector
|
// Calculate the index of the reference rotation vector
|
||||||
// This is done by calculating the closest index of the last received vector
|
// This is done by calculating the closest index of the last received vector
|
||||||
@@ -367,26 +395,24 @@ public class InputProcessor {
|
|||||||
// i = | (t % T) / T * N |
|
// i = | (t % T) / T * N |
|
||||||
|
|
||||||
int i, referenceIndex;
|
int i, referenceIndex;
|
||||||
|
float distance;
|
||||||
|
|
||||||
for ( i = 0; i < selfRotationVectorPaths.length; i++)
|
for ( i = 0; i < selfRotationVectorPaths.length; i++)
|
||||||
{
|
{
|
||||||
referenceIndex = (int) (Math.round(
|
referenceIndex = (int) (Math.round(
|
||||||
((time % this.exerciseRepetitionDurationInSeconds) /
|
((this.secondsPassed % this.exerciseRepetitionDurationInSeconds) /
|
||||||
(this.exerciseRepetitionDurationInSeconds)) * this.targetRotationVectorPaths[i].length))
|
(this.exerciseRepetitionDurationInSeconds)) * this.targetRotationVectorPaths[i].length))
|
||||||
% this.targetRotationVectorPaths[i].length;
|
% this.targetRotationVectorPaths[i].length;
|
||||||
// If distance is greater than the threshold, return true
|
// If distance is greater than the threshold, return true
|
||||||
if (this.selfRotationVectorPaths[i].get(this.selfRotationVectorPaths[i].size() - 1).distance(
|
distance = this.selfRotationVectorPaths[i].get(this.selfRotationVectorPaths[i].size() - 1).distance(
|
||||||
this.targetRotationVectorPaths[i][referenceIndex]) > ExerciseManager.EXERCISE_ERROR_MARGIN)
|
this.targetRotationVectorPaths[i][referenceIndex]);
|
||||||
|
|
||||||
|
if (distance > ExerciseManager.EXERCISE_ERROR_MARGIN)
|
||||||
|
{
|
||||||
|
Log.i("MotionProcessor", "Faulty movement detected: " + distance + " > " + ExerciseManager.EXERCISE_ERROR_MARGIN);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float secondsPassed() {
|
|
||||||
return (float) secondsPassed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRecording() {
|
|
||||||
return this.recordingMovement;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user