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:
@@ -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 */
|
||||
|
@@ -14,8 +14,8 @@
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
|
||||
|
||||
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);
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -1,4 +0,0 @@
|
||||
package com.example.fitbot.ui.activities;
|
||||
|
||||
public class CompletionActivity {
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -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<Vector3f>[] selfRotationVectorPaths; // Relative path of the motion data
|
||||
private List<Vector3f>[] 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<Vector3f> 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
|
||||
}
|
||||
}
|
||||
|
@@ -8,13 +8,14 @@
|
||||
tools:context=".ui.activities.HelpActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linearLayout"
|
||||
android:layout_width="800dp"
|
||||
android:layout_height="450dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="80dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginTop="80dp"
|
||||
android:background="@drawable/border_background"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
android:padding="40dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
@@ -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"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="10dp"
|
||||
android:background="@drawable/border_background_3"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textViewScoreEndScreen"
|
||||
style="@style/TextStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/score"
|
||||
android:textAlignment="center"/>
|
||||
android:textAlignment="center" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -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" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/startButtonEndScreen"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="75dp"
|
||||
android:layout_marginStart="280dp"
|
||||
android:layout_marginBottom="30dp"
|
||||
android:background="@drawable/red_button_gradient"
|
||||
android:padding="15dp"
|
||||
android:text="@string/start"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="30sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
@@ -113,7 +113,7 @@
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="false"
|
||||
android:max="10"
|
||||
android:progress="0"
|
||||
android:progress="1"
|
||||
android:progressDrawable="@drawable/progress_circle" />
|
||||
|
||||
<TextView
|
||||
@@ -122,7 +122,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:text="0/10" />
|
||||
android:text="1/10" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
BIN
code/src/Fitbot/app/src/main/res/raw/arm_raises.mp4
Normal file
BIN
code/src/Fitbot/app/src/main/res/raw/arm_raises.mp4
Normal file
Binary file not shown.
@@ -2,12 +2,14 @@
|
||||
|
||||
### Embedded hardware
|
||||
|
||||
- [BNO085](https://shop.slimevr.dev/products/slimevr-imu-module-bno085) (IMU)
|
||||
- [Custom PCB](https://github.com/Sorakage033/SlimeVR-CheeseCake/tree/main/002-%E2%80%98%E2%80%99Choco%E2%80%98%E2%80%99SpecialRemake) (Use file 8 9 and 10 and pcb thickness 1 mm)
|
||||
- [Battery](https://nl.aliexpress.com/item/32583443309.html) (900 mAh)
|
||||
- [3D print model](https://github.com/Sorakage033/SlimeVR-CheeseCake/blob/main/004-3D%20Print%20Model/001.3-Chocolate-Case_TypeC-Only.stl)
|
||||
|
||||
- [Optional Acrylic lid](https://github.com/Sorakage033/SlimeVR-CheeseCake/blob/main/004-3D%20Print%20Model/acryliclid.svg)
|
||||
| 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.
|
||||
|
Reference in New Issue
Block a user