> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/opentrack/opentrack/llms.txt
> Use this file to discover all available pages before exploring further.

# FreePIE UDP

> Receive tracking data via UDP from FreePIE or compatible applications

The FreePIE UDP tracker receives head tracking data over UDP network protocol from FreePIE scripts or any compatible application. This enables wireless tracking, integration with other software, or using devices that aren't directly supported by OpenTrack.

## How It Works

Any application can send orientation data to OpenTrack by broadcasting UDP packets to a specified port. The data format is simple: three rotation angles (yaw, pitch, roll) sent as floating-point values. This makes FreePIE UDP ideal for:

* Smartphone IMU apps
* Custom tracking solutions
* VR/AR headset integration
* Wireless IMU devices
* Bridge from other tracking software

<Info>
  FreePIE is a programmable input emulator originally designed for VR and motion control. The UDP receiver in OpenTrack follows the same protocol, making it compatible with FreePIE scripts and similar tools.
</Info>

## Requirements

### Software

* OpenTrack with FreePIE UDP tracker
* Data source (one of):
  * FreePIE with tracking script
  * Smartphone app (e.g., FreePIE IMU for Android)
  * Custom application sending UDP data
  * Another OpenTrack instance (for remote tracking)

### Network

* Both devices on same network (or route between them)
* Firewall allowing UDP traffic on configured port
* Low-latency network connection (WiFi or wired)

<Note>
  No special hardware required beyond what your data source needs (e.g., smartphone with gyro/accelerometer).
</Note>

## Setup Instructions

<Steps>
  <Step title="Configure OpenTrack">
    In OpenTrack tracker settings:

    ```yaml theme={null}
    UDP Port: 5555 (or your chosen port)
    Axis X Index: 0 (yaw)
    Axis Y Index: 1 (pitch)  
    Axis Z Index: 2 (roll)
    ```

    The axis indices determine which incoming data channel maps to which rotation.
  </Step>

  <Step title="Configure Firewall">
    Allow UDP traffic:

    **Windows Firewall:**

    ```powershell theme={null}
    # Allow OpenTrack to receive UDP
    netsh advfirewall firewall add rule name="OpenTrack UDP" dir=in action=allow protocol=UDP localport=5555
    ```

    **Linux (ufw):**

    ```bash theme={null}
    sudo ufw allow 5555/udp
    ```

    Or add exception in your firewall GUI.
  </Step>

  <Step title="Find Your PC's IP Address">
    Your data source needs to know where to send data:

    **Windows:**

    ```cmd theme={null}
    ipconfig
    # Look for IPv4 Address under your active connection
    ```

    **Linux:**

    ```bash theme={null}
    ip addr show
    # or
    hostname -I
    ```

    Note the IP address (e.g., 192.168.1.100).
  </Step>

  <Step title="Configure Data Source">
    **Option A: FreePIE (PC):**

    Install FreePIE and create a script:

    ```python theme={null}
    # Example FreePIE script
    from System.Net import IPEndPoint, IPAddress
    from System.Net.Sockets import UdpClient

    if starting:
        client = UdpClient()
        endpoint = IPEndPoint(IPAddress.Parse("192.168.1.100"), 5555)

    # Get data from source (e.g., Android sensor)
    yaw = android[0].yaw
    pitch = android[0].pitch  
    roll = android[0].roll

    # Send to OpenTrack
    data = struct.pack('fff', yaw, pitch, roll)
    client.Send(data, len(data), endpoint)
    ```

    **Option B: Smartphone App:**

    1. Install "FreePIE IMU" or similar app
    2. Enter PC's IP address: 192.168.1.100
    3. Enter Port: 5555
    4. Start sending data

    **Option C: Custom Application:**
    Send UDP packets with 12 bytes (3 x float32):

    ```python theme={null}
    import socket
    import struct

    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    yaw, pitch, roll = 0.0, 0.0, 0.0  # Your tracking data
    data = struct.pack('fff', yaw, pitch, roll)
    sock.sendto(data, ('192.168.1.100', 5555))
    ```
  </Step>

  <Step title="Test Connection">
    1. Start OpenTrack with FreePIE UDP tracker
    2. Start your data source
    3. Move your tracking device
    4. Verify OpenTrack receives data (check output window)

    If not working:

    * Verify IP address and port
    * Check firewall settings
    * Ensure both devices on same network
    * Test with localhost (127.0.0.1) first
  </Step>

  <Step title="Adjust Axis Mapping">
    If rotations are wrong:

    1. Change axis indices (try different combinations)
    2. Use angle offsets to adjust zero point:
       ```yaml theme={null}
       Add Yaw: 0 degrees
       Add Pitch: 0 degrees  
       Add Roll: 0 degrees
       ```
    3. Test until movements match expectations
  </Step>
</Steps>

## Configuration Options

### Network Settings

| Option       | Default | Description                         |
| ------------ | ------- | ----------------------------------- |
| **UDP Port** | 5555    | Port to listen on for incoming data |

<Info>
  Choose a port between 1024-65535. Avoid commonly used ports. Default 5555 works well.
</Info>

### Axis Mapping

| Option           | Default | Description                        |
| ---------------- | ------- | ---------------------------------- |
| **Axis X Index** | 0       | Which data channel for yaw (0-2)   |
| **Axis Y Index** | 1       | Which data channel for pitch (0-2) |
| **Axis Z Index** | 2       | Which data channel for roll (0-2)  |

### Angle Offsets

| Option        | Default | Description                       |
| ------------- | ------- | --------------------------------- |
| **Add Yaw**   | 0°      | Offset added to yaw (heading)     |
| **Add Pitch** | 0°      | Offset added to pitch (elevation) |
| **Add Roll**  | 0°      | Offset added to roll (bank)       |

<Accordion title="Axis Index Mapping">
  The incoming UDP packet contains 3 float values. Axis indices determine which value maps to which rotation:

  * **Index 0**: First float in packet
  * **Index 1**: Second float in packet
  * **Index 2**: Third float in packet

  If your rotations are mixed up, try different index combinations:

  * Common: X=0, Y=1, Z=2 (yaw, pitch, roll)
  * Alternative: X=2, Y=1, Z=0 (roll, pitch, yaw)
</Accordion>

## UDP Protocol Details

### Packet Format

The FreePIE UDP protocol is straightforward:

```
Byte 0-3:   float32 - First rotation value
Byte 4-7:   float32 - Second rotation value  
Byte 8-11:  float32 - Third rotation value
Total: 12 bytes
```

* **Endianness**: Little-endian (standard on x86/ARM)
* **Units**: Degrees (not radians)
* **Range**: Typically -180 to +180 degrees

### Example Packet

```python theme={null}
import struct

yaw = 45.0    # degrees
pitch = -10.0 # degrees
roll = 5.0    # degrees

packet = struct.pack('<fff', yaw, pitch, roll)
# '<' = little-endian, 'fff' = three floats
# Result: 12 bytes ready to send via UDP
```

### Sending Data

**Python:**

```python theme={null}
import socket
import struct
import time

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('192.168.1.100', 5555)

while True:
    yaw, pitch, roll = get_rotation_data()  # Your function
    packet = struct.pack('fff', yaw, pitch, roll)
    sock.sendto(packet, server_address)
    time.sleep(0.02)  # 50Hz update rate
```

**C/C++:**

```cpp theme={null}
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int sock = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(5555);
inet_pton(AF_INET, "192.168.1.100", &addr.sin_addr);

float data[3] = {yaw, pitch, roll};
sendto(sock, data, sizeof(data), 0, 
       (struct sockaddr*)&addr, sizeof(addr));
```

**JavaScript (Node.js):**

```javascript theme={null}
const dgram = require('dgram');
const client = dgram.createSocket('udp4');

const buffer = Buffer.allocUnsafe(12);
buffer.writeFloatLE(yaw, 0);
buffer.writeFloatLE(pitch, 4);
buffer.writeFloatLE(roll, 8);

client.send(buffer, 5555, '192.168.1.100');
```

## Use Cases

<CardGroup cols={2}>
  <Card title="Smartphone Tracking" icon="mobile">
    Use your phone's gyro/accelerometer as a wireless head tracker.

    Apps:

    * FreePIE IMU (Android)
    * SensorUDP (iOS/Android)
    * Custom app with gyro API
  </Card>

  <Card title="Remote Tracking" icon="wifi">
    Track on one PC, send data to another PC running the game.

    Example:

    * Laptop with webcam for tracking
    * Desktop PC for gaming
    * Send tracking data over LAN
  </Card>

  <Card title="Custom Hardware" icon="microchip">
    Interface custom tracking hardware:

    * ESP32 with IMU (wireless)
    * Custom VR headset
    * Modified game controller
    * Experimental sensors
  </Card>

  <Card title="Software Bridge" icon="bridge">
    Bridge from other tracking software:

    * Convert SteamVR tracking to OpenTrack
    * Relay from mobile tracking apps
    * Integrate with Unity/Unreal projects
    * Custom processing pipeline
  </Card>
</CardGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="No data received">
    * Verify IP address is correct
    * Check port number matches (5555)
    * Test firewall is allowing UDP
    * Ensure both devices on same network/subnet
    * Try localhost (127.0.0.1) first to verify OpenTrack
    * Use Wireshark to verify packets are being sent
  </Accordion>

  <Accordion title="Wrong rotation axes">
    * Change axis index mapping
    * Try all combinations (6 possibilities)
    * Check if data source sends radians vs degrees
    * Verify data source coordinate system
    * Use angle offsets if axes are correct but rotated
  </Accordion>

  <Accordion title="High latency or lag">
    * Use wired connection instead of WiFi
    * Reduce update rate if network congested
    * Close bandwidth-heavy applications
    * Use 5GHz WiFi if available
    * Check for network packet loss
  </Accordion>

  <Accordion title="Jittery or unstable">
    * Enable filtering in OpenTrack filter settings
    * Reduce data source noise (sensor fusion)
    * Increase update rate for smoother interpolation
    * Use Accela filter in OpenTrack
    * Check for packet loss
  </Accordion>

  <Accordion title="Tracking drifts over time">
    * Issue is with data source (gyro drift)
    * Use sensor fusion in data source
    * Add magnetometer for yaw stability
    * Recenter view regularly in OpenTrack
    * Not an issue with UDP receiver itself
  </Accordion>
</AccordionGroup>

## Advantages and Limitations

<CardGroup cols={2}>
  <Card title="Advantages" icon="check">
    * Wireless tracking possible
    * Very flexible - any data source
    * Network-based (can track remotely)
    * Simple protocol, easy to implement
    * No special hardware required
    * Cross-platform compatible
    * Low CPU usage
    * Great for prototyping
  </Card>

  <Card title="Limitations" icon="exclamation">
    * Network latency (WiFi \~20-50ms)
    * Rotation only (no position)
    * Requires separate data source
    * Network reliability affects tracking
    * Must configure firewall
    * Quality depends on data source
    * Possible packet loss
  </Card>
</CardGroup>

## Smartphone Apps

### Android

* **FreePIE IMU**: Original FreePIE companion app
* **SensorUDP**: Sends various sensor data via UDP
* **IP Webcam**: Can send motion data alongside video

### iOS

* **SensorLog**: Logs and streams sensor data
* **UDP Sender**: Generic UDP data sender
* Custom apps using Core Motion API

<Note>
  Most apps let you configure IP address, port, and update rate. Use 50-100Hz for smooth tracking.
</Note>

## ESP32 Wireless IMU Example

```cpp theme={null}
#include <WiFi.h>
#include <WiFiUdp.h>
#include <Wire.h>
#include <MPU6050.h>

const char* ssid = "YourWiFi";
const char* password = "YourPassword";
const char* udpAddress = "192.168.1.100";
const int udpPort = 5555;

WiFiUDP udp;
MPU6050 mpu;

void setup() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) delay(500);
  
  Wire.begin();
  mpu.initialize();
}

void loop() {
  float yaw, pitch, roll;
  // Get rotation from MPU6050 (implement sensor fusion)
  
  uint8_t buffer[12];
  memcpy(buffer, &yaw, 4);
  memcpy(buffer + 4, &pitch, 4);
  memcpy(buffer + 8, &roll, 4);
  
  udp.beginPacket(udpAddress, udpPort);
  udp.write(buffer, 12);
  udp.endPacket();
  
  delay(20); // 50Hz
}
```

## Comparison with Other Trackers

| Feature       | FreePIE UDP      | HATire        | PointTracker    |
| ------------- | ---------------- | ------------- | --------------- |
| Tracking type | Rotation only    | Rotation only | 6DOF            |
| Connection    | UDP/WiFi         | Serial/USB    | USB camera      |
| Wireless      | Yes              | Optional      | No              |
| Latency       | Medium (20-50ms) | Low (20ms)    | Very Low (10ms) |
| Flexibility   | Very High        | Medium        | Low             |
| DIY friendly  | Yes              | Yes           | Some            |
| Cost          | Varies           | Very Low      | Low-Medium      |

## Tips for Best Results

1. **Network**: Use wired Ethernet or 5GHz WiFi for lowest latency
2. **Update Rate**: 50-100Hz is sweet spot (more = higher bandwidth)
3. **Filtering**: Enable filtering in OpenTrack to smooth network jitter
4. **Data Source**: Use good sensor fusion algorithm for stable orientation
5. **Local First**: Test on localhost before trying wireless
6. **Firewall**: Add permanent firewall rule instead of temporary
7. **QoS**: Enable QoS on router to prioritize UDP tracking packets

## See Also

* [HATire](/trackers/hatire) - Wired IMU tracking via serial
* [NeuralNet](/trackers/neuralnet) - Camera-based, no markers
* [Hardware Guide](/trackers/hardware) - General hardware information
