Trackers are input modules that provide 6DOF (degrees of freedom) head position and rotation data. OpenTrack supports a wide variety of tracking technologies.
Tracker Module System
OpenTrack uses a plugin-based tracker system:
struct OTR_API_EXPORT ITracker {
virtual module_status start_tracker ( QFrame * frame ) = 0 ;
virtual void data ( double * data ) = 0 ;
virtual bool center ();
};
Module Selection
Trackers are selected through the module settings:
struct module_settings {
bundle b { make_bundle ( "modules" ) };
value < QString > tracker_dll { b, "tracker-dll" , "pt" };
};
Available Trackers
OpenTrack includes support for many tracking technologies:
Optical
Inertial
Network
VR/AR
PointTracker (pt) Uses webcam to track LEDs or reflective markers. Best for : DIY LED tracking setups, TrackIR alternativesRequirements :
Webcam (higher resolution = better accuracy)
3 LED or reflective points on headset
Good lighting conditions
Aruco Markers Tracks printed ArUco fiducial markers. Best for : Quick testing without special hardwareRequirements :
Webcam
Printed ArUco marker attached to headset
Easy Tracker Face tracking using computer vision. Best for : No additional hardware neededFreeTrack/TrackIR Commercial optical tracking systems. Hatire (Arduino) Arduino-based IMU tracking via serial port. Configuration :// Serial communication at 250Hz
// 6DOF: TX, TY, TZ, Yaw, Pitch, Roll
Joystick Use game controller as head tracker input. FreePIE UDP Receives tracking data via UDP from FreePIE or compatible applications. Port : Configurable (default varies by tracker)UDP Generic Generic UDP receiver for custom tracking solutions. Data format : 6 doubles (X, Y, Z, Yaw, Pitch, Roll)Eyeware Beam Head tracking using Eyeware Beam iOS app. Tobii Eye Tracker Integration with Tobii eye tracking hardware. Xreal One Support for Xreal AR glasses tracking.
Tracker Initialization
When a tracker starts, it goes through this initialization sequence:
Module Loading
The tracker plugin is loaded from the shared library: std ::shared_ptr < ITracker > pTracker;
// Loaded from tracker-{name}.dll/so
Initialization
The tracker’s start_tracker method is called: module_status start_tracker ( QFrame * frame ) {
// Initialize hardware/software
// Optional: Display video feed in frame
return status_ok (); // or error("message")
}
Data Streaming
The data() method is called at ~250Hz: void data ( double * data ) {
// data[0-2]: TX, TY, TZ (cm)
// data[3-5]: Yaw, Pitch, Roll (degrees)
}
All trackers must provide data in OpenTrack’s standard format:
using Pose = Mat < double , 6 , 1 >;
enum Axis : int {
TX = 0 , TY = 1 , TZ = 2 , // Translation (cm)
Yaw = 3 , Pitch = 4 , Roll = 5 // Rotation (degrees)
};
Translation units : Centimeters
Rotation units : Degrees
Coordinate system : Right-handed
Axis Definitions
TX : Left (-) / Right (+)
TY : Down (-) / Up (+)
TZ : Forward (-) / Backward (+)
Yaw : Left (-) / Right (+)
Pitch : Down (-) / Up (+)
Roll : Left (-) / Right (+)
Centering Support
Trackers can optionally handle centering internally:
virtual bool center () {
// Return true if tracker handles centering internally
// Return false to use OpenTrack's centering
return false ;
}
Centering Flow
const bool own_center_logic = center_ordered && libs . pTracker -> center ();
if (own_center_logic) {
// Tracker resets itself
center . P = {};
center . QC = {};
center . QR = {};
} else {
// OpenTrack handles centering
center . P = value;
center . QC = dquat :: from_euler (...). conjugated ();
center . QR = dquat :: from_euler (...). conjugated ();
}
Tracker Dialog
Each tracker can provide a configuration dialog:
struct OTR_API_EXPORT ITrackerDialog : public BaseDialog {
virtual void register_tracker ( ITracker * tracker );
virtual void unregister_tracker ();
};
The dialog receives a pointer to the active tracker instance for live configuration updates.
Common Tracker Settings
Video Feed Display
Optical trackers can display camera feed:
module_status start_tracker ( QFrame * frame ) {
if (frame) {
// Set up video widget in frame
video_widget = new VideoWidget (frame);
}
return status_ok ();
}
Exposure and Gain
For optical trackers, proper camera settings are critical:
Low exposure (1-5ms) and high gain provide best results for LED tracking.
Automatic exposure often causes tracking issues.
Optical trackers typically use threshold-based point extraction:
Apply brightness threshold
Find connected components (blobs)
Calculate blob centroids
Match points to 3D model
The pipeline runs at ~250Hz (4ms interval):
void pipeline :: run () {
while ( ! isInterruptionRequested ()) {
logic ();
constexpr ms interval{ 4 };
backlog_time += ms{ t . elapsed_ms ()} - interval;
const int sleep_ms = ( int ) std :: clamp (
interval - backlog_time, ms{ 0 }, ms{ 10 }
). count ();
portable :: sleep (sleep_ms);
}
}
Trackers should not block in the data() method. Use a separate thread for computation and return the latest data.
Error Handling
Trackers can report errors during initialization:
module_status initialize () override {
if ( ! hardware_found ()) {
return error ( tr ( "Hardware not found" ));
}
if ( ! calibration_valid ()) {
return error ( tr ( "Calibration required" ));
}
return status_ok ();
}
Creating Custom Trackers
To implement a custom tracker:
Implement ITracker interface
class MyTracker : public ITracker {
module_status start_tracker ( QFrame * frame ) override ;
void data ( double * data ) override ;
};
Implement dialog (optional)
class MyTrackerDialog : public ITrackerDialog {
void register_tracker ( ITracker * t ) override ;
void unregister_tracker () override ;
};
Implement metadata
class MyTrackerMetadata : public Metadata {
QString name () override { return tr ( "My Tracker" ); }
QIcon icon () override { return QIcon ( ":/icon.png" ); }
};
Register plugin
OPENTRACK_DECLARE_TRACKER (
MyTracker,
MyTrackerDialog,
MyTrackerMetadata
)
Troubleshooting
Check tracker update rate (should be stable)
Verify lighting conditions (for optical trackers)
Enable filtering (see Filters guide )
Check for USB bandwidth issues
Tracking drifts over time
Inertial drift is normal for IMU trackers
Enable fusion with optical tracking if possible
Periodically recenter
Check for magnetic interference (IMU trackers)
Verify hardware is connected
Check device drivers are installed
Try different USB ports
Check OpenTrack logs for error messages
Data is inverted or swapped
Use axis mapping and inversion in Configuration : axis_opts ::src = desired_axis; // Map input axis
axis_opts ::invert_pre = true ; // Invert if needed
Next Steps
Output Setup Configure game/simulator output protocols
Filters Add smoothing and noise reduction
Mapping Curves Fine-tune tracking response