Compare commits
6 Commits
51-als-geb
...
35-als-geb
Author | SHA1 | Date | |
---|---|---|---|
|
13fca50d6f | ||
|
7442d1fca4 | ||
|
cfcbe7d51c | ||
|
3edab82535 | ||
|
3fe90ce547 | ||
|
59c374eb02 |
@@ -1,6 +1,6 @@
|
||||
#include "headerFile.h"
|
||||
|
||||
// SensorManager::Rotation offset;
|
||||
SensorManager::Rotation offset;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
@@ -10,49 +10,51 @@ void setup() {
|
||||
sensorManager.sensorSetup();
|
||||
|
||||
//ws server address, port and URL
|
||||
webSocket.begin("145.28.160.108", 8001, "");
|
||||
webSocket.begin("145.3.245.22", 8001, "");
|
||||
// try every 500 again if connection has failed
|
||||
webSocket.setReconnectInterval(500);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
SensorManager::eulerAngles eulerRotation = sensorManager.getEulerAngles();
|
||||
SensorManager::Rotation rotation = sensorManager.readLoop();
|
||||
|
||||
// Subtract offset
|
||||
// rotation.i -= offset.i;
|
||||
// rotation.j -= offset.j;
|
||||
// rotation.k -= offset.k;
|
||||
// rotation.w -= offset.w;
|
||||
rotation.i -= offset.i;
|
||||
rotation.j -= offset.j;
|
||||
rotation.k -= offset.k;
|
||||
rotation.w -= offset.w;
|
||||
|
||||
// Convert quaternion to Euler angles in radians
|
||||
|
||||
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));
|
||||
|
||||
// Convert to degrees
|
||||
// float rollDegrees = roll * 180.0f / PI;
|
||||
// float pitchDegrees = pitch * 180.0f / PI;
|
||||
// float yawDegrees = yaw * 180.0f / PI;
|
||||
float rollDegrees = roll * 180.0f / PI;
|
||||
float pitchDegrees = pitch * 180.0f / PI;
|
||||
float yawDegrees = yaw * 180.0f / PI;
|
||||
|
||||
Serial.print(eulerRotation.roll);
|
||||
Serial.print(roll);
|
||||
Serial.print(" ");
|
||||
Serial.print(eulerRotation.pitch);
|
||||
Serial.print(pitch);
|
||||
Serial.print(" ");
|
||||
Serial.print(eulerRotation.yaw);
|
||||
sendData(eulerRotation.roll, eulerRotation.pitch, eulerRotation.yaw);
|
||||
Serial.print(yaw);
|
||||
sendData(roll, pitch, yaw);
|
||||
|
||||
Serial.println();
|
||||
webSocket.loop();
|
||||
|
||||
if (Serial.available()) {
|
||||
String command = Serial.readStringUntil('\n');
|
||||
command.trim(); // remove any trailing whitespace
|
||||
if (command == "setZeroPoint") {
|
||||
setZeroPoint();
|
||||
}
|
||||
}
|
||||
}
|
||||
void setZeroPoint() {
|
||||
offset = sensorManager.readLoop();
|
||||
}
|
||||
// if (Serial.available()) {
|
||||
// String command = Serial.readStringUntil('\n');
|
||||
// command.trim(); // remove any trailing whitespace
|
||||
// if (command == "setZeroPoint") {
|
||||
// setZeroPoint();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// void setZeroPoint() {
|
||||
// offset = sensorManager.readLoop();
|
||||
// }
|
||||
|
||||
void sendData(float roll, float pitch, float yaw){
|
||||
String message = "{\"Sensor\": 1, \"roll\":\"" + String(roll) + "\",\"pitch\":\"" + String(pitch) + "\",\"yaw\":\"" + String(yaw) + "\"}";
|
||||
|
@@ -15,12 +15,12 @@ void SensorManager::sensorSetup() {
|
||||
//start sensorfunction and start autocalibration
|
||||
//once calibration is enabled it attempts to every 5 min
|
||||
|
||||
Wire.setClock(400000); //Increase I2C data rate to 400kHz
|
||||
myIMU.calibrateAll(); //Turn on cal for Accel, Gyro, and Mag
|
||||
myIMU.enableGyroIntegratedRotationVector(100); //send data every 100ms
|
||||
myIMU.enableMagnetometer(100); //Send data update every 100ms
|
||||
myIMU.saveCalibration(); //Saves the current dynamic calibration data (DCD) to memory
|
||||
myIMU.requestCalibrationStatus(); //Sends command to get the latest calibration status
|
||||
Wire.setClock(400000); //Increase I2C data rate to 400kHz
|
||||
myIMU.calibrateAll(); //Turn on cal for Accel, Gyro, and Mag
|
||||
myIMU.enableGyroIntegratedRotationVector(100); //send data every 100ms
|
||||
myIMU.enableMagnetometer(100); //Send data update every 100ms
|
||||
myIMU.saveCalibration(); //Saves the current dynamic calibration data (DCD) to memory
|
||||
myIMU.requestCalibrationStatus(); //Sends command to get the latest calibration status
|
||||
|
||||
if (myIMU.calibrationComplete() == true) {
|
||||
Serial.println("Calibration data successfully stored");
|
||||
@@ -29,31 +29,23 @@ void SensorManager::sensorSetup() {
|
||||
Serial.println(F("magnetometer rotation enabled"));
|
||||
}
|
||||
|
||||
SensorManager::RotationQuintillions SensorManager::getQuintillions() {
|
||||
SensorManager::Rotation SensorManager::readLoop() {
|
||||
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 };
|
||||
Rotation rotation = { i, j, k, w };
|
||||
return rotation;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
float i = myIMU.getQuatI();
|
||||
float j = myIMU.getQuatJ();
|
||||
float k = myIMU.getQuatK();
|
||||
float w = myIMU.getQuatReal();
|
||||
|
||||
RotationQuintillions rotation = { i, j, k, w };
|
||||
Rotation rotation = { i, j, k, w };
|
||||
return rotation;
|
||||
}
|
||||
}
|
||||
|
||||
SensorManager::eulerAngles SensorManager::getEulerAngles() {
|
||||
SensorManager::RotationQuintillions rotation = getQuintillions();
|
||||
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));
|
||||
eulerAngles EulerAngles = { roll, pitch, yaw };
|
||||
return EulerAngles;
|
||||
}
|
@@ -5,26 +5,18 @@
|
||||
#include "SparkFun_BNO080_Arduino_Library.h"
|
||||
|
||||
class SensorManager {
|
||||
public:
|
||||
SensorManager();
|
||||
void sensorSetup();
|
||||
struct eulerAngles {
|
||||
float roll;
|
||||
float pitch;
|
||||
float yaw;
|
||||
};
|
||||
eulerAngles getEulerAngles();
|
||||
|
||||
|
||||
private:
|
||||
struct RotationQuintillions {
|
||||
float i;
|
||||
float j;
|
||||
float k;
|
||||
float w;
|
||||
};
|
||||
RotationQuintillions getQuintillions();
|
||||
BNO080 myIMU;
|
||||
public:
|
||||
SensorManager();
|
||||
void sensorSetup();
|
||||
struct Rotation {
|
||||
float i;
|
||||
float j;
|
||||
float k;
|
||||
float w;
|
||||
};
|
||||
Rotation readLoop();
|
||||
private:
|
||||
BNO080 myIMU;
|
||||
};
|
||||
|
||||
#endif
|
3
code/src/.idea/.gitignore
generated
vendored
3
code/src/.idea/.gitignore
generated
vendored
@@ -1,3 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
2
code/src/Fitbot/.gitignore
vendored
2
code/src/Fitbot/.gitignore
vendored
@@ -13,3 +13,5 @@
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
.idea
|
||||
.vscode
|
1
code/src/Fitbot/.idea/gradle.xml
generated
1
code/src/Fitbot/.idea/gradle.xml
generated
@@ -7,7 +7,6 @@
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="jbr-17" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
|
@@ -7,7 +7,7 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.example.fitbot"
|
||||
minSdk 23
|
||||
minSdk 29
|
||||
targetSdk 29
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
@@ -35,7 +35,11 @@ dependencies {
|
||||
implementation 'com.android.support:cardview-v7:28.0.0'
|
||||
implementation 'com.android.support:design:28.0.0'
|
||||
implementation 'org.joml:joml:1.10.5'
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
implementation 'com.aldebaran:qisdk:1.7.5'
|
||||
|
@@ -15,6 +15,9 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Fitbot" >
|
||||
<activity
|
||||
android:name=".ui.activities.FitnessActivity"
|
||||
android:exported="true" />
|
||||
<activity
|
||||
android:name=".ui.activities.MainActivity"
|
||||
android:exported="true" >
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package com.example.fitbot.sports;
|
||||
package com.example.fitbot;
|
||||
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
@@ -7,7 +7,6 @@ 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 com.example.fitbot.ui.activities.MainActivity;
|
||||
|
||||
public class Animations extends AppCompatActivity {
|
||||
|
@@ -0,0 +1,104 @@
|
||||
package com.example.fitbot.exercise;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.example.fitbot.util.path.GesturePath;
|
||||
import com.example.fitbot.util.server.IWebSocketHandler;
|
||||
import com.example.fitbot.util.server.WebSocket;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class AbstractExercise implements IWebSocketHandler {
|
||||
|
||||
private EMuscleGroup muscleGroup;
|
||||
private GesturePath path;
|
||||
|
||||
// Static fields.
|
||||
private static WebSocket webSocket;
|
||||
private static AbstractExercise currentExercise = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for the AbstractExercise class.
|
||||
*
|
||||
* @param muscleGroup The muscle group of the exercise.
|
||||
* @param path The path of the exercise.
|
||||
*/
|
||||
public AbstractExercise(EMuscleGroup muscleGroup, GesturePath path) {
|
||||
this.muscleGroup = muscleGroup;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the exercise.
|
||||
* This method starts a WebSocket server
|
||||
*/
|
||||
public final void startExercise() {
|
||||
|
||||
// Ensure no other exercise is active.
|
||||
if (currentExercise != null && currentExercise != this) {
|
||||
currentExercise.__stopExercise();
|
||||
Log.i("Exercises", "Another exercise was started when another was still running.");
|
||||
}
|
||||
|
||||
// If a WebSocket server is already running, change the event handler to be this class.
|
||||
if (webSocket != null && webSocket.isConnected()) {
|
||||
webSocket.setEventHandler(this);
|
||||
}
|
||||
|
||||
try {
|
||||
webSocket = WebSocket.createServer();
|
||||
Objects.requireNonNull(webSocket, "WebSocket server could not be created.");
|
||||
|
||||
webSocket.startListening();
|
||||
webSocket.setEventHandler(this);
|
||||
currentExercise = this;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for ending this exercise and returning the grade of the performance
|
||||
* of this activity.
|
||||
*/
|
||||
public final double finishExercise() {
|
||||
this.__stopExercise();
|
||||
|
||||
// TODO: Implement grade calculation
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the exercise.
|
||||
* This method stops the WebSocket server.
|
||||
*/
|
||||
private void __stopExercise() {
|
||||
if (webSocket != null && webSocket.isConnected()) {
|
||||
webSocket.stop();
|
||||
webSocket = null;
|
||||
}
|
||||
currentExercise = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current exercise is the current activity.
|
||||
*/
|
||||
public final boolean isCurrentActivity() {
|
||||
return currentExercise == this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the muscle group of the exercise.
|
||||
*/
|
||||
public EMuscleGroup getMuscleGroup() {
|
||||
return muscleGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path of the exercise.
|
||||
*/
|
||||
public GesturePath getPath() {
|
||||
return path;
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
package com.example.fitbot.exercise;
|
||||
|
||||
public enum EMuscleGroup {
|
||||
// TODO: Implement
|
||||
|
||||
TORSO(0),
|
||||
ARMS(1),
|
||||
LEGS(2),
|
||||
BALANCE(3);
|
||||
|
||||
int muscleGroupIdentifier;
|
||||
|
||||
EMuscleGroup(int identifier) {
|
||||
this.muscleGroupIdentifier = identifier;
|
||||
}
|
||||
|
||||
public int getIdentifier() {
|
||||
return this.muscleGroupIdentifier;
|
||||
}
|
||||
|
||||
public static EMuscleGroup parse(int identifier) {
|
||||
for (EMuscleGroup muscleGroup : EMuscleGroup.values()) {
|
||||
if (muscleGroup.getIdentifier() == identifier) {
|
||||
return muscleGroup;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
package com.example.fitbot.exercise;
|
||||
|
||||
|
||||
/**
|
||||
* The ExerciseUser class represents a user of the exercise application.
|
||||
* This contains all necessary information of the current user.
|
||||
*/
|
||||
public class ExerciseUser {
|
||||
|
||||
public float upperArmLength;
|
||||
public float lowerArmLength;
|
||||
public float upperLegLength;
|
||||
public float lowerLegLength;
|
||||
public float height;
|
||||
|
||||
/**
|
||||
* Constructor for the ExerciseUser class.
|
||||
* @param upperArmLength The length of the upper arm.
|
||||
* @param lowerArmLength The length of the lower arm.
|
||||
* @param height The height of the user.
|
||||
* @param upperLegLength The length of the upper leg.
|
||||
* @param lowerLegLength The length of the lower leg.
|
||||
*/
|
||||
public ExerciseUser(float upperArmLength, float lowerArmLength, float height, float upperLegLength, float lowerLegLength) {
|
||||
this.upperArmLength = upperArmLength;
|
||||
this.lowerArmLength = lowerArmLength;
|
||||
this.upperLegLength = upperLegLength;
|
||||
this.lowerLegLength = lowerLegLength;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for the ExerciseUser class.
|
||||
* @param height The height of the user.
|
||||
*/
|
||||
public ExerciseUser(float height) {
|
||||
this.height = height;
|
||||
this.upperArmLength = height * 0.2f;
|
||||
this.lowerArmLength = height * 0.2f;
|
||||
this.upperLegLength = height * 0.3f;
|
||||
this.lowerLegLength = height * 0.3f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor for the ExerciseUser class.
|
||||
* This sets the default height to 180.0f. (1.80m)
|
||||
*/
|
||||
public ExerciseUser() {
|
||||
this(180.0f);
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,113 @@
|
||||
package com.example.fitbot.exercise;
|
||||
|
||||
import com.example.fitbot.util.path.GesturePath;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
public class FitnessManager {
|
||||
|
||||
private static final String HOST_ADDRESS = "http://145.92.8.132";
|
||||
|
||||
private static final String PROPERTY_DESC = "description";
|
||||
private static final String PROPERTY_VECTORS = "vector_data";
|
||||
private static final String PROPERTY_NAME = "name";
|
||||
private static final String PROPERTY_MUSCLE_GROUP = "muscle_group";
|
||||
|
||||
private static String sendHTTP(String url, String method, String contentType, String body) {
|
||||
try {
|
||||
URLConnection connection = new URL(url).openConnection();
|
||||
connection.addRequestProperty("Content-Type", contentType);
|
||||
connection.addRequestProperty("Request-Method", method);
|
||||
connection.getOutputStream().write(body.getBytes());
|
||||
connection.connect();
|
||||
InputStream stream = connection.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
return builder.toString();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for retrieving an exercise from the Raspberry Pi Database.
|
||||
*
|
||||
* @param uniqueIdentifier The unique identifier of the exercise
|
||||
* @return The exercise, if it exists on the server. Otherwise null.
|
||||
*/
|
||||
public static <T extends AbstractExercise> AbstractExercise acquireExercise(String uniqueIdentifier, Class<T> referenceClass) {
|
||||
String response = sendHTTP(
|
||||
HOST_ADDRESS + "/acquire", "GET", "application/json", "{\"kind\":\"" + uniqueIdentifier + "\"}"
|
||||
);
|
||||
// Validate the response
|
||||
if (response != null) {
|
||||
try {
|
||||
JsonObject content = JsonParser.parseString(response).getAsJsonObject();
|
||||
Constructor<T> constructor = referenceClass.getConstructor(referenceClass);
|
||||
T instance = null;
|
||||
try {
|
||||
instance = constructor.newInstance(
|
||||
EMuscleGroup.parse(content.get(PROPERTY_MUSCLE_GROUP).getAsInt()),
|
||||
gesturePathFromString(content.get(PROPERTY_VECTORS).getAsString())
|
||||
);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return instance;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for converting a string to a GesturePath object.
|
||||
* The input string bytes will be directly converted into 3d vectors.
|
||||
* Every coordinate is composed of 32 bits, so four characters per coordinate.
|
||||
*
|
||||
* @param input The string to convert
|
||||
* @return The GesturePath object
|
||||
*/
|
||||
private static GesturePath gesturePathFromString(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");
|
||||
}
|
||||
GesturePath.Builder builder = new GesturePath.Builder();
|
||||
|
||||
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)
|
||||
);
|
||||
}
|
||||
builder.addVector(new Vector3f(
|
||||
xyz[0], xyz[1], xyz[2]
|
||||
));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
package com.example.fitbot.sports;
|
||||
|
||||
public enum ESportType {
|
||||
|
||||
FITNESS("Fitness"),
|
||||
POWER("Krachttrening");
|
||||
|
||||
private final String name;
|
||||
|
||||
ESportType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
@@ -1,28 +1,20 @@
|
||||
package com.example.fitbot.ui.activities;
|
||||
|
||||
import static com.example.fitbot.sports.Animations.Animate;
|
||||
|
||||
import android.os.Bundle;
|
||||
import com.aldebaran.qi.sdk.QiContext;
|
||||
import com.aldebaran.qi.sdk.QiSDK;
|
||||
import com.aldebaran.qi.sdk.RobotLifecycleCallbacks;
|
||||
import com.aldebaran.qi.sdk.design.activity.RobotActivity;
|
||||
import com.example.fitbot.sports.Animations;
|
||||
|
||||
public class FitnessActivity extends RobotActivity implements RobotLifecycleCallbacks {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
QiSDK.register(this, this);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRobotFocusGained(QiContext qiContext) {
|
||||
// Implement your logic when the robot focus is gained
|
||||
Animate("bicepcurl", qiContext);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -34,11 +26,4 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall
|
||||
public void onRobotFocusRefused(String reason) {
|
||||
// Implement your logic when the robot focus is refused
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
QiSDK.unregister(this, this);
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,7 @@
|
||||
package com.example.fitbot.ui.activities;
|
||||
|
||||
import static com.example.fitbot.sports.Animations.Animate;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.NavigationView;
|
||||
import android.support.v4.view.GravityCompat;
|
||||
@@ -10,10 +9,9 @@ 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.widget.Button;
|
||||
|
||||
import com.aldebaran.qi.sdk.QiContext;
|
||||
import com.aldebaran.qi.sdk.QiSDK;
|
||||
import com.aldebaran.qi.sdk.RobotLifecycleCallbacks;
|
||||
import com.example.fitbot.R;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
@@ -22,18 +20,26 @@ public class MainActivity extends AppCompatActivity {
|
||||
DrawerLayout drawerLayout;
|
||||
NavigationView navigationView;
|
||||
Toolbar toolbar;
|
||||
Button startButton;
|
||||
|
||||
@SuppressLint("WrongViewCast")
|
||||
@Override
|
||||
protected void onCreate (Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
QiSDK.register(this, (RobotLifecycleCallbacks) this);
|
||||
setContentView(R.layout.activity_main );
|
||||
|
||||
/*---Hooks---*/
|
||||
drawerLayout = findViewById(R.id.drawer_layout);
|
||||
navigationView = findViewById(R.id.nav_view);
|
||||
toolbar = findViewById(R.id.toolbar);
|
||||
startButton = findViewById(R.id.startButton);
|
||||
|
||||
startButton.setOnClickListener(v -> {
|
||||
// Switch to fitness activity
|
||||
Log.i("MainActivity", "Switching to FitnessActivity");
|
||||
Intent intent = new Intent(MainActivity.this, FitnessActivity.class);
|
||||
startActivity(intent);
|
||||
});
|
||||
|
||||
/*---Tool Bar---*/
|
||||
// setSupportActionBar(toolbar);
|
||||
|
@@ -4,6 +4,7 @@ import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.example.fitbot.util.path.GesturePath;
|
||||
@@ -24,6 +25,8 @@ public class PersonalMotionPreviewElement extends View {
|
||||
private Path referencePath, performingPath;
|
||||
private Paint referencePaint, performingPaint;
|
||||
|
||||
private Paint backgroundColor = new Paint();
|
||||
|
||||
/**
|
||||
* Constants for the preview path projection.
|
||||
*/
|
||||
@@ -42,6 +45,9 @@ public class PersonalMotionPreviewElement extends View {
|
||||
*/
|
||||
public PersonalMotionPreviewElement(Context context, GesturePath path) {
|
||||
super(context);
|
||||
Log.i("PersonalMotionPreviewElement", "Creating new PersonalMotionPreviewElement.");
|
||||
this.backgroundColor = new Paint();
|
||||
this.backgroundColor.setColor(0xFF000000); // Black
|
||||
this.path = path;
|
||||
this.motionProcessor = new MotionProcessor();
|
||||
this.motionProcessor.startListening();
|
||||
@@ -158,6 +164,7 @@ public class PersonalMotionPreviewElement extends View {
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas canvas) {
|
||||
canvas.drawRect(0, 0, getWidth(), getHeight(), backgroundColor);
|
||||
// Draw the sport preview canvas
|
||||
canvas.drawPath(referencePath, referencePaint);
|
||||
canvas.drawPath(performingPath, performingPaint);
|
||||
|
@@ -10,7 +10,6 @@ public class GesturePath {
|
||||
|
||||
// The vectors that make up the path.
|
||||
private final PathSegment[] segments;
|
||||
private double curvature;
|
||||
|
||||
public GesturePath(Vector3f[] vectors) {
|
||||
this(vectors, 0.0D);
|
||||
@@ -27,7 +26,6 @@ public class GesturePath {
|
||||
if ( vectors.length < 2)
|
||||
throw new IllegalArgumentException("A path must have at least two points.");
|
||||
|
||||
this.curvature = curvature;
|
||||
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]);
|
||||
@@ -39,7 +37,6 @@ public class GesturePath {
|
||||
*/
|
||||
public GesturePath(PathSegment... segments) {
|
||||
this.segments = segments;
|
||||
this.curvature = 0.0d;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -25,10 +25,9 @@ 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 dst The destination vector to interpolate to.
|
||||
* @param t The interpolation value between 0 and 1.
|
||||
*/
|
||||
public Vector3f interpolate(Vector3f dst, double t) {
|
||||
public Vector3f interpolate(double t) {
|
||||
return new Vector3f(this.start)
|
||||
.lerp(this.end, (float) Math.min(1.0F, Math.max(0.0F, t)));
|
||||
}
|
||||
|
@@ -1,10 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
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="#232323"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".ui.activities.FitnessActivity"
|
||||
tools:openDrawer="start">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.example.fitbot.ui.components.PersonalMotionPreviewElement
|
||||
android:id="@+id/personalMotionPreviewElement"
|
||||
android:visibility="visible"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</android.support.v4.widget.DrawerLayout>
|
@@ -0,0 +1,37 @@
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -6,4 +6,4 @@ plugins {
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
}
|
@@ -3,11 +3,11 @@
|
||||
Which sensor are we gonna use for this project and why?
|
||||
|
||||
|
||||
### What do we want to measure?
|
||||
### What do we wanna measure?
|
||||
|
||||
We wanna measure the movement of the people doing our exercises. We want to know how many times they have done the exercise and how many times they have done it correctly.
|
||||
|
||||
### What sensor are we going to use?
|
||||
### What sensor are we gonna use?
|
||||
To measure these movements we are gonna use gyroscopes. With gyroscopes we can measure the rotation of the body. With some math we can also measure the speed of the rotation. So we know how fast the person is doing the exercise.
|
||||
|
||||
### Which gyroscopes are there?
|
||||
|
Reference in New Issue
Block a user