mirror of
https://github.com/SlimeVR/SlimeVR-Server.git
synced 2026-04-05 18:01:56 +02:00
Update Kotlin and gradle plugins (#957)
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
plugins {
|
||||
id("org.ajoberstar.grgit") version "5.2.0"
|
||||
id("org.ajoberstar.grgit")
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ android.useAndroidX=true
|
||||
android.nonTransitiveRClass=true
|
||||
org.gradle.unsafe.configuration-cache=false
|
||||
|
||||
kotlinVersion=1.9.0-RC
|
||||
spotlessVersion=6.12.0
|
||||
kotlinVersion=1.9.23
|
||||
spotlessVersion=6.25.0
|
||||
shadowJarVersion=8.1.1
|
||||
buildconfigVersion=3.1.0
|
||||
buildconfigVersion=5.3.5
|
||||
grgitVersion=5.2.2
|
||||
|
||||
@@ -84,36 +84,26 @@ dependencies {
|
||||
implementation("com.github.mik3y:usb-serial-for-android:3.7.0")
|
||||
}
|
||||
|
||||
/**
|
||||
* The android block is where you configure all your Android-specific
|
||||
* build options.
|
||||
*/
|
||||
|
||||
// The android block is where you configure all your Android-specific build options.
|
||||
extra.apply {
|
||||
set("gitVersionCode", grgit.tag.list().size)
|
||||
set("gitVersionName", grgit.describe(mapOf("tags" to true, "always" to true)))
|
||||
}
|
||||
android {
|
||||
/**
|
||||
* The app's namespace. Used primarily to access app resources.
|
||||
*/
|
||||
// The app's namespace. Used primarily to access app resources.
|
||||
|
||||
namespace = "dev.slimevr.android"
|
||||
|
||||
/**
|
||||
* compileSdk specifies the Android API level Gradle should use to
|
||||
* compile your app. This means your app can use the API features included in
|
||||
* this API level and lower.
|
||||
*/
|
||||
/* compileSdk specifies the Android API level Gradle should use to
|
||||
compile your app. This means your app can use the API features included in
|
||||
this API level and lower. */
|
||||
|
||||
compileSdk = 33
|
||||
|
||||
/**
|
||||
* The defaultConfig block encapsulates default settings and entries for all
|
||||
* build variants and can override some attributes in main/AndroidManifest.xml
|
||||
* dynamically from the build system. You can configure product flavors to override
|
||||
* these values for different versions of your app.
|
||||
*/
|
||||
/* The defaultConfig block encapsulates default settings and entries for all
|
||||
build variants and can override some attributes in main/AndroidManifest.xml
|
||||
dynamically from the build system. You can configure product flavors to override
|
||||
these values for different versions of your app. */
|
||||
|
||||
packaging {
|
||||
resources.excludes.add("META-INF/*")
|
||||
@@ -139,26 +129,22 @@ android {
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
/**
|
||||
* The buildTypes block is where you can configure multiple build types.
|
||||
* By default, the build system defines two build types: debug and release. The
|
||||
* debug build type is not explicitly shown in the default build configuration,
|
||||
* but it includes debugging tools and is signed with the debug key. The release
|
||||
* build type applies ProGuard settings and is not signed by default.
|
||||
*/
|
||||
/* The buildTypes block is where you can configure multiple build types.
|
||||
By default, the build system defines two build types: debug and release. The
|
||||
debug build type is not explicitly shown in the default build configuration,
|
||||
but it includes debugging tools and is signed with the debug key. The release
|
||||
build type applies ProGuard settings and is not signed by default. */
|
||||
|
||||
buildTypes {
|
||||
|
||||
/**
|
||||
* By default, Android Studio configures the release build type to enable code
|
||||
* shrinking, using minifyEnabled, and specifies the default ProGuard rules file.
|
||||
*/
|
||||
/* By default, Android Studio configures the release build type to enable code
|
||||
shrinking, using minifyEnabled, and specifies the default ProGuard rules file. */
|
||||
|
||||
getByName("release") {
|
||||
isMinifyEnabled = true // Enables code shrinking for the release build type.
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android.txt"),
|
||||
"proguard-rules.pro"
|
||||
"proguard-rules.pro",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ fun main(activity: AppCompatActivity) {
|
||||
try {
|
||||
vrServer = VRServer(
|
||||
configPath = File(activity.filesDir, "vrconfig.yml").absolutePath,
|
||||
serialHandlerProvider = { _ -> AndroidSerialHandler(activity) }
|
||||
serialHandlerProvider = { _ -> AndroidSerialHandler(activity) },
|
||||
)
|
||||
vrServer.start()
|
||||
Keybinding(vrServer)
|
||||
|
||||
@@ -64,9 +64,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
|
||||
startWatchingNewDevices()
|
||||
}
|
||||
|
||||
private fun getPorts(): List<UsbSerialDriver> {
|
||||
return UsbSerialProber.getDefaultProber().findAllDrivers(manager)
|
||||
}
|
||||
private fun getPorts(): List<UsbSerialDriver> = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
|
||||
|
||||
private fun startWatchingNewDevices() {
|
||||
if (watchingNewDevices) return
|
||||
@@ -78,13 +76,13 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
|
||||
} catch (t: Throwable) {
|
||||
LogManager.severe(
|
||||
"[SerialHandler] Error while watching for new devices, cancelling the \"getDevicesTimer\".",
|
||||
t
|
||||
t,
|
||||
)
|
||||
getDevicesTimer.cancel()
|
||||
}
|
||||
},
|
||||
0,
|
||||
3000
|
||||
3000,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -116,7 +114,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
|
||||
|
||||
if (newPort == null) {
|
||||
LogManager.info(
|
||||
"[SerialHandler] No serial ports found to connect to (${lastKnownPorts.size}) total ports"
|
||||
"[SerialHandler] No serial ports found to connect to (${lastKnownPorts.size}) total ports",
|
||||
)
|
||||
return false
|
||||
}
|
||||
@@ -126,7 +124,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
|
||||
if (newPort != port) {
|
||||
LogManager.info(
|
||||
"[SerialHandler] Closing current serial port " +
|
||||
port.descriptivePortName
|
||||
port.descriptivePortName,
|
||||
)
|
||||
closeSerial()
|
||||
} else {
|
||||
@@ -138,7 +136,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
|
||||
|
||||
LogManager.info(
|
||||
"[SerialHandler] Trying to connect to new serial port " +
|
||||
newPort.descriptivePortName
|
||||
newPort.descriptivePortName,
|
||||
)
|
||||
|
||||
if (!manager.hasPermission(newPort.port.device)) {
|
||||
@@ -147,7 +145,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
|
||||
activity,
|
||||
0,
|
||||
Intent(ACTION_USB_PERMISSION),
|
||||
flags
|
||||
flags,
|
||||
)
|
||||
if (requestingPermission != newPort.portLocation) {
|
||||
println("Requesting permission for ${newPort.portLocation}")
|
||||
@@ -155,7 +153,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
|
||||
requestingPermission = newPort.portLocation
|
||||
}
|
||||
LogManager.warning(
|
||||
"[SerialHandler] Can't open serial port ${newPort.descriptivePortName}, invalid permissions"
|
||||
"[SerialHandler] Can't open serial port ${newPort.descriptivePortName}, invalid permissions",
|
||||
)
|
||||
return false
|
||||
}
|
||||
@@ -163,7 +161,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
|
||||
val connection = manager.openDevice(newPort.port.device)
|
||||
if (connection == null) {
|
||||
LogManager.warning(
|
||||
"[SerialHandler] Can't open serial port ${newPort.descriptivePortName}, connection failed"
|
||||
"[SerialHandler] Can't open serial port ${newPort.descriptivePortName}, connection failed",
|
||||
|
||||
)
|
||||
return false
|
||||
@@ -215,7 +213,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
|
||||
}
|
||||
listeners.forEach { it.onSerialDisconnected() }
|
||||
LogManager.info(
|
||||
"[SerialHandler] Port ${currentPort?.descriptivePortName} closed okay"
|
||||
"[SerialHandler] Port ${currentPort?.descriptivePortName} closed okay",
|
||||
)
|
||||
usbIoManager?.stop()
|
||||
usbIoManager = null
|
||||
@@ -223,7 +221,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
|
||||
} catch (e: Exception) {
|
||||
LogManager.warning(
|
||||
"[SerialHandler] Error closing port ${currentPort?.descriptivePortName}",
|
||||
e
|
||||
e,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,30 +27,26 @@ configure<com.diffplug.gradle.spotless.SpotlessExtension> {
|
||||
// indentWithSpaces(2) // YAML cannot contain tabs: https://yaml.org/faq.html
|
||||
// }
|
||||
|
||||
// .editorconfig doesn't work so, manual override
|
||||
// https://github.com/diffplug/spotless/issues/142
|
||||
val editorConfig =
|
||||
mapOf(
|
||||
"indent_size" to 4,
|
||||
"indent_style" to "tab",
|
||||
// "max_line_length" to 88,
|
||||
"max_line_length" to "off",
|
||||
"ktlint_experimental" to "enabled",
|
||||
"ktlint_standard_condition-wrapping" to "disabled",
|
||||
"ktlint_standard_property-naming" to "disabled",
|
||||
"ij_kotlin_packages_to_use_import_on_demand" to
|
||||
"java.util.*,kotlin.math.*,dev.slimevr.autobone.errors.*,io.github.axisangles.ktmath.*,kotlinx.atomicfu.*",
|
||||
"ij_kotlin_allow_trailing_comma" to true
|
||||
"ij_kotlin_allow_trailing_comma" to true,
|
||||
)
|
||||
val ktlintVersion = "0.47.1"
|
||||
val ktlintVersion = "1.2.1"
|
||||
kotlinGradle {
|
||||
target("**/*.gradle.kts") // default target for kotlinGradle
|
||||
ktlint(ktlintVersion)
|
||||
.setUseExperimental(true)
|
||||
.editorConfigOverride(editorConfig)
|
||||
}
|
||||
kotlin {
|
||||
target("**/*.kt")
|
||||
targetExclude("**/build/**/**.kt")
|
||||
targetExclude("**/build/**/**.kt", "bin/")
|
||||
ktlint(ktlintVersion)
|
||||
.setUseExperimental(true)
|
||||
.editorConfigOverride(editorConfig)
|
||||
}
|
||||
java {
|
||||
|
||||
@@ -65,7 +65,7 @@ dependencies {
|
||||
implementation("com.illposed.osc:javaosc-core:0.8")
|
||||
implementation("org.java-websocket:Java-WebSocket:1.+")
|
||||
implementation("com.melloware:jintellitype:1.+")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
||||
implementation("it.unimi.dsi:fastutil:8.5.12")
|
||||
|
||||
testImplementation(kotlin("test"))
|
||||
|
||||
@@ -117,7 +117,7 @@ class VRServer @JvmOverloads constructor(
|
||||
LogManager.info("Starting the tracker server on port $trackerPort...")
|
||||
trackersServer = TrackersUDPServer(
|
||||
trackerPort,
|
||||
"Sensors UDP server"
|
||||
"Sensors UDP server",
|
||||
) { tracker: Tracker -> registerTracker(tracker) }
|
||||
|
||||
// Start bridges for SteamVR and Feeder
|
||||
@@ -143,13 +143,13 @@ class VRServer @JvmOverloads constructor(
|
||||
humanPoseManager,
|
||||
driverBridge,
|
||||
configManager.vrConfig.vrcOSC,
|
||||
computedTrackers
|
||||
computedTrackers,
|
||||
)
|
||||
vMCHandler = VMCHandler(
|
||||
this,
|
||||
humanPoseManager,
|
||||
configManager.vrConfig.vmc,
|
||||
computedTrackers
|
||||
computedTrackers,
|
||||
)
|
||||
|
||||
// Initialize OSC router
|
||||
@@ -279,7 +279,7 @@ class VRServer @JvmOverloads constructor(
|
||||
fun updateSkeletonModel() {
|
||||
queueTask { humanPoseManager.updateSkeletonModelFromServer() }
|
||||
vrcOSCHandler.setHeadTracker(
|
||||
TrackerUtils.getTrackerForSkeleton(trackers, TrackerPosition.HEAD)
|
||||
TrackerUtils.getTrackerForSkeleton(trackers, TrackerPosition.HEAD),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -398,9 +398,7 @@ class VRServer @JvmOverloads constructor(
|
||||
get() = ::instance.isInitialized
|
||||
|
||||
@JvmStatic
|
||||
fun getNextLocalTrackerId(): Int {
|
||||
return nextLocalTrackerId.incrementAndGet()
|
||||
}
|
||||
fun getNextLocalTrackerId(): Int = nextLocalTrackerId.incrementAndGet()
|
||||
|
||||
@JvmStatic
|
||||
val currentLocalTrackerId: Int
|
||||
|
||||
@@ -25,7 +25,7 @@ import java.util.function.Function
|
||||
class AutoBone(server: VRServer) {
|
||||
// This is filled by loadConfigValues()
|
||||
val offsets = EnumMap<SkeletonConfigOffsets, Float>(
|
||||
SkeletonConfigOffsets::class.java
|
||||
SkeletonConfigOffsets::class.java,
|
||||
)
|
||||
val adjustOffsets = FastList(
|
||||
arrayOf(
|
||||
@@ -39,8 +39,8 @@ class AutoBone(server: VRServer) {
|
||||
// best still, but it is somewhat functional
|
||||
SkeletonConfigOffsets.HIPS_WIDTH,
|
||||
SkeletonConfigOffsets.UPPER_LEG,
|
||||
SkeletonConfigOffsets.LOWER_LEG
|
||||
)
|
||||
SkeletonConfigOffsets.LOWER_LEG,
|
||||
),
|
||||
)
|
||||
|
||||
var estimatedHeight: Float = 1f
|
||||
@@ -109,6 +109,7 @@ class AutoBone(server: VRServer) {
|
||||
SkeletonConfigOffsets.LOWER_LEG, SkeletonConfigOffsets.FOOT_LENGTH,
|
||||
->
|
||||
if (rightSide) configOffset.affectedOffsets[1] else configOffset.affectedOffsets[0]
|
||||
|
||||
else -> configOffset.affectedOffsets[0]
|
||||
}
|
||||
return skeleton.getBone(boneType).getGlobalRotation().toRotationVector()
|
||||
@@ -160,7 +161,7 @@ class AutoBone(server: VRServer) {
|
||||
targetHeight = humanPoseManager.userHeightFromConfig
|
||||
LogManager
|
||||
.warning(
|
||||
"[AutoBone] Target height loaded from skeleton (Make sure you reset before running!): $targetHeight"
|
||||
"[AutoBone] Target height loaded from skeleton (Make sure you reset before running!): $targetHeight",
|
||||
)
|
||||
} else {
|
||||
// Otherwise if there is no skeleton available, attempt to get the
|
||||
@@ -169,7 +170,7 @@ class AutoBone(server: VRServer) {
|
||||
if (hmdHeight <= 0.4f) {
|
||||
LogManager
|
||||
.warning(
|
||||
"[AutoBone] Max headset height detected (Value seems too low, did you not stand up straight while measuring?): $hmdHeight"
|
||||
"[AutoBone] Max headset height detected (Value seems too low, did you not stand up straight while measuring?): $hmdHeight",
|
||||
)
|
||||
} else {
|
||||
LogManager.info("[AutoBone] Max headset height detected: $hmdHeight")
|
||||
@@ -217,7 +218,7 @@ class AutoBone(server: VRServer) {
|
||||
targetFullHeight = targetFullHeight,
|
||||
frames = frames,
|
||||
epochCallback = epochCallback,
|
||||
serverConfig = server.configManager
|
||||
serverConfig = server.configManager,
|
||||
)
|
||||
|
||||
// Initialize the frame order randomizer with a repeatable seed
|
||||
@@ -252,7 +253,7 @@ class AutoBone(server: VRServer) {
|
||||
trainingStep.setCursors(
|
||||
i,
|
||||
j,
|
||||
updatePlayerCursors = true
|
||||
updatePlayerCursors = true,
|
||||
)
|
||||
|
||||
frameStats.addValue(getErrorDeriv(trainingStep))
|
||||
@@ -287,7 +288,7 @@ class AutoBone(server: VRServer) {
|
||||
trainingStep.setCursors(
|
||||
i,
|
||||
j,
|
||||
updatePlayerCursors = true
|
||||
updatePlayerCursors = true,
|
||||
)
|
||||
|
||||
frameStats.addValue(getErrorDeriv(trainingStep))
|
||||
@@ -313,14 +314,14 @@ class AutoBone(server: VRServer) {
|
||||
|
||||
LogManager
|
||||
.info(
|
||||
"[AutoBone] Target height: ${trainingStep.targetHmdHeight}, Final height: $estimatedHeight"
|
||||
"[AutoBone] Target height: ${trainingStep.targetHmdHeight}, Final height: $estimatedHeight",
|
||||
)
|
||||
|
||||
return AutoBoneResults(
|
||||
estimatedHeight,
|
||||
trainingStep.targetHmdHeight,
|
||||
trainingStep.errorStats,
|
||||
offsets
|
||||
offsets,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -367,13 +368,13 @@ class AutoBone(server: VRServer) {
|
||||
.setCursors(
|
||||
randomFrameIndices[frameCursor],
|
||||
randomFrameIndices[frameCursor2],
|
||||
updatePlayerCursors = true
|
||||
updatePlayerCursors = true,
|
||||
)
|
||||
} else {
|
||||
trainingStep.setCursors(
|
||||
frameCursor,
|
||||
frameCursor2,
|
||||
updatePlayerCursors = true
|
||||
updatePlayerCursors = true,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -390,11 +391,11 @@ class AutoBone(server: VRServer) {
|
||||
if (epoch <= 0 || epoch >= config.numEpochs - 1 || (epoch + 1) % config.printEveryNumEpochs == 0) {
|
||||
LogManager
|
||||
.info(
|
||||
"[AutoBone] Epoch: ${epoch + 1}, Mean error: ${errorStats.mean} (SD ${errorStats.standardDeviation}), Adjust rate: ${trainingStep.curAdjustRate}"
|
||||
"[AutoBone] Epoch: ${epoch + 1}, Mean error: ${errorStats.mean} (SD ${errorStats.standardDeviation}), Adjust rate: ${trainingStep.curAdjustRate}",
|
||||
)
|
||||
LogManager
|
||||
.info(
|
||||
"[AutoBone] Target height: ${trainingStep.targetHmdHeight}, Estimated height: $estimatedHeight"
|
||||
"[AutoBone] Target height: ${trainingStep.targetHmdHeight}, Estimated height: $estimatedHeight",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -459,7 +460,7 @@ class AutoBone(server: VRServer) {
|
||||
// Extinguish
|
||||
LogManager
|
||||
.warning(
|
||||
"[AutoBone] Error value is invalid, resetting variables to recover"
|
||||
"[AutoBone] Error value is invalid, resetting variables to recover",
|
||||
)
|
||||
// Reset adjustable config values
|
||||
loadConfigValues()
|
||||
@@ -502,14 +503,14 @@ class AutoBone(server: VRServer) {
|
||||
skeleton2,
|
||||
entry.key,
|
||||
false,
|
||||
slideLeft
|
||||
slideLeft,
|
||||
)
|
||||
val rightDotProduct = getDotProductDiff(
|
||||
skeleton1,
|
||||
skeleton2,
|
||||
entry.key,
|
||||
true,
|
||||
slideRight
|
||||
slideRight,
|
||||
)
|
||||
|
||||
// Calculate the total effect of the bone based on change in rotation
|
||||
@@ -675,18 +676,18 @@ class AutoBone(server: VRServer) {
|
||||
if (PoseFrameIO.tryWriteToFile(recordingFile, frames)) {
|
||||
LogManager
|
||||
.info(
|
||||
"[AutoBone] Done exporting! Recording can be found at \"${recordingFile.path}\"."
|
||||
"[AutoBone] Done exporting! Recording can be found at \"${recordingFile.path}\".",
|
||||
)
|
||||
} else {
|
||||
LogManager
|
||||
.severe(
|
||||
"[AutoBone] Failed to export the recording to \"${recordingFile.path}\"."
|
||||
"[AutoBone] Failed to export the recording to \"${recordingFile.path}\".",
|
||||
)
|
||||
}
|
||||
} else {
|
||||
LogManager
|
||||
.severe(
|
||||
"[AutoBone] Failed to create the recording directory \"${saveDir.path}\"."
|
||||
"[AutoBone] Failed to create the recording directory \"${saveDir.path}\".",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -713,7 +714,7 @@ class AutoBone(server: VRServer) {
|
||||
|
||||
LogManager
|
||||
.info(
|
||||
"[AutoBone] Detected recording at \"${file.path}\", loading frames..."
|
||||
"[AutoBone] Detected recording at \"${file.path}\", loading frames...",
|
||||
)
|
||||
val frames = PoseFrameIO.tryReadFromFile(file)
|
||||
if (frames == null) {
|
||||
@@ -731,9 +732,7 @@ class AutoBone(server: VRServer) {
|
||||
val epochError: StatsCalculator,
|
||||
val configValues: EnumMap<SkeletonConfigOffsets, Float>,
|
||||
) {
|
||||
override fun toString(): String {
|
||||
return "Epoch: $epoch, Epoch error: $epochError"
|
||||
}
|
||||
override fun toString(): String = "Epoch: $epoch, Epoch error: $epochError"
|
||||
}
|
||||
|
||||
inner class AutoBoneResults(
|
||||
@@ -753,22 +752,18 @@ class AutoBone(server: VRServer) {
|
||||
// FIXME: Won't work on iOS and Android, maybe fix resolveConfigDirectory more than this
|
||||
val saveDir = File(
|
||||
OperatingSystem.resolveConfigDirectory(SLIMEVR_IDENTIFIER)?.resolve(
|
||||
AUTOBONE_FOLDER
|
||||
)?.toString() ?: AUTOBONE_FOLDER
|
||||
AUTOBONE_FOLDER,
|
||||
)?.toString() ?: AUTOBONE_FOLDER,
|
||||
)
|
||||
val loadDir = File(
|
||||
OperatingSystem.resolveConfigDirectory(SLIMEVR_IDENTIFIER)?.resolve(
|
||||
LOADAUTOBONE_FOLDER
|
||||
)?.toString() ?: LOADAUTOBONE_FOLDER
|
||||
LOADAUTOBONE_FOLDER,
|
||||
)?.toString() ?: LOADAUTOBONE_FOLDER,
|
||||
)
|
||||
|
||||
// Mean square error function
|
||||
private fun errorFunc(errorDeriv: Float): Float {
|
||||
return 0.5f * (errorDeriv * errorDeriv)
|
||||
}
|
||||
private fun errorFunc(errorDeriv: Float): Float = 0.5f * (errorDeriv * errorDeriv)
|
||||
|
||||
private fun decayFunc(initialAdjustRate: Float, adjustRateDecay: Float, epoch: Int): Float {
|
||||
return if (epoch >= 0) initialAdjustRate / (1 + (adjustRateDecay * epoch)) else 0.0f
|
||||
}
|
||||
private fun decayFunc(initialAdjustRate: Float, adjustRateDecay: Float, epoch: Int): Float = if (epoch >= 0) initialAdjustRate / (1 + (adjustRateDecay * epoch)) else 0.0f
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,24 +59,25 @@ class AutoBoneHandler(private val server: VRServer) {
|
||||
total,
|
||||
eta,
|
||||
completed,
|
||||
success
|
||||
success,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(AutoBoneException::class)
|
||||
private fun processFrames(frames: PoseFrames): AutoBoneResults {
|
||||
return autoBone
|
||||
.processFrames(frames) { epoch ->
|
||||
listeners.forEach { listener -> listener.onAutoBoneEpoch(epoch) }
|
||||
}
|
||||
}
|
||||
private fun processFrames(frames: PoseFrames): AutoBoneResults = autoBone
|
||||
.processFrames(frames) { epoch ->
|
||||
listeners.forEach { listener -> listener.onAutoBoneEpoch(epoch) }
|
||||
}
|
||||
|
||||
fun startProcessByType(processType: AutoBoneProcessType?): Boolean {
|
||||
when (processType) {
|
||||
AutoBoneProcessType.RECORD -> startRecording()
|
||||
|
||||
AutoBoneProcessType.SAVE -> saveRecording()
|
||||
|
||||
AutoBoneProcessType.PROCESS -> processRecording()
|
||||
|
||||
else -> {
|
||||
return false
|
||||
}
|
||||
@@ -108,13 +109,13 @@ class AutoBoneHandler(private val server: VRServer) {
|
||||
val framesFuture = poseRecorder
|
||||
.startFrameRecording(
|
||||
sampleCount,
|
||||
sampleRate
|
||||
sampleRate,
|
||||
) { progress: RecordingProgress ->
|
||||
announceProcessStatus(
|
||||
AutoBoneProcessType.RECORD,
|
||||
current = progress.frame.toLong(),
|
||||
total = progress.totalFrames.toLong(),
|
||||
eta = totalTime - (progress.frame * totalTime / progress.totalFrames)
|
||||
eta = totalTime - (progress.frame * totalTime / progress.totalFrames),
|
||||
)
|
||||
}
|
||||
val frames = framesFuture.get()
|
||||
@@ -126,7 +127,7 @@ class AutoBoneHandler(private val server: VRServer) {
|
||||
if (autoBone.globalConfig.saveRecordings) {
|
||||
announceProcessStatus(
|
||||
AutoBoneProcessType.RECORD,
|
||||
"Saving recording (from config option)..."
|
||||
"Saving recording (from config option)...",
|
||||
)
|
||||
autoBone.saveRecording(frames)
|
||||
}
|
||||
@@ -135,14 +136,14 @@ class AutoBoneHandler(private val server: VRServer) {
|
||||
AutoBoneProcessType.RECORD,
|
||||
"Done recording!",
|
||||
completed = true,
|
||||
success = true
|
||||
success = true,
|
||||
)
|
||||
} else {
|
||||
announceProcessStatus(
|
||||
AutoBoneProcessType.RECORD,
|
||||
"The server is not ready to record",
|
||||
completed = true,
|
||||
success = false
|
||||
success = false,
|
||||
)
|
||||
LogManager.severe("[AutoBone] Unable to record...")
|
||||
return
|
||||
@@ -152,7 +153,7 @@ class AutoBoneHandler(private val server: VRServer) {
|
||||
AutoBoneProcessType.RECORD,
|
||||
String.format("Recording failed: %s", e.message),
|
||||
completed = true,
|
||||
success = false
|
||||
success = false,
|
||||
)
|
||||
LogManager.severe("[AutoBone] Failed recording!", e)
|
||||
} finally {
|
||||
@@ -196,14 +197,14 @@ class AutoBoneHandler(private val server: VRServer) {
|
||||
AutoBoneProcessType.SAVE,
|
||||
"Recording saved!",
|
||||
completed = true,
|
||||
success = true
|
||||
success = true,
|
||||
)
|
||||
} else {
|
||||
announceProcessStatus(
|
||||
AutoBoneProcessType.SAVE,
|
||||
"No recording found",
|
||||
completed = true,
|
||||
success = false
|
||||
success = false,
|
||||
)
|
||||
LogManager.severe("[AutoBone] Unable to save, no recording was done...")
|
||||
return
|
||||
@@ -213,7 +214,7 @@ class AutoBoneHandler(private val server: VRServer) {
|
||||
AutoBoneProcessType.SAVE,
|
||||
String.format("Failed to save recording: %s", e.message),
|
||||
completed = true,
|
||||
success = false
|
||||
success = false,
|
||||
)
|
||||
LogManager.severe("[AutoBone] Failed to save recording!", e)
|
||||
} finally {
|
||||
@@ -250,11 +251,11 @@ class AutoBoneHandler(private val server: VRServer) {
|
||||
AutoBoneProcessType.PROCESS,
|
||||
"No recordings found...",
|
||||
completed = true,
|
||||
success = false
|
||||
success = false,
|
||||
)
|
||||
LogManager
|
||||
.severe(
|
||||
"[AutoBone] No recordings found in \"${loadDir.path}\" and no recording was done..."
|
||||
"[AutoBone] No recordings found in \"${loadDir.path}\" and no recording was done...",
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -263,7 +264,7 @@ class AutoBoneHandler(private val server: VRServer) {
|
||||
LogManager.info("[AutoBone] Processing frames...")
|
||||
val errorStats = StatsCalculator()
|
||||
val offsetStats = EnumMap<SkeletonConfigOffsets, StatsCalculator>(
|
||||
SkeletonConfigOffsets::class.java
|
||||
SkeletonConfigOffsets::class.java,
|
||||
)
|
||||
val skeletonConfigManagerBuffer = SkeletonConfigManager(false)
|
||||
for ((key, value) in frameRecordings) {
|
||||
@@ -314,8 +315,8 @@ class AutoBoneHandler(private val server: VRServer) {
|
||||
LogManager
|
||||
.info(
|
||||
"[AutoBone] Average height error: ${
|
||||
StringUtils.prettyNumber(errorStats.mean, 6)
|
||||
} (SD ${StringUtils.prettyNumber(errorStats.standardDeviation, 6)})"
|
||||
StringUtils.prettyNumber(errorStats.mean, 6)
|
||||
} (SD ${StringUtils.prettyNumber(errorStats.standardDeviation, 6)})",
|
||||
)
|
||||
// #endregion
|
||||
listeners.forEach { listener: AutoBoneListener -> listener.onAutoBoneEnd(autoBone.offsets) }
|
||||
@@ -323,14 +324,14 @@ class AutoBoneHandler(private val server: VRServer) {
|
||||
AutoBoneProcessType.PROCESS,
|
||||
"Done processing!",
|
||||
completed = true,
|
||||
success = true
|
||||
success = true,
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
announceProcessStatus(
|
||||
AutoBoneProcessType.PROCESS,
|
||||
String.format("Processing failed: %s", e.message),
|
||||
completed = true,
|
||||
success = false
|
||||
success = false,
|
||||
)
|
||||
LogManager.severe("[AutoBone] Failed adjustment!", e)
|
||||
} finally {
|
||||
@@ -394,12 +395,12 @@ class AutoBoneHandler(private val server: VRServer) {
|
||||
|
||||
LogManager.info(
|
||||
"[AutoBone] Ratios: [{Neck-Torso: ${
|
||||
StringUtils.prettyNumber(neckTorso)}}, {Chest-Torso: ${
|
||||
StringUtils.prettyNumber(chestTorso)}}, {Torso-Waist: ${
|
||||
StringUtils.prettyNumber(torsoWaist)}}, {Leg-Torso: ${
|
||||
StringUtils.prettyNumber(legTorso)}}, {Leg-Body: ${
|
||||
StringUtils.prettyNumber(legBody)}}, {Knee-Leg: ${
|
||||
StringUtils.prettyNumber(kneeLeg)}}]"
|
||||
StringUtils.prettyNumber(neckTorso)}}, {Chest-Torso: ${
|
||||
StringUtils.prettyNumber(chestTorso)}}, {Torso-Waist: ${
|
||||
StringUtils.prettyNumber(torsoWaist)}}, {Leg-Torso: ${
|
||||
StringUtils.prettyNumber(legTorso)}}, {Leg-Body: ${
|
||||
StringUtils.prettyNumber(legBody)}}, {Knee-Leg: ${
|
||||
StringUtils.prettyNumber(kneeLeg)}}]",
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package dev.slimevr.autobone
|
||||
|
||||
enum class AutoBoneProcessType(val id: Int) {
|
||||
NONE(0), RECORD(1), SAVE(2), PROCESS(3);
|
||||
NONE(0),
|
||||
RECORD(1),
|
||||
SAVE(2),
|
||||
PROCESS(3),
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun getById(id: Int): AutoBoneProcessType? = byId[id]
|
||||
|
||||
@@ -27,9 +27,17 @@ class StatsCalculator {
|
||||
}
|
||||
|
||||
val variance: Float
|
||||
get() = if (count < 1) { Float.NaN } else { m2 / count }
|
||||
get() = if (count < 1) {
|
||||
Float.NaN
|
||||
} else {
|
||||
m2 / count
|
||||
}
|
||||
val sampleVariance: Float
|
||||
get() = if (count < 2) { Float.NaN } else { m2 / (count - 1) }
|
||||
get() = if (count < 2) {
|
||||
Float.NaN
|
||||
} else {
|
||||
m2 / (count - 1)
|
||||
}
|
||||
val standardDeviation: Float
|
||||
get() = FastMath.sqrt(variance)
|
||||
}
|
||||
|
||||
@@ -10,13 +10,11 @@ import dev.slimevr.tracking.processor.config.SkeletonConfigOffsets
|
||||
// The distance from average human proportions
|
||||
class BodyProportionError : IAutoBoneError {
|
||||
@Throws(AutoBoneException::class)
|
||||
override fun getStepError(trainingStep: AutoBoneStep): Float {
|
||||
return getBodyProportionError(
|
||||
trainingStep.skeleton1,
|
||||
// Skeletons are now normalized to reduce bias, so height is always 1
|
||||
1f
|
||||
)
|
||||
}
|
||||
override fun getStepError(trainingStep: AutoBoneStep): Float = getBodyProportionError(
|
||||
trainingStep.skeleton1,
|
||||
// Skeletons are now normalized to reduce bias, so height is always 1
|
||||
1f,
|
||||
)
|
||||
|
||||
fun getBodyProportionError(humanPoseManager: HumanPoseManager, fullHeight: Float): Float {
|
||||
var sum = 0f
|
||||
@@ -54,7 +52,7 @@ class BodyProportionError : IAutoBoneError {
|
||||
RangeProportionLimiter(
|
||||
0.059f,
|
||||
SkeletonConfigOffsets.HEAD,
|
||||
0.01f
|
||||
0.01f,
|
||||
),
|
||||
// Neck
|
||||
// Expected: 0.052
|
||||
@@ -62,35 +60,35 @@ class BodyProportionError : IAutoBoneError {
|
||||
RangeProportionLimiter(
|
||||
0.054f,
|
||||
SkeletonConfigOffsets.NECK,
|
||||
0.0015f
|
||||
0.0015f,
|
||||
),
|
||||
// Upper Chest
|
||||
// Experimental: 0.0945
|
||||
RangeProportionLimiter(
|
||||
0.0945f,
|
||||
SkeletonConfigOffsets.UPPER_CHEST,
|
||||
0.01f
|
||||
0.01f,
|
||||
),
|
||||
// Chest
|
||||
// Experimental: 0.0945
|
||||
RangeProportionLimiter(
|
||||
0.0945f,
|
||||
SkeletonConfigOffsets.CHEST,
|
||||
0.01f
|
||||
0.01f,
|
||||
),
|
||||
// Waist
|
||||
// Experimental: 0.118
|
||||
RangeProportionLimiter(
|
||||
0.118f,
|
||||
SkeletonConfigOffsets.WAIST,
|
||||
0.05f
|
||||
0.05f,
|
||||
),
|
||||
// Hip
|
||||
// Experimental: 0.0237
|
||||
RangeProportionLimiter(
|
||||
0.0237f,
|
||||
SkeletonConfigOffsets.HIP,
|
||||
0.01f
|
||||
0.01f,
|
||||
),
|
||||
// Hip Width
|
||||
// Expected: 0.191
|
||||
@@ -98,14 +96,14 @@ class BodyProportionError : IAutoBoneError {
|
||||
RangeProportionLimiter(
|
||||
0.184f,
|
||||
SkeletonConfigOffsets.HIPS_WIDTH,
|
||||
0.04f
|
||||
0.04f,
|
||||
),
|
||||
// Upper Leg
|
||||
// Expected: 0.245
|
||||
RangeProportionLimiter(
|
||||
0.245f,
|
||||
SkeletonConfigOffsets.UPPER_LEG,
|
||||
0.015f
|
||||
0.015f,
|
||||
),
|
||||
// Lower Leg
|
||||
// Expected: 0.246 (0.285 including below ankle, could use a separate
|
||||
@@ -113,8 +111,8 @@ class BodyProportionError : IAutoBoneError {
|
||||
RangeProportionLimiter(
|
||||
0.285f,
|
||||
SkeletonConfigOffsets.LOWER_LEG,
|
||||
0.02f
|
||||
)
|
||||
0.02f,
|
||||
),
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@@ -9,12 +9,10 @@ import dev.slimevr.tracking.trackers.TrackerRole
|
||||
// The offset between the height both feet at one instant and over time
|
||||
class FootHeightOffsetError : IAutoBoneError {
|
||||
@Throws(AutoBoneException::class)
|
||||
override fun getStepError(trainingStep: AutoBoneStep): Float {
|
||||
return getSlideError(
|
||||
trainingStep.skeleton1.skeleton,
|
||||
trainingStep.skeleton2.skeleton
|
||||
)
|
||||
}
|
||||
override fun getStepError(trainingStep: AutoBoneStep): Float = getSlideError(
|
||||
trainingStep.skeleton1.skeleton,
|
||||
trainingStep.skeleton2.skeleton,
|
||||
)
|
||||
|
||||
companion object {
|
||||
fun getSlideError(skeleton1: HumanSkeleton, skeleton2: HumanSkeleton): Float {
|
||||
|
||||
@@ -6,14 +6,10 @@ import dev.slimevr.autobone.AutoBoneStep
|
||||
// The difference from the current height to the target height
|
||||
class HeightError : IAutoBoneError {
|
||||
@Throws(AutoBoneException::class)
|
||||
override fun getStepError(trainingStep: AutoBoneStep): Float {
|
||||
return getHeightError(
|
||||
trainingStep.currentHmdHeight,
|
||||
trainingStep.targetHmdHeight
|
||||
)
|
||||
}
|
||||
override fun getStepError(trainingStep: AutoBoneStep): Float = getHeightError(
|
||||
trainingStep.currentHmdHeight,
|
||||
trainingStep.targetHmdHeight,
|
||||
)
|
||||
|
||||
fun getHeightError(currentHeight: Float, targetHeight: Float): Float {
|
||||
return FastMath.abs(targetHeight - currentHeight)
|
||||
}
|
||||
fun getHeightError(currentHeight: Float, targetHeight: Float): Float = FastMath.abs(targetHeight - currentHeight)
|
||||
}
|
||||
|
||||
@@ -9,12 +9,10 @@ import dev.slimevr.tracking.trackers.TrackerRole
|
||||
// The change in distance between both of the ankles over time
|
||||
class OffsetSlideError : IAutoBoneError {
|
||||
@Throws(AutoBoneException::class)
|
||||
override fun getStepError(trainingStep: AutoBoneStep): Float {
|
||||
return getSlideError(
|
||||
trainingStep.skeleton1.skeleton,
|
||||
trainingStep.skeleton2.skeleton
|
||||
)
|
||||
}
|
||||
override fun getStepError(trainingStep: AutoBoneStep): Float = getSlideError(
|
||||
trainingStep.skeleton1.skeleton,
|
||||
trainingStep.skeleton2.skeleton,
|
||||
)
|
||||
|
||||
companion object {
|
||||
fun getSlideError(skeleton1: HumanSkeleton, skeleton2: HumanSkeleton): Float {
|
||||
|
||||
@@ -14,12 +14,12 @@ class PositionError : IAutoBoneError {
|
||||
getPositionError(
|
||||
trackers,
|
||||
trainingStep.cursor1,
|
||||
trainingStep.skeleton1.skeleton
|
||||
trainingStep.skeleton1.skeleton,
|
||||
) +
|
||||
getPositionError(
|
||||
trackers,
|
||||
trainingStep.cursor2,
|
||||
trainingStep.skeleton2.skeleton
|
||||
trainingStep.skeleton2.skeleton,
|
||||
)
|
||||
) /
|
||||
2f
|
||||
|
||||
@@ -15,7 +15,7 @@ class PositionOffsetError : IAutoBoneError {
|
||||
trainingStep.cursor1,
|
||||
trainingStep.cursor2,
|
||||
trainingStep.skeleton1.skeleton,
|
||||
trainingStep.skeleton2.skeleton
|
||||
trainingStep.skeleton2.skeleton,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,10 @@ import dev.slimevr.tracking.trackers.TrackerRole
|
||||
// The change in position of the ankle over time
|
||||
class SlideError : IAutoBoneError {
|
||||
@Throws(AutoBoneException::class)
|
||||
override fun getStepError(trainingStep: AutoBoneStep): Float {
|
||||
return getSlideError(
|
||||
trainingStep.skeleton1.skeleton,
|
||||
trainingStep.skeleton2.skeleton
|
||||
)
|
||||
}
|
||||
override fun getStepError(trainingStep: AutoBoneStep): Float = getSlideError(
|
||||
trainingStep.skeleton1.skeleton,
|
||||
trainingStep.skeleton2.skeleton,
|
||||
)
|
||||
|
||||
companion object {
|
||||
fun getSlideError(skeleton1: HumanSkeleton, skeleton2: HumanSkeleton): Float {
|
||||
@@ -32,7 +30,7 @@ class SlideError : IAutoBoneError {
|
||||
// Calculate and average between both feet
|
||||
return getSlideError(
|
||||
skeleton1.getComputedTracker(trackerRole),
|
||||
skeleton2.getComputedTracker(trackerRole)
|
||||
skeleton2.getComputedTracker(trackerRole),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,7 @@ class VRCOSCConfig : OSCConfig() {
|
||||
@JsonSerialize(keyUsing = StdKeySerializers.StringKeySerializer::class)
|
||||
var trackers: MutableMap<String, Boolean> = HashMap()
|
||||
|
||||
fun getOSCTrackerRole(role: TrackerRole, def: Boolean): Boolean {
|
||||
return trackers.getOrDefault(role.name.lowercase(Locale.getDefault()), def)
|
||||
}
|
||||
fun getOSCTrackerRole(role: TrackerRole, def: Boolean): Boolean = trackers.getOrDefault(role.name.lowercase(Locale.getDefault()), def)
|
||||
|
||||
fun setOSCTrackerRole(role: TrackerRole, `val`: Boolean) {
|
||||
trackers[role.name.lowercase(Locale.getDefault())] = `val`
|
||||
|
||||
@@ -29,8 +29,6 @@ enum class TrackerFilters(val id: Int, val configKey: String) {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getByConfigkey(configKey: String?): TrackerFilters? {
|
||||
return if (configKey == null) null else byConfigkey[configKey.lowercase(Locale.getDefault())]
|
||||
}
|
||||
fun getByConfigkey(configKey: String?): TrackerFilters? = if (configKey == null) null else byConfigkey[configKey.lowercase(Locale.getDefault())]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,33 +170,31 @@ class UnityArmature(localRot: Boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
fun getHeadNodeOfBone(unityBone: UnityBone?): TransformNode? {
|
||||
return if (unityBone == null) {
|
||||
null
|
||||
} else {
|
||||
when (unityBone) {
|
||||
UnityBone.HEAD -> neckTailNode
|
||||
UnityBone.NECK -> neckHeadNode
|
||||
UnityBone.UPPER_CHEST -> chestNode
|
||||
UnityBone.CHEST -> spineTailNode
|
||||
UnityBone.SPINE -> spineHeadNode
|
||||
UnityBone.HIPS -> hipsNode
|
||||
UnityBone.LEFT_UPPER_LEG -> leftHipNode
|
||||
UnityBone.RIGHT_UPPER_LEG -> rightHipNode
|
||||
UnityBone.LEFT_LOWER_LEG -> leftKneeNode
|
||||
UnityBone.RIGHT_LOWER_LEG -> rightKneeNode
|
||||
UnityBone.LEFT_FOOT -> leftAnkleNode
|
||||
UnityBone.RIGHT_FOOT -> rightAnkleNode
|
||||
UnityBone.LEFT_SHOULDER -> leftShoulderHeadNode
|
||||
UnityBone.RIGHT_SHOULDER -> rightShoulderHeadNode
|
||||
UnityBone.LEFT_UPPER_ARM -> leftShoulderTailNode
|
||||
UnityBone.RIGHT_UPPER_ARM -> rightShoulderTailNode
|
||||
UnityBone.LEFT_LOWER_ARM -> leftElbowNode
|
||||
UnityBone.RIGHT_LOWER_ARM -> rightElbowNode
|
||||
UnityBone.LEFT_HAND -> leftWristNode
|
||||
UnityBone.RIGHT_HAND -> rightWristNode
|
||||
else -> null
|
||||
}
|
||||
fun getHeadNodeOfBone(unityBone: UnityBone?): TransformNode? = if (unityBone == null) {
|
||||
null
|
||||
} else {
|
||||
when (unityBone) {
|
||||
UnityBone.HEAD -> neckTailNode
|
||||
UnityBone.NECK -> neckHeadNode
|
||||
UnityBone.UPPER_CHEST -> chestNode
|
||||
UnityBone.CHEST -> spineTailNode
|
||||
UnityBone.SPINE -> spineHeadNode
|
||||
UnityBone.HIPS -> hipsNode
|
||||
UnityBone.LEFT_UPPER_LEG -> leftHipNode
|
||||
UnityBone.RIGHT_UPPER_LEG -> rightHipNode
|
||||
UnityBone.LEFT_LOWER_LEG -> leftKneeNode
|
||||
UnityBone.RIGHT_LOWER_LEG -> rightKneeNode
|
||||
UnityBone.LEFT_FOOT -> leftAnkleNode
|
||||
UnityBone.RIGHT_FOOT -> rightAnkleNode
|
||||
UnityBone.LEFT_SHOULDER -> leftShoulderHeadNode
|
||||
UnityBone.RIGHT_SHOULDER -> rightShoulderHeadNode
|
||||
UnityBone.LEFT_UPPER_ARM -> leftShoulderTailNode
|
||||
UnityBone.RIGHT_UPPER_ARM -> rightShoulderTailNode
|
||||
UnityBone.LEFT_LOWER_ARM -> leftElbowNode
|
||||
UnityBone.RIGHT_LOWER_ARM -> rightElbowNode
|
||||
UnityBone.LEFT_HAND -> leftWristNode
|
||||
UnityBone.RIGHT_HAND -> rightWristNode
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ class VRCOSCHandler(
|
||||
trackersEnabled[i] = config
|
||||
.getOSCTrackerRole(
|
||||
computedTrackers[i].trackerPosition!!.trackerRole!!,
|
||||
false
|
||||
false,
|
||||
)
|
||||
} else {
|
||||
trackersEnabled[i] = false
|
||||
@@ -110,7 +110,7 @@ class VRCOSCHandler(
|
||||
"[VRCOSCHandler] Error listening to the port " +
|
||||
config.portIn +
|
||||
": " +
|
||||
e
|
||||
e,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -118,13 +118,13 @@ class VRCOSCHandler(
|
||||
if (oscReceiver != null) {
|
||||
val listener = OSCMessageListener { event: OSCMessageEvent -> handleReceivedMessage(event) }
|
||||
val vrcSelector: MessageSelector = OSCPatternAddressMessageSelector(
|
||||
"/avatar/parameters/Upright"
|
||||
"/avatar/parameters/Upright",
|
||||
)
|
||||
val trackersPositionSelector: MessageSelector = OSCPatternAddressMessageSelector(
|
||||
"/tracking/trackers/*/position"
|
||||
"/tracking/trackers/*/position",
|
||||
)
|
||||
val trackersRotationSelector: MessageSelector = OSCPatternAddressMessageSelector(
|
||||
"/tracking/trackers/*/rotation"
|
||||
"/tracking/trackers/*/rotation",
|
||||
)
|
||||
oscReceiver!!.dispatcher.addListener(vrcSelector, listener)
|
||||
oscReceiver!!.dispatcher.addListener(trackersPositionSelector, listener)
|
||||
@@ -140,13 +140,13 @@ class VRCOSCHandler(
|
||||
val address = InetAddress.getByName(config.address)
|
||||
val port = config.portOut
|
||||
oscSender = OSCPortOut(InetSocketAddress(address, port))
|
||||
if (lastPortOut != port && lastAddress !== address || !wasConnected) {
|
||||
if ((lastPortOut != port && lastAddress !== address) || !wasConnected) {
|
||||
LogManager
|
||||
.info(
|
||||
"[VRCOSCHandler] Sending to port " +
|
||||
port +
|
||||
" at address " +
|
||||
address.toString()
|
||||
address.toString(),
|
||||
)
|
||||
}
|
||||
lastPortOut = port
|
||||
@@ -160,7 +160,7 @@ class VRCOSCHandler(
|
||||
" at the address " +
|
||||
config.address +
|
||||
": " +
|
||||
e
|
||||
e,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -194,7 +194,7 @@ class VRCOSCHandler(
|
||||
hasPosition = true,
|
||||
userEditable = false,
|
||||
isComputed = true,
|
||||
usesTimeout = true
|
||||
usesTimeout = true,
|
||||
)
|
||||
vrcDevice.trackers[0] = vrcHmd!!
|
||||
server.registerTracker(vrcHmd!!)
|
||||
@@ -211,7 +211,7 @@ class VRCOSCHandler(
|
||||
event
|
||||
.message
|
||||
.arguments[0] as Float * humanPoseManager.userHeightFromConfig,
|
||||
0f
|
||||
0f,
|
||||
)
|
||||
vrcHmd!!.dataTick()
|
||||
}
|
||||
@@ -233,7 +233,7 @@ class VRCOSCHandler(
|
||||
receivingPositionOffset = Vector3(
|
||||
event.message.arguments[0] as Float,
|
||||
event.message.arguments[1] as Float,
|
||||
-(event.message.arguments[2] as Float)
|
||||
-(event.message.arguments[2] as Float),
|
||||
)
|
||||
|
||||
if (slimeHead != null && slimeHead.hasPosition) {
|
||||
@@ -276,7 +276,7 @@ class VRCOSCHandler(
|
||||
userEditable = true,
|
||||
isComputed = true,
|
||||
needsReset = true,
|
||||
usesTimeout = true
|
||||
usesTimeout = true,
|
||||
)
|
||||
oscTrackersDevice!!.trackers[trackerId] = tracker
|
||||
server.registerTracker(tracker)
|
||||
@@ -290,8 +290,8 @@ class VRCOSCHandler(
|
||||
Vector3(
|
||||
event.message.arguments[0] as Float,
|
||||
event.message.arguments[1] as Float,
|
||||
-(event.message.arguments[2] as Float)
|
||||
) - receivingPositionOffset
|
||||
-(event.message.arguments[2] as Float),
|
||||
) - receivingPositionOffset,
|
||||
) + postReceivingPositionOffset
|
||||
} else {
|
||||
val (w, x, y, z) = EulerAngles(EulerOrder.YXZ, event.message.arguments[0] as Float * FastMath.DEG_TO_RAD, event.message.arguments[1] as Float * FastMath.DEG_TO_RAD, event.message.arguments[2] as Float * FastMath.DEG_TO_RAD).toQuaternion()
|
||||
@@ -334,8 +334,8 @@ class VRCOSCHandler(
|
||||
bundle.addPacket(
|
||||
OSCMessage(
|
||||
"/tracking/trackers/${getVRCOSCTrackersId(computedTrackers[i].trackerPosition)}/position",
|
||||
oscArgs.clone()
|
||||
)
|
||||
oscArgs.clone(),
|
||||
),
|
||||
)
|
||||
|
||||
// Send regular trackers' rotations
|
||||
@@ -351,7 +351,7 @@ class VRCOSCHandler(
|
||||
w,
|
||||
-x1,
|
||||
-y1,
|
||||
z1
|
||||
z1,
|
||||
).toEulerAngles(EulerOrder.YXZ)
|
||||
oscArgs.clear()
|
||||
oscArgs.add(x2 * FastMath.RAD_TO_DEG)
|
||||
@@ -360,8 +360,8 @@ class VRCOSCHandler(
|
||||
bundle.addPacket(
|
||||
OSCMessage(
|
||||
"/tracking/trackers/${getVRCOSCTrackersId(computedTrackers[i].trackerPosition)}/rotation",
|
||||
oscArgs.clone()
|
||||
)
|
||||
oscArgs.clone(),
|
||||
),
|
||||
)
|
||||
}
|
||||
if (computedTrackers[i].trackerPosition === TrackerPosition.HEAD) {
|
||||
@@ -374,8 +374,8 @@ class VRCOSCHandler(
|
||||
bundle.addPacket(
|
||||
OSCMessage(
|
||||
"/tracking/trackers/head/position",
|
||||
oscArgs.clone()
|
||||
)
|
||||
oscArgs.clone(),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -431,7 +431,7 @@ class VRCOSCHandler(
|
||||
oscArgs.add(0f)
|
||||
oscMessage = OSCMessage(
|
||||
"/tracking/trackers/head/rotation",
|
||||
oscArgs
|
||||
oscArgs,
|
||||
)
|
||||
try {
|
||||
oscSender!!.send(oscMessage)
|
||||
@@ -445,23 +445,13 @@ class VRCOSCHandler(
|
||||
}
|
||||
}
|
||||
|
||||
override fun getOscSender(): OSCPortOut {
|
||||
return oscSender!!
|
||||
}
|
||||
override fun getOscSender(): OSCPortOut = oscSender!!
|
||||
|
||||
override fun getPortOut(): Int {
|
||||
return lastPortOut
|
||||
}
|
||||
override fun getPortOut(): Int = lastPortOut
|
||||
|
||||
override fun getAddress(): InetAddress {
|
||||
return lastAddress!!
|
||||
}
|
||||
override fun getAddress(): InetAddress = lastAddress!!
|
||||
|
||||
override fun getOscReceiver(): OSCPortIn {
|
||||
return oscReceiver!!
|
||||
}
|
||||
override fun getOscReceiver(): OSCPortIn = oscReceiver!!
|
||||
|
||||
override fun getPortIn(): Int {
|
||||
return lastPortIn
|
||||
}
|
||||
override fun getPortIn(): Int = lastPortIn
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ object PoseFrameIO {
|
||||
|
||||
fun writeToFile(file: File, frames: PoseFrames) {
|
||||
DataOutputStream(
|
||||
BufferedOutputStream(FileOutputStream(file))
|
||||
BufferedOutputStream(FileOutputStream(file)),
|
||||
).use { outputStream -> writeFrames(outputStream, frames) }
|
||||
}
|
||||
|
||||
@@ -100,13 +100,11 @@ object PoseFrameIO {
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun readVector3f(inputStream: DataInputStream): Vector3 {
|
||||
return Vector3(
|
||||
inputStream.readFloat(),
|
||||
inputStream.readFloat(),
|
||||
inputStream.readFloat()
|
||||
)
|
||||
}
|
||||
private fun readVector3f(inputStream: DataInputStream): Vector3 = Vector3(
|
||||
inputStream.readFloat(),
|
||||
inputStream.readFloat(),
|
||||
inputStream.readFloat(),
|
||||
)
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun readQuaternion(inputStream: DataInputStream): Quaternion {
|
||||
@@ -125,7 +123,7 @@ object PoseFrameIO {
|
||||
val name = inputStream.readUTF()
|
||||
val trackerFrameCount = inputStream.readInt()
|
||||
val trackerFrames = FastList<TrackerFrame?>(
|
||||
trackerFrameCount
|
||||
trackerFrameCount,
|
||||
)
|
||||
for (j in 0 until trackerFrameCount) {
|
||||
val dataFlags = inputStream.readInt()
|
||||
@@ -159,8 +157,8 @@ object PoseFrameIO {
|
||||
rotation,
|
||||
position,
|
||||
acceleration,
|
||||
rawRotation
|
||||
)
|
||||
rawRotation,
|
||||
),
|
||||
)
|
||||
}
|
||||
trackers.add(TrackerFrames(name, trackerFrames))
|
||||
@@ -177,16 +175,14 @@ object PoseFrameIO {
|
||||
}
|
||||
}
|
||||
|
||||
fun readFromFile(file: File): PoseFrames {
|
||||
return readFrames(
|
||||
DataInputStream(BufferedInputStream(FileInputStream(file)))
|
||||
)
|
||||
}
|
||||
fun readFromFile(file: File): PoseFrames = readFrames(
|
||||
DataInputStream(BufferedInputStream(FileInputStream(file))),
|
||||
)
|
||||
|
||||
fun tryReadFromFile(file: File): PoseFrames? {
|
||||
return try {
|
||||
return readFrames(
|
||||
DataInputStream(BufferedInputStream(FileInputStream(file)))
|
||||
DataInputStream(BufferedInputStream(FileInputStream(file))),
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
LogManager.severe("Error reading frames from file", e)
|
||||
|
||||
@@ -34,8 +34,9 @@ class PoseFrames : Iterable<Array<TrackerFrame?>> {
|
||||
* index [index].
|
||||
*/
|
||||
fun getTrackerForPosition(position: TrackerPosition, index: Int = 0): TrackerFrames? {
|
||||
for (tracker in frameHolders)
|
||||
for (tracker in frameHolders) {
|
||||
if (tracker.tryGetFrame(index)?.trackerPosition == position) return tracker
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -51,7 +52,7 @@ class PoseFrames : Iterable<Array<TrackerFrame?>> {
|
||||
get() {
|
||||
return getMaxHeight(
|
||||
getTrackerForPosition(TrackerPosition.HEAD)
|
||||
?: return 0f
|
||||
?: return 0f,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -74,13 +75,13 @@ class PoseFrames : Iterable<Array<TrackerFrame?>> {
|
||||
}
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* @return The maximum number of [TrackerFrame]s contained within each
|
||||
* [TrackerFrames] in the internal [TrackerFrames] list.
|
||||
* @see [TrackerFrames.frames]
|
||||
* @see [List.size]
|
||||
*/
|
||||
val maxFrameCount: Int
|
||||
/**
|
||||
* @return The maximum number of [TrackerFrame]s contained within each
|
||||
* [TrackerFrames] in the internal [TrackerFrames] list.
|
||||
* @see [TrackerFrames.frames]
|
||||
* @see [List.size]
|
||||
*/
|
||||
get() {
|
||||
return frameHolders.maxOfOrNull { tracker -> tracker.frames.size } ?: 0
|
||||
}
|
||||
@@ -137,18 +138,14 @@ class PoseFrames : Iterable<Array<TrackerFrame?>> {
|
||||
return trackerFrames
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<Array<TrackerFrame?>> {
|
||||
return PoseFrameIterator(this)
|
||||
}
|
||||
override fun iterator(): Iterator<Array<TrackerFrame?>> = PoseFrameIterator(this)
|
||||
|
||||
inner class PoseFrameIterator(private val poseFrame: PoseFrames) : Iterator<Array<TrackerFrame?>> {
|
||||
private val trackerFrameBuffer: Array<TrackerFrame?> = arrayOfNulls(poseFrame.frameHolders.size)
|
||||
private val maxCursor = poseFrame.maxFrameCount
|
||||
private var cursor = 0
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return frameHolders.isNotEmpty() && cursor < maxCursor
|
||||
}
|
||||
override fun hasNext(): Boolean = frameHolders.isNotEmpty() && cursor < maxCursor
|
||||
|
||||
override fun next(): Array<TrackerFrame?> {
|
||||
if (!hasNext()) {
|
||||
|
||||
@@ -113,7 +113,7 @@ class PoseRecorder(private val server: VRServer) {
|
||||
|
||||
LogManager
|
||||
.info(
|
||||
"[PoseRecorder] Recording $numFrames samples at a $intervalMs ms frame interval"
|
||||
"[PoseRecorder] Recording $numFrames samples at a $intervalMs ms frame interval",
|
||||
)
|
||||
|
||||
currentFrameCallback = frameCallback
|
||||
@@ -161,9 +161,7 @@ class PoseRecorder(private val server: VRServer) {
|
||||
get() = numFrames > frameCursor
|
||||
|
||||
@Synchronized
|
||||
fun hasRecording(): Boolean {
|
||||
return currentRecording != null
|
||||
}
|
||||
fun hasRecording(): Boolean = currentRecording != null
|
||||
|
||||
@get:Synchronized
|
||||
val framesAsync: Future<PoseFrames>?
|
||||
|
||||
@@ -10,20 +10,20 @@ class TrackerFramesPlayer(vararg val frameHolders: TrackerFrames) {
|
||||
val playerTrackers: Array<PlayerTracker> = frameHolders.map { trackerFrames ->
|
||||
PlayerTracker(
|
||||
trackerFrames,
|
||||
trackerFrames.toTracker()
|
||||
trackerFrames.toTracker(),
|
||||
)
|
||||
}.toTypedArray()
|
||||
|
||||
val trackers: Array<Tracker> =
|
||||
playerTrackers.map { playerTracker -> playerTracker.tracker }.toTypedArray()
|
||||
|
||||
/**
|
||||
* @return The maximum number of [TrackerFrame]s contained within each
|
||||
* [TrackerFrames] in the internal [TrackerFrames] array.
|
||||
* @see [TrackerFrames.frames]
|
||||
* @see [List.size]
|
||||
*/
|
||||
val maxFrameCount: Int
|
||||
/**
|
||||
* @return The maximum number of [TrackerFrame]s contained within each
|
||||
* [TrackerFrames] in the internal [TrackerFrames] array.
|
||||
* @see [TrackerFrames.frames]
|
||||
* @see [List.size]
|
||||
*/
|
||||
get() {
|
||||
return frameHolders.maxOfOrNull { tracker -> tracker.frames.size } ?: 0
|
||||
}
|
||||
|
||||
@@ -40,62 +40,44 @@ data class TrackerFrame(
|
||||
dataFlags = initDataFlags
|
||||
}
|
||||
|
||||
fun hasData(flag: TrackerFrameData): Boolean {
|
||||
return flag.check(dataFlags)
|
||||
}
|
||||
fun hasData(flag: TrackerFrameData): Boolean = flag.check(dataFlags)
|
||||
|
||||
// region Tracker Try Getters
|
||||
fun tryGetTrackerPosition(): TrackerPosition? {
|
||||
return if (hasData(TrackerFrameData.TRACKER_POSITION_ENUM) || hasData(TrackerFrameData.DESIGNATION_STRING)) {
|
||||
trackerPosition
|
||||
} else {
|
||||
null
|
||||
}
|
||||
fun tryGetTrackerPosition(): TrackerPosition? = if (hasData(TrackerFrameData.TRACKER_POSITION_ENUM) || hasData(TrackerFrameData.DESIGNATION_STRING)) {
|
||||
trackerPosition
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
fun tryGetRotation(): Quaternion? {
|
||||
return if (hasData(TrackerFrameData.ROTATION)) {
|
||||
rotation
|
||||
} else {
|
||||
null
|
||||
}
|
||||
fun tryGetRotation(): Quaternion? = if (hasData(TrackerFrameData.ROTATION)) {
|
||||
rotation
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
fun tryGetRawRotation(): Quaternion? {
|
||||
return if (hasData(TrackerFrameData.RAW_ROTATION)) {
|
||||
rawRotation
|
||||
} else {
|
||||
null
|
||||
}
|
||||
fun tryGetRawRotation(): Quaternion? = if (hasData(TrackerFrameData.RAW_ROTATION)) {
|
||||
rawRotation
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
fun tryGetPosition(): Vector3? {
|
||||
return if (hasData(TrackerFrameData.POSITION)) {
|
||||
position
|
||||
} else {
|
||||
null
|
||||
}
|
||||
fun tryGetPosition(): Vector3? = if (hasData(TrackerFrameData.POSITION)) {
|
||||
position
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
fun tryGetAcceleration(): Vector3? {
|
||||
return if (hasData(TrackerFrameData.ACCELERATION)) {
|
||||
acceleration
|
||||
} else {
|
||||
null
|
||||
}
|
||||
fun tryGetAcceleration(): Vector3? = if (hasData(TrackerFrameData.ACCELERATION)) {
|
||||
acceleration
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
fun hasRotation(): Boolean {
|
||||
return hasData(TrackerFrameData.ROTATION)
|
||||
}
|
||||
fun hasRotation(): Boolean = hasData(TrackerFrameData.ROTATION)
|
||||
|
||||
fun hasPosition(): Boolean {
|
||||
return hasData(TrackerFrameData.POSITION)
|
||||
}
|
||||
fun hasPosition(): Boolean = hasData(TrackerFrameData.POSITION)
|
||||
|
||||
fun hasAcceleration(): Boolean {
|
||||
return hasData(TrackerFrameData.ACCELERATION)
|
||||
}
|
||||
fun hasAcceleration(): Boolean = hasData(TrackerFrameData.ACCELERATION)
|
||||
// endregion
|
||||
|
||||
companion object {
|
||||
@@ -128,7 +110,7 @@ data class TrackerFrame(
|
||||
rotation,
|
||||
position,
|
||||
acceleration,
|
||||
rawRotation
|
||||
rawRotation,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
package dev.slimevr.poseframeformat.trackerdata
|
||||
|
||||
enum class TrackerFrameData(id: Int) {
|
||||
DESIGNATION_STRING(0), ROTATION(1), POSITION(2), TRACKER_POSITION_ENUM(3), ACCELERATION(4), RAW_ROTATION(5);
|
||||
DESIGNATION_STRING(0),
|
||||
ROTATION(1),
|
||||
POSITION(2),
|
||||
TRACKER_POSITION_ENUM(3),
|
||||
ACCELERATION(4),
|
||||
RAW_ROTATION(5),
|
||||
;
|
||||
|
||||
val flag: Int
|
||||
|
||||
@@ -13,15 +19,9 @@ enum class TrackerFrameData(id: Int) {
|
||||
* Inline is fine for these, there's no negative to inlining them as they'll never
|
||||
* change, so any warning about it can be safely ignored
|
||||
*/
|
||||
inline fun check(dataFlags: Int): Boolean {
|
||||
return dataFlags and flag != 0
|
||||
}
|
||||
inline fun check(dataFlags: Int): Boolean = dataFlags and flag != 0
|
||||
|
||||
inline fun add(dataFlags: Int): Int {
|
||||
return dataFlags or flag
|
||||
}
|
||||
inline fun add(dataFlags: Int): Int = dataFlags or flag
|
||||
|
||||
inline fun remove(dataFlags: Int): Int {
|
||||
return dataFlags xor flag
|
||||
}
|
||||
inline fun remove(dataFlags: Int): Int = dataFlags xor flag
|
||||
}
|
||||
|
||||
@@ -24,13 +24,9 @@ data class TrackerFrames(val name: String = "", val frames: FastList<TrackerFram
|
||||
return trackerFrame
|
||||
}
|
||||
|
||||
fun tryGetFrame(index: Int): TrackerFrame? {
|
||||
return if (index < 0 || index >= frames.size) null else frames[index]
|
||||
}
|
||||
fun tryGetFrame(index: Int): TrackerFrame? = if (index < 0 || index >= frames.size) null else frames[index]
|
||||
|
||||
fun tryGetFirstNotNullFrame(): TrackerFrame? {
|
||||
return frames.firstOrNull { frame -> frame != null }
|
||||
}
|
||||
fun tryGetFirstNotNullFrame(): TrackerFrame? = frames.firstOrNull { frame -> frame != null }
|
||||
|
||||
fun toTracker(): Tracker {
|
||||
val firstFrame = tryGetFirstNotNullFrame() ?: TrackerFrame.empty
|
||||
@@ -44,7 +40,7 @@ data class TrackerFrames(val name: String = "", val frames: FastList<TrackerFram
|
||||
hasAcceleration = firstFrame.hasAcceleration(),
|
||||
// Make sure this is false!! Otherwise HumanSkeleton ignores it
|
||||
isInternal = false,
|
||||
isComputed = true
|
||||
isComputed = true,
|
||||
)
|
||||
|
||||
tracker.status = TrackerStatus.OK
|
||||
|
||||
@@ -26,19 +26,19 @@ class RPCAutoBoneHandler(
|
||||
init {
|
||||
rpcHandler.registerPacketListener(
|
||||
RpcMessage.AutoBoneProcessRequest,
|
||||
::onAutoBoneProcessRequest
|
||||
::onAutoBoneProcessRequest,
|
||||
)
|
||||
rpcHandler.registerPacketListener(
|
||||
RpcMessage.AutoBoneApplyRequest,
|
||||
::onAutoBoneApplyRequest
|
||||
::onAutoBoneApplyRequest,
|
||||
)
|
||||
rpcHandler.registerPacketListener(
|
||||
RpcMessage.AutoBoneStopRecordingRequest,
|
||||
::onAutoBoneStopRecordingRequest
|
||||
::onAutoBoneStopRecordingRequest,
|
||||
)
|
||||
rpcHandler.registerPacketListener(
|
||||
RpcMessage.AutoBoneCancelRecordingRequest,
|
||||
::onAutoBoneCancelRecordingRequest
|
||||
::onAutoBoneCancelRecordingRequest,
|
||||
)
|
||||
|
||||
this.api.server.autoBoneHandler.addListener(this)
|
||||
@@ -76,7 +76,7 @@ class RPCAutoBoneHandler(
|
||||
AutoBoneProcessStatusResponse.startAutoBoneProcessStatusResponse(fbb)
|
||||
AutoBoneProcessStatusResponse.addProcessType(
|
||||
fbb,
|
||||
processType.id
|
||||
processType.id,
|
||||
)
|
||||
|
||||
AutoBoneProcessStatusResponse.addCurrent(fbb, current)
|
||||
@@ -90,7 +90,7 @@ class RPCAutoBoneHandler(
|
||||
val outbound: Int = rpcHandler.createRPCMessage(
|
||||
fbb,
|
||||
RpcMessage.AutoBoneProcessStatusResponse,
|
||||
update
|
||||
update,
|
||||
)
|
||||
fbb.finish(outbound)
|
||||
conn.send(fbb.dataBuffer())
|
||||
@@ -117,7 +117,7 @@ class RPCAutoBoneHandler(
|
||||
fbb,
|
||||
epoch.configValues.map { (key, value) ->
|
||||
SkeletonPart.createSkeletonPart(fbb, key.id, value)
|
||||
}.toIntArray()
|
||||
}.toIntArray(),
|
||||
)
|
||||
val update = AutoBoneEpochResponse
|
||||
.createAutoBoneEpochResponse(
|
||||
@@ -125,12 +125,12 @@ class RPCAutoBoneHandler(
|
||||
epoch.epoch.toLong(),
|
||||
epoch.totalEpochs.toLong(),
|
||||
epoch.epochError.mean,
|
||||
skeletonPartsOffset
|
||||
skeletonPartsOffset,
|
||||
)
|
||||
val outbound: Int = rpcHandler.createRPCMessage(
|
||||
fbb,
|
||||
RpcMessage.AutoBoneEpochResponse,
|
||||
update
|
||||
update,
|
||||
)
|
||||
fbb.finish(outbound)
|
||||
conn.send(fbb.dataBuffer())
|
||||
@@ -153,7 +153,7 @@ class RPCAutoBoneHandler(
|
||||
val outbound = rpcHandler.createRPCMessage(
|
||||
fbb,
|
||||
RpcMessage.SkeletonConfigResponse,
|
||||
RPCBuilder.createSkeletonConfig(fbb, api.server.humanPoseManager)
|
||||
RPCBuilder.createSkeletonConfig(fbb, api.server.humanPoseManager),
|
||||
)
|
||||
fbb.finish(outbound)
|
||||
conn.send(fbb.dataBuffer())
|
||||
|
||||
@@ -13,8 +13,7 @@ import solarxr_protocol.rpc.TapDetectionSetupNotification
|
||||
class RPCTapSetupHandler(
|
||||
private val rpcHandler: RPCHandler,
|
||||
val api: ProtocolAPI,
|
||||
) :
|
||||
TapSetupListener {
|
||||
) : TapSetupListener {
|
||||
init {
|
||||
this.api.server.tapSetupHandler.addListener(this)
|
||||
}
|
||||
@@ -29,7 +28,7 @@ class RPCTapSetupHandler(
|
||||
|
||||
forAllListeners {
|
||||
it.send(
|
||||
fbb.dataBuffer()
|
||||
fbb.dataBuffer(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ class RPCStatusHandler(
|
||||
val outbound = this.rpcHandler.createRPCMessage(
|
||||
fbb,
|
||||
RpcMessage.StatusSystemUpdate,
|
||||
update
|
||||
update,
|
||||
)
|
||||
fbb.finish(outbound)
|
||||
|
||||
@@ -61,7 +61,7 @@ class RPCStatusHandler(
|
||||
val outbound = this.rpcHandler.createRPCMessage(
|
||||
fbb,
|
||||
RpcMessage.StatusSystemFixed,
|
||||
update
|
||||
update,
|
||||
)
|
||||
fbb.finish(outbound)
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ class RPCTrackingPause(private val rpcHandler: RPCHandler, private val api: Prot
|
||||
init {
|
||||
rpcHandler.registerPacketListener(
|
||||
RpcMessage.TrackingPauseStateRequest,
|
||||
::onTrackingPauseStateRequest
|
||||
::onTrackingPauseStateRequest,
|
||||
)
|
||||
|
||||
// HumanPoseManager might not be immediately available, so queue the server
|
||||
|
||||
@@ -38,14 +38,14 @@ abstract class SerialHandler {
|
||||
// FT232RL/Q, FT245RL/Q
|
||||
// VNC1L with VDPS Firmware
|
||||
// VNC2 with FT232Slave
|
||||
Pair(0x0403, 0x6001)
|
||||
Pair(0x0403, 0x6001),
|
||||
)
|
||||
fun isKnownBoard(port: SerialPort): Boolean =
|
||||
supportedSerial.contains(Pair(port.vendorId, port.productId))
|
||||
}
|
||||
}
|
||||
|
||||
class SerialHandlerStub() : SerialHandler() {
|
||||
class SerialHandlerStub : SerialHandler() {
|
||||
override val isConnected: Boolean = false
|
||||
override val knownPorts: Stream<out SerialPort> = Stream.empty()
|
||||
|
||||
@@ -53,9 +53,7 @@ class SerialHandlerStub() : SerialHandler() {
|
||||
|
||||
override fun removeListener(channel: SerialListener) {}
|
||||
|
||||
override fun openSerial(portLocation: String?, auto: Boolean): Boolean {
|
||||
return false
|
||||
}
|
||||
override fun openSerial(portLocation: String?, auto: Boolean): Boolean = false
|
||||
|
||||
override fun rebootRequest() {}
|
||||
|
||||
|
||||
@@ -61,16 +61,12 @@ class Bone(val boneType: BoneType) {
|
||||
/**
|
||||
* Returns the world-aligned rotation of the bone
|
||||
*/
|
||||
fun getGlobalRotation(): Quaternion {
|
||||
return headNode.worldTransform.rotation
|
||||
}
|
||||
fun getGlobalRotation(): Quaternion = headNode.worldTransform.rotation
|
||||
|
||||
/**
|
||||
* Returns the rotation of the bone relative to its parent
|
||||
*/
|
||||
fun getLocalRotation(): Quaternion {
|
||||
return headNode.localTransform.rotation
|
||||
}
|
||||
fun getLocalRotation(): Quaternion = headNode.localTransform.rotation
|
||||
|
||||
/**
|
||||
* Sets the global rotation of the bone
|
||||
@@ -82,16 +78,12 @@ class Bone(val boneType: BoneType) {
|
||||
/**
|
||||
* Returns the global position of the head of the bone
|
||||
*/
|
||||
fun getPosition(): Vector3 {
|
||||
return headNode.worldTransform.translation
|
||||
}
|
||||
fun getPosition(): Vector3 = headNode.worldTransform.translation
|
||||
|
||||
/**
|
||||
* Returns the global position of the tail of the bone
|
||||
*/
|
||||
fun getTailPosition(): Vector3 {
|
||||
return tailNode.worldTransform.translation
|
||||
}
|
||||
fun getTailPosition(): Vector3 = tailNode.worldTransform.translation
|
||||
|
||||
/**
|
||||
* Sets the global position of the head of the bone.
|
||||
|
||||
@@ -160,7 +160,7 @@ class HumanSkeleton(
|
||||
server.configManager.vrConfig.tapDetection,
|
||||
server.resetHandler,
|
||||
server.tapSetupHandler,
|
||||
server.allTrackers
|
||||
server.allTrackers,
|
||||
)
|
||||
legTweaks.setConfig(server.configManager.vrConfig.legTweaks)
|
||||
localizer.setEnabled(humanPoseManager.getToggle(SkeletonConfigToggles.SELF_LOCALIZATION))
|
||||
@@ -336,21 +336,19 @@ class HumanSkeleton(
|
||||
/**
|
||||
* Get output tracker from TrackerRole
|
||||
*/
|
||||
fun getComputedTracker(trackerRole: TrackerRole): Tracker {
|
||||
return when (trackerRole) {
|
||||
TrackerRole.HEAD -> computedHeadTracker!!
|
||||
TrackerRole.CHEST -> computedChestTracker!!
|
||||
TrackerRole.WAIST -> computedHipTracker!!
|
||||
TrackerRole.LEFT_KNEE -> computedLeftKneeTracker!!
|
||||
TrackerRole.LEFT_FOOT -> computedLeftFootTracker!!
|
||||
TrackerRole.RIGHT_KNEE -> computedRightKneeTracker!!
|
||||
TrackerRole.RIGHT_FOOT -> computedRightFootTracker!!
|
||||
TrackerRole.LEFT_ELBOW -> computedLeftElbowTracker!!
|
||||
TrackerRole.RIGHT_ELBOW -> computedRightElbowTracker!!
|
||||
TrackerRole.LEFT_HAND -> computedLeftHandTracker!!
|
||||
TrackerRole.RIGHT_HAND -> computedRightHandTracker!!
|
||||
else -> throw IllegalArgumentException("Unsupported computed tracker's TrackerRole in HumanSkeleton")
|
||||
}
|
||||
fun getComputedTracker(trackerRole: TrackerRole): Tracker = when (trackerRole) {
|
||||
TrackerRole.HEAD -> computedHeadTracker!!
|
||||
TrackerRole.CHEST -> computedChestTracker!!
|
||||
TrackerRole.WAIST -> computedHipTracker!!
|
||||
TrackerRole.LEFT_KNEE -> computedLeftKneeTracker!!
|
||||
TrackerRole.LEFT_FOOT -> computedLeftFootTracker!!
|
||||
TrackerRole.RIGHT_KNEE -> computedRightKneeTracker!!
|
||||
TrackerRole.RIGHT_FOOT -> computedRightFootTracker!!
|
||||
TrackerRole.LEFT_ELBOW -> computedLeftElbowTracker!!
|
||||
TrackerRole.RIGHT_ELBOW -> computedRightElbowTracker!!
|
||||
TrackerRole.LEFT_HAND -> computedLeftHandTracker!!
|
||||
TrackerRole.RIGHT_HAND -> computedRightHandTracker!!
|
||||
else -> throw IllegalArgumentException("Unsupported computed tracker's TrackerRole in HumanSkeleton")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -403,7 +401,7 @@ class HumanSkeleton(
|
||||
leftFootTrackerBone,
|
||||
leftUpperLegTracker,
|
||||
leftLowerLegTracker,
|
||||
leftFootTracker
|
||||
leftFootTracker,
|
||||
)
|
||||
// Right leg
|
||||
updateLegTransforms(
|
||||
@@ -414,7 +412,7 @@ class HumanSkeleton(
|
||||
rightFootTrackerBone,
|
||||
rightUpperLegTracker,
|
||||
rightLowerLegTracker,
|
||||
rightFootTracker
|
||||
rightFootTracker,
|
||||
)
|
||||
// Left arm
|
||||
updateArmTransforms(
|
||||
@@ -428,7 +426,7 @@ class HumanSkeleton(
|
||||
leftShoulderTracker,
|
||||
leftUpperArmTracker,
|
||||
leftLowerArmTracker,
|
||||
leftHandTracker
|
||||
leftHandTracker,
|
||||
)
|
||||
// Right arm
|
||||
updateArmTransforms(
|
||||
@@ -442,7 +440,7 @@ class HumanSkeleton(
|
||||
rightShoulderTracker,
|
||||
rightUpperArmTracker,
|
||||
rightLowerArmTracker,
|
||||
rightHandTracker
|
||||
rightHandTracker,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -477,7 +475,7 @@ class HumanSkeleton(
|
||||
upperChestTracker,
|
||||
chestTracker,
|
||||
waistTracker,
|
||||
hipTracker
|
||||
hipTracker,
|
||||
)?.let { headRot = it.getRotation() }
|
||||
|
||||
headBone.setRotation(headRot)
|
||||
@@ -840,18 +838,27 @@ class HumanSkeleton(
|
||||
fun updateToggleState(configToggle: SkeletonConfigToggles, newValue: Boolean) {
|
||||
when (configToggle) {
|
||||
SkeletonConfigToggles.EXTENDED_SPINE_MODEL -> extendedSpineModel = newValue
|
||||
|
||||
SkeletonConfigToggles.EXTENDED_PELVIS_MODEL -> extendedPelvisModel = newValue
|
||||
|
||||
SkeletonConfigToggles.EXTENDED_KNEE_MODEL -> extendedKneeModel = newValue
|
||||
|
||||
SkeletonConfigToggles.FORCE_ARMS_FROM_HMD -> {
|
||||
forceArmsFromHMD = newValue
|
||||
assembleSkeletonArms(true) // Rebuilds the arm skeleton nodes attachments
|
||||
computeDependentArmOffsets() // Refresh node offsets for arms
|
||||
}
|
||||
|
||||
SkeletonConfigToggles.SKATING_CORRECTION -> legTweaks.setSkatingCorrectionEnabled(newValue)
|
||||
|
||||
SkeletonConfigToggles.FLOOR_CLIP -> legTweaks.setFloorClipEnabled(newValue)
|
||||
|
||||
SkeletonConfigToggles.VIVE_EMULATION -> viveEmulation.enabled = newValue
|
||||
|
||||
SkeletonConfigToggles.TOE_SNAP -> legTweaks.toeSnapEnabled = newValue
|
||||
|
||||
SkeletonConfigToggles.FOOT_PLANT -> legTweaks.footPlantEnabled = newValue
|
||||
|
||||
SkeletonConfigToggles.SELF_LOCALIZATION -> localizer.setEnabled(newValue)
|
||||
}
|
||||
}
|
||||
@@ -912,42 +919,40 @@ class HumanSkeleton(
|
||||
humanPoseManager.computeNodeOffset(BoneType.RIGHT_HAND)
|
||||
}
|
||||
|
||||
fun getBone(bone: BoneType): Bone {
|
||||
return when (bone) {
|
||||
BoneType.HEAD -> headBone
|
||||
BoneType.HEAD_TRACKER -> headTrackerBone
|
||||
BoneType.NECK -> neckBone
|
||||
BoneType.UPPER_CHEST -> upperChestBone
|
||||
BoneType.CHEST_TRACKER -> chestTrackerBone
|
||||
BoneType.CHEST -> chestBone
|
||||
BoneType.WAIST -> waistBone
|
||||
BoneType.HIP -> hipBone
|
||||
BoneType.HIP_TRACKER -> hipTrackerBone
|
||||
BoneType.LEFT_HIP -> leftHipBone
|
||||
BoneType.RIGHT_HIP -> rightHipBone
|
||||
BoneType.LEFT_UPPER_LEG -> leftUpperLegBone
|
||||
BoneType.RIGHT_UPPER_LEG -> rightUpperLegBone
|
||||
BoneType.LEFT_KNEE_TRACKER -> leftKneeTrackerBone
|
||||
BoneType.RIGHT_KNEE_TRACKER -> rightKneeTrackerBone
|
||||
BoneType.LEFT_LOWER_LEG -> leftLowerLegBone
|
||||
BoneType.RIGHT_LOWER_LEG -> rightLowerLegBone
|
||||
BoneType.LEFT_FOOT -> leftFootBone
|
||||
BoneType.RIGHT_FOOT -> rightFootBone
|
||||
BoneType.LEFT_FOOT_TRACKER -> leftFootTrackerBone
|
||||
BoneType.RIGHT_FOOT_TRACKER -> rightFootTrackerBone
|
||||
BoneType.LEFT_SHOULDER -> leftShoulderBone
|
||||
BoneType.RIGHT_SHOULDER -> rightShoulderBone
|
||||
BoneType.LEFT_UPPER_ARM -> leftUpperArmBone
|
||||
BoneType.RIGHT_UPPER_ARM -> rightUpperArmBone
|
||||
BoneType.LEFT_ELBOW_TRACKER -> leftElbowTrackerBone
|
||||
BoneType.RIGHT_ELBOW_TRACKER -> rightElbowTrackerBone
|
||||
BoneType.LEFT_LOWER_ARM -> leftLowerArmBone
|
||||
BoneType.RIGHT_LOWER_ARM -> rightLowerArmBone
|
||||
BoneType.LEFT_HAND -> leftHandBone
|
||||
BoneType.RIGHT_HAND -> rightHandBone
|
||||
BoneType.LEFT_HAND_TRACKER -> leftHandTrackerBone
|
||||
BoneType.RIGHT_HAND_TRACKER -> rightHandTrackerBone
|
||||
}
|
||||
fun getBone(bone: BoneType): Bone = when (bone) {
|
||||
BoneType.HEAD -> headBone
|
||||
BoneType.HEAD_TRACKER -> headTrackerBone
|
||||
BoneType.NECK -> neckBone
|
||||
BoneType.UPPER_CHEST -> upperChestBone
|
||||
BoneType.CHEST_TRACKER -> chestTrackerBone
|
||||
BoneType.CHEST -> chestBone
|
||||
BoneType.WAIST -> waistBone
|
||||
BoneType.HIP -> hipBone
|
||||
BoneType.HIP_TRACKER -> hipTrackerBone
|
||||
BoneType.LEFT_HIP -> leftHipBone
|
||||
BoneType.RIGHT_HIP -> rightHipBone
|
||||
BoneType.LEFT_UPPER_LEG -> leftUpperLegBone
|
||||
BoneType.RIGHT_UPPER_LEG -> rightUpperLegBone
|
||||
BoneType.LEFT_KNEE_TRACKER -> leftKneeTrackerBone
|
||||
BoneType.RIGHT_KNEE_TRACKER -> rightKneeTrackerBone
|
||||
BoneType.LEFT_LOWER_LEG -> leftLowerLegBone
|
||||
BoneType.RIGHT_LOWER_LEG -> rightLowerLegBone
|
||||
BoneType.LEFT_FOOT -> leftFootBone
|
||||
BoneType.RIGHT_FOOT -> rightFootBone
|
||||
BoneType.LEFT_FOOT_TRACKER -> leftFootTrackerBone
|
||||
BoneType.RIGHT_FOOT_TRACKER -> rightFootTrackerBone
|
||||
BoneType.LEFT_SHOULDER -> leftShoulderBone
|
||||
BoneType.RIGHT_SHOULDER -> rightShoulderBone
|
||||
BoneType.LEFT_UPPER_ARM -> leftUpperArmBone
|
||||
BoneType.RIGHT_UPPER_ARM -> rightUpperArmBone
|
||||
BoneType.LEFT_ELBOW_TRACKER -> leftElbowTrackerBone
|
||||
BoneType.RIGHT_ELBOW_TRACKER -> rightElbowTrackerBone
|
||||
BoneType.LEFT_LOWER_ARM -> leftLowerArmBone
|
||||
BoneType.RIGHT_LOWER_ARM -> rightLowerArmBone
|
||||
BoneType.LEFT_HAND -> leftHandBone
|
||||
BoneType.RIGHT_HAND -> rightHandBone
|
||||
BoneType.LEFT_HAND_TRACKER -> leftHandTrackerBone
|
||||
BoneType.RIGHT_HAND_TRACKER -> rightHandTrackerBone
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -976,7 +981,7 @@ class HumanSkeleton(
|
||||
leftLowerArmBone,
|
||||
rightLowerArmBone,
|
||||
leftHandBone,
|
||||
rightHandBone
|
||||
rightHandBone,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -995,28 +1000,30 @@ class HumanSkeleton(
|
||||
leftHandBone,
|
||||
rightHandBone,
|
||||
leftHandTrackerBone,
|
||||
rightHandTrackerBone
|
||||
rightHandTrackerBone,
|
||||
)
|
||||
|
||||
val hmdHeight: Float
|
||||
get() = headTracker?.position?.y ?: 0f
|
||||
|
||||
/**
|
||||
* Runs checks to know if we should (and are) performing the tracking of the
|
||||
* left arm from the controller.
|
||||
*
|
||||
* @return a bool telling us if we are tracking the left arm from the
|
||||
* controller or not.
|
||||
*/
|
||||
val isTrackingLeftArmFromController: Boolean
|
||||
/**
|
||||
* Runs checks to know if we should (and are) performing the tracking of the
|
||||
* left arm from the controller.
|
||||
*
|
||||
* @return a bool telling us if we are tracking the left arm from the
|
||||
* controller or not.
|
||||
*/
|
||||
get() = leftHandTracker != null && leftHandTracker!!.hasPosition && !forceArmsFromHMD
|
||||
|
||||
/**
|
||||
* Runs checks to know if we should (and are) performing the tracking of the
|
||||
* right arm from the controller.
|
||||
*
|
||||
* @return a bool telling us if we are tracking the right arm from the
|
||||
* controller or not.
|
||||
*/
|
||||
val isTrackingRightArmFromController: Boolean
|
||||
/**
|
||||
* Runs checks to know if we should (and are) performing the tracking of the
|
||||
* right arm from the controller.
|
||||
*
|
||||
* @return a bool telling us if we are tracking the right arm from the
|
||||
* controller or not.
|
||||
*/
|
||||
get() = rightHandTracker != null && rightHandTracker!!.hasPosition && !forceArmsFromHMD
|
||||
val localTrackers: List<Tracker?>
|
||||
get() = listOf(
|
||||
@@ -1037,7 +1044,7 @@ class HumanSkeleton(
|
||||
leftHandTracker,
|
||||
rightHandTracker,
|
||||
leftShoulderTracker,
|
||||
rightShoulderTracker
|
||||
rightShoulderTracker,
|
||||
)
|
||||
|
||||
fun resetTrackersFull(resetSourceName: String?) {
|
||||
@@ -1167,7 +1174,7 @@ class HumanSkeleton(
|
||||
if (skatingCorrection) {
|
||||
legTweaks
|
||||
.setSkatingCorrectionEnabled(
|
||||
humanPoseManager.getToggle(SkeletonConfigToggles.SKATING_CORRECTION)
|
||||
humanPoseManager.getToggle(SkeletonConfigToggles.SKATING_CORRECTION),
|
||||
)
|
||||
}
|
||||
if (floorClip) {
|
||||
@@ -1206,9 +1213,7 @@ class HumanSkeleton(
|
||||
humanPoseManager.setToggle(SkeletonConfigToggles.SKATING_CORRECTION, value)
|
||||
}
|
||||
|
||||
fun getPauseTracking(): Boolean {
|
||||
return pauseTracking
|
||||
}
|
||||
fun getPauseTracking(): Boolean = pauseTracking
|
||||
|
||||
fun setPauseTracking(pauseTracking: Boolean, sourceName: String?) {
|
||||
if (!pauseTracking && this.pauseTracking) {
|
||||
@@ -1232,7 +1237,7 @@ class HumanSkeleton(
|
||||
EulerOrder.YZX,
|
||||
FastMath.HALF_PI,
|
||||
0f,
|
||||
0f
|
||||
0f,
|
||||
).toQuaternion()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
fun tweakLegs() {
|
||||
// If user doesn't have knees or legtweaks is disabled,
|
||||
// don't spend time doing calculations!
|
||||
if (!skeleton.hasKneeTrackers && !alwaysUseFloorclip || !enabled) return
|
||||
if ((!skeleton.hasKneeTrackers && !alwaysUseFloorclip) || !enabled) return
|
||||
|
||||
// update the class with the latest data from the skeleton
|
||||
// if false is returned something indicated that the legs should not
|
||||
@@ -205,11 +205,11 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
// (use the buffer to get the positions before corrections)
|
||||
val leftFootDif = FastMath
|
||||
.abs(
|
||||
(bufferHead.leftFootPosition - leftFootPosition).y
|
||||
(bufferHead.leftFootPosition - leftFootPosition).y,
|
||||
)
|
||||
val rightFootDif = FastMath
|
||||
.abs(
|
||||
(bufferHead.rightFootPosition - rightFootPosition).y
|
||||
(bufferHead.rightFootPosition - rightFootPosition).y,
|
||||
)
|
||||
|
||||
if (!active && leftFootDif < NEARLY_ZERO) {
|
||||
@@ -228,24 +228,24 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
leftFootPosition = Vector3(
|
||||
leftFootPosition.x,
|
||||
bufferHead.leftFootPosition.y,
|
||||
leftFootPosition.z
|
||||
leftFootPosition.z,
|
||||
)
|
||||
leftKneePosition = Vector3(
|
||||
leftKneePosition.x,
|
||||
bufferHead.leftKneePosition.y,
|
||||
leftKneePosition.z
|
||||
leftKneePosition.z,
|
||||
)
|
||||
}
|
||||
if (!rightLegActive) {
|
||||
rightFootPosition = Vector3(
|
||||
rightFootPosition.x,
|
||||
bufferHead.rightFootPosition.y,
|
||||
rightFootPosition.z
|
||||
rightFootPosition.z,
|
||||
)
|
||||
rightKneePosition = Vector3(
|
||||
rightKneePosition.x,
|
||||
bufferHead.rightKneePosition.y,
|
||||
rightKneePosition.z
|
||||
rightKneePosition.z,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
rightFootPosition,
|
||||
leftKneePosition,
|
||||
rightKneePosition,
|
||||
hipPosition
|
||||
hipPosition,
|
||||
)
|
||||
|
||||
// Set the corrected positions in the skeleton
|
||||
@@ -275,21 +275,19 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
LegTweaksBuffer.setSkatingVelocityThreshold(
|
||||
getScaledHyperParameter(
|
||||
newStrength,
|
||||
LegTweaksBuffer.getSkatingVelocityThreshold()
|
||||
)
|
||||
LegTweaksBuffer.getSkatingVelocityThreshold(),
|
||||
),
|
||||
)
|
||||
LegTweaksBuffer.setSkatingAccelerationThreshold(
|
||||
getScaledHyperParameter(
|
||||
newStrength,
|
||||
LegTweaksBuffer.getSkatingAccelerationThreshold()
|
||||
)
|
||||
LegTweaksBuffer.getSkatingAccelerationThreshold(),
|
||||
),
|
||||
)
|
||||
currentCorrectionStrength = newStrength
|
||||
}
|
||||
|
||||
private fun getScaledHyperParameter(newStrength: Float, currentValue: Float): Float {
|
||||
return currentValue - currentCorrectionStrength * MAX_CORRECTION_STRENGTH_DELTA + newStrength * MAX_CORRECTION_STRENGTH_DELTA
|
||||
}
|
||||
private fun getScaledHyperParameter(newStrength: Float, currentValue: Float): Float = currentValue - currentCorrectionStrength * MAX_CORRECTION_STRENGTH_DELTA + newStrength * MAX_CORRECTION_STRENGTH_DELTA
|
||||
|
||||
private fun setFloorLevel(floorLevel: Float) {
|
||||
this.floorLevel = floorLevel
|
||||
@@ -350,7 +348,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
rightFootPosition,
|
||||
leftKneePosition,
|
||||
rightKneePosition,
|
||||
hipPosition
|
||||
hipPosition,
|
||||
)
|
||||
|
||||
// if active correct clipping before populating corrected positions
|
||||
@@ -364,7 +362,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
rightFootPosition,
|
||||
leftKneePosition,
|
||||
rightKneePosition,
|
||||
hipPosition
|
||||
hipPosition,
|
||||
)
|
||||
bufferHead.leftLegState = LegTweaksBuffer.UNLOCKED
|
||||
bufferHead.rightLegState = LegTweaksBuffer.UNLOCKED
|
||||
@@ -404,7 +402,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
hipPosition,
|
||||
centerOfMass,
|
||||
bufferHead,
|
||||
active
|
||||
active,
|
||||
)
|
||||
|
||||
// update the lock duration counters
|
||||
@@ -412,12 +410,10 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
}
|
||||
|
||||
// returns true if the foot is clipped and false if it is not
|
||||
private fun isClipped(leftOffset: Float, rightOffset: Float): Boolean {
|
||||
return (
|
||||
leftFootPosition.y < floorLevel + leftOffset * footLength ||
|
||||
rightFootPosition.y < floorLevel + rightOffset * footLength
|
||||
)
|
||||
}
|
||||
private fun isClipped(leftOffset: Float, rightOffset: Float): Boolean = (
|
||||
leftFootPosition.y < floorLevel + leftOffset * footLength ||
|
||||
rightFootPosition.y < floorLevel + rightOffset * footLength
|
||||
)
|
||||
|
||||
// corrects the foot position to be above the floor level that is calculated
|
||||
// on calibration
|
||||
@@ -440,17 +436,17 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
(
|
||||
floorLevel + footLength * leftOffset - leftFootPosition.y -
|
||||
currentDisengagementOffset
|
||||
)
|
||||
),
|
||||
)
|
||||
leftFootPosition = Vector3(
|
||||
leftFootPosition.x,
|
||||
leftFootPosition.y + displacement,
|
||||
leftFootPosition.z
|
||||
leftFootPosition.z,
|
||||
)
|
||||
leftKneePosition = Vector3(
|
||||
leftKneePosition.x,
|
||||
leftKneePosition.y + displacement,
|
||||
leftKneePosition.z
|
||||
leftKneePosition.z,
|
||||
)
|
||||
avgOffset += displacement
|
||||
}
|
||||
@@ -463,17 +459,17 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
(
|
||||
floorLevel + footLength * rightOffset - rightFootPosition.y -
|
||||
currentDisengagementOffset
|
||||
)
|
||||
),
|
||||
)
|
||||
rightFootPosition = Vector3(
|
||||
rightFootPosition.x,
|
||||
rightFootPosition.y + displacement,
|
||||
rightFootPosition.z
|
||||
rightFootPosition.z,
|
||||
)
|
||||
rightKneePosition = Vector3(
|
||||
rightKneePosition.x,
|
||||
rightKneePosition.y + displacement,
|
||||
rightKneePosition.z
|
||||
rightKneePosition.z,
|
||||
)
|
||||
avgOffset += displacement
|
||||
}
|
||||
@@ -481,7 +477,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
hipPosition = Vector3(
|
||||
hipPosition.x,
|
||||
hipPosition.y + avgOffset / 2 * WAIST_PUSH_WEIGHT,
|
||||
hipPosition.z
|
||||
hipPosition.z,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -500,7 +496,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
leftFootPosition.y,
|
||||
bufPrev
|
||||
.leftFootPositionCorrected
|
||||
.z
|
||||
.z,
|
||||
)
|
||||
}
|
||||
if (bufferHead.rightLegState == LegTweaksBuffer.LOCKED) {
|
||||
@@ -511,7 +507,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
rightFootPosition.y,
|
||||
bufPrev
|
||||
.rightFootPositionCorrected
|
||||
.z
|
||||
.z,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -549,7 +545,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
// applied
|
||||
val weight: Float = calculateCorrectionWeight(
|
||||
newFootPosition,
|
||||
previousFootPositionCorrected
|
||||
previousFootPositionCorrected,
|
||||
)
|
||||
val constantCorrection = getConstantCorrectionQuantity(framesUnlocked)
|
||||
var newX = newFootPosition.x
|
||||
@@ -598,7 +594,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
if (checkOverShoot(
|
||||
footPosition.x,
|
||||
previousFootPositionCorrected.x,
|
||||
newX
|
||||
newX,
|
||||
)
|
||||
) {
|
||||
newX = footPosition.x
|
||||
@@ -606,7 +602,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
if (checkOverShoot(
|
||||
footPosition.z,
|
||||
previousFootPositionCorrected.z,
|
||||
newZ
|
||||
newZ,
|
||||
)
|
||||
) {
|
||||
newZ = footPosition.z
|
||||
@@ -618,15 +614,13 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
}
|
||||
|
||||
// get the amount of the constant correction to apply.
|
||||
private fun getConstantCorrectionQuantity(framesUnlocked: Int): Float {
|
||||
return if (framesUnlocked >= CONTINUOUS_CORRECTION_WARMUP) {
|
||||
private fun getConstantCorrectionQuantity(framesUnlocked: Int): Float = if (framesUnlocked >= CONTINUOUS_CORRECTION_WARMUP) {
|
||||
CONTINUOUS_CORRECTION_DIST
|
||||
} else {
|
||||
(
|
||||
CONTINUOUS_CORRECTION_DIST
|
||||
} else {
|
||||
(
|
||||
CONTINUOUS_CORRECTION_DIST
|
||||
* (leftFramesUnlocked.toFloat() / CONTINUOUS_CORRECTION_WARMUP)
|
||||
)
|
||||
}
|
||||
* (leftFramesUnlocked.toFloat() / CONTINUOUS_CORRECTION_WARMUP)
|
||||
)
|
||||
}
|
||||
|
||||
// correct the rotations of the feet
|
||||
@@ -660,12 +654,12 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
// if foot trackers exist add to the weights
|
||||
if (leftFootTracker) {
|
||||
weightL *= getRotationalDistanceToPlant(
|
||||
leftFootRotation
|
||||
leftFootRotation,
|
||||
)
|
||||
}
|
||||
if (rightFootTracker) {
|
||||
weightR *= getRotationalDistanceToPlant(
|
||||
rightFootRotation
|
||||
rightFootRotation,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -673,12 +667,12 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
leftFootRotation = leftFootRotation
|
||||
.interpR(
|
||||
isolateYaw(leftFootRotation),
|
||||
weightL * masterWeightL
|
||||
weightL * masterWeightL,
|
||||
)
|
||||
rightFootRotation = rightFootRotation
|
||||
.interpR(
|
||||
isolateYaw(rightFootRotation),
|
||||
weightR * masterWeightR
|
||||
weightR * masterWeightR,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -711,14 +705,14 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
leftFootRotation = leftFootRotation
|
||||
.interpR(
|
||||
replacePitch(leftFootRotation, -angleL),
|
||||
weightL * masterWeightL
|
||||
weightL * masterWeightL,
|
||||
)
|
||||
}
|
||||
if (!rightFootTracker) {
|
||||
rightFootRotation = rightFootRotation
|
||||
.interpR(
|
||||
replacePitch(rightFootRotation, -angleR),
|
||||
weightR * masterWeightR
|
||||
weightR * masterWeightR,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -796,11 +790,11 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
val angle = FastMath.clamp(footPos.y - floorLevel, 0.0f, footLength)
|
||||
return if (angle > footLength * MAXIMUM_TOE_DOWN_ANGLE) {
|
||||
FastMath.asin(
|
||||
footLength * MAXIMUM_TOE_DOWN_ANGLE / footLength
|
||||
footLength * MAXIMUM_TOE_DOWN_ANGLE / footLength,
|
||||
)
|
||||
} else {
|
||||
FastMath.asin(
|
||||
angle / footLength
|
||||
angle / footLength,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -820,7 +814,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
angle = FastMath.clamp(
|
||||
angle,
|
||||
MIN_DISTANCE_FOR_PLANT,
|
||||
MAX_DISTANCE_FOR_PLANT
|
||||
MAX_DISTANCE_FOR_PLANT,
|
||||
)
|
||||
return (
|
||||
1 -
|
||||
@@ -955,16 +949,16 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
|
||||
if (armsAvailable) {
|
||||
val leftUpperArm: Vector3 = getCenterOfJoint(
|
||||
skeleton.leftUpperArmBone
|
||||
skeleton.leftUpperArmBone,
|
||||
)
|
||||
val rightUpperArm: Vector3 = getCenterOfJoint(
|
||||
skeleton.rightUpperArmBone
|
||||
skeleton.rightUpperArmBone,
|
||||
)
|
||||
val leftForearm: Vector3 = getCenterOfJoint(
|
||||
skeleton.leftLowerArmBone
|
||||
skeleton.leftLowerArmBone,
|
||||
)
|
||||
val rightForearm: Vector3 = getCenterOfJoint(
|
||||
skeleton.rightLowerArmBone
|
||||
skeleton.rightLowerArmBone,
|
||||
)
|
||||
centerOfMass += leftUpperArm * UPPER_ARM_MASS
|
||||
centerOfMass += rightUpperArm * UPPER_ARM_MASS
|
||||
@@ -974,7 +968,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
// if the arms are not available put them slightly in front
|
||||
// of the upper chest.
|
||||
val chestUnitVector: Vector3 = computeUnitVector(
|
||||
skeleton.upperChestBone.getGlobalRotation()
|
||||
skeleton.upperChestBone.getGlobalRotation(),
|
||||
)
|
||||
val armLocation =
|
||||
abdomen + (chestUnitVector * DEFAULT_ARM_DISTANCE)
|
||||
@@ -989,13 +983,11 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
}
|
||||
|
||||
// get the center of two joints
|
||||
private fun getCenterOfJoint(bone: Bone): Vector3 {
|
||||
return (
|
||||
bone.getPosition() +
|
||||
bone.getTailPosition()
|
||||
) *
|
||||
0.5f
|
||||
}
|
||||
private fun getCenterOfJoint(bone: Bone): Vector3 = (
|
||||
bone.getPosition() +
|
||||
bone.getTailPosition()
|
||||
) *
|
||||
0.5f
|
||||
|
||||
// update counters for the lock state of the feet
|
||||
private fun updateLockStateCounters() {
|
||||
@@ -1016,14 +1008,12 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
}
|
||||
|
||||
// remove the x and z components of the given quaternion
|
||||
private fun isolateYaw(quaternion: Quaternion): Quaternion {
|
||||
return Quaternion(
|
||||
quaternion.w,
|
||||
0f,
|
||||
quaternion.y,
|
||||
0f
|
||||
)
|
||||
}
|
||||
private fun isolateYaw(quaternion: Quaternion): Quaternion = Quaternion(
|
||||
quaternion.w,
|
||||
0f,
|
||||
quaternion.y,
|
||||
0f,
|
||||
)
|
||||
|
||||
// return a quaternion that has been rotated by the new pitch amount
|
||||
private fun replacePitch(quaternion: Quaternion, newPitch: Float): Quaternion {
|
||||
@@ -1032,7 +1022,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
EulerOrder.YZX,
|
||||
newPitch,
|
||||
y,
|
||||
z
|
||||
z,
|
||||
)
|
||||
return newAngs.toQuaternion()
|
||||
}
|
||||
@@ -1043,12 +1033,8 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
|
||||
trueVal: Float,
|
||||
valBefore: Float,
|
||||
valAfter: Float,
|
||||
): Boolean {
|
||||
return (trueVal - valBefore) * (trueVal - valAfter) < 0
|
||||
}
|
||||
): Boolean = (trueVal - valBefore) * (trueVal - valAfter) < 0
|
||||
|
||||
// get the unit vector of the given rotation
|
||||
private fun computeUnitVector(quaternion: Quaternion): Vector3 {
|
||||
return quaternion.toMatrix().z.unit()
|
||||
}
|
||||
private fun computeUnitVector(quaternion: Quaternion): Vector3 = quaternion.toMatrix().z.unit()
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import io.github.axisangles.ktmath.Vector3
|
||||
* large range of actions and body types.
|
||||
*/
|
||||
|
||||
class LegTweaksBuffer() {
|
||||
class LegTweaksBuffer @Suppress("ktlint") constructor() {
|
||||
// hyperparameters / constants
|
||||
companion object {
|
||||
const val STATE_UNKNOWN = 0
|
||||
@@ -92,9 +92,7 @@ class LegTweaksBuffer() {
|
||||
)
|
||||
}
|
||||
|
||||
fun getSkatingVelocityThreshold(): Float {
|
||||
return SKATING_VELOCITY_THRESHOLD
|
||||
}
|
||||
fun getSkatingVelocityThreshold(): Float = SKATING_VELOCITY_THRESHOLD
|
||||
|
||||
fun setSkatingAccelerationThreshold(value: Float) {
|
||||
SKATING_ACCELERATION_THRESHOLD = value
|
||||
@@ -104,9 +102,7 @@ class LegTweaksBuffer() {
|
||||
)
|
||||
}
|
||||
|
||||
fun getSkatingAccelerationThreshold(): Float {
|
||||
return SKATING_ACCELERATION_THRESHOLD
|
||||
}
|
||||
fun getSkatingAccelerationThreshold(): Float = SKATING_ACCELERATION_THRESHOLD
|
||||
}
|
||||
|
||||
// states for the legs
|
||||
@@ -267,9 +263,7 @@ class LegTweaksBuffer() {
|
||||
}
|
||||
|
||||
// returns 1 / delta time
|
||||
fun getTimeDelta(): Float {
|
||||
return if (parent == null) 0.0f else 1.0f / ((timeOfFrame - parent!!.timeOfFrame) / NS_CONVERT)
|
||||
}
|
||||
fun getTimeDelta(): Float = if (parent == null) 0.0f else 1.0f / ((timeOfFrame - parent!!.timeOfFrame) / NS_CONVERT)
|
||||
|
||||
// calculate movement attributes
|
||||
private fun calculateFootAttributes(active: Boolean) {
|
||||
@@ -322,7 +316,7 @@ class LegTweaksBuffer() {
|
||||
leftFootAngleDiff,
|
||||
leftFloorLevel,
|
||||
accelerationAboveThresholdLeft,
|
||||
leftFootPosition
|
||||
leftFootPosition,
|
||||
)
|
||||
rightLegState = checkState(
|
||||
parent!!.rightLegState,
|
||||
@@ -332,7 +326,7 @@ class LegTweaksBuffer() {
|
||||
rightFootAngleDiff,
|
||||
rightFloorLevel,
|
||||
accelerationAboveThresholdRight,
|
||||
rightFootPosition
|
||||
rightFootPosition,
|
||||
)
|
||||
|
||||
computeNumericalState()
|
||||
@@ -381,13 +375,13 @@ class LegTweaksBuffer() {
|
||||
leftFootVelocityMagnitude,
|
||||
leftFootAccelerationMagnitude,
|
||||
leftFootSensitivityAccel,
|
||||
leftFootSensitivityVel
|
||||
leftFootSensitivityVel,
|
||||
)
|
||||
rightLegNumericalState = computeNumericalState(
|
||||
rightFootVelocityMagnitude,
|
||||
rightFootAccelerationMagnitude,
|
||||
rightFootSensitivityAccel,
|
||||
rightFootSensitivityVel
|
||||
rightFootSensitivityVel,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -417,14 +411,12 @@ class LegTweaksBuffer() {
|
||||
return Vector3(
|
||||
diff.x,
|
||||
0f,
|
||||
diff.z
|
||||
diff.z,
|
||||
).len()
|
||||
}
|
||||
|
||||
// get the angular velocity of the left foot (kinda we just want a scalar)
|
||||
private fun getFootAngularVelocity(oldRot: Quaternion, rot: Quaternion): Float {
|
||||
return (rot.toMatrix().z.unit() - oldRot.toMatrix().z.unit()).len()
|
||||
}
|
||||
private fun getFootAngularVelocity(oldRot: Quaternion, rot: Quaternion): Float = (rot.toMatrix().z.unit() - oldRot.toMatrix().z.unit()).len()
|
||||
|
||||
// compute the velocity of the feet from the position in the last frames
|
||||
private fun computeVelocity() {
|
||||
@@ -438,9 +430,7 @@ class LegTweaksBuffer() {
|
||||
}
|
||||
|
||||
// get the nth parent of this frame
|
||||
private fun getNParent(n: Int): LegTweaksBuffer? {
|
||||
return if (n == 0 || parent == null) this else parent!!.getNParent(n - 1)
|
||||
}
|
||||
private fun getNParent(n: Int): LegTweaksBuffer? = if (n == 0 || parent == null) this else parent!!.getNParent(n - 1)
|
||||
|
||||
// compute the acceleration magnitude of the feet from the acceleration
|
||||
// given by the imus
|
||||
@@ -459,11 +449,11 @@ class LegTweaksBuffer() {
|
||||
private fun computeAccelerationAboveThresholdFootTrackers() {
|
||||
accelerationAboveThresholdLeft = (
|
||||
leftFootAccelerationMagnitude
|
||||
> SKATING_ACCELERATION_CUTOFF_ENGAGE * leftFootSensitivityAccel
|
||||
> SKATING_ACCELERATION_CUTOFF_ENGAGE * leftFootSensitivityAccel
|
||||
)
|
||||
accelerationAboveThresholdRight = (
|
||||
rightFootAccelerationMagnitude
|
||||
> SKATING_ACCELERATION_CUTOFF_ENGAGE * rightFootSensitivityAccel
|
||||
> SKATING_ACCELERATION_CUTOFF_ENGAGE * rightFootSensitivityAccel
|
||||
)
|
||||
}
|
||||
|
||||
@@ -472,11 +462,11 @@ class LegTweaksBuffer() {
|
||||
private fun computeAccelerationAboveThresholdAnkleTrackers() {
|
||||
accelerationAboveThresholdLeft = (
|
||||
leftFootAccelerationMagnitude
|
||||
> (SKATING_ACCELERATION_THRESHOLD + SIX_TRACKER_TOLERANCE) * leftFootSensitivityAccel
|
||||
> (SKATING_ACCELERATION_THRESHOLD + SIX_TRACKER_TOLERANCE) * leftFootSensitivityAccel
|
||||
)
|
||||
accelerationAboveThresholdRight = (
|
||||
rightFootAccelerationMagnitude
|
||||
> (SKATING_ACCELERATION_THRESHOLD + SIX_TRACKER_TOLERANCE) * rightFootSensitivityAccel
|
||||
> (SKATING_ACCELERATION_THRESHOLD + SIX_TRACKER_TOLERANCE) * rightFootSensitivityAccel
|
||||
)
|
||||
}
|
||||
|
||||
@@ -494,13 +484,13 @@ class LegTweaksBuffer() {
|
||||
leftFootVelocity,
|
||||
rightFootVelocity,
|
||||
leftFootVelocityMagnitude,
|
||||
rightFootVelocityMagnitude
|
||||
rightFootVelocityMagnitude,
|
||||
)
|
||||
val rightFootScalarVel: Float = getFootLockLikelihood(
|
||||
rightFootVelocity,
|
||||
leftFootVelocity,
|
||||
rightFootVelocityMagnitude,
|
||||
leftFootVelocityMagnitude
|
||||
leftFootVelocityMagnitude,
|
||||
)
|
||||
|
||||
// get the third set of scalars that is based on where the COM is
|
||||
@@ -515,7 +505,7 @@ class LegTweaksBuffer() {
|
||||
FastMath.clamp(
|
||||
pressureScalars[0] * 2.0f,
|
||||
PRESSURE_SCALAR_MIN,
|
||||
PRESSURE_SCALAR_MAX
|
||||
PRESSURE_SCALAR_MAX,
|
||||
)
|
||||
)
|
||||
rightFootSensitivityVel = (
|
||||
@@ -526,7 +516,7 @@ class LegTweaksBuffer() {
|
||||
FastMath.clamp(
|
||||
pressureScalars[1] * 2.0f,
|
||||
PRESSURE_SCALAR_MIN,
|
||||
PRESSURE_SCALAR_MAX
|
||||
PRESSURE_SCALAR_MAX,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -728,7 +718,5 @@ class LegTweaksBuffer() {
|
||||
}
|
||||
|
||||
// simple error function for the force vector gradient descent
|
||||
private fun getForceVectorError(testForce: Vector3, otherForce: Vector3): Vector3 {
|
||||
return centerOfMassAcceleration - (testForce + otherForce + GRAVITY)
|
||||
}
|
||||
private fun getForceVectorError(testForce: Vector3, otherForce: Vector3): Vector3 = centerOfMassAcceleration - (testForce + otherForce + GRAVITY)
|
||||
}
|
||||
|
||||
@@ -66,9 +66,7 @@ class Localizer(humanSkeleton: HumanSkeleton) {
|
||||
private var comTravel: Vector3 = Vector3.NULL
|
||||
private var sittingTravel: Vector3 = Vector3.NULL
|
||||
|
||||
fun getEnabled(): Boolean {
|
||||
return enabled
|
||||
}
|
||||
fun getEnabled(): Boolean = enabled
|
||||
|
||||
fun setEnabled(enabled: Boolean) {
|
||||
this.enabled = enabled
|
||||
@@ -133,7 +131,7 @@ class Localizer(humanSkeleton: HumanSkeleton) {
|
||||
finalTravel = Vector3(
|
||||
finalTravel.x,
|
||||
comTravel.y,
|
||||
finalTravel.z
|
||||
finalTravel.z,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -214,9 +212,7 @@ class Localizer(humanSkeleton: HumanSkeleton) {
|
||||
}
|
||||
|
||||
// get the travel of a foot over a frame
|
||||
private fun getFootTravel(loc: Vector3): Vector3 {
|
||||
return loc - targetFoot
|
||||
}
|
||||
private fun getFootTravel(loc: Vector3): Vector3 = loc - targetFoot
|
||||
|
||||
// update the target position of the foot
|
||||
private fun updateTargetPos(loc: Vector3, foot: MovementStates) {
|
||||
@@ -319,7 +315,7 @@ class Localizer(humanSkeleton: HumanSkeleton) {
|
||||
comAccel = Vector3(
|
||||
comAccel.x,
|
||||
FastMath.clamp(comAccel.y, -9999.0f, 0.0f),
|
||||
comAccel.z
|
||||
comAccel.z,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -331,19 +327,17 @@ class Localizer(humanSkeleton: HumanSkeleton) {
|
||||
comVelocity = Vector3(
|
||||
comVelocity.x,
|
||||
comY + (gravity / bufCur.getTimeDelta()),
|
||||
comVelocity.z
|
||||
comVelocity.z,
|
||||
)
|
||||
|
||||
return comVelocity
|
||||
}
|
||||
|
||||
// returns true if either foot is below 0.0
|
||||
private fun isFootOnGround(): Boolean {
|
||||
return (
|
||||
bufCur.leftFootPosition.y <= floor ||
|
||||
bufCur.rightFootPosition.y <= floor
|
||||
)
|
||||
}
|
||||
private fun isFootOnGround(): Boolean = (
|
||||
bufCur.leftFootPosition.y <= floor ||
|
||||
bufCur.rightFootPosition.y <= floor
|
||||
)
|
||||
|
||||
// returns the tracker closest to or the furthest in the ground
|
||||
private fun getLowestTracker(): Tracker? {
|
||||
@@ -358,7 +352,7 @@ class Localizer(humanSkeleton: HumanSkeleton) {
|
||||
skeleton.computedLeftKneeTracker,
|
||||
skeleton.computedRightKneeTracker,
|
||||
skeleton.computedLeftFootTracker,
|
||||
skeleton.computedRightFootTracker
|
||||
skeleton.computedRightFootTracker,
|
||||
)
|
||||
|
||||
var minVal = trackerList[0]?.position?.y
|
||||
|
||||
@@ -84,8 +84,7 @@ class Tracker @JvmOverloads constructor(
|
||||
*/
|
||||
var statusResetRecently = false
|
||||
private var alreadyInitialized = false
|
||||
var status: TrackerStatus by Delegates.observable(TrackerStatus.DISCONNECTED) {
|
||||
_, old, new ->
|
||||
var status: TrackerStatus by Delegates.observable(TrackerStatus.DISCONNECTED) { _, old, new ->
|
||||
if (old == new) return@observable
|
||||
|
||||
if (!new.reset) {
|
||||
@@ -106,8 +105,7 @@ class Tracker @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
var trackerPosition: TrackerPosition? by Delegates.observable(trackerPosition) {
|
||||
_, old, new ->
|
||||
var trackerPosition: TrackerPosition? by Delegates.observable(trackerPosition) { _, old, new ->
|
||||
if (old == new) return@observable
|
||||
|
||||
if (!isInternal) {
|
||||
@@ -307,12 +305,10 @@ class Tracker @JvmOverloads constructor(
|
||||
/**
|
||||
* Gets the world-adjusted acceleration
|
||||
*/
|
||||
fun getAcceleration(): Vector3 {
|
||||
return if (needsReset) {
|
||||
resetsHandler.getReferenceAdjustedAccel(rotation, acceleration)
|
||||
} else {
|
||||
acceleration
|
||||
}
|
||||
fun getAcceleration(): Vector3 = if (needsReset) {
|
||||
resetsHandler.getReferenceAdjustedAccel(rotation, acceleration)
|
||||
} else {
|
||||
acceleration
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -341,9 +337,7 @@ class Tracker @JvmOverloads constructor(
|
||||
* Gets the raw (unadjusted) rotation of the tracker.
|
||||
* If this is an IMU, this will be the raw sensor rotation.
|
||||
*/
|
||||
fun getRawRotation(): Quaternion {
|
||||
return rotation
|
||||
}
|
||||
fun getRawRotation(): Quaternion = rotation
|
||||
|
||||
/**
|
||||
* Sets the raw (unadjusted) rotation of the tracker.
|
||||
@@ -359,9 +353,7 @@ class Tracker @JvmOverloads constructor(
|
||||
this.acceleration = vec
|
||||
}
|
||||
|
||||
fun isImu(): Boolean {
|
||||
return imuType != null
|
||||
}
|
||||
fun isImu(): Boolean = imuType != null
|
||||
|
||||
/**
|
||||
* Gets the current TPS of the tracker
|
||||
|
||||
@@ -24,7 +24,7 @@ class TrackerFilteringHandler {
|
||||
movingAverage = QuaternionMovingAverage(
|
||||
type,
|
||||
config.amount,
|
||||
currentRawRotation
|
||||
currentRawRotation,
|
||||
)
|
||||
enabled = true
|
||||
} else {
|
||||
@@ -50,7 +50,5 @@ class TrackerFilteringHandler {
|
||||
/**
|
||||
* Get the filtered rotation from the moving average
|
||||
*/
|
||||
fun getFilteredRotation(): Quaternion {
|
||||
return movingAverage?.filteredQuaternion ?: Quaternion.IDENTITY
|
||||
}
|
||||
fun getFilteredRotation(): Quaternion = movingAverage?.filteredQuaternion ?: Quaternion.IDENTITY
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ class TrackerResetsHandler(val tracker: Tracker) {
|
||||
EulerOrder.YZX,
|
||||
0f,
|
||||
Math.PI.toFloat(),
|
||||
0f
|
||||
0f,
|
||||
).toQuaternion()
|
||||
set(value) {
|
||||
field = value
|
||||
@@ -93,11 +93,12 @@ class TrackerResetsHandler(val tracker: Tracker) {
|
||||
* a computed head tracker exists.
|
||||
*/
|
||||
fun refreshDriftCompensationEnabled() {
|
||||
driftCompensationEnabled = compensateDrift && allowDriftCompensation &&
|
||||
driftCompensationEnabled = compensateDrift &&
|
||||
allowDriftCompensation &&
|
||||
TrackerUtils.getNonInternalNonImuTrackerForBodyPosition(
|
||||
VRServer.instance.allTrackers,
|
||||
TrackerPosition.HEAD
|
||||
) != null
|
||||
VRServer.instance.allTrackers,
|
||||
TrackerPosition.HEAD,
|
||||
) != null
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,24 +113,18 @@ class TrackerResetsHandler(val tracker: Tracker) {
|
||||
* Takes a rotation and adjusts it to resets, mounting,
|
||||
* and drift compensation, with the HMD as the reference.
|
||||
*/
|
||||
fun getReferenceAdjustedDriftRotationFrom(rotation: Quaternion): Quaternion {
|
||||
return adjustToDrift(adjustToReference(rotation))
|
||||
}
|
||||
fun getReferenceAdjustedDriftRotationFrom(rotation: Quaternion): Quaternion = adjustToDrift(adjustToReference(rotation))
|
||||
|
||||
/**
|
||||
* Takes a rotation and adjusts it to resets and mounting,
|
||||
* with the identity Quaternion as the reference.
|
||||
*/
|
||||
fun getIdentityAdjustedDriftRotationFrom(rotation: Quaternion): Quaternion {
|
||||
return adjustToDrift(adjustToIdentity(rotation))
|
||||
}
|
||||
fun getIdentityAdjustedDriftRotationFrom(rotation: Quaternion): Quaternion = adjustToDrift(adjustToIdentity(rotation))
|
||||
|
||||
/**
|
||||
* Get the adjusted accel from yawFixZeroReference
|
||||
*/
|
||||
fun getReferenceAdjustedAccel(rawRot: Quaternion, accel: Vector3): Vector3 {
|
||||
return (adjustToReference(rawRot) / yawFix).sandwich(accel)
|
||||
}
|
||||
fun getReferenceAdjustedAccel(rawRot: Quaternion, accel: Vector3): Vector3 = (adjustToReference(rawRot) / yawFix).sandwich(accel)
|
||||
|
||||
/**
|
||||
* Converts raw or filtered rotation into reference- and
|
||||
@@ -166,7 +161,7 @@ class TrackerResetsHandler(val tracker: Tracker) {
|
||||
return rotation
|
||||
.interpR(
|
||||
averagedDriftQuat * rotation,
|
||||
driftAmount * ((System.currentTimeMillis() - driftSince).toFloat() / totalDriftTime)
|
||||
driftAmount * ((System.currentTimeMillis() - driftSince).toFloat() / totalDriftTime),
|
||||
)
|
||||
}
|
||||
return rotation
|
||||
@@ -183,7 +178,7 @@ class TrackerResetsHandler(val tracker: Tracker) {
|
||||
EulerOrder.YZX,
|
||||
0f,
|
||||
0f,
|
||||
-FastMath.HALF_PI
|
||||
-FastMath.HALF_PI,
|
||||
).toQuaternion()
|
||||
} else if ((isRightArmTracker() && armsResetMode == ArmsResetModes.TPOSE_DOWN)) {
|
||||
tposeFix = EulerAngles(EulerOrder.YZX, 0f, 0f, FastMath.HALF_PI).toQuaternion()
|
||||
@@ -308,13 +303,9 @@ class TrackerResetsHandler(val tracker: Tracker) {
|
||||
mountRotFix = Quaternion.IDENTITY
|
||||
}
|
||||
|
||||
private fun fixGyroscope(sensorRotation: Quaternion): Quaternion {
|
||||
return getYawQuaternion(sensorRotation).inv()
|
||||
}
|
||||
private fun fixGyroscope(sensorRotation: Quaternion): Quaternion = getYawQuaternion(sensorRotation).inv()
|
||||
|
||||
private fun fixAttachment(sensorRotation: Quaternion): Quaternion {
|
||||
return (gyroFix * sensorRotation).inv()
|
||||
}
|
||||
private fun fixAttachment(sensorRotation: Quaternion): Quaternion = (gyroFix * sensorRotation).inv()
|
||||
|
||||
private fun fixYaw(sensorRotation: Quaternion, reference: Quaternion): Quaternion {
|
||||
var rot = gyroFix * sensorRotation
|
||||
@@ -329,9 +320,7 @@ class TrackerResetsHandler(val tracker: Tracker) {
|
||||
// incorrect. Projection around the Y-axis is worse.
|
||||
// In both cases, the isolated yaw value changes
|
||||
// with the tracker's roll when pointing forward.
|
||||
private fun getYawQuaternion(rot: Quaternion): Quaternion {
|
||||
return EulerAngles(EulerOrder.YZX, 0f, rot.toEulerAngles(EulerOrder.YZX).y, 0f).toQuaternion()
|
||||
}
|
||||
private fun getYawQuaternion(rot: Quaternion): Quaternion = EulerAngles(EulerOrder.YZX, 0f, rot.toEulerAngles(EulerOrder.YZX).y, 0f).toQuaternion()
|
||||
|
||||
private fun makeIdentityAdjustmentQuatsFull() {
|
||||
val sensorRotation = tracker.getRawRotation()
|
||||
@@ -368,11 +357,15 @@ class TrackerResetsHandler(val tracker: Tracker) {
|
||||
// Add drift time to total
|
||||
driftTimes.add(System.currentTimeMillis() - driftSince)
|
||||
totalDriftTime = 0
|
||||
for (time in driftTimes) { totalDriftTime += time }
|
||||
for (time in driftTimes) {
|
||||
totalDriftTime += time
|
||||
}
|
||||
|
||||
// Calculate drift Quaternions' weights
|
||||
val driftWeights = ArrayList<Float>(driftTimes.size)
|
||||
for (time in driftTimes) { driftWeights.add(time.toFloat() / totalDriftTime.toFloat()) }
|
||||
for (time in driftTimes) {
|
||||
driftWeights.add(time.toFloat() / totalDriftTime.toFloat())
|
||||
}
|
||||
|
||||
// Make it so recent Quaternions weigh more
|
||||
for (i in driftWeights.size - 1 downTo 1) {
|
||||
@@ -396,11 +389,15 @@ class TrackerResetsHandler(val tracker: Tracker) {
|
||||
// Add drift time to total
|
||||
driftTimes[driftTimes.size - 1] = driftTimes.latest + System.currentTimeMillis() - driftSince
|
||||
totalDriftTime = 0
|
||||
for (time in driftTimes) { totalDriftTime += time }
|
||||
for (time in driftTimes) {
|
||||
totalDriftTime += time
|
||||
}
|
||||
|
||||
// Calculate drift Quaternions' weights
|
||||
val driftWeights = ArrayList<Float>(driftTimes.size)
|
||||
for (time in driftTimes) { driftWeights.add(time.toFloat() / totalDriftTime.toFloat()) }
|
||||
for (time in driftTimes) {
|
||||
driftWeights.add(time.toFloat() / totalDriftTime.toFloat())
|
||||
}
|
||||
|
||||
// Make it so recent Quaternions weigh more
|
||||
for (i in driftWeights.size - 1 downTo 1) {
|
||||
|
||||
@@ -16,9 +16,7 @@ object TrackerUtils {
|
||||
fun getTrackerForSkeleton(
|
||||
allTrackers: List<Tracker>,
|
||||
position: TrackerPosition,
|
||||
): Tracker? {
|
||||
return getNonInternalTrackerForBodyPosition(allTrackers, position)
|
||||
}
|
||||
): Tracker? = getNonInternalTrackerForBodyPosition(allTrackers, position)
|
||||
|
||||
/**
|
||||
* Finds the first non-internal tracker from allTrackers
|
||||
|
||||
@@ -13,7 +13,7 @@ class FirmwareFeatures {
|
||||
|
||||
// Add new flags here
|
||||
|
||||
BITS_TOTAL, ;
|
||||
BITS_TOTAL,
|
||||
}
|
||||
|
||||
fun has(flag: FirmwareFeatureFlags): Boolean {
|
||||
@@ -50,7 +50,7 @@ enum class ServerFeatureFlags {
|
||||
|
||||
companion object {
|
||||
val flagsEnabled: Set<ServerFeatureFlags> = setOf(
|
||||
PROTOCOL_BUNDLE_SUPPORT
|
||||
PROTOCOL_BUNDLE_SUPPORT,
|
||||
|
||||
// Add enabled flags here
|
||||
)
|
||||
|
||||
@@ -45,27 +45,25 @@ enum class BoardType(val id: UInt) {
|
||||
DEV_RESERVED(250u),
|
||||
;
|
||||
|
||||
override fun toString(): String {
|
||||
return when (this) {
|
||||
UNKNOWN -> "Unknown"
|
||||
SLIMEVR_LEGACY -> "SlimeVR Legacy"
|
||||
SLIMEVR_DEV -> "SlimeVR Dev"
|
||||
NODEMCU -> "NodeMCU"
|
||||
CUSTOM -> "Custom Board"
|
||||
WROOM32 -> "WROOM32"
|
||||
WEMOSD1MINI -> "Wemos D1 Mini"
|
||||
TTGO_TBASE -> "TTGO T-Base"
|
||||
ESP01 -> "ESP-01"
|
||||
SLIMEVR -> "SlimeVR"
|
||||
LOLIN_C3_MINI -> "Lolin C3 Mini"
|
||||
BEETLE32C32 -> "Beetle ESP32-C3"
|
||||
ES32C3DEVKITM1 -> "Espressif ESP32-C3 DevKitM-1"
|
||||
OWOTRACK -> "owoTrack"
|
||||
WRANGLER -> "Wrangler Joycons"
|
||||
MOCOPI -> "Sony Mocopi"
|
||||
WEMOSWROOM02 -> "Wemos Wroom-02 D1 Mini"
|
||||
DEV_RESERVED -> "Prototype"
|
||||
}
|
||||
override fun toString(): String = when (this) {
|
||||
UNKNOWN -> "Unknown"
|
||||
SLIMEVR_LEGACY -> "SlimeVR Legacy"
|
||||
SLIMEVR_DEV -> "SlimeVR Dev"
|
||||
NODEMCU -> "NodeMCU"
|
||||
CUSTOM -> "Custom Board"
|
||||
WROOM32 -> "WROOM32"
|
||||
WEMOSD1MINI -> "Wemos D1 Mini"
|
||||
TTGO_TBASE -> "TTGO T-Base"
|
||||
ESP01 -> "ESP-01"
|
||||
SLIMEVR -> "SlimeVR"
|
||||
LOLIN_C3_MINI -> "Lolin C3 Mini"
|
||||
BEETLE32C32 -> "Beetle ESP32-C3"
|
||||
ES32C3DEVKITM1 -> "Espressif ESP32-C3 DevKitM-1"
|
||||
OWOTRACK -> "owoTrack"
|
||||
WRANGLER -> "Wrangler Joycons"
|
||||
MOCOPI -> "Sony Mocopi"
|
||||
WEMOSWROOM02 -> "Wemos Wroom-02 D1 Mini"
|
||||
DEV_RESERVED -> "Prototype"
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -4,6 +4,8 @@ data class SensorTap(val tapBits: Int) {
|
||||
val doubleTap = tapBits and 0x40 > 0
|
||||
|
||||
enum class TapAxis {
|
||||
X, Y, Z
|
||||
X,
|
||||
Y,
|
||||
Z,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,7 @@ import java.util.function.Consumer
|
||||
/**
|
||||
* Receives trackers data by UDP using extended owoTrack protocol.
|
||||
*/
|
||||
class TrackersUDPServer(private val port: Int, name: String, private val trackersConsumer: Consumer<Tracker>) :
|
||||
Thread(name) {
|
||||
class TrackersUDPServer(private val port: Int, name: String, private val trackersConsumer: Consumer<Tracker>) : Thread(name) {
|
||||
private val random = Random()
|
||||
private val connections: MutableList<UDPDevice> = FastList()
|
||||
private val connectionsByAddress: MutableMap<SocketAddress, UDPDevice> = HashMap()
|
||||
@@ -83,7 +82,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
firmware: ${handshake.firmware} ($firmwareBuild),
|
||||
mac: ${handshake.macString},
|
||||
name: $name
|
||||
""".trimIndent()
|
||||
""".trimIndent(),
|
||||
)
|
||||
} ?: connectionsByAddress[socketAddr]?.apply {
|
||||
// Look for an existing connection by the socket address (IP and port)
|
||||
@@ -104,7 +103,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
firmware: ${handshake.firmware} ($firmwareBuild),
|
||||
mac: ${handshake.macString},
|
||||
name: $name
|
||||
""".trimIndent()
|
||||
""".trimIndent(),
|
||||
)
|
||||
}
|
||||
} ?: run {
|
||||
@@ -114,7 +113,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
addr,
|
||||
handshake.macString ?: addr.hostAddress,
|
||||
handshake.boardType,
|
||||
handshake.mcuType
|
||||
handshake.mcuType,
|
||||
)
|
||||
VRServer.instance.deviceManager.addDevice(connection)
|
||||
connection.firmwareBuild = handshake.firmwareBuild
|
||||
@@ -148,7 +147,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
firmware: ${handshake.firmware} (${connection.firmwareBuild}),
|
||||
mac: ${handshake.macString},
|
||||
name: ${connection.name}
|
||||
""".trimIndent()
|
||||
""".trimIndent(),
|
||||
)
|
||||
}
|
||||
if (connection.protocol == NetworkProtocol.OWO_LEGACY || connection.firmwareBuild < 9) {
|
||||
@@ -189,7 +188,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
allowFiltering = true,
|
||||
needsReset = true,
|
||||
needsMounting = true,
|
||||
usesTimeout = true
|
||||
usesTimeout = true,
|
||||
)
|
||||
connection.trackers[trackerId] = imuTracker
|
||||
trackersConsumer.accept(imuTracker)
|
||||
@@ -233,7 +232,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
} catch (e: Exception) {
|
||||
LogManager.warning(
|
||||
"[TrackerServer] Error parsing packet ${packetToString(received)}",
|
||||
e
|
||||
e,
|
||||
)
|
||||
}
|
||||
if (lastKeepup + 500 < System.currentTimeMillis()) {
|
||||
@@ -298,7 +297,9 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
val tracker: Tracker?
|
||||
when (packet) {
|
||||
is UDPPacket0Heartbeat, is UDPPacket1Heartbeat -> {}
|
||||
|
||||
is UDPPacket3Handshake -> setUpNewConnection(received, packet)
|
||||
|
||||
is RotationPacket -> {
|
||||
var rot = packet.rotation
|
||||
rot = AXES_OFFSET.times(rot)
|
||||
@@ -307,6 +308,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
tracker.setRotation(rot)
|
||||
tracker.dataTick()
|
||||
}
|
||||
|
||||
is UDPPacket17RotationData -> {
|
||||
tracker = connection?.getTracker(packet.sensorId)
|
||||
if (tracker == null) return
|
||||
@@ -328,13 +330,16 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is UDPPacket18MagnetometerAccuracy -> {}
|
||||
|
||||
is UDPPacket4Acceleration -> {
|
||||
tracker = connection?.getTracker(packet.sensorId)
|
||||
if (tracker == null) return
|
||||
// Switch x and y around to adjust for different axes
|
||||
tracker.setAcceleration(Vector3(packet.acceleration.y, packet.acceleration.x, packet.acceleration.z))
|
||||
}
|
||||
|
||||
is UDPPacket10PingPong -> {
|
||||
if (connection == null) return
|
||||
if (connection.lastPingPacketId == packet.pingId) {
|
||||
@@ -344,7 +349,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
}
|
||||
} else {
|
||||
LogManager.debug(
|
||||
"[TrackerServer] Wrong ping id ${packet.pingId} != ${connection.lastPingPacketId}"
|
||||
"[TrackerServer] Wrong ping id ${packet.pingId} != ${connection.lastPingPacketId}",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -363,13 +368,13 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
tracker = connection?.getTracker(packet.sensorId)
|
||||
if (tracker == null) return
|
||||
LogManager.info(
|
||||
"[TrackerServer] Tap packet received from ${tracker.name}: ${packet.tap}"
|
||||
"[TrackerServer] Tap packet received from ${tracker.name}: ${packet.tap}",
|
||||
)
|
||||
}
|
||||
|
||||
is UDPPacket14Error -> {
|
||||
LogManager.severe(
|
||||
"[TrackerServer] Error received from ${received.socketAddress}: ${packet.errorNumber}"
|
||||
"[TrackerServer] Error received from ${received.socketAddress}: ${packet.errorNumber}",
|
||||
)
|
||||
tracker = connection?.getTracker(packet.sensorId)
|
||||
if (tracker == null) return
|
||||
@@ -385,7 +390,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
parser.writeSensorInfoResponse(bb, connection, packet)
|
||||
socket.send(DatagramPacket(rcvBuffer, bb.position(), connection.address))
|
||||
LogManager.info(
|
||||
"[TrackerServer] Sensor info for ${connection.descriptiveName}/${packet.sensorId}: ${packet.sensorStatus}"
|
||||
"[TrackerServer] Sensor info for ${connection.descriptiveName}/${packet.sensorId}: ${packet.sensorStatus}",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -406,13 +411,13 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
UDPPacket21UserAction.RESET_FULL -> {
|
||||
name = "Full reset"
|
||||
VRServer.instance.resetHandler.sendStarted(ResetType.Full)
|
||||
VRServer.instance.resetTrackersFull(resetSourceName)
|
||||
VRServer.instance.resetTrackersFull(RESET_SOURCE_NAME)
|
||||
}
|
||||
|
||||
UDPPacket21UserAction.RESET_YAW -> {
|
||||
name = "Yaw reset"
|
||||
VRServer.instance.resetHandler.sendStarted(ResetType.Yaw)
|
||||
VRServer.instance.resetTrackersYaw(resetSourceName)
|
||||
VRServer.instance.resetTrackersYaw(RESET_SOURCE_NAME)
|
||||
}
|
||||
|
||||
UDPPacket21UserAction.RESET_MOUNTING -> {
|
||||
@@ -421,17 +426,17 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
.instance
|
||||
.resetHandler
|
||||
.sendStarted(ResetType.Mounting)
|
||||
VRServer.instance.resetTrackersMounting(resetSourceName)
|
||||
VRServer.instance.resetTrackersMounting(RESET_SOURCE_NAME)
|
||||
}
|
||||
|
||||
UDPPacket21UserAction.PAUSE_TRACKING -> {
|
||||
name = "Pause tracking toggle"
|
||||
VRServer.instance.togglePauseTracking(resetSourceName)
|
||||
VRServer.instance.togglePauseTracking(RESET_SOURCE_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
LogManager.info(
|
||||
"[TrackerServer] User action from ${connection.descriptiveName } received. $name performed."
|
||||
"[TrackerServer] User action from ${connection.descriptiveName } received. $name performed.",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -449,16 +454,14 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
}
|
||||
}
|
||||
|
||||
fun getConnections(): List<UDPDevice?> {
|
||||
return connections
|
||||
}
|
||||
fun getConnections(): List<UDPDevice?> = connections
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Change between IMU axes and OpenGL/SteamVR axes
|
||||
*/
|
||||
private val AXES_OFFSET = fromRotationVector(-FastMath.HALF_PI, 0f, 0f)
|
||||
private const val resetSourceName = "TrackerServer"
|
||||
private const val RESET_SOURCE_NAME = "TrackerServer"
|
||||
private fun packetToString(packet: DatagramPacket?): String {
|
||||
val sb = StringBuilder()
|
||||
sb.append("DatagramPacket{")
|
||||
|
||||
@@ -61,9 +61,7 @@ class UDPDevice(
|
||||
return true
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "udp:/$ipAddress"
|
||||
}
|
||||
override fun toString(): String = "udp:/$ipAddress"
|
||||
|
||||
override var manufacturer: String?
|
||||
get() = "SlimeVR"
|
||||
@@ -76,7 +74,5 @@ class UDPDevice(
|
||||
super.firmwareVersion = firmwareVersion
|
||||
}
|
||||
|
||||
fun getTracker(id: Int): Tracker? {
|
||||
return trackers[id]
|
||||
}
|
||||
fun getTracker(id: Int): Tracker? = trackers[id]
|
||||
}
|
||||
|
||||
@@ -72,9 +72,7 @@ sealed interface SensorSpecificPacket {
|
||||
* @param sensorId
|
||||
* @return
|
||||
*/
|
||||
fun isGlobal(sensorId: Int): Boolean {
|
||||
return sensorId == 255
|
||||
}
|
||||
fun isGlobal(sensorId: Int): Boolean = sensorId == 255
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +83,8 @@ sealed interface RotationPacket : SensorSpecificPacket {
|
||||
data object UDPPacket0Heartbeat : UDPPacket(0)
|
||||
data object UDPPacket1Heartbeat : UDPPacket(1)
|
||||
data class UDPPacket1Rotation(override var rotation: Quaternion = Quaternion.IDENTITY) :
|
||||
UDPPacket(1), RotationPacket {
|
||||
UDPPacket(1),
|
||||
RotationPacket {
|
||||
override val sensorId = 0
|
||||
override fun readData(buf: ByteBuffer) {
|
||||
rotation = UDPUtils.getSafeBufferQuaternion(buf)
|
||||
@@ -112,7 +111,9 @@ data class UDPPacket3Handshake(
|
||||
mcuType = MCUType.getById(buf.int.toUInt()) ?: MCUType.UNKNOWN
|
||||
} // MCU TYPE
|
||||
if (buf.remaining() > 11) {
|
||||
buf.int; buf.int; buf.int // IMU info
|
||||
buf.int
|
||||
buf.int
|
||||
buf.int // IMU info
|
||||
}
|
||||
if (buf.remaining() > 3) firmwareBuild = buf.int
|
||||
var length = 0
|
||||
@@ -130,7 +131,7 @@ data class UDPPacket3Handshake(
|
||||
mac[2],
|
||||
mac[3],
|
||||
mac[4],
|
||||
mac[5]
|
||||
mac[5],
|
||||
)
|
||||
if (macString == "00:00:00:00:00:00") macString = null
|
||||
}
|
||||
@@ -146,7 +147,8 @@ data class UDPPacket3Handshake(
|
||||
}
|
||||
|
||||
data class UDPPacket4Acceleration(var acceleration: Vector3 = Vector3.NULL) :
|
||||
UDPPacket(4), SensorSpecificPacket {
|
||||
UDPPacket(4),
|
||||
SensorSpecificPacket {
|
||||
override var sensorId = 0
|
||||
override fun readData(buf: ByteBuffer) {
|
||||
acceleration = Vector3(UDPUtils.getSafeBufferFloat(buf), UDPUtils.getSafeBufferFloat(buf), UDPUtils.getSafeBufferFloat(buf))
|
||||
@@ -199,7 +201,8 @@ data class UDPPacket12BatteryLevel(
|
||||
}
|
||||
|
||||
data class UDPPacket13Tap(var tap: SensorTap = SensorTap(0)) :
|
||||
UDPPacket(13), SensorSpecificPacket {
|
||||
UDPPacket(13),
|
||||
SensorSpecificPacket {
|
||||
override var sensorId = 0
|
||||
override fun readData(buf: ByteBuffer) {
|
||||
sensorId = buf.get().toInt() and 0xFF
|
||||
@@ -208,7 +211,8 @@ data class UDPPacket13Tap(var tap: SensorTap = SensorTap(0)) :
|
||||
}
|
||||
|
||||
data class UDPPacket14Error(var errorNumber: Int = 0) :
|
||||
UDPPacket(14), SensorSpecificPacket {
|
||||
UDPPacket(14),
|
||||
SensorSpecificPacket {
|
||||
override var sensorId = 0
|
||||
override fun readData(buf: ByteBuffer) {
|
||||
sensorId = buf.get().toInt() and 0xFF
|
||||
@@ -219,7 +223,8 @@ data class UDPPacket14Error(var errorNumber: Int = 0) :
|
||||
data class UDPPacket15SensorInfo(
|
||||
var sensorStatus: Int = 0,
|
||||
var sensorType: IMUType = IMUType.UNKNOWN,
|
||||
) : UDPPacket(15), SensorSpecificPacket {
|
||||
) : UDPPacket(15),
|
||||
SensorSpecificPacket {
|
||||
override var sensorId = 0
|
||||
override fun readData(buf: ByteBuffer) {
|
||||
sensorId = buf.get().toInt() and 0xFF
|
||||
@@ -231,19 +236,18 @@ data class UDPPacket15SensorInfo(
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getStatus(sensorStatus: Int): TrackerStatus? {
|
||||
return when (sensorStatus) {
|
||||
0 -> TrackerStatus.DISCONNECTED
|
||||
1 -> TrackerStatus.OK
|
||||
2 -> TrackerStatus.ERROR
|
||||
else -> null
|
||||
}
|
||||
fun getStatus(sensorStatus: Int): TrackerStatus? = when (sensorStatus) {
|
||||
0 -> TrackerStatus.DISCONNECTED
|
||||
1 -> TrackerStatus.OK
|
||||
2 -> TrackerStatus.ERROR
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class UDPPacket16Rotation2(override var rotation: Quaternion = Quaternion.IDENTITY) :
|
||||
UDPPacket(16), RotationPacket {
|
||||
UDPPacket(16),
|
||||
RotationPacket {
|
||||
override val sensorId = 1
|
||||
override fun readData(buf: ByteBuffer) {
|
||||
rotation = UDPUtils.getSafeBufferQuaternion(buf)
|
||||
@@ -254,7 +258,8 @@ data class UDPPacket17RotationData(
|
||||
var rotation: Quaternion = Quaternion.IDENTITY,
|
||||
var dataType: Int = 0,
|
||||
var calibrationInfo: Int = 0,
|
||||
) : UDPPacket(17), SensorSpecificPacket {
|
||||
) : UDPPacket(17),
|
||||
SensorSpecificPacket {
|
||||
override var sensorId: Int = 0
|
||||
override fun readData(buf: ByteBuffer) {
|
||||
sensorId = buf.get().toInt() and 0xFF
|
||||
@@ -270,7 +275,8 @@ data class UDPPacket17RotationData(
|
||||
}
|
||||
|
||||
data class UDPPacket18MagnetometerAccuracy(var accuracyInfo: Float = 0.0f) :
|
||||
UDPPacket(18), SensorSpecificPacket {
|
||||
UDPPacket(18),
|
||||
SensorSpecificPacket {
|
||||
override var sensorId = 0
|
||||
override fun readData(buf: ByteBuffer) {
|
||||
sensorId = buf.get().toInt() and 0xFF
|
||||
@@ -279,7 +285,8 @@ data class UDPPacket18MagnetometerAccuracy(var accuracyInfo: Float = 0.0f) :
|
||||
}
|
||||
|
||||
data class UDPPacket19SignalStrength(var signalStrength: Int = 0) :
|
||||
UDPPacket(19), SensorSpecificPacket {
|
||||
UDPPacket(19),
|
||||
SensorSpecificPacket {
|
||||
override var sensorId = 0
|
||||
override fun readData(buf: ByteBuffer) {
|
||||
sensorId = buf.get().toInt() and 0xFF
|
||||
@@ -288,7 +295,8 @@ data class UDPPacket19SignalStrength(var signalStrength: Int = 0) :
|
||||
}
|
||||
|
||||
data class UDPPacket20Temperature(var temperature: Float = 0.0f) :
|
||||
UDPPacket(20), SensorSpecificPacket {
|
||||
UDPPacket(20),
|
||||
SensorSpecificPacket {
|
||||
override var sensorId = 0
|
||||
override fun readData(buf: ByteBuffer) {
|
||||
sensorId = buf.get().toInt() and 0xFF
|
||||
@@ -311,8 +319,7 @@ data class UDPPacket21UserAction(var type: Int = 0) : UDPPacket(21) {
|
||||
|
||||
class UDPPacket22FeatureFlags(
|
||||
var firmwareFeatures: FirmwareFeatures = FirmwareFeatures(),
|
||||
) :
|
||||
UDPPacket(22) {
|
||||
) : UDPPacket(22) {
|
||||
override fun readData(buf: ByteBuffer) {
|
||||
firmwareFeatures = FirmwareFeatures.from(buf, buf.remaining())
|
||||
}
|
||||
@@ -325,8 +332,7 @@ class UDPPacket22FeatureFlags(
|
||||
data class UDPPacket200ProtocolChange(
|
||||
var targetProtocol: Int = 0,
|
||||
var targetProtocolVersion: Int = 0,
|
||||
) :
|
||||
UDPPacket(200) {
|
||||
) : UDPPacket(200) {
|
||||
override fun readData(buf: ByteBuffer) {
|
||||
targetProtocol = buf.get().toInt() and 0xFF
|
||||
targetProtocolVersion = buf.get().toInt() and 0xFF
|
||||
|
||||
@@ -13,7 +13,7 @@ class UDPProtocolParser {
|
||||
if (!connection.isNextPacket(packetNumber)) {
|
||||
// Skip packet because it's not next
|
||||
throw IOException(
|
||||
"Out of order packet received: id $packetId, number $packetNumber, last ${connection.lastPacketNumber}, from $connection"
|
||||
"Out of order packet received: id $packetId, number $packetNumber, last ${connection.lastPacketNumber}, from $connection",
|
||||
)
|
||||
}
|
||||
connection.lastPacket = System.currentTimeMillis()
|
||||
@@ -77,28 +77,26 @@ class UDPProtocolParser {
|
||||
buf.put(packet.sensorStatus.toByte())
|
||||
}
|
||||
|
||||
protected fun getNewPacket(packetId: Int): UDPPacket? {
|
||||
return when (packetId) {
|
||||
PACKET_HEARTBEAT -> UDPPacket0Heartbeat
|
||||
PACKET_ROTATION -> UDPPacket1Rotation()
|
||||
PACKET_HANDSHAKE -> UDPPacket3Handshake()
|
||||
PACKET_PING_PONG -> UDPPacket10PingPong()
|
||||
PACKET_ACCEL -> UDPPacket4Acceleration()
|
||||
PACKET_SERIAL -> UDPPacket11Serial()
|
||||
PACKET_BATTERY_LEVEL -> UDPPacket12BatteryLevel()
|
||||
PACKET_TAP -> UDPPacket13Tap()
|
||||
PACKET_ERROR -> UDPPacket14Error()
|
||||
PACKET_SENSOR_INFO -> UDPPacket15SensorInfo()
|
||||
PACKET_ROTATION_2 -> UDPPacket16Rotation2()
|
||||
PACKET_ROTATION_DATA -> UDPPacket17RotationData()
|
||||
PACKET_MAGNETOMETER_ACCURACY -> UDPPacket18MagnetometerAccuracy()
|
||||
PACKET_SIGNAL_STRENGTH -> UDPPacket19SignalStrength()
|
||||
PACKET_TEMPERATURE -> UDPPacket20Temperature()
|
||||
PACKET_USER_ACTION -> UDPPacket21UserAction()
|
||||
PACKET_FEATURE_FLAGS -> UDPPacket22FeatureFlags()
|
||||
PACKET_PROTOCOL_CHANGE -> UDPPacket200ProtocolChange()
|
||||
else -> null
|
||||
}
|
||||
protected fun getNewPacket(packetId: Int): UDPPacket? = when (packetId) {
|
||||
PACKET_HEARTBEAT -> UDPPacket0Heartbeat
|
||||
PACKET_ROTATION -> UDPPacket1Rotation()
|
||||
PACKET_HANDSHAKE -> UDPPacket3Handshake()
|
||||
PACKET_PING_PONG -> UDPPacket10PingPong()
|
||||
PACKET_ACCEL -> UDPPacket4Acceleration()
|
||||
PACKET_SERIAL -> UDPPacket11Serial()
|
||||
PACKET_BATTERY_LEVEL -> UDPPacket12BatteryLevel()
|
||||
PACKET_TAP -> UDPPacket13Tap()
|
||||
PACKET_ERROR -> UDPPacket14Error()
|
||||
PACKET_SENSOR_INFO -> UDPPacket15SensorInfo()
|
||||
PACKET_ROTATION_2 -> UDPPacket16Rotation2()
|
||||
PACKET_ROTATION_DATA -> UDPPacket17RotationData()
|
||||
PACKET_MAGNETOMETER_ACCURACY -> UDPPacket18MagnetometerAccuracy()
|
||||
PACKET_SIGNAL_STRENGTH -> UDPPacket19SignalStrength()
|
||||
PACKET_TEMPERATURE -> UDPPacket20Temperature()
|
||||
PACKET_USER_ACTION -> UDPPacket21UserAction()
|
||||
PACKET_FEATURE_FLAGS -> UDPPacket22FeatureFlags()
|
||||
PACKET_PROTOCOL_CHANGE -> UDPPacket200ProtocolChange()
|
||||
else -> null
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -14,6 +14,7 @@ enum class OperatingSystem(
|
||||
OSX("osx", arrayOf("mac")),
|
||||
UNKNOWN("unknown", arrayOf()),
|
||||
;
|
||||
|
||||
companion object {
|
||||
val currentPlatform: OperatingSystem by lazy {
|
||||
val osName = System.getProperty("os.name").lowercase(Locale.getDefault())
|
||||
@@ -46,16 +47,22 @@ enum class OperatingSystem(
|
||||
fun resolveConfigDirectory(identifier: String): Path? = when (currentPlatform) {
|
||||
LINUX -> System.getenv("XDG_CONFIG_HOME")?.let { Path(it, identifier) }
|
||||
?: System.getenv("HOME")?.let { Path(it, ".config", identifier) }
|
||||
|
||||
WINDOWS -> System.getenv("AppData")?.let { Path(it, identifier) }
|
||||
|
||||
OSX -> System.getenv("HOME")?.let { Path(it, "Library", "Application Support", identifier) }
|
||||
|
||||
UNKNOWN -> null
|
||||
}
|
||||
|
||||
fun resolveLogDirectory(identifier: String): Path? = when (currentPlatform) {
|
||||
LINUX -> System.getenv("XDG_DATA_HOME")?.let { Path(it, identifier, "logs") }
|
||||
?: System.getenv("HOME")?.let { Path(it, ".local", "share", identifier, "logs") }
|
||||
|
||||
WINDOWS -> System.getenv("AppData")?.let { Path(it, identifier, "logs") }
|
||||
|
||||
OSX -> System.getenv("HOME")?.let { Path(it, "Library", "Logs", identifier) }
|
||||
|
||||
UNKNOWN -> null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,37 +25,42 @@ data class EulerAngles(val order: EulerOrder, val x: Float, val y: Float, val z:
|
||||
cX * cY * cZ - sX * sY * sZ,
|
||||
cY * cZ * sX + cX * sY * sZ,
|
||||
cX * cZ * sY - cY * sX * sZ,
|
||||
cZ * sX * sY + cX * cY * sZ
|
||||
cZ * sX * sY + cX * cY * sZ,
|
||||
)
|
||||
|
||||
EulerOrder.YZX -> Quaternion(
|
||||
cX * cY * cZ - sX * sY * sZ,
|
||||
cY * cZ * sX + cX * sY * sZ,
|
||||
cX * cZ * sY + cY * sX * sZ,
|
||||
cX * cY * sZ - cZ * sX * sY
|
||||
cX * cY * sZ - cZ * sX * sY,
|
||||
)
|
||||
|
||||
EulerOrder.ZXY -> Quaternion(
|
||||
cX * cY * cZ - sX * sY * sZ,
|
||||
cY * cZ * sX - cX * sY * sZ,
|
||||
cX * cZ * sY + cY * sX * sZ,
|
||||
cZ * sX * sY + cX * cY * sZ
|
||||
cZ * sX * sY + cX * cY * sZ,
|
||||
)
|
||||
|
||||
EulerOrder.ZYX -> Quaternion(
|
||||
cX * cY * cZ + sX * sY * sZ,
|
||||
cY * cZ * sX - cX * sY * sZ,
|
||||
cX * cZ * sY + cY * sX * sZ,
|
||||
cX * cY * sZ - cZ * sX * sY
|
||||
cX * cY * sZ - cZ * sX * sY,
|
||||
)
|
||||
|
||||
EulerOrder.YXZ -> Quaternion(
|
||||
cX * cY * cZ + sX * sY * sZ,
|
||||
cY * cZ * sX + cX * sY * sZ,
|
||||
cX * cZ * sY - cY * sX * sZ,
|
||||
cX * cY * sZ - cZ * sX * sY
|
||||
cX * cY * sZ - cZ * sX * sY,
|
||||
)
|
||||
|
||||
EulerOrder.XZY -> Quaternion(
|
||||
cX * cY * cZ + sX * sY * sZ,
|
||||
cY * cZ * sX - cX * sY * sZ,
|
||||
cX * cZ * sY - cY * sX * sZ,
|
||||
cZ * sX * sY + cX * cY * sZ
|
||||
cZ * sX * sY + cX * cY * sZ,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -74,9 +79,9 @@ data class EulerAngles(val order: EulerOrder, val x: Float, val y: Float, val z:
|
||||
val sY = sin(y)
|
||||
val sZ = sin(z)
|
||||
|
||||
@Suppress("ktlint")
|
||||
return when (order) {
|
||||
// ktlint ruining spacing
|
||||
/* ktlint-disable */
|
||||
EulerOrder.XYZ -> Matrix3(
|
||||
cY*cZ , -cY*sZ , sY ,
|
||||
cZ*sX*sY + cX*sZ , cX*cZ - sX*sY*sZ , -cY*sX ,
|
||||
@@ -106,7 +111,6 @@ data class EulerAngles(val order: EulerOrder, val x: Float, val y: Float, val z:
|
||||
cY*cZ , -sZ , cZ*sY ,
|
||||
sX*sY + cX*cY*sZ , cX*cZ , cX*sY*sZ - cY*sX ,
|
||||
cY*sX*sZ - cX*sY , cZ*sX , cX*cY + sX*sY*sZ )
|
||||
/* ktlint-enable */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
@file:Suppress("unused")
|
||||
@file:Suppress("ktlint", "unused")
|
||||
|
||||
package io.github.axisangles.ktmath
|
||||
|
||||
import kotlin.math.*
|
||||
|
||||
/* ktlint-disable */
|
||||
data class Matrix3(
|
||||
val xx: Float, val yx: Float, val zx: Float,
|
||||
val xy: Float, val yy: Float, val zy: Float,
|
||||
val xz: Float, val yz: Float, val zz: Float
|
||||
) {
|
||||
/* ktlint-enable */
|
||||
companion object {
|
||||
val NULL = Matrix3(
|
||||
0f, 0f, 0f,
|
||||
@@ -416,4 +414,4 @@ data class Matrix3(
|
||||
|
||||
operator fun Float.times(that: Matrix3): Matrix3 = that * this
|
||||
|
||||
operator fun Float.div(that: Matrix3): Matrix3 = that.inv() * this
|
||||
operator fun Float.div(that: Matrix3): Matrix3 = that.inv() * this
|
||||
@@ -44,11 +44,11 @@ data class Quaternion(val w: Float, val x: Float, val y: Float, val z: Float) {
|
||||
* @return Q
|
||||
**/
|
||||
fun fromTo(u: Vector3, v: Vector3): Quaternion {
|
||||
val U = Quaternion(0f, u)
|
||||
val V = Quaternion(0f, v)
|
||||
val D = V / U
|
||||
val u = Quaternion(0f, u)
|
||||
val v = Quaternion(0f, v)
|
||||
val d = v / u
|
||||
|
||||
return (D + D.len()).unit()
|
||||
return (d + d.len()).unit()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +92,7 @@ data class Quaternion(val w: Float, val x: Float, val y: Float, val z: Float) {
|
||||
this.w + that.w,
|
||||
this.x + that.x,
|
||||
this.y + that.y,
|
||||
this.z + that.z
|
||||
this.z + that.z,
|
||||
)
|
||||
|
||||
operator fun plus(that: Float): Quaternion =
|
||||
@@ -102,7 +102,7 @@ data class Quaternion(val w: Float, val x: Float, val y: Float, val z: Float) {
|
||||
this.w - that.w,
|
||||
this.x - that.x,
|
||||
this.y - that.y,
|
||||
this.z - that.z
|
||||
this.z - that.z,
|
||||
)
|
||||
|
||||
operator fun minus(that: Float): Quaternion =
|
||||
@@ -140,14 +140,14 @@ data class Quaternion(val w: Float, val x: Float, val y: Float, val z: Float) {
|
||||
this.w * that,
|
||||
this.x * that,
|
||||
this.y * that,
|
||||
this.z * that
|
||||
this.z * that,
|
||||
)
|
||||
|
||||
operator fun times(that: Quaternion): Quaternion = Quaternion(
|
||||
this.w * that.w - this.x * that.x - this.y * that.y - this.z * that.z,
|
||||
this.x * that.w + this.w * that.x - this.z * that.y + this.y * that.z,
|
||||
this.y * that.w + this.z * that.x + this.w * that.y - this.x * that.z,
|
||||
this.z * that.w - this.y * that.x + this.x * that.y + this.w * that.z
|
||||
this.z * that.w - this.y * that.x + this.x * that.y + this.w * that.z,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -160,7 +160,7 @@ data class Quaternion(val w: Float, val x: Float, val y: Float, val z: Float) {
|
||||
w / lenSq,
|
||||
-x / lenSq,
|
||||
-y / lenSq,
|
||||
-z / lenSq
|
||||
-z / lenSq,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -336,10 +336,10 @@ data class Quaternion(val w: Float, val x: Float, val y: Float, val z: Float) {
|
||||
* @return Q
|
||||
**/
|
||||
fun align(u: Vector3, v: Vector3): Quaternion {
|
||||
val U = Quaternion(0f, u)
|
||||
val V = Quaternion(0f, v)
|
||||
val u = Quaternion(0f, u)
|
||||
val v = Quaternion(0f, v)
|
||||
|
||||
return (V * this / U + (V / U).len() * this) / 2f
|
||||
return (v * this / u + (v / u).len() * this) / 2f
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -379,18 +379,17 @@ data class Quaternion(val w: Float, val x: Float, val y: Float, val z: Float) {
|
||||
**/
|
||||
fun toRotationVector(): Vector3 = 2f * twinNearest(IDENTITY).log().xyz
|
||||
|
||||
@Suppress("ktlint")
|
||||
/**
|
||||
* computes the matrix representing this quaternion's rotation
|
||||
* @return rotation matrix
|
||||
**/
|
||||
fun toMatrix(): Matrix3 {
|
||||
val d = lenSq()
|
||||
/* ktlint-disable */
|
||||
return Matrix3(
|
||||
(w*w + x*x - y*y - z*z)/d , 2f*(x*y - w*z)/d , 2f*(w*y + x*z)/d ,
|
||||
2f*(x*y + w*z)/d , (w*w - x*x + y*y - z*z)/d , 2f*(y*z - w*x)/d ,
|
||||
2f*(x*z - w*y)/d , 2f*(w*x + y*z)/d , (w*w - x*x - y*y + z*z)/d )
|
||||
/* ktlint-enable */
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,13 +20,13 @@ data class Vector3(val x: Float, val y: Float, val z: Float) {
|
||||
operator fun plus(that: Vector3) = Vector3(
|
||||
this.x + that.x,
|
||||
this.y + that.y,
|
||||
this.z + that.z
|
||||
this.z + that.z,
|
||||
)
|
||||
|
||||
operator fun minus(that: Vector3) = Vector3(
|
||||
this.x - that.x,
|
||||
this.y - that.y,
|
||||
this.z - that.z
|
||||
this.z - that.z,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -44,13 +44,13 @@ data class Vector3(val x: Float, val y: Float, val z: Float) {
|
||||
infix fun cross(that: Vector3) = Vector3(
|
||||
this.y * that.z - this.z * that.y,
|
||||
this.z * that.x - this.x * that.z,
|
||||
this.x * that.y - this.y * that.x
|
||||
this.x * that.y - this.y * that.x,
|
||||
)
|
||||
|
||||
infix fun hadamard(that: Vector3) = Vector3(
|
||||
this.x * that.x,
|
||||
this.y * that.y,
|
||||
this.z * that.z
|
||||
this.z * that.z,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -76,14 +76,14 @@ data class Vector3(val x: Float, val y: Float, val z: Float) {
|
||||
operator fun times(that: Float) = Vector3(
|
||||
this.x * that,
|
||||
this.y * that,
|
||||
this.z * that
|
||||
this.z * that,
|
||||
)
|
||||
|
||||
// computes division of this vector3 by a float
|
||||
operator fun div(that: Float) = Vector3(
|
||||
this.x / that,
|
||||
this.y / that,
|
||||
this.z / that
|
||||
this.z / that,
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,14 +26,14 @@ class ReferenceAdjustmentsTests {
|
||||
get() = anglesSet
|
||||
.map { p: AnglesSet ->
|
||||
DynamicTest.dynamicTest(
|
||||
"Adjustment Yaw Test of Tracker(${p.pitch},${p.yaw},${p.roll})"
|
||||
"Adjustment Yaw Test of Tracker(${p.pitch},${p.yaw},${p.roll})",
|
||||
) {
|
||||
yaws.forEach {
|
||||
checkReferenceAdjustmentYaw(
|
||||
q(p.pitch.toFloat(), p.yaw.toFloat(), p.roll.toFloat()),
|
||||
0,
|
||||
it,
|
||||
0
|
||||
0,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ class ReferenceAdjustmentsTests {
|
||||
get() = anglesSet
|
||||
.map { p: AnglesSet ->
|
||||
DynamicTest.dynamicTest(
|
||||
"Adjustment Full Test of Tracker(${p.pitch},${p.yaw},${p.roll})"
|
||||
"Adjustment Full Test of Tracker(${p.pitch},${p.yaw},${p.roll})",
|
||||
) {
|
||||
anglesSet
|
||||
.forEach {
|
||||
@@ -52,7 +52,7 @@ class ReferenceAdjustmentsTests {
|
||||
q(p.pitch.toFloat(), p.yaw.toFloat(), p.roll.toFloat()),
|
||||
it.pitch,
|
||||
it.yaw,
|
||||
it.roll
|
||||
it.roll,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -66,13 +66,13 @@ class ReferenceAdjustmentsTests {
|
||||
.flatMap { p: AnglesSet ->
|
||||
yaws.asSequence().map {
|
||||
DynamicTest.dynamicTest(
|
||||
"Adjustment Rotation Test of Tracker(${p.pitch},${p.yaw},${p.roll}), Ref $it"
|
||||
"Adjustment Rotation Test of Tracker(${p.pitch},${p.yaw},${p.roll}), Ref $it",
|
||||
) {
|
||||
testAdjustedTrackerRotation(
|
||||
q(p.pitch.toFloat(), p.yaw.toFloat(), p.roll.toFloat()),
|
||||
0,
|
||||
it,
|
||||
0
|
||||
0,
|
||||
)
|
||||
}
|
||||
}.asStream()
|
||||
@@ -94,7 +94,7 @@ class ReferenceAdjustmentsTests {
|
||||
hasRotation = true,
|
||||
isInternal = true,
|
||||
imuType = IMUType.UNKNOWN,
|
||||
needsReset = true
|
||||
needsReset = true,
|
||||
)
|
||||
tracker.setRotation(trackerQuat)
|
||||
tracker.resetsHandler.resetFull(referenceQuat)
|
||||
@@ -106,7 +106,7 @@ class ReferenceAdjustmentsTests {
|
||||
Assertions.assertEquals(
|
||||
QuatEqualFullWithEpsilon(referenceQuat),
|
||||
QuatEqualFullWithEpsilon(read),
|
||||
"Adjusted quat is not equal to reference quat (${toDegs(referenceQuat)} vs ${toDegs(read)})"
|
||||
"Adjusted quat is not equal to reference quat (${toDegs(referenceQuat)} vs ${toDegs(read)})",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ class ReferenceAdjustmentsTests {
|
||||
hasRotation = true,
|
||||
isInternal = true,
|
||||
imuType = IMUType.UNKNOWN,
|
||||
needsReset = true
|
||||
needsReset = true,
|
||||
)
|
||||
tracker.setRotation(trackerQuat)
|
||||
tracker.resetsHandler.resetYaw(referenceQuat)
|
||||
@@ -136,7 +136,7 @@ class ReferenceAdjustmentsTests {
|
||||
Assertions.assertEquals(
|
||||
QuatEqualYawWithEpsilon(referenceQuat),
|
||||
QuatEqualYawWithEpsilon(read),
|
||||
"Adjusted quat is not equal to reference quat (${toDegs(referenceQuat)} vs ${toDegs(read)})"
|
||||
"Adjusted quat is not equal to reference quat (${toDegs(referenceQuat)} vs ${toDegs(read)})",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ class ReferenceAdjustmentsTests {
|
||||
hasRotation = true,
|
||||
isInternal = true,
|
||||
imuType = IMUType.UNKNOWN,
|
||||
needsReset = true
|
||||
needsReset = true,
|
||||
)
|
||||
tracker.setRotation(trackerQuat)
|
||||
tracker.resetsHandler.resetFull(referenceQuat)
|
||||
@@ -177,13 +177,13 @@ class ReferenceAdjustmentsTests {
|
||||
EulerOrder.YZX,
|
||||
pitch * FastMath.DEG_TO_RAD,
|
||||
yaw * FastMath.DEG_TO_RAD,
|
||||
roll * FastMath.DEG_TO_RAD
|
||||
roll * FastMath.DEG_TO_RAD,
|
||||
).toQuaternion()
|
||||
val rotationCompare = EulerAngles(
|
||||
EulerOrder.YZX,
|
||||
pitch * FastMath.DEG_TO_RAD,
|
||||
(yaw + refYaw) * FastMath.DEG_TO_RAD,
|
||||
roll * FastMath.DEG_TO_RAD
|
||||
roll * FastMath.DEG_TO_RAD,
|
||||
).toQuaternion()
|
||||
rotationNode.localTransform.rotation = rotation
|
||||
rotationNode.update()
|
||||
@@ -200,7 +200,7 @@ class ReferenceAdjustmentsTests {
|
||||
FloatMath.equalsToZero(anglesDiff.x) &&
|
||||
FloatMath.equalsToZero(anglesDiff.y) &&
|
||||
FloatMath.equalsToZero(anglesDiff.z),
|
||||
name(yaw, pitch, roll, angles, anglesAdj, anglesDiff)
|
||||
name(yaw, pitch, roll, angles, anglesAdj, anglesDiff),
|
||||
)
|
||||
} else {
|
||||
if (FloatMath.equalsToZero(anglesDiff.x) &&
|
||||
@@ -237,7 +237,7 @@ class ReferenceAdjustmentsTests {
|
||||
EulerOrder.YZX,
|
||||
degs1.x,
|
||||
degs1.y + FastMath.TWO_PI,
|
||||
degs1.z
|
||||
degs1.z,
|
||||
)
|
||||
}
|
||||
if (degs2.y < -FloatMath.ANGLE_EPSILON_RAD) {
|
||||
@@ -245,21 +245,17 @@ class ReferenceAdjustmentsTests {
|
||||
EulerOrder.YZX,
|
||||
degs2.x,
|
||||
degs2.y + FastMath.TWO_PI,
|
||||
degs2.z
|
||||
degs2.z,
|
||||
)
|
||||
}
|
||||
return FloatMath.equalsWithEpsilon(degs1.y, degs2.y)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return q.hashCode()
|
||||
}
|
||||
override fun hashCode(): Int = q.hashCode()
|
||||
}
|
||||
|
||||
data class QuatEqualFullWithEpsilon(val q: Quaternion) {
|
||||
override fun hashCode(): Int {
|
||||
return q.hashCode()
|
||||
}
|
||||
override fun hashCode(): Int = q.hashCode()
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other == null) return false
|
||||
@@ -275,7 +271,7 @@ class ReferenceAdjustmentsTests {
|
||||
EulerOrder.YZX,
|
||||
degs1.x,
|
||||
degs1.y + FastMath.TWO_PI,
|
||||
degs1.z
|
||||
degs1.z,
|
||||
)
|
||||
}
|
||||
if (degs2.y < -FloatMath.ANGLE_EPSILON_RAD) {
|
||||
@@ -283,7 +279,7 @@ class ReferenceAdjustmentsTests {
|
||||
EulerOrder.YZX,
|
||||
degs2.x,
|
||||
degs2.y + FastMath.TWO_PI,
|
||||
degs2.z
|
||||
degs2.z,
|
||||
)
|
||||
}
|
||||
return (
|
||||
@@ -305,8 +301,7 @@ class ReferenceAdjustmentsTests {
|
||||
val anglesSet: Stream<AnglesSet>
|
||||
get() = yaws.asSequence()
|
||||
.zip(pitches.asSequence())
|
||||
.zip(rolls.asSequence()) {
|
||||
(yaw, pitch), roll ->
|
||||
.zip(rolls.asSequence()) { (yaw, pitch), roll ->
|
||||
AnglesSet(pitch, yaw, roll)
|
||||
}.asStream()
|
||||
|
||||
@@ -317,8 +312,7 @@ class ReferenceAdjustmentsTests {
|
||||
angles: EulerAngles,
|
||||
anglesAdj: EulerAngles,
|
||||
anglesDiff: EulerAngles,
|
||||
): String {
|
||||
return """Rot: $yaw/$pitch/$roll.
|
||||
): String = """Rot: $yaw/$pitch/$roll.
|
||||
Angles: ${prettyNumber(angles.x * FastMath.RAD_TO_DEG, 1)}/${prettyNumber(anglesAdj.x * FastMath.RAD_TO_DEG, 1)},
|
||||
${prettyNumber(angles.y * FastMath.RAD_TO_DEG, 1)}/${prettyNumber(anglesAdj.y * FastMath.RAD_TO_DEG, 1)},
|
||||
${prettyNumber(angles.z * FastMath.RAD_TO_DEG, 1)}/${prettyNumber(anglesAdj.z * FastMath.RAD_TO_DEG, 1)}.
|
||||
@@ -326,16 +320,13 @@ class ReferenceAdjustmentsTests {
|
||||
${prettyNumber(anglesDiff.y * FastMath.RAD_TO_DEG, 1)},
|
||||
${prettyNumber(anglesDiff.z * FastMath.RAD_TO_DEG, 1)}
|
||||
""".replace('\n', ' ')
|
||||
}
|
||||
|
||||
fun q(pitch: Float, yaw: Float, roll: Float): Quaternion {
|
||||
return EulerAngles(
|
||||
EulerOrder.YZX,
|
||||
pitch * FastMath.DEG_TO_RAD,
|
||||
yaw * FastMath.DEG_TO_RAD,
|
||||
roll * FastMath.DEG_TO_RAD
|
||||
).toQuaternion()
|
||||
}
|
||||
fun q(pitch: Float, yaw: Float, roll: Float): Quaternion = EulerAngles(
|
||||
EulerOrder.YZX,
|
||||
pitch * FastMath.DEG_TO_RAD,
|
||||
yaw * FastMath.DEG_TO_RAD,
|
||||
roll * FastMath.DEG_TO_RAD,
|
||||
).toQuaternion()
|
||||
|
||||
fun toDegs(q: Quaternion): String {
|
||||
val (_, x, y, z) = q.toEulerAngles(EulerOrder.YZX)
|
||||
|
||||
@@ -201,14 +201,13 @@ class QuaternionTest {
|
||||
assertEquals(v2, v1)
|
||||
}
|
||||
|
||||
@Suppress("ktlint")
|
||||
@Test
|
||||
fun toMatrix() {
|
||||
/* ktlint-disable */
|
||||
val m1 = Matrix3(
|
||||
-1f, 0f, 0f,
|
||||
0f, -1f, 0f,
|
||||
0f, 0f, 1f)
|
||||
/* ktlint-enable */
|
||||
val m2 = Quaternion(0f, 0f, 0f, 2f).toMatrix()
|
||||
assertEquals(m1, m2)
|
||||
}
|
||||
@@ -262,7 +261,7 @@ class QuaternionTest {
|
||||
val squareSum = expected.lenSq() + actual.lenSq()
|
||||
assertTrue(
|
||||
len <= tolerance * tolerance * squareSum,
|
||||
"Expected: $expected but got: $actual"
|
||||
"Expected: $expected but got: $actual",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -274,9 +273,7 @@ fun randInt(): Int {
|
||||
return randSeed
|
||||
}
|
||||
|
||||
fun randFloat(): Float {
|
||||
return randInt().toFloat() / 2147483648
|
||||
}
|
||||
fun randFloat(): Float = randInt().toFloat() / 2147483648
|
||||
|
||||
fun randGaussian(): Float {
|
||||
var thing = 1f - randFloat()
|
||||
@@ -287,22 +284,14 @@ fun randGaussian(): Float {
|
||||
return sqrt(-2f * ln(thing)) * cos(PI.toFloat() * randFloat())
|
||||
}
|
||||
|
||||
fun randMatrix(): Matrix3 {
|
||||
return Matrix3(
|
||||
randGaussian(), randGaussian(), randGaussian(),
|
||||
randGaussian(), randGaussian(), randGaussian(),
|
||||
randGaussian(), randGaussian(), randGaussian()
|
||||
)
|
||||
}
|
||||
fun randMatrix(): Matrix3 = Matrix3(
|
||||
randGaussian(), randGaussian(), randGaussian(),
|
||||
randGaussian(), randGaussian(), randGaussian(),
|
||||
randGaussian(), randGaussian(), randGaussian(),
|
||||
)
|
||||
|
||||
fun randQuaternion(): Quaternion {
|
||||
return Quaternion(randGaussian(), randGaussian(), randGaussian(), randGaussian())
|
||||
}
|
||||
fun randQuaternion(): Quaternion = Quaternion(randGaussian(), randGaussian(), randGaussian(), randGaussian())
|
||||
|
||||
fun randRotMatrix(): Matrix3 {
|
||||
return randQuaternion().toMatrix()
|
||||
}
|
||||
fun randRotMatrix(): Matrix3 = randQuaternion().toMatrix()
|
||||
|
||||
fun randVector(): Vector3 {
|
||||
return Vector3(randGaussian(), randGaussian(), randGaussian())
|
||||
}
|
||||
fun randVector(): Vector3 = Vector3(randGaussian(), randGaussian(), randGaussian())
|
||||
|
||||
@@ -88,7 +88,7 @@ fun main(args: Array<String>) {
|
||||
null,
|
||||
"SlimeVR start-up error! A minimum of Java 17 is required.",
|
||||
"SlimeVR: Java Runtime Mismatch",
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
JOptionPane.ERROR_MESSAGE,
|
||||
)
|
||||
LogManager.closeLogger()
|
||||
return
|
||||
@@ -102,7 +102,7 @@ fun main(args: Array<String>) {
|
||||
LogManager
|
||||
.severe(
|
||||
"SlimeVR start-up error! Required ports are busy. " +
|
||||
"Make sure there is no other instance of SlimeVR Server running."
|
||||
"Make sure there is no other instance of SlimeVR Server running.",
|
||||
)
|
||||
JOptionPane
|
||||
.showMessageDialog(
|
||||
@@ -110,7 +110,7 @@ fun main(args: Array<String>) {
|
||||
"SlimeVR start-up error! Required ports are busy. " +
|
||||
"Make sure there is no other instance of SlimeVR Server running.",
|
||||
"SlimeVR: Ports are busy",
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
JOptionPane.ERROR_MESSAGE,
|
||||
)
|
||||
LogManager.closeLogger()
|
||||
return
|
||||
@@ -122,13 +122,13 @@ fun main(args: Array<String>) {
|
||||
::provideSteamVRBridge,
|
||||
::provideFeederBridge,
|
||||
{ _ -> DesktopSerialHandler() },
|
||||
configDir
|
||||
configDir,
|
||||
)
|
||||
vrServer.start()
|
||||
|
||||
// Start service for USB HID trackers
|
||||
TrackersHID(
|
||||
"Sensors HID service"
|
||||
"Sensors HID service",
|
||||
) { tracker: Tracker -> vrServer.registerTracker(tracker) }
|
||||
|
||||
Keybinding(vrServer)
|
||||
@@ -162,7 +162,7 @@ fun provideSteamVRBridge(
|
||||
"steamvr",
|
||||
"SteamVR Driver Bridge",
|
||||
"""\\.\pipe\SlimeVRDriver""",
|
||||
computedTrackers
|
||||
computedTrackers,
|
||||
)
|
||||
} else if (OperatingSystem.currentPlatform == OperatingSystem.LINUX) {
|
||||
var linuxBridge: SteamVRBridge? = null
|
||||
@@ -173,12 +173,12 @@ fun provideSteamVRBridge(
|
||||
"SteamVR Driver Bridge",
|
||||
Paths.get(OperatingSystem.socketDirectory, "SlimeVRDriver")
|
||||
.toString(),
|
||||
computedTrackers
|
||||
computedTrackers,
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
LogManager.severe(
|
||||
"Failed to initiate Unix socket, disabling driver bridge...",
|
||||
ex
|
||||
ex,
|
||||
)
|
||||
}
|
||||
driverBridge = linuxBridge
|
||||
@@ -191,7 +191,7 @@ fun provideSteamVRBridge(
|
||||
} catch (e: Exception) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@@ -213,9 +213,10 @@ fun provideFeederBridge(
|
||||
"steamvr_feeder",
|
||||
"SteamVR Feeder Bridge",
|
||||
"""\\.\pipe\SlimeVRInput""",
|
||||
FastList()
|
||||
FastList(),
|
||||
)
|
||||
}
|
||||
|
||||
OperatingSystem.LINUX -> {
|
||||
feederBridge = UnixSocketBridge(
|
||||
server,
|
||||
@@ -223,9 +224,10 @@ fun provideFeederBridge(
|
||||
"SteamVR Feeder Bridge",
|
||||
Paths.get(OperatingSystem.socketDirectory, "SlimeVRInput")
|
||||
.toString(),
|
||||
FastList()
|
||||
FastList(),
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
feederBridge = null
|
||||
}
|
||||
|
||||
@@ -31,7 +31,9 @@ class SerialPortWrapper(val port: SerialPort) : SlimeSerialPort() {
|
||||
get() = port.productID
|
||||
}
|
||||
|
||||
class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
|
||||
class DesktopSerialHandler :
|
||||
SerialHandler(),
|
||||
SerialPortMessageListener {
|
||||
private val listeners: MutableList<SerialListener> = CopyOnWriteArrayList()
|
||||
private val getDevicesTimer = Timer("GetDevicesTimer")
|
||||
private var currentPort: SerialPort? = null
|
||||
@@ -52,13 +54,13 @@ class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
|
||||
} catch (t: Throwable) {
|
||||
LogManager.severe(
|
||||
"[SerialHandler] Error while watching for new devices, cancelling the \"getDevicesTimer\".",
|
||||
t
|
||||
t,
|
||||
)
|
||||
getDevicesTimer.cancel()
|
||||
}
|
||||
},
|
||||
0,
|
||||
3000
|
||||
3000,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -92,7 +94,7 @@ class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
|
||||
}
|
||||
if (newPort == null) {
|
||||
LogManager.info(
|
||||
"[SerialHandler] No serial ports found to connect to (${ports.size}) total ports"
|
||||
"[SerialHandler] No serial ports found to connect to (${ports.size}) total ports",
|
||||
)
|
||||
return false
|
||||
}
|
||||
@@ -100,7 +102,7 @@ class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
|
||||
if (SerialPortWrapper(newPort) != currentPort?.let { SerialPortWrapper(it) }) {
|
||||
LogManager.info(
|
||||
"[SerialHandler] Closing current serial port " +
|
||||
currentPort!!.descriptivePortName
|
||||
currentPort!!.descriptivePortName,
|
||||
)
|
||||
currentPort!!.removeDataListener()
|
||||
currentPort!!.closePort()
|
||||
@@ -113,14 +115,14 @@ class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
|
||||
currentPort = newPort
|
||||
LogManager.info(
|
||||
"[SerialHandler] Trying to connect to new serial port " +
|
||||
currentPort!!.descriptivePortName
|
||||
currentPort!!.descriptivePortName,
|
||||
)
|
||||
currentPort?.setBaudRate(115200)
|
||||
currentPort?.clearRTS()
|
||||
currentPort?.clearDTR()
|
||||
if (currentPort?.openPort(1000) == false) {
|
||||
LogManager.warning(
|
||||
"[SerialHandler] Can't open serial port ${currentPort?.descriptivePortName}, last error: ${currentPort?.lastErrorCode}"
|
||||
"[SerialHandler] Can't open serial port ${currentPort?.descriptivePortName}, last error: ${currentPort?.lastErrorCode}",
|
||||
|
||||
)
|
||||
currentPort = null
|
||||
@@ -154,13 +156,13 @@ class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
|
||||
currentPort?.closePort()
|
||||
listeners.forEach { it.onSerialDisconnected() }
|
||||
LogManager.info(
|
||||
"[SerialHandler] Port ${currentPort?.descriptivePortName} closed okay"
|
||||
"[SerialHandler] Port ${currentPort?.descriptivePortName} closed okay",
|
||||
)
|
||||
currentPort = null
|
||||
} catch (e: Exception) {
|
||||
LogManager.warning(
|
||||
"[SerialHandler] Error closing port ${currentPort?.descriptivePortName}",
|
||||
e
|
||||
e,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -198,12 +200,10 @@ class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
|
||||
listeners.forEach { it.onSerialLog(str) }
|
||||
}
|
||||
|
||||
override fun getListeningEvents(): Int {
|
||||
return (
|
||||
SerialPort.LISTENING_EVENT_PORT_DISCONNECTED
|
||||
or SerialPort.LISTENING_EVENT_DATA_RECEIVED
|
||||
)
|
||||
}
|
||||
override fun getListeningEvents(): Int = (
|
||||
SerialPort.LISTENING_EVENT_PORT_DISCONNECTED
|
||||
or SerialPort.LISTENING_EVENT_DATA_RECEIVED
|
||||
)
|
||||
|
||||
override fun serialEvent(event: SerialPortEvent) {
|
||||
when (event.eventType) {
|
||||
@@ -212,6 +212,7 @@ class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
|
||||
val s = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(newData)).toString()
|
||||
addLog(s)
|
||||
}
|
||||
|
||||
SerialPort.LISTENING_EVENT_PORT_DISCONNECTED -> {
|
||||
closeSerial()
|
||||
}
|
||||
@@ -222,13 +223,9 @@ class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
|
||||
override val isConnected: Boolean
|
||||
get() = currentPort?.isOpen ?: false
|
||||
|
||||
override fun getMessageDelimiter(): ByteArray {
|
||||
return byteArrayOf(0x0A.toByte())
|
||||
}
|
||||
override fun getMessageDelimiter(): ByteArray = byteArrayOf(0x0A.toByte())
|
||||
|
||||
override fun delimiterIndicatesEndOfMessage(): Boolean {
|
||||
return true
|
||||
}
|
||||
override fun delimiterIndicatesEndOfMessage(): Boolean = true
|
||||
|
||||
override val knownPorts: Stream<SerialPortWrapper>
|
||||
get() = SerialPort.getCommPorts()
|
||||
|
||||
@@ -4,7 +4,5 @@ import dev.slimevr.tracking.trackers.Device
|
||||
import dev.slimevr.tracking.trackers.Tracker
|
||||
|
||||
class HIDDevice(val hidId: Int) : Device() {
|
||||
fun getTracker(id: Int): Tracker? {
|
||||
return trackers[id]
|
||||
}
|
||||
fun getTracker(id: Int): Tracker? = trackers[id]
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@ import kotlin.experimental.and
|
||||
/**
|
||||
* Receives trackers data by UDP using extended owoTrack protocol.
|
||||
*/
|
||||
class TrackersHID(name: String, private val trackersConsumer: Consumer<Tracker>) : Thread(name), HidServicesListener {
|
||||
class TrackersHID(name: String, private val trackersConsumer: Consumer<Tracker>) :
|
||||
Thread(name),
|
||||
HidServicesListener {
|
||||
private val devices: MutableList<HIDDevice> = mutableListOf()
|
||||
private val devicesBySerial: MutableMap<String, MutableList<Int>> = HashMap()
|
||||
private val devicesByHID: MutableMap<HidDevice, MutableList<Int>> = HashMap()
|
||||
@@ -107,7 +109,7 @@ class TrackersHID(name: String, private val trackersConsumer: Consumer<Tracker>)
|
||||
allowFiltering = true,
|
||||
needsReset = true,
|
||||
needsMounting = true,
|
||||
usesTimeout = false
|
||||
usesTimeout = false,
|
||||
)
|
||||
// usesTimeout false because HID trackers aren't "Disconnected" unless receiver is physically removed probably
|
||||
// TODO: Could tracker maybe use "Timed out" status without marking as disconnecting?
|
||||
@@ -116,7 +118,7 @@ class TrackersHID(name: String, private val trackersConsumer: Consumer<Tracker>)
|
||||
imuTracker.status = sensorStatus
|
||||
LogManager
|
||||
.info(
|
||||
"[TrackerServer] Added sensor $trackerId for ${device.name}, type $sensorType"
|
||||
"[TrackerServer] Added sensor $trackerId for ${device.name}, type $sensorType",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -227,9 +229,7 @@ class TrackersHID(name: String, private val trackersConsumer: Consumer<Tracker>)
|
||||
override fun run() { // Doesn't seem to run
|
||||
}
|
||||
|
||||
fun getDevices(): List<Device> {
|
||||
return devices
|
||||
}
|
||||
fun getDevices(): List<Device> = devices
|
||||
|
||||
override fun hidDeviceAttached(event: HidServicesEvent) {
|
||||
checkConfigureDevice(event.hidDevice)
|
||||
|
||||
@@ -20,6 +20,7 @@ pluginManagement {
|
||||
val spotlessVersion: String by settings
|
||||
val shadowJarVersion: String by settings
|
||||
val buildconfigVersion: String by settings
|
||||
val grgitVersion: String by settings
|
||||
plugins {
|
||||
kotlin("plugin.serialization") version kotlinVersion
|
||||
kotlin("jvm") version kotlinVersion
|
||||
@@ -27,6 +28,7 @@ pluginManagement {
|
||||
id("com.diffplug.spotless") version spotlessVersion
|
||||
id("com.github.johnrengelman.shadow") version shadowJarVersion
|
||||
id("com.github.gmazzo.buildconfig") version buildconfigVersion
|
||||
id("org.ajoberstar.grgit") version grgitVersion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user