Attempt to make good
This commit is contained in:
@@ -152,7 +152,7 @@ public class PersonalMotionPreviewElement extends View {
|
||||
);
|
||||
|
||||
timePassed = (System.nanoTime() - startingTime) / 1E9D;
|
||||
this.exerciseProgress = timePassed*.4 % 1.0d;
|
||||
this.exerciseProgress = Math.min(1, this.motionProcessor.getAverageError() / 10);
|
||||
|
||||
this.invalidate(); // Causes a redraw.
|
||||
}
|
||||
|
@@ -2,11 +2,11 @@ package com.example.fitbot.util.processing;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.aldebaran.qi.sdk.QiContext;
|
||||
import com.example.fitbot.util.FitnessCycle;
|
||||
import com.example.fitbot.util.path.GesturePath;
|
||||
import com.example.fitbot.util.server.IWebServerHandler;
|
||||
import com.example.fitbot.util.server.WebServer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.joml.Vector3f;
|
||||
@@ -20,11 +20,16 @@ public class MotionProcessor {
|
||||
public static final String DELIMITER = ";";
|
||||
|
||||
private final List<MotionData> preprocessedData = new ArrayList<>(); // Preprocessed motion data
|
||||
private final List<Vector3f> relativePath = new ArrayList<>(); // Relative path of the motion data
|
||||
|
||||
private final List<Vector3f> relativeLeftPath = new ArrayList<>(); // Relative path of the left motion data
|
||||
private final List<Vector3f> relativeRightPath = new ArrayList<>(); // Relative path of the motion data
|
||||
|
||||
private Vector3f ZERO = new Vector3f(0, 0, 0);
|
||||
|
||||
private float sampleRate = 1.0F; // samples/second
|
||||
private IMotionDataConsumer motionDataConsumer = (p1, p2, p3, p4, p5) -> {};
|
||||
private final float sampleRate = 10.0F; // samples/second
|
||||
|
||||
private IMotionDataConsumer motionDataConsumer = (p1, p2, p3, p4, p5) -> {
|
||||
};
|
||||
private GesturePath path;
|
||||
private WebServer server;
|
||||
|
||||
@@ -65,30 +70,51 @@ public class MotionProcessor {
|
||||
|
||||
/**
|
||||
* Function for parsing arbitrary packet data.
|
||||
*
|
||||
* @param data The data to parse.
|
||||
*/
|
||||
public void parsePacket(@NotNull String data) {
|
||||
|
||||
// If the message starts with 'data', it's a data packet.
|
||||
if ( data.startsWith("data")) {
|
||||
Log.i("MotionProcessor", "Received data packet: " + data.split(" ")[1]);
|
||||
MotionData parsedData = MotionData.decode(data.split(" ")[1]);
|
||||
if (parsedData != null) {
|
||||
addMotionData(parsedData);
|
||||
try {
|
||||
JsonElement json = JsonParser.parseString(data);
|
||||
|
||||
if (!json.isJsonObject())
|
||||
return;
|
||||
|
||||
JsonObject object = json.getAsJsonObject();
|
||||
|
||||
// Object must contain device identifier
|
||||
if (!object.has("deviceId"))
|
||||
return;
|
||||
|
||||
String[] required = {
|
||||
"rotationX", "rotationY", "rotationZ",
|
||||
"accelerationX", "accelerationY", "accelerationZ",
|
||||
"type",
|
||||
"deviceId"
|
||||
};
|
||||
|
||||
// Ensure all properties are present in the received JSON object
|
||||
for (String s : required) {
|
||||
if (!object.has(s))
|
||||
return;
|
||||
}
|
||||
// Otherwise check if it starts with 'calibrate', this is the ZERO point.
|
||||
} else if ( data.startsWith("zero")) { // message to calibrate device
|
||||
String[] vectorData = data.split(" ")[1].split(DELIMITER);
|
||||
ZERO = new Vector3f(
|
||||
Float.parseFloat(vectorData[0]),
|
||||
Float.parseFloat(vectorData[1]),
|
||||
Float.parseFloat(vectorData[2])
|
||||
);
|
||||
Log.i("MotionProcessor", "Device calibrated at " + ZERO);
|
||||
} else if ( data.startsWith("sampleRate")) {
|
||||
this.sampleRate = Float.parseFloat(data.split(" ")[1]);
|
||||
} else {
|
||||
Log.i("MotionProcessor", "Received unknown packet: " + data);
|
||||
|
||||
// Parse the data
|
||||
Vector3f rotation = new Vector3f(object.get("rotationX").getAsFloat(), object.get("rotationY").getAsFloat(), object.get("rotationZ").getAsFloat());
|
||||
Vector3f acceleration = new Vector3f(object.get("accelerationX").getAsFloat(), object.get("accelerationY").getAsFloat(), object.get("accelerationZ").getAsFloat());
|
||||
int deviceId = object.get("deviceId").getAsInt();
|
||||
String type = object.get("type").getAsString();
|
||||
MotionData motionData = new MotionData(rotation, acceleration, deviceId);
|
||||
|
||||
if (type.equals("calibrate")) {
|
||||
ZERO = getRelativeVector(motionData);
|
||||
return;
|
||||
}
|
||||
|
||||
addMotionData(motionData);
|
||||
} catch (Exception e) {
|
||||
// Don't do anything ... just ignore the exception
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,24 +134,31 @@ public class MotionProcessor {
|
||||
*/
|
||||
public void addMotionData(MotionData data) {
|
||||
preprocessedData.add(data);
|
||||
Vector3f previous = this.relativePath.isEmpty() ? ZERO : this.relativePath.get(this.relativePath.size() - 1);
|
||||
List<Vector3f> target;
|
||||
if (data.sensorId == 0)
|
||||
target = relativeLeftPath;
|
||||
else target = relativeRightPath;
|
||||
Vector3f previous = target.isEmpty() ? ZERO : target.get(target.size() - 1);
|
||||
Vector3f relativeVector = getRelativeVector(data).add(previous);
|
||||
this.relativePath.add(relativeVector);
|
||||
motionDataConsumer.accept(relativeVector, data, this.relativePath.size(), this.sampleRate, data.sensorId);
|
||||
target.add(relativeVector);
|
||||
motionDataConsumer.accept(relativeVector, data, target.size(), this.sampleRate, data.sensorId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for updating the relative path.
|
||||
*
|
||||
* @param relativePath The new relative path.
|
||||
* @param relativeRightPath The new relative path.
|
||||
*/
|
||||
public void setRelativePath(List<Vector3f> relativePath) {
|
||||
this.relativePath.clear();
|
||||
this.relativePath.addAll(relativePath);
|
||||
public void setRelativeRightPath(List<Vector3f> relativeLeftPath, List<Vector3f> relativeRightPath) {
|
||||
this.relativeRightPath.clear();
|
||||
this.relativeLeftPath.clear();
|
||||
this.relativeLeftPath.addAll(relativeLeftPath);
|
||||
this.relativeRightPath.addAll(relativeRightPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for setting the motion data receiver.
|
||||
*
|
||||
* @param consumer The consumer to set.
|
||||
*/
|
||||
public void setMotionDataEventHandler(IMotionDataConsumer consumer) {
|
||||
@@ -164,11 +197,11 @@ public class MotionProcessor {
|
||||
*/
|
||||
public List<Double> getErrors(GesturePath referencePath) {
|
||||
|
||||
// Return the errors of the relative path compared to the reference path.
|
||||
return relativePath
|
||||
.stream()
|
||||
.map(referencePath::getError)
|
||||
.collect(Collectors.toList());
|
||||
List<Double> errors = new ArrayList<>();
|
||||
for (Vector3f vector : relativeRightPath) {
|
||||
errors.add(referencePath.getError(vector));
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,8 +224,7 @@ public class MotionProcessor {
|
||||
* @param referencePoint The reference point to compare the motion data to.
|
||||
* @return The error of the motion data compared to the reference path.
|
||||
*/
|
||||
public double getError(GesturePath path, Vector3f referencePoint)
|
||||
{
|
||||
public double getError(GesturePath path, Vector3f referencePoint) {
|
||||
return path.getError(referencePoint);
|
||||
}
|
||||
|
||||
@@ -217,11 +249,11 @@ public class MotionProcessor {
|
||||
* @return The average error of the motion data compared to the reference path.
|
||||
*/
|
||||
public double getAverageError(GesturePath referencePath) {
|
||||
return getErrors(referencePath)
|
||||
.stream()
|
||||
.mapToDouble(Double::doubleValue)
|
||||
.average()
|
||||
.orElse(0.0D);
|
||||
double error = 0;
|
||||
for (Double e : getErrors(referencePath)) {
|
||||
error += e;
|
||||
}
|
||||
return error / Math.max(1, relativeRightPath.size());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,7 +275,7 @@ public class MotionProcessor {
|
||||
*/
|
||||
public void logStatistics(GesturePath referencePath) {
|
||||
Log.i("MotionProcessor", "Average path error: " + getAverageError(referencePath));
|
||||
Log.i("MotionProcessor", "Path length: " + relativePath.size());
|
||||
Log.i("MotionProcessor", "Path length: " + relativeRightPath.size());
|
||||
Log.i("MotionProcessor", "Sample rate: " + sampleRate);
|
||||
Log.i("MotionProcessor", "Calibration point: " + ZERO.toString());
|
||||
}
|
||||
|
Reference in New Issue
Block a user