Better tap detection (#778)

This commit is contained in:
Collin
2023-07-20 01:06:48 -07:00
committed by GitHub
parent b6a681b1bb
commit e18bd2d382
9 changed files with 98 additions and 40 deletions

View File

@@ -23,7 +23,7 @@ jobs:
with:
submodules: recursive
- name: Get tags
run: git fetch --tags origin
run: git fetch --tags origin --recurse-submodules=no
- name: Set up JDK 17
uses: actions/setup-java@v3
@@ -52,7 +52,7 @@ jobs:
with:
submodules: recursive
- name: Get tags
run: git fetch --tags origin
run: git fetch --tags origin --recurse-submodules=no
- name: Set up JDK 17
uses: actions/setup-java@v3

View File

@@ -339,13 +339,19 @@ settings-general-fk_settings-vive_emulation-label = Enable Vive emulation
## Gesture control settings (tracker tapping)
settings-general-gesture_control = Gesture control
settings-general-gesture_control-subtitle = Tap based resets
settings-general-gesture_control-description = Allows for resets to be triggered by tapping a tracker. The tracker highest up on your torso is used for Yaw Reset, the tracker highest up on your left leg is used for Full Reset, and the tracker highest up on your right leg is used for Mounting Reset. It should be mentioned that taps must happen within 0.6 seconds to be registered.
settings-general-gesture_control-description = Allows for resets to be triggered by tapping a tracker. The tracker highest up on your torso is used for Yaw Reset, the tracker highest up on your left leg is used for Full Reset, and the tracker highest up on your right leg is used for Mounting Reset. Taps must occur within the time limit of 0.3 seconds times the number of taps to be recognized.
# This is a unit: 3 taps, 2 taps, 1 tap
# $amount (Number) - Amount of taps (touches to the tracker's case)
settings-general-gesture_control-taps = { $amount ->
[one] 1 tap
*[other] { $amount } taps
}
# This is a unit: 3 trackers, 2 trackers, 1 tracker
# $amount (Number) - Amount of trackers
settings-general-gesture_control-trackers = { $amount ->
[one] 1 tracker
*[other] { $amount } trackers
}
settings-general-gesture_control-yawResetEnabled = Enable tap to yaw reset
settings-general-gesture_control-yawResetDelay = Yaw reset delay
settings-general-gesture_control-yawResetTaps = Taps for yaw reset
@@ -355,6 +361,9 @@ settings-general-gesture_control-fullResetTaps = Taps for full reset
settings-general-gesture_control-mountingResetEnabled = Enable tap to reset mounting
settings-general-gesture_control-mountingResetDelay = Mounting reset delay
settings-general-gesture_control-mountingResetTaps = Taps for mounting reset
# The number of trackers that can have higher acceleration before a tap is rejected
settings-general-gesture_control-numberTrackersOverThreshold = Trackers over threshold
settings-general-gesture_control-numberTrackersOverThreshold-description = Increase this value if tap detection is not working. Do not increase it above what is needed to make tap detection work this will cause false positives
## Interface settings
settings-general-interface = Interface

View File

@@ -72,6 +72,7 @@ interface SettingsForm {
yawResetTaps: number;
fullResetTaps: number;
mountingResetTaps: number;
numberTrackersOverThreshold;
};
legTweaks: {
correctionStrength: number;
@@ -122,6 +123,7 @@ const defaultValues = {
yawResetTaps: 2,
fullResetTaps: 3,
mountingResetTaps: 3,
numberTrackersOverThreshold: 1,
},
legTweaks: { correctionStrength: 0.3 },
interface: {
@@ -195,6 +197,8 @@ export function GeneralSettings() {
values.tapDetection.mountingResetEnabled;
tapDetection.mountingResetDelay = values.tapDetection.mountingResetDelay;
tapDetection.mountingResetTaps = values.tapDetection.mountingResetTaps;
tapDetection.numberTrackersOverThreshold =
values.tapDetection.numberTrackersOverThreshold;
tapDetection.setupMode = false;
settings.tapDetectionSettings = tapDetection;
@@ -294,6 +298,9 @@ export function GeneralSettings() {
mountingResetTaps:
settings.tapDetectionSettings.mountingResetTaps ||
defaultValues.tapDetection.mountingResetTaps,
numberTrackersOverThreshold:
settings.tapDetectionSettings.numberTrackersOverThreshold ||
defaultValues.tapDetection.numberTrackersOverThreshold,
};
}
@@ -869,6 +876,35 @@ export function GeneralSettings() {
step={1}
/>
</div>
{config?.debug && (
<div className="grid sm:grid-cols-1 gap-2 pt-2">
<Typography bold>
{l10n.getString(
'settings-general-gesture_control-numberTrackersOverThreshold'
)}
</Typography>
<Typography color="secondary">
{l10n.getString(
'settings-general-gesture_control-numberTrackersOverThreshold-description'
)}
</Typography>
<NumberSelector
control={control}
name="tapDetection.numberTrackersOverThreshold"
valueLabelFormat={(value) =>
l10n.getString(
'settings-general-gesture_control-trackers',
{
amount: Math.round(value),
}
)
}
min={1}
max={20}
step={1}
/>
</div>
)}
</>
</SettingsPagePaneLayout>

View File

@@ -142,7 +142,8 @@ public class RPCSettingsBuilder {
tapDetectionConfig.getMountingResetDelay(),
tapDetectionConfig.getMountingResetEnabled(),
tapDetectionConfig.getMountingResetTaps(),
tapDetectionConfig.getSetupMode()
tapDetectionConfig.getSetupMode(),
tapDetectionConfig.getNumberTrackersOverThreshold()
);
}

View File

@@ -220,6 +220,15 @@ public class RPCSettingsHandler {
.setMountingResetEnabled(tapDetectionSettings.mountingResetEnabled());
tapDetectionConfig.setSetupMode(tapDetectionSettings.setupMode());
// set number of trackers that can have high accel before taps
// are rejected
if (tapDetectionSettings.hasNumberTrackersOverThreshold()) {
tapDetectionConfig
.setNumberTrackersOverThreshold(
tapDetectionSettings.numberTrackersOverThreshold()
);
}
// set tap detection delays
if (tapDetectionSettings.hasYawResetDelay()) {
tapDetectionConfig.setYawResetDelay(tapDetectionSettings.yawResetDelay());

View File

@@ -510,6 +510,9 @@ public class HumanSkeleton {
// Rebuild the bone list
resetBones();
// Update tap detection's trackers
tapDetectionManager.updateConfig();
}
protected void setComputedTracker(Tracker tracker) {

View File

@@ -23,9 +23,9 @@ public class TapDetection {
// hyperparameters
private static final float NS_CONVERTER = 1.0e9f;
private static final float NEEDED_ACCEL_DELTA = 6.0f;
private static final float ALLOWED_BODY_ACCEL = 1.5f;
private static final float ALLOWED_BODY_ACCEL = 2.5f;
private static final float ALLOWED_BODY_ACCEL_SQUARED = ALLOWED_BODY_ACCEL * ALLOWED_BODY_ACCEL;
private static final float CLUMP_TIME_NS = 0.08f * NS_CONVERTER;
private static final float CLUMP_TIME_NS = 0.06f * NS_CONVERTER;
private float timeWindowNS = 0.6f * NS_CONVERTER;
// state
@@ -114,8 +114,9 @@ public class TapDetection {
}
// if waiting for low accel
if (accelDelta < ALLOWED_BODY_ACCEL)
if (getMaxAccel() < ALLOWED_BODY_ACCEL) {
waitForLowAccel = false;
}
// remove old taps from the list (if they are too old)
if (!tapTimes.isEmpty()) {
@@ -134,12 +135,15 @@ public class TapDetection {
// get the amount of taps in the list
// and set the detection time
int newTaps = getTapEvents();
int newTaps = tapTimes.size();
if (newTaps > taps) {
taps = newTaps;
detectionTime = time;
}
if (time - detectionTime > timeWindowNS) {
tapTimes.clear();
}
}
private float getAccelDelta() {
@@ -154,20 +158,14 @@ public class TapDetection {
return max - min;
}
// return the number of distinct tap events in tapTimes
private int getTapEvents() {
if (tapTimes.isEmpty())
return 0;
int tapEvents = 1;
float lastTapTime = tapTimes.getFirst();
for (Float tapTime : tapTimes) {
if (tapTime - lastTapTime > CLUMP_TIME_NS) {
tapEvents++;
lastTapTime = tapTime;
private float getMaxAccel() {
float max = 0.0f;
for (float[] val : accelList) {
if (val[0] > max) {
max = val[0];
}
}
return tapEvents;
return max;
}
// returns true if the user is not imparting more than allowedBodyAccel of

View File

@@ -68,10 +68,6 @@ public class TapDetectionManager {
this.resetHandler = resetHandler;
this.tapSetupHandler = tapSetupHandler;
yawResetDetector = new TapDetection(skeleton, getTrackerToWatchYawReset());
fullResetDetector = new TapDetection(skeleton, getTrackerToWatchFullReset());
mountingResetDetector = new TapDetection(skeleton, getTrackerToWatchMountingReset());
// a list of tap detectors for each tracker
tapDetectors = new ArrayList<>();
for (Tracker tracker : trackers) {
@@ -80,25 +76,19 @@ public class TapDetectionManager {
tapDetectors.add(tapDetector);
}
// since this config value is only modified by editing the config file,
// we can set it here
yawResetDetector
.setNumberTrackersOverThreshold(
config.getNumberTrackersOverThreshold()
);
fullResetDetector
.setNumberTrackersOverThreshold(
config.getNumberTrackersOverThreshold()
);
mountingResetDetector
.setNumberTrackersOverThreshold(
config.getNumberTrackersOverThreshold()
);
updateConfig();
}
public void updateConfig() {
// check the skeleton for new trackers
yawResetDetector = new TapDetection(skeleton, getTrackerToWatchYawReset());
fullResetDetector = new TapDetection(skeleton, getTrackerToWatchFullReset());
mountingResetDetector = new TapDetection(skeleton, getTrackerToWatchMountingReset());
if (this.config == null) {
return;
}
this.yawResetDelayNs = config.getYawResetDelay() * NS_CONVERTER;
this.fullResetDelayNs = config.getFullResetDelay() * NS_CONVERTER;
this.mountingResetDelayNs = config.getMountingResetDelay() * NS_CONVERTER;
@@ -111,6 +101,18 @@ public class TapDetectionManager {
yawResetDetector.setMaxTaps(yawResetTaps);
fullResetDetector.setMaxTaps(fullResetTaps);
mountingResetDetector.setMaxTaps(mountingResetTaps);
yawResetDetector
.setNumberTrackersOverThreshold(
config.getNumberTrackersOverThreshold()
);
fullResetDetector
.setNumberTrackersOverThreshold(
config.getNumberTrackersOverThreshold()
);
mountingResetDetector
.setNumberTrackersOverThreshold(
config.getNumberTrackersOverThreshold()
);
}
public void update() {