About that IVRInput
…
This is the supported, modern way forward.
- Allows for frequency modulation
- Even with ERMs instead of LRAs, offers a slightly adjustable haptics feel on Tundra Trackers
- Allows Steam to automatically map Vive/Tundra/etc Trackers with given SteamVR roles (e.g. Chest, Left Foot)
- Haptic Pancake would just be mapping from e.g. "Chest tracker" to
/avatar/parameters/something_here
- Solves the Tundra Tracker issue with the legacy haptics pulses being cut off, requiring 4 ms loops
- As part of this, we'll want a
.vrmanifest
file which will make the Bridge App auto-start with SteamVR, too
But.. it is an involved change.
I still don't get why lighthouse_console
's haptic2
command can use the new haptics API without the need for the entire SteamVR Actions system - if we could simply copy that, then Haptic Pancake itself would need almost no changes.
Further research on triggerHapticVibrationAction
and how the Lighthouse console uses it is needed.
This is a large enough project we may want to make this a v2 of Tundra Tracker support, or even a v2 of the entire Bridge App.
Considering Valve is pushing SteamVR towards OpenXR (an actually independent standard) as the replacement for OpenVR (Valve's own standard), perhaps OpenXR will provide another path forward? It looks like OpenXR uses the same rebindable Action system, though.
Using lighthouse_console
With SteamVR open and your headset connected to your PC…
Launching console
Linux
Run as your normal user:
$HOME/.local/share/Steam/steamapps/common/SteamVR/tools/lighthouse/bin/linux64/lighthouse_console
Windows
May need to run as administrator:
C:\Program Files (x86)\Steam\steamapps\common\SteamVR\tools\lighthouse\bin\win32\lighthouse_console.exe
(See this HTC thread)
Examples
Haptics help
lh> help
[…]
haptic [<duration_us>] [<interval_us>] [<repeat_count>] Trigger haptic pulse
haptic2 [<frequency_hz>] [<duration_ms>] [<amplitude_percent>] Trigger haptics
[…]
Legacy API
triggerHapticPulse()
Some long duration (4000µs duration, 4000µs interval, 100× repeat):
Modern API
triggerHapticVibrationAction()
400 Hz for 4 seconds:
SteamVR OpenVR API
Legacy API (in use now)
def triggerHapticPulse(self, controllerDeviceIndex, axisId, durationMicroSec: int) -> None:
"""
Trigger a single haptic pulse on a controller. After this call the application may not trigger another haptic pulse on this controller
and axis combination for 5ms. This function is deprecated in favor of the new IVRInput system.
"""
[…]
OpenVR says the duration is in microseconds, NOT milliseconds!
Vive Trackers are doing something wrong. (Perhaps they were built to an older spec, and HTC didn't want to break backwards compatibility for their enterprise customers?) Tundra Trackers, Index Wands, etc are doing things correctly.
Tundra Trackers do have a problem with cutting off haptic pulses longer than about 4000 microseconds, though.
Modern API (IVRInput
)
def triggerHapticVibrationAction(self, action, startSecondsFromNow: float, durationSeconds: float, frequency: float, amplitude: float, restrictToDevice) -> None:
"""Triggers a haptic event as described by the specified action"""
[…]
SteamVR now makes everything - including haptics! - rebindable with SteamVR Input 2.0, as per the Action manifest.
Haptic Pancake will no longer handle mapping to specific trackers. This is handled by SteamVR's own UI with assigning roles to trackers.
This should allow changing tracker bindings inside SteamVR and when Haptic Pancake isn't running.
This involves a lot of haptics vibrations:
vibration - The action is a output haptic vibration. Include one of these per type of haptic output in your application so they can be bound to different output devices if the user has them available. Examples include haptics due to firing a gun (that would usually be bound directly to a controller) or haptics from getting shot (which could be bound to a feedback vest worn on the chest).
And I think this is looking at…
def setActionManifestPath(self, actionManifestPath: str) -> None:
which will need generated according to the Valve wiki page
def getActionHandle(self, actionName: str):
on tracker load
def triggerHapticVibrationAction(self, action, [...]) -> None:
inside the Bridge App haptics loop
And to allow binding when Bridge App isn't running, and to have SteamVR auto-start the Bridge App, then we need a .vrmanifest
file, like how WlxOverlay-S creates it - see below.
Other context
The whole action manifest is the route VRCOSC went, though they're only handling controllers.
VRC-OSC-Manager looked interesting initially as it supports both Linux and Windows and allows multiple plugins to use one OSC input, but that entirely skips VR manifests.
Example config files
Adapted from Valve's documentation.
BridgeApp/hp_actions.json
:
{
"default_bindings": [
{
"controller_type": "some_controller",
"binding_url": "hp_bindings_fbt_trackers.json"
}
],
"actions": [
{
"name": "/actions/hp_haptics/out/chest",
"requirement" : "optional",
"type": "vibration"
},
{
"name": "/actions/hp_haptics/out/foot_left",
"requirement" : "optional",
"type": "vibration"
}
],
"action_sets": [
{
"name": "/actions/hp_haptics",
"usage": "leftright"
}
],
"localization" : [
{
"language_tag": "en_us",
"/actions/hp_haptics" : "Haptics",
"/actions/hp_haptics/out/chest" : "Touch near Chest",
"/actions/hp_haptics/out/foot_left" : "Touch near Left Foot",
}
]
}
Adapted from WlxOverlay-S actions_binding_vive.json
.
BridgeApp/hp_bindings_fbt_trackers.json
:
{
"action_manifest_version" : 0,
"app_key" : "galister.wlxoverlay-s",
"bindings" : {
"/actions/default": {
"haptics": [
{
"output": "/actions/hp_haptics/out/chest",
"path": "/user/[path for SteamVR's chest tracker role, e.g. 'hand/left']/output/haptic"
},
{
"output": "/actions/hp_haptics/out/foot_left",
"path": "/user/[path for SteamVR's left foot tracker role, e.g. 'hand/left']/output/haptic"
}
]
}
},
"category" : "steamvr_input",
"controller_type" : "TODO_vive_controller",
"description" : "Ver1",
"interaction_profile" : "",
"name" : "Haptic Pancake configuration for Full Body Trackers",
"options" : {
"mirror_actions" : false,
"simulated_controller_type" : "none"
},
"simulated_actions" : []
}
Adapted from WlxOverlay-S openvr/manifest.rs
.
BridgeApp/haptic_pancake.vrmanifest
:
{
"source" : "builtin",
"applications" : [
{
"app_key" : "z4urce.vrc-haptic-pancake",
"launch_type" : "binary",
"binary_path_linux" : "PATH/TO/hapticpancake",
"binary_path_windows" : "PATH\\TO\\hapticpancake.exe",
"is_dashboard_overlay" : false,
"strings" : {
"en_us": {
"name" : "Haptic Pancake",
"description" : "A cheap solution to enable haptic feedback on full body trackers in OSC compatible games.",
}
}
}
]
}