Skip to content

Comments

Add Derived Velocity Tracking Support for Natural Locomotion#1750

Closed
M1DNYT3 wants to merge 13 commits intoSlimeVR:mainfrom
M1DNYT3:velocity
Closed

Add Derived Velocity Tracking Support for Natural Locomotion#1750
M1DNYT3 wants to merge 13 commits intoSlimeVR:mainfrom
M1DNYT3:velocity

Conversation

@M1DNYT3
Copy link

@M1DNYT3 M1DNYT3 commented Feb 16, 2026

Add Derived Velocity Tracking Support for Natural Locomotion

Overview

This PR implements comprehensive velocity tracking functionality for SlimeVR trackers, enabling support for Natural Locomotion and similar locomotion systems that rely on velocity data. The implementation includes server-side velocity calculation, configurable scaling presets, role-based policies, and a complete GUI for configuration and real-time monitoring.

⚠️ Merge Order: This PR depends on the corresponding SolarXR Protocol PR being merged first. The protocol PR updates the submodule, and this PR contains the server implementation that uses the new protocol fields. Merging this PR before the protocol PR will break the build.

Key Features

Server-Side Implementation

  • Velocity Calculation System: Added derived velocity calculation for tracked positions with configurable update intervals and smoothing
  • Role-Based Policy Engine: Implemented VelocityRolePolicy to control which tracker roles can send velocity data, with implicit blacklisting of non-movement trackers (HMD, controllers, shoulders, neck, lower arms)
  • Configuration System: Added VelocityConfig with persistent settings for enable/disable state, role presets (ALL, HYBRID, CUSTOM), and scaling presets (UNSCALED, HYBRID, CUSTOM_UNIFIED, CUSTOM_PER_AXIS)
  • Per-Axis Scaling: Support for independent X/Y/Z velocity scaling with optional upscaling beyond 1.0 (experimental feature with warnings)
  • Hybrid Preset: Pre-tuned scaling values (X: 0.10, Y: 0.75, Z: 0.10) optimized for Natural Locomotion with FBT in VRChat

Protocol Integration

  • Updated ProtobufMessages: Regenerated from latest OpenVR Driver to support velocity transmission to SteamVR
  • SolarXR Protocol Extension: Added velocity data to tracker data feed with raw and scaled velocity vectors
  • RPC Settings Support: Full bidirectional communication for velocity settings between server and GUI

GUI Features

  • Comprehensive Settings Panel (Settings > General > Tracker Settings):
    • Global velocity enable/disable toggle
    • Tracker role preset selection (ALL/HYBRID/CUSTOM) with per-role checkboxes for CUSTOM mode
    • Velocity scaling overrides with preset selection
    • Advanced scaling controls with per-axis sliders (0.01-1.00 range, 0.01-5.00 with upscaling enabled)
    • Context-aware tooltips and warnings
  • Real-Time Velocity Display: Added velocity monitoring to IMU Visualizer Widget showing both raw and scaled velocity with appropriate status messages
  • Instructions Modal: Comprehensive setup guide covering prerequisites, recommended Natural Locomotion settings, and common issues troubleshooting
  • Full Localization: All new UI strings added to English translation file with proper FTL formatting

Dynamic Behavior

  • Runtime Configuration: All settings can be changed on-the-fly without server restart
  • Intelligent Mapping: Automatic physical-to-synthetic tracker mapping with fallback logic for unmapped body parts
  • Status-Aware UI: Velocity fields show appropriate messages based on tracker state:
    • Active velocity display when data is available
    • "Supplied by HMD/controllers" for head and hands
    • "Movement captured by other body parts" for implicitly disabled trackers
    • "Disabled in settings" when explicitly disabled via configuration
    • Greyed-out display when tracker is not allowed to send velocity

Technical Details

Modified Components

  • Core Server (server/core/):

    • Tracker.kt: Added velocity calculation, scaling logic, and policy checks
    • VelocityRolePolicy.kt: Role-to-group mappings and allowance logic
    • VelocityConfig.kt: Configuration data classes and defaults
    • HumanSkeleton.kt: Integration hook for velocity configuration
    • ProtobufBridge.kt: Velocity data transmission to OpenVR Driver
    • RPCSettingsBuilder.kt & RPCSettingsHandler.kt: RPC protocol handlers for settings
    • DataFeedBuilder.kt: Tracker data feed with velocity information
  • GUI (gui/src/):

    • GeneralSettings.tsx: Main velocity settings UI with dynamic rendering
    • IMUVisualizerWidget.tsx: Real-time velocity display in tracker cards
    • VelocityInstructionsModal.tsx: Setup instructions and troubleshooting guide
    • tracker.ts & velocity-settings.ts: React hooks for data management
    • datafeed-config.ts: Configuration types
  • Protocol (solarxr-protocol): Updated to include velocity schema and regenerated all language bindings

Configuration File Changes

The feature adds the following to vrconfig.yml:

velocityConfig:
  sendDerivedVelocity: false  # Global enable/disable
  preset: ALL                 # Role preset: ALL, HYBRID, or CUSTOM
  enabledGroups: []           # Array of role groups for CUSTOM mode (e.g., ["CHEST", "WAIST", "FEET"])
  overrideScalingPreset: false # Enable custom scaling
  scalingPreset: UNSCALED     # Scaling preset selection
  enableUpscaling: false      # Allow values > 1.0 (experimental)
  scale:
    scaleX: 0.5
    scaleY: 0.5
    scaleZ: 0.5

Use Cases

Primary: Natural Locomotion with FBT

  • Recommended settings: HYBRID role preset + HYBRID scaling preset
  • Provides lower body + waist velocity while maintaining FBT stability
  • Requires "walk-in-place" activation in NaLo to prevent constant walking

Secondary: Natural Locomotion without FBT

  • Can use ALL tracker preset with custom scaling as needed
  • Greater flexibility for experimentation with scaling values

Warning: Not Recommended for FBT-Only Setups

  • Velocity calculation adds minor jitter due to SteamVR position prediction
  • Should be disabled entirely if not using Natural Locomotion or similar systems

Testing Recommendations

  1. Verify proper floor level and boundary setup in the VR headset
  2. Test with HYBRID preset first for known-good baseline
  3. Monitor jitter in VRChat/Beat Saber while moving trackers
  4. Validate Natural Locomotion detects tracker movement correctly
  5. Test runtime configuration changes apply immediately

Breaking Changes

None - feature is disabled by default and opt-in.

Dependencies

  • SolarXR Protocol PR (must be merged first): Add Velocity Tracking Protocol Support SolarXR-Protocol#197
    • This PR updates the solarxr-protocol submodule reference to include velocity support
    • The protocol PR can be merged independently, but this server PR requires it to be merged first
  • Regenerated ProtobufMessages from the latest OpenVR Driver main branch

Related Issues

Implements support for Natural Locomotion integration while maintaining FBT compatibility: #25

@github-actions github-actions bot added Area: Skeletal Model Deals with the model of the skeleton and its pose Area: Application Protocol Related to communication with apps like the GUI, overlay, games Area: GUI Related to the GUI Area: Translation Improvements or additions to translations Area: SteamVR Driver Related to the SteamVR Driver Area: Server Related to the server labels Feb 16, 2026
@Eirenliel
Copy link
Member

What the fuck...

First, we don't accept AI-generated code. I'm not even reading all that, this should have been a couple hundred lines feature, not +10k -10k...

Second, why is it so unnecessarily "comprehensive"? Who needs all of these settings, policies and other stuff. You either send real speed or you don't, maybe have a on/off setting.

@Eirenliel Eirenliel closed this Feb 16, 2026
@M1DNYT3
Copy link
Author

M1DNYT3 commented Feb 16, 2026

There was a prolonged discussion with @ButterscotchV and @kitlith on Discord. 10k lines are because Protobuf was regenerated. The entirety of the code is tested and I spent like two months developing and testing it. You spent like maybe 5 minutes looking at the PR and started bitching. Job well done I suppose.

@Eirenliel
Copy link
Member

We have rules on AI-generated code and this PR breaks them:

  1. No substantially AI-generated content should be shared or contributed seriously. That includes posting AI-generated images as "art", AI-generated sounds as "music", and especially AI-generated code.
  • ...
  • We especially do not allow AI-generated code submitted or committed to our repositories. Limited use of AI-assisted tools like auto-completition, data filtering, and repetitive code generation is allowed, but if the code submitted is of a poor quality (AI slop), it's not allowed. We leave the final decision to our discretion. Don't use AI if you don't know what you're doing.

In addition, maybe I have spent less than 5 minutes reviewing code, because I don't want to get brain damage, but maintainers including @ButterscotchV and @loucass003 have reviewed it and had things to say... I'm just taking a bullet here enforcing the rules.

@M1DNYT3
Copy link
Author

M1DNYT3 commented Feb 16, 2026

I agree that frontend part is not the best, as it's not one of my strongest suits. However, I may assure that the backend is pretty clean. I would've really accepted any request to eliminate bad practices in the UI or rewrite entire blocks of code on certain files accordingly. There's also a suggestion mentioned on Discord to put Protobuf update into a separate PR so it won't look like 10k lines got changed as part of my actual code.

Some of the UI code is AI assisted, but not vibe coded.

@jabberrock
Copy link
Contributor

I'd agree with @Eirenliel that the change is too big, but most of the code actually comes from:

  1. Re-generated protobuf file (+7,968 -9,157)
  2. Fine-grained configuration (which adds SolarXR changes, config changes, GUI changes)

It's not up to me if SlimeVR wants to add full NaLo support, but if all we are doing is sending velocity to the driver, I believe that we can create a MVP which is just a few hundred lines of code.

I'd suggest:

  1. Regenerate the protobuf file in its own commit (which should be super easy to review)
  2. Just a single setting in vrconfig.yaml to enable/disable computing velocity (don't even need UI in the first version)
  3. Find some beta testers in the beta-testing-forum

@jabberrock
Copy link
Contributor

We chatted further on Discord.

It sounds like just sending velocity to OpenVR isn't good enough for NaLo to behave well. The reason this PR has a lot of config is so that the user can customize the NaLo behavior.

I'm worried that adding these settings to SlimeVR means that SlimeVR will be supporting NaLo as a feature. The separation would be better if SlimeVR published raw velocities, and some program or driver outside of SlimeVR would apply the NaLo adjustments. Unfortunately, NaLo itself doesn't seem to be maintained anymore.

@kitlith
Copy link
Member

kitlith commented Feb 17, 2026

since I have been mentioned here, I feel the need to clarify my position.

I am a 3rd party contributor. I happen to be the main person approving PRs to SlimeVR-Feeder-App, as I was the person who originally developed it. I also (somehow) have some amount of weight when it comes to reviewing PRs on the OpenVR driver, but do not have merge permissions there. I have mostly avoided working on the server due to both a dislike of Java and UI code, as well as unfamiliarity with the math involved in FK, IK, and motion prediction. This is to say, my opinions usually only extend to interaction with openvr.

I am supportive of piping velocity and/or accel through the whole stack. TBH, ideally, this would've happened before slimevr sprung up its own prediction mechanisms. Too late for that now, and it may take a while to fix that as a result.

I have not reviewed the code or the approach taken in this PR. The conversation I participated in was focused on "would having real velocities from the driver/feeder for the HMD/Trackers be useful?" with butterscotch answering in the affirmative, for their own needs, unrelated to this PR. I could be thinking of the wrong conversation, though.


Regarding the AI summary: As a reviewer, I would prefer to see the prompt you gave the AI over the nicely formatted, but fluffy/noisy AI generated output.

The PR description doesn't have to be long in most cases. It needs to hold what you think is the most important information we need to know, since it is the first thing we will read, and will be in the back of our heads as we review the code. Preferably, the description focuses on the "why", or your reasoning behind the choices you made, particularly on choices that may look weird at first glance, and not the "what", since we will be able to see the "what" when we take a look at the commits themselves.

Taking an old PR of mine as an example: SlimeVR/SlimeVR-OpenVR-Driver#24 (comment)

This first comment contains information that should've been in the PR description. Instead it was clarified over discord (before/during opening the PR? I don't remember) and then I backfilled it to Github for posterity. (Good thing, otherwise I would never be able to find it again.)

The weird choice that needs justification in my PR is the use of a non-standard, invented, tracking universe. Then caveats are covered both in that comment and as review comments, and in another comment I wrote up a sketch of what testing should look like.

For this PR, the weird choice would have been all the extra configuration options, and caveats could have included that you were struggling with writing the UI code.


My biggest question here is how this is interacting with the prediction mechanism built into slimevr server, and what the correct way to combine slimevr's prediction with steamvr's prediction (which this will effectively enable).

My gut feeling says that the initial implementation, before the addition of velocity scaling, felt wrong because the interaction between slimevr prediction and steamvr prediction was wrong, somehow. Unfortunately, I don't have a background in this type of math, and my gut feelings in this regard have been wrong before.

So, I agree with @jabberrock. I think the best way forward is to create an MVP version (without any AI use), of this so that people who are more familiar with the math can weigh in. If you are struggling with UI code, then you should omit the UI code entirely instead of using AI. That way, someone else who is more familiar with the UI can write it.

Aside, it can sometimes be useful to throw up a PR even before you think it is finished/polished/ready so that you have a place to receive early feedback & ask questions. I have a PR to monado that I'm going to get up soon-ish, after a prereq gets merged, even though it doesn't perfectly solve the problem, because I want to try and get feedback from people more familiar with the codebase and the other systems involved on how to fix it. This can help avoid cases where you spend a long time working on a solution to a problem, only to find out later that your solution was going in the wrong direction.

@M1DNYT3
Copy link
Author

M1DNYT3 commented Feb 17, 2026

I'll make another PR with an MVP backend-only version.

I'll try to make a UI toggle (and only toggle), separately, after I make the backend MVP PR, and I don't expect any issues with making a toggle because, for the component itself, I can reuse the existing logic, and only hook it to the right config setting.
I believe no harm will be done if I just mirror the logic of another toggle that's already in the app.

And I'll refrain from using AI to help me compose a PR description in the future because I figured it gives off a feeling that I used the same approach in writing a code.

I think the protobuf in Main branch of the server still doesn't have velocity definitions in it, so I'll make a separate PR to update protobuf in case that's actually required, so it won't confuse anyone into thinking that I added/removed 10k lines of code.

Regarding the future of the feature. If it ever gets merged, that is.
Kitlith fairly estimated:

My biggest question here is how this is interacting with the prediction mechanism built into slimevr server, and what the correct way to combine slimevr's prediction with steamvr's prediction (which this will effectively enable).

My gut feeling says that the initial implementation, before the addition of velocity scaling, felt wrong because the interaction between slimevr prediction and steamvr prediction was wrong, somehow. Unfortunately, I don't have a background in this type of math, and my gut feelings in this regard have been wrong before.

I am currently hooked to the final resolved position of a virtual tracker anchored to the skeleton.
Meaning this is after filtering and prediction made by SlimeVR. Unless I missed something, and there's something that's going on after we write a HumanSkeleton update into a tracker.

The reason for that was actually because I consider the final resolved position from SlimeVR similar to that of Vive when they resolve theirs on the hardware + driver level (Lighthouse handles corrections, so they also apply filtering of sorts before resolving and sending to SteamVR).

I drew the parallels between how Vive does this and how SlimeVR does this and came to this design choice.
This is, however, open for discussion in the future.

Oh, and it never occurred to me that we can turn off certain filtering features in the server, which, in theory, may improve the SteamVR behavior when Velocity is supplied.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: Application Protocol Related to communication with apps like the GUI, overlay, games Area: GUI Related to the GUI Area: Server Related to the server Area: Skeletal Model Deals with the model of the skeleton and its pose Area: SteamVR Driver Related to the SteamVR Driver Area: Translation Improvements or additions to translations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants