Skip to content

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 09 Sep 20:13
· 100 commits to main since this release

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 —
    and tobii debug on 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 --udev

scripts/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 $HOME was not the install
    prefix — sudo tobii debug printed 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's 73-seat-late.rules is what turns TAG+="uaccess" into an ACL — so
    the tag was set twenty-six files too late and MODE="0666" was doing all the
    work, handing every local process access to an infrared camera. It is
    60-tobii.rules with 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 the PKGBUILD parses under real
    makepkg, but nobody has installed any of these packages on a clean machine
    of the distribution it targets
    , and the .rpm is built for the first time by
    this release — most developer machines have no rpmbuild, 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.
  • 0x501 and 0x50e are 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.