v0.1.0
The first release. A native Linux runtime and GTK4 GUI for the Tobii Eye
Tracker 5, written in Rust, with no Tobii software installed — the USB
protocol was reverse-engineered clean-room.
Unofficial. Not affiliated with, endorsed by, or supported by Tobii.
Use at your own risk.
What works
Eye tracking
- Gaze streaming over USB: 2D gaze point, per-eye validity, eye position in the
trackbox, eye origins in millimetres, pupil size. - Follow-the-dot calibration — 7 points in three groups, computed and applied on
the device after each group, then persisted and re-applied on every connect.
Measured accuracy on a 49" 32:9 panel: 12.1 mm mean error within the
device's usable ±28° — about 0.92° at a 750 mm viewing distance. - Guided display setup, seeded from your monitor's EDID. On a curved panel the
device is told the EDID arc width (it only accepts a flat plane) and the
per-user calibration absorbs the curve. - Select which eyes to detect: both, left only, or right only.
Head tracking
- 5 DOF with no download: position, yaw and roll from the two eye origins.
- 6 DOF with an optional model: adds pitch, which two eye origins cannot
express. Read from the tracker's infrared camera at ~12.4 ms a frame. The
model is not shipped — its weights are non-commercial-only, so the program
shows the terms and fetches it only if you agree. - Output to games over opentrack's UDP protocol.
The app
- A GTK4 hub with a live instrument panel: the trackbox with a graticule, your
eyes as dots, the head drawn around them turning as you turn, a readout of
position, distance, yaw, pitch and roll, and the infrared sensor view. - Preview my gaze — a translucent click-through dot following your gaze.
- An accuracy diagnostic: a 39-target sweep reporting error per target, per
angle band and per eye. - A desktop entry, and optional start-at-login.
- A cogwheel in the header for the settings that are not about tracking —
start at login, check for updates, and save or copy the diagnostics report —
andtobii debugon the command line, so a bug report is one paste.
The tracker is only on when something needs it. Its infrared illuminators
are lit for as long as a USB session is open, so the session exists only while
the hub has focus, the gaze overlay is shown, or a flow is running — and closes
three seconds after the last of those lets go. A consequence worth knowing:
while the hub is unfocused it holds no session, so tobii headpose can claim
the device for a game without closing the hub.
Installing
Every release ships an archive and three packages. Which you want depends on
one question: do you want the built-in updater, or do you want your system to
own this?
| Install | Updates via | |
|---|---|---|
tobii-linux-<version>-<triple>.tar.gz |
tar -xzf it, then ./install.sh |
the built-in updater |
tobii-linux_<version>_amd64.deb |
sudo apt install ./tobii-linux_*.deb |
apt |
tobii-linux-<version>-1.<arch>.rpm |
sudo dnf install ./tobii-linux-*.rpm |
dnf |
PKGBUILD + tobii-linux.install |
both into one directory, then makepkg -si |
pacman |
All four install the same three things: the two binaries, the application-menu
entry, and the udev rule that makes the tracker usable without root. All four
also delete /etc/udev/rules.d/99-tobii.rules if you have one from before this
release — it says MODE="0666" and, because 99 sorts after 60, it would
override the new rule and leave the tracker world-readable. The
archive's install.sh puts the binaries in ~/.local/bin (pass a directory for
somewhere else) and asks before using sudo for the rule; the packages install
into /usr/bin and place the rule as part of the install.
The built-in updater deliberately refuses to touch a package-managed install
— it asks dpkg, rpm and pacman whether they own the binary, and if one does it
tells you to update with that instead. Overwriting a package-managed file would
leave the package database describing a file that is no longer there, and the
next upgrade would revert the update anyway.
So: to try the built-in updater, install the tar.gz.
Or from source, which works everywhere and builds against your own GTK:
git clone https://github.com/Tropaion/Tobii_Linux.git && cd Tobii_Linux
scripts/build.sh --install --udevscripts/build.sh checks its dependencies first and names anything missing with
the command to install it for your distribution. Per-distro instructions are in
the README. Re-plug the tracker afterwards so
the udev rule takes effect.
Prebuilt binaries and packages in this release are built in a Debian 13
container, so they need glibc 2.41 or newer — and the .deb and .rpm
declare that, so your package manager refuses rather than installing something
that cannot start. On an older distribution, build from source; the PKGBUILD
does this by design.
Updating
The hub checks for a new release when it opens and can show the changelog and
install it. The check can be switched off, in Settings or with
TOBII_NO_UPDATE_CHECK=1.
Please read this once. The checksums published with a release are fetched
from that same release over the same connection, so they prove the download
arrived intact and nothing about who produced it. There is no signature.
Installing an update trusts this project's GitHub releases exactly as much as
downloading a binary from the releases page and running it by hand. That is a
normal amount of trust for a program you already run, but it is not the
guarantee a checksum is often assumed to give.
What the updater does protect against: a corrupted or truncated download; an
archive whose members are symlinks; and — the one that matters most — a release
built against newer system libraries than your machine has. The new binaries are
run once before they are installed, so that failure is refused while the
working ones are still in place, and any failure rolls every binary back.
Reporting a problem
tobii debug prints everything an issue needs in one paste — versions, the
distro and kernel, library versions, whether the tracker is on the bus, what is
configured, and the tail of the log. The hub does the same from the cogwheel
in its header: a save button that asks where to put it, and a copy button.
It is meant to be read before you send it: no calibration data, your monitor id
hashed, and no username, home path or hostname. The hash is salted per
install — an unsalted one is not a redaction but an encoding, and the
maintainer's own monitor id was recovered from its digest in 0.07 seconds on one
core. Two reports from the same machine still carry the same id, which is the
only thing that hash was ever for.
Issues use a form that asks for it. If you would rather not paste diagnostics,
Discussions is linked from the same page and asks for nothing.
What the pre-release review changed
This release was reviewed in five rounds, and the last one found things worth
naming here because they are the kind a user is entitled to know were wrong:
- The monitor hash was reversible. A brute force over 100,000 candidates
recovered the maintainer's own id from its 8-character digest in 0.07s. It is
salted per install now. - The report leaked the home path whenever
$HOMEwas not the install
prefix —sudo tobii debugprinted it in full, under a footer saying it was
redacted. It folds the invoking user's home, and anything shaped like a home
directory, and truncates whatever is left. - The udev rule never worked as designed. It was named
99-tobii.rules, and
systemd's73-seat-late.rulesis what turnsTAG+="uaccess"into an ACL — so
the tag was set twenty-six files too late andMODE="0666"was doing all the
work, handing every local process access to an infrared camera. It is
60-tobii.ruleswith mode 0660 now, and the installer removes a leftover copy
of the old one, which would otherwise still win on mode. - The updater read a failed ownership query as "nobody owns this file", and
the query had no timeout. Both are fixed; an unanswerable query now refuses. - Neither package declared the glibc floor the notes promise.
- The archive had no installer and no udev rule, and these notes told you to
unpack it into~/.local/bin, which produces a directory rather than binaries.
Known limitations
- The head-pose model's focal length is assumed (
DEFAULT_FOCAL_PX = 355),
which feeds a perspective correction worth 12–16° of pitch. The real value can
be computed from data already on the wire; it is not yet wired up. - This release path has never run before. The repository had no tags until
now, so this is the first execution of the release workflow and the first
time the updater's download-and-install path meets a real release. The.deb
has been unpacked and read field by field and thePKGBUILDparses under real
makepkg, but nobody has installed any of these packages on a clean machine
of the distribution it targets, and the.rpmis built for the first time by
this release — most developer machines have norpmbuild, so its spec was
written where it could not be read back. CI now opens both finished packages
and fails if they do not declare the glibc floor, which is the only check that
runs where they are actually built. - The head-pose model's yaw and roll signs are confirmed on hardware; pitch is
not comparable to anything. Pitch has no geometric counterpart to check
against, only a zero you measure once with
tobii headpose --calibrate-pitch. - Glyph clipping at fractional display scale. Tops of tall glyphs can appear
shaved. CSS, the GSK renderer and widget-label theories have all been ruled
out by measurement; the remaining suspect is the compositor's own downscale.
Setting an integer display scale is the test. 0x501and0x50eare the same camera exposed twice, not a stereo pair —
199/199 byte-identical frames with a face in view. There is no stereo depth to
be had from this device.- Game output beyond opentrack UDP — a TrackIR/FreeTrack bridge for Wine, and a
daemon so the hub and a game can use the tracker at once — is on a branch, not
in this release.
The full list, including confirmed defects that are documented but not yet
fixed, is in Quality-and-Risks. That page is
written to be read before you file a bug, not after.
How this was tested
593 automated tests, plus the parts that need the device.
Most of what "needs an ET5" does not, once a session has been recorded:
tobii record captures a real USB session and the replay tests drive the driver
against exactly the replies the device gave, asserting byte-for-byte on what
the driver sends. A second capture covers the one fragmented response this
driver produces — a 778 KB calibration blob arriving across 52 of the capture's 60 reads — because a
change that looked obviously correct and broke every calibration retrieval on
real hardware got through when that coverage did not exist.
What still cannot be checked without the tracker: the 12.1 mm accuracy figure,
whether the illuminators physically go dark, and everything below the transport
seam. Those were measured by hand, and
Quality-and-Risks says which numbers came from
where.
For contributors
Architecture documentation follows arc42:
Architecture · Runtime-View
· Architecture-Decisions ·
Quality-and-Risks ·
Development.
The reverse-engineered protocol is documented separately in
docs/wiki/, with every non-obvious claim tagged CONFIRMED /
CODE-VERIFIED / HYPOTHESIS.
Most of what needs a tracker does not. tobii record captures a real USB
session and cargo test -p tobii-usb --test replay regression-tests the
protocol against it with no hardware attached.
Credits
Protocol reference: the tobiifree
project. Head-pose model: opentrack
(fetched at your request, not bundled). Licensed GPL-3.0-only.