axol tracker.* commands set up and check the trackers for Mantis Tracking. The Tracking section of the control panel’s Mantis settings runs the same commands. This page lists their flags and file formats. For the setup walkthrough, see Mantis Tracking.
When you run
axol collect-data --mantis true from the command line, it uses the tracking source, bindings and Quest calibration saved in the panel. It starts the bridge and runs the same readiness checks as the panel.
- Don’t start a second
tracker.bridgenext to a collection run. It can’t take control of the poses. axol teleop --mantisdoesn’t use tracking. It drives the grippers from the rig triggers over CAN.- Quest uses none of these commands. The headset is the pose source, and you choose its calibration in the panel.
- Collect DAgger and Run Policy don’t support Mantis.
axol tracker.bridge
Streams each tracker’s pose and each side’s trigger value to the VR server as VRFrame messages.
How the bridge handles problems:
- A tracker loses tracking. That side holds its last good pose and logs a warning.
- A trigger stops sending for about 250 ms. That side holds its last grip command and logs the dropout.
survive-clicrashes. The bridge restarts it after about a second. The rigs hold still until both trackers report again. More than 3 crashes in a minute stops the bridge, and the error shows the last lines ofsurvive-cli’s output.- A tracker drops off USB. The bridge restarts
survive-clievery 5 seconds, for up to 60 seconds, until every tracker reports again.
Hardware-free protocol demo
To try the bridge without Mantis, run the sim and a static bridge:static and synthetic backends don’t need tracker.identify.
axol tracker.identify
Finds the powered trackers, then asks you to move each rig in turn. The tracker that moves most is bound to that side. For Lighthouse, it first runs the same check as tracker.lighthouse.check and won’t bind while two base stations share a channel. Lighthouse and Ultimate bindings are saved separately, so you can switch between them in the panel.
Saves
~/.almond/tracker/config.json:
expected_base_stations (--expected_stations). lighthouse_quality is the Lighthouse tracking policy.
Lighthouse trackers are bound by serial number. libsurvive’s device names (WM0, WM1) can swap between runs, so Axol clears a saved binding that uses one. Run Identify trackers once to bind by serial.
axol tracker.pair
Pairs one VIVE Tracker 3.0 with its Watchman dongle. Unplug the tracker from USB and make sure it is blinking blue. Run it once for each tracker and dongle.
A dongle can pair only when no tracker is connected to it. If every dongle already has a powered tracker, the command says they are already paired. To pair a different tracker to a dongle, switch off the tracker that is paired to it first.
axol tracker.install
Installs a tested build of libsurvive (commit f1e6eddb669320f2a30760f4b42936bdb4306da0) with Almond’s fixes, plus the Vive udev rule. axol provision runs it for you. Run it again to repair the install.
almond_axol/tracker/libsurvive_patches/. They fix crashes with three or four base stations and during long sessions, deliver poses without delay, and add the strict tracking policy. Under the standard policy, libsurvive tracks as it normally does.
If the build is already current, tracker.install only refreshes the udev rule and checks the installed files.
After you update Axol, stop collection, install the updated runtime, and restart the service:
Close SteamVR if it is running, because it competes for the trackers.
Lighthouse tracking policy
lighthouse_quality in ~/.almond/tracker/config.json sets how strictly Axol checks Lighthouse tracking. In the control panel it is Tracking policy, under Mantis settings. It applies to collection, the tracker bridge, Check base stations and Identify trackers on this computer.
Under
standard, a passed check shows as Last check passed 10 min ago. Calibration refined since then., because libsurvive keeps refining the calibration.
Choose strict for a fixed installation whose base stations never move, where you’d rather retake than keep a slightly worse take. Choose standard for portable setups, rooms with two base stations, and bring-up. Change the policy only while no operation is running.
axol tracker.lighthouse.check
- two base stations share a channel
- it sees fewer base stations than you expect
- fewer than two trackers report
~/.almond/tracker/lighthouse_survey.json. The panel needs a passing check before the Trackers step.
Under the strict policy, the check never calibrates. On a new computer, or after you add or re-channel a base station, run Recalibrate Lighthouse first.
The base station calibration lives in libsurvive’s file ~/.config/libsurvive/config.json, or under $XDG_CONFIG_HOME when that is set. The service, which runs as root, uses /root/.config/libsurvive/config.json.
axol tracker.lighthouse.validate
- Put both identified rigs still on the table, with their trackers in view.
- Follow the prompts: a 5-second hold, a 12-second slow sweep through the workspace (at least 10 cm and 15° per rig), and a 5-second hold at another position. Move only during the sweep.
Under the strict policy, validate before the first session each day. A report expires after 12 hours, or sooner if the setup changes. If validation fails, fix the visibility, base station or identity problem and run it again. If the report asks for recalibration, run Recalibrate Lighthouse, because validation alone can’t clear that fault. This command never changes the calibration.
axol tracker.lighthouse.calibrate
tracker.lighthouse.validate.
- Rest both rigs at three different positions and orientations, for eight seconds each, when prompted. Keep the tracker sensors in view.
- Complete the same hold, sweep and hold as
tracker.lighthouse.validate.
axol tracker.ultimate.install
fcfcd33f4c1f16b0d84f5f741dc1319abdc7942a), the hid>=1.0.5 Python package (not the unrelated hidapi), the system HID libraries and a udev rule for dongle 0bb4:0350. It is safe to run again. Don’t replace it with uv pip install or a chmod of /dev/hidraw*. The Windows pairing and mapping steps you do first are on the tracking page.
Ultimate Wi-Fi file
The panel’s Wi-Fi step writesultimate_wifi.json, the network settings for the trackers’ shared map. To set it up by hand, create ~/.almond/tracker/ultimate_wifi.json (or $ALMOND_HOME/tracker/ultimate_wifi.json) in this shape, then chmod 600 it:
ssid, pass and freq are only a fallback. Choose a country and freq that are valid where you work. The readiness check reports whether the file is valid, never the values in it.
axol tracker.ultimate.check
tracker.identify again.
Transform file
~/.almond/mantis/tcp_transform.json holds measured tracker-to-gripper transforms for each side, keyed by the identified device. Axol has built-in factory values for the standard Tracker 3.0 and Ultimate mounts, and for Quest 3 Touch Plus controllers (quest:meta-quest-touch-plus:grip). It uses a factory value when no conflicting entry is saved. A saved entry overrides the factory value. Other Quest controllers have no factory value and need an entry for both sides.
~/.almond/tracker/config.json, or the Quest key the panel shows, and each value with your measurement.
posis the gripper TCP origin in the tracker’s frame, in metres.quatis the TCP orientation in the tracker’s frame, as[qx, qy, qz, qw]. It is normalized when loaded.
PUT /api/tracker/calibration/<source>. The control panel doesn’t edit it.
Rules Axol applies when it loads the file:
- Quest collection needs a
quest:<reported-profile>:gripentry on both sides, or the built-in Quest 3 Touch Plus value. A barequestkey, a different controller profile, missing profile details or atarget-rayentry is refused. - Ultimate entries need an
ultimate_pose_conventionthat matches the activeultimate_quat_orderandultimate_up_axis. An entry without one, or with a different one, blocks the factory value for that side until you fix or remove it. - An unkeyed entry, a bare
surviveorultimatekey, or an entry for a tracker you no longer use also blocks the factory value for that side until you re-key or delete it. - Production
collect-dataneeds a saved device entry or a factory value on both sides. Use--mantis_allow_uncalibrated trueonly for a calibration capture that won’t be used for training.
Vive factory values
Both Vive tracker types sit flat on top of the rig, behind the gripper motor. Both use the rotationRy(180°), stored as the quaternion [0, 1, 0, 0]. The tracker’s +z axis points along the gripper fingers (gripper −z), its +x axis along the gripper’s −x, and the y axes match.
Positions are given in the gripper frame, whose origin is the center of the gripper motor’s mounting face:
Quest factory value
Quest 3 Touch Plus controllers (quest:meta-quest-touch-plus:grip) sit in standard cradles. Their grip origin is at [0, −45, 62] mm in the gripper frame, 62 mm behind and 45 mm above the motor face. The grip axes are turned 180° about the gripper’s z axis, with a cradle tilt of about 10°. The left cradle mirrors the right, so the tilt mirrors too:
Other controllers need a measured entry.
Deriving a missing constant
If you have no transform for your source, such as a Quest controller other than the Touch Plus or an Ultimate with a non-standard pose setting:- Pass the acceptance checks for side, scale and recovery.
- Record a short capture with
--mantis_allow_uncalibrated true. - Work out the transform from that capture, and save it under the exact source and device key.
- Repeat the loss and recovery check.
collect-data --mantis stays blocked until both sides have a transform. Never use an uncalibrated capture as training data.