Skip to content

[Bug]: Right Touch: most of its solves are rejected by the gravity check (8–13° off its IMU), position keeps dropping #5

Open

Description

@mlc76520

Before you file

  • I searched the existing issues and the README's Known issues, and this is not among them.
  • I am on the latest release and can still reproduce it. (0.1.3, and the 0.1.4 pre-release)
  • I quit SteamVR, started it again, and the problem is still there.

RiftLinux version: 0.1.4 (also seen on 0.1.3)
How did you install it? .rpm package (Fedora and others)
Distribution, desktop and session: Fedora 45, GNOME 51.1, Wayland
Graphics card and driver version: NVIDIA RTX 4080, driver 615.78.08 (open kernel module)
SteamVR version, sensors and their USB ports: SteamVR build 1792185270, two CV1 sensors, both on USB 3 (5 Gbit/s, Intel chipset controller); headset on USB 3 too; no USB errors in the kernel log

Steps to reproduce

  1. Start SteamVR from Steam with both Touch controllers on (sensors at the same height, room setup done).
  2. Play anything that uses both hands (here: Universe Sandbox, SteamVR Home).
  3. Watch the monado: Controller left/right: lines in vrserver.txt and poseMatchesGravity in vrstartup-linux.txt.

What you expected

Both controllers tracked about equally well, as they were with the Oculus software on Windows on the same hardware.

What happened instead

The right controller (Touch 3, tracker Device 2) keeps dropping to orientation tracked, position not tracked (held),
the left one rarely does. Orientation is never lost, so the radio and the IMU are fine.

With recording on, the tracker log shows why: the right controller's solves are rejected by the gravity check, almost
always just above the tolerance, the left controller's almost never:

Session (recording on) Gravity tolerance Right (Device 2) rejected Left (Device 1) rejected Right's rejection angles
2026-11-04, 0.1.3, ~7 min 8° (default) 6274 142 8–13°
2026-11-06, 0.1.4, ~30 min 12° (CONSTELLATION_TRACKER_GRAVITY_TOLERANCE_DEG=12) 2415 7 12–14°, nearly all 12–13

Raising the tolerance just moves the cluster up with it: the right controller's camera solves seem to be tilted
some 10° or more from its IMU's down all the time, not now and then. Its LED fit is good (the solves are accepted
once the tolerance is wide enough), so it looks like a constant offset between the right controller's IMU and its LED
model rather than wrong solves (the comment at the tolerance says wrong Touch solves were 25–38° off).

Effect on tracking (from vrserver.txt, losses of position):

8°, 40 min 12°, 30 min
Right: losses of 2–60 s 25 8
Right: time without position (losses under 60 s) 290 s (~12 %) 66 s (~3.6 %)
Left: time without position (losses under 60 s) 140 s 102 s
Left: losses under 2 s 1 47

So 12° helps the right controller a lot, but the left one then gets many short drops (more wrong solves let through
and caught later by poseMatchesPrior?), so it is a workaround, not a fix.

A guess, not checked: the right controller's factory accelerometer offset is much larger than the left's
(AccCalibration offsets: right -0.0387, 0.0623, -0.5670, left -0.0048, 0.1711, 0.1654). rift_radio.c applies it
as M · (raw − offset); if Oculus meant M · raw − offset, the right controller would be off by more than the left.
That alone is about 5°, not 10, so there may be more to it (the IMU's seat in the controller?).

Separately, in a 2 min test with both controllers lying still, the right controller was never found: camera 1's slow
search ran out of its 50 ms budget on nearly every frame (18 search(es) out of time, 5–16 static spots left out).

Output of riftlinux-setup --json check

{
  "checks": [
    {
      "id": "arch",
      "title": "Computer",
      "state": "ok",
      "detail": "x86-64",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "steam",
      "title": "Steam and SteamVR",
      "state": "ok",
      "detail": "SteamVR (build 1792185270) at ~/.local/share/Steam/steamapps/common/SteamVR",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "package",
      "title": "Driver package",
      "state": "ok",
      "detail": "~/.local/share/riftlinux/steamvr/rift-cv1",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "registered",
      "title": "Driver registered with SteamVR",
      "state": "ok",
      "detail": "~/.local/share/riftlinux/steamvr/rift-cv1",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "others",
      "title": "Other headset drivers in SteamVR",
      "state": "ok",
      "detail": "None: SteamVR uses this driver for the headset.",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "sandboxed",
      "title": "Driver registered with Flatpak or Snap Steam",
      "state": "ok",
      "detail": "no Flatpak or Snap Steam",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "nvidia-vrr",
      "title": "NVIDIA and adaptive sync (Wayland)",
      "state": "ok",
      "detail": "no monitor offers adaptive sync",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "enabled",
      "title": "Driver enabled in SteamVR",
      "state": "ok",
      "detail": "Enabled, not blocked.",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "devices",
      "title": "Rift connected",
      "state": "ok",
      "detail": "headset, 2 sensor(s).",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "lsusb",
      "title": "Steam's headset detection",
      "state": "ok",
      "detail": "lsusb is installed; Steam can tell that the Rift is connected.",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "access",
      "title": "Device access",
      "state": "ok",
      "detail": "6 USB devices and 3 HID interfaces usable.",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "usbpower",
      "title": "USB power saving",
      "state": "ok",
      "detail": "Off for the Rift's devices.",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "holders",
      "title": "Other programs using the Rift",
      "state": "ok",
      "detail": "None (only SteamVR, Steam and RiftLinux use it).",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "headset",
      "title": "Headset mode",
      "state": "ok",
      "detail": "Normal (not in pairing mode).",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "display",
      "title": "Headset display",
      "state": "info",
      "detail": "Not visible from here: the CV1 is on HDMI only while its display is on (SteamVR running and the headset worn), and NVIDIA's driver does not show its EDID to this check. SteamVR's log says whether it found it.",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "priority",
      "title": "SteamVR compositor priority",
      "state": "ok",
      "detail": "vrcompositor-launcher has CAP_SYS_NICE.",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "openvr",
      "title": "OpenVR runtime (what Steam's games load)",
      "state": "ok",
      "detail": "SteamVR.",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "launch",
      "title": "SteamVR settings games depend on",
      "state": "ok",
      "detail": "SteamVR's defaults (no forced headset, a compositor for games).",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "steamvr-tool",
      "title": "SteamVR's compatibility tool",
      "state": "ok",
      "detail": "None forced (SteamVR runs as a Linux program).",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "env",
      "title": "Variables that take games elsewhere",
      "state": "ok",
      "detail": "None set (XR_RUNTIME_JSON, VR_OVERRIDE, VR_CONFIG_PATH, VR_LOG_PATH).",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "launchopts",
      "title": "Games' launch options",
      "state": "ok",
      "detail": "None point games at another VR runtime.",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "handles",
      "title": "Leaked GPU handles in the desktop session",
      "state": "ok",
      "detail": "None found (Steam and the desktop shell).",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "home",
      "title": "SteamVR Home left running",
      "state": "ok",
      "detail": "None (SteamVR Home runs only with SteamVR).",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "leftovers",
      "title": "Leftovers from RiftLinux tests",
      "state": "ok",
      "detail": "None found.",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "probe",
      "title": "SteamVR started by Steam's driver check",
      "state": "ok",
      "detail": "Not seen in Steam's log.",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "watchdog",
      "title": "SteamVR start watchdog in Steam",
      "state": "warn",
      "detail": "Steam still runs the watchdog from before the update: restart Steam (Steam menu, Exit, then start it again) to load the new one.",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "openxr",
      "title": "OpenXR runtime",
      "state": "ok",
      "detail": "SteamVR (OpenXR games go through SteamVR and this driver).",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "room",
      "title": "Room setup",
      "state": "ok",
      "detail": "None saved: the driver gives SteamVR a standing 2 x 2 m room at each start, so no Room Setup is needed (SteamVR's Room Setup sets your own).",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "settings",
      "title": "RiftLinux settings",
      "state": "ok",
      "detail": "Direct mode on; SteamVR starts by itself: on, when the Rift is put on or picked up; quits again when it is not put on; Steam's menu over a starting game: closed; SteamVR's standby ends when the headset is worn; controllers sleep: 5 min after the headset is off; headset taken off: black, switched off after 10 min black; moving as on a head counts as worn after 20 s (medium), for a face shield or pad; ~/.config/riftlinux/settings.json.",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "realtime",
      "title": "Real-time priority",
      "state": "ok",
      "detail": "RealtimeKit present; Steam (pid 69802) may use it.",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "calibration",
      "title": "Sensor calibration",
      "state": "ok",
      "detail": "Saved (~/.config/monado/constellation/rig.json); a moved sensor is found and placed again.",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    },
    {
      "id": "native",
      "title": "Own runtime (OpenXR without SteamVR)",
      "state": "ok",
      "detail": "/usr/lib/riftlinux/native, every library found; start it with `riftlinux-runtime`",
      "kind": null,
      "root_cmds": [],
      "fixable": false
    }
  ]
}

SteamVR's log

vrserver.txt and vrstartup-linux.txt of both sessions are available on request (they hold the devices' serial numbers). Excerpt:

[2026-11-04 23:57:16]  INFO [poseMatchesGravity] Device 2: rejected 118 solve(s) in the last second that disagree with its IMU on which way is down, the latest by 9 degrees (camera 1, source 1).
[2026-11-04 23:58:28]  INFO [poseMatchesGravity] Device 2: rejected 109 solve(s) in the last second that disagree with its IMU on which way is down, the latest by 11 degrees (camera 1, source 1).
[2026-11-06 00:41:17]  INFO [poseMatchesGravity] Device 2: rejected 58 solve(s) in the last second that disagree with its IMU on which way is down, the latest by 12 degrees (camera 0, source 0).
[2026-11-06 00:46:45]  INFO [poseMatchesGravity] Device 2: rejected 11 solve(s) in the last second that disagree with its IMU on which way is down, the latest by 12 degrees (camera 1, source 5).
[2026-11-06 00:47:53]  INFO [poseMatchesGravity] Device 2: rejected 8 solve(s) in the last second that disagree with its IMU on which way is down, the latest by 14 degrees (camera 1, source 1).

A recording

Available on request:

  • riftlinux-20261106-001925.ctdata (0.1.4, tolerance 12°, 30 min of play, 1.3 GB)
  • riftlinux-20261104-234927.ctdata (0.1.3, both controllers lying still, 2 min, 16 MB with xz)

What you already tried

  • LEDs of the right controller checked: all light up.
  • Sensors at the same height, room setup redone.
  • Battery out and back in, riftlinux-setup pair again: no change.
  • Right controller's calibration cache removed so the driver read it again: byte-identical, no change.
  • Updated to 0.1.4: no change.
  • CONSTELLATION_TRACKER_GRAVITY_TOLERANCE_DEG=12: right much better, left worse (see above).

Activity

  1. self-assigned this
    on Nov 6, 2026
  2. added
    trackingHead or controller tracking, sensors
    on Nov 6, 2026
  3. AIIX commented on Nov 6, 2026

    @AIIX
    Owner

    I checked the offset order. I picked it by measuring my own controllers lying in a lot of different positions, and M*raw - offset was one of the orders I compared. With your right controller's offset, a wrong order would tilt it by 3 to 7 degrees at most, and only in some positions. It wouldn't give you 10+ degrees all the time. My two controllers agree with their IMU within about 2 degrees.

    My guess is that the right controller's LED ring sits at a slight angle to its IMU. Has it ever been opened, had the ring replaced or glued back, or been dropped hard?

    Can you share these so I can check:

    • the two recordings, riftlinux-20261106-001925.ctdata (the 30 min one) and riftlinux-20261104-234927.ctdata (both lying still). They are in ~/.cache/riftlinux
    • both controllers' calibration files from ~/.config/monado/rift: touch2_.cal is the left one, touch3_.cal the right one
    • vrserver.txt and vrstartup-linux.txt from one of those sessions, the ones you kept. SteamVR writes them to ~/.local/share/Steam/logs

    A download link is fine.

    I won't fix this by raising the tolerance, because that's what gave your left controller the short drops. The driver will work out each controller's own offset while it's tracked well, and the check stays at 8 degrees. The right controller not being found while lying still is a separate problem, and I'll look at it with the 2 min recording.

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

Metadata

Metadata

Assignees

Labels

trackingHead or controller tracking, sensors

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions