A real-time wireless head tracking system using ESP32 microcontrollers that captures human head orientation and replicates it mechanically using servo motors. The system uses dual IMU sensors for accurate motion sensing and ESP-NOW protocol for fast, low-latency wireless communication.
This project enables precise 2-degree-of-freedom (2-DOF) rotational tracking — yaw (left-right) and pitch (up-down) — allowing real-time motion transfer from a wearable sensing unit to a mechanical actuation unit.
- Overview
- Features
- Hardware Requirements
- System Architecture
- How It Works
- Circuit Diagrams
- Installation & Setup
- Calibration
- Usage
- Troubleshooting
- Applications
- Contributors
- License
This project implements a wireless head tracking system consisting of two main units:
- Transmitter Unit: A wearable device with dual IMU sensors that measures head orientation
- Receiver Unit: A servo-controlled mechanism that replicates the tracked head movements
The system provides real-time tracking with approximately 100ms latency at 10Hz update rate using the ESP-NOW protocol for reliable wireless communication.
- Dual IMU Sensor Fusion: Combines MPU6500 and MPU6050 sensors for accurate tracking
- Yaw Tracking: 360° continuous rotation tracking via gyroscope integration (servo output limited to 180°)
- Pitch Tracking: ±90° tilt detection using accelerometer data
- Wireless Communication: ESP-NOW protocol for low-latency data transmission
- Gyroscope Calibration: Automatic offset calibration at startup to minimize drift
- Signal Filtering: 5-sample moving average filter for smooth motion
- Data Validation: Built-in checks for unrealistic sensor readings
- Manual Reset: Serial command interface to reset yaw orientation
- Servo Control: Precise mechanical replication of head movements
- ESP32 Development Board
- MPU6500 (or MPU9250) - Gyroscope for yaw tracking
- MPU6050 - Accelerometer for pitch tracking
- Power source (battery recommended for wearable use)
- ESP32 Development Board
- 2× Servo Motors (180° range)
- Yaw servo (horizontal rotation)
- Pitch servo (vertical tilt)
- Power supply suitable for servos (5V, adequate current)
- I2C pull-up resistors (if not integrated on sensor modules)
- Connecting wires
- Mounting hardware/headset frame
graph LR
subgraph TX[" TRANSMITTER "]
direction TB
IMU["MPU6500 + MPU6050\nGyro & Accelerometer\nI²C · 0x69 & 0x68"]
MCU_TX["ESP32\nCalibration · Filtering\nYaw & Pitch Fusion"]
IMU --> MCU_TX
end
subgraph LINK[" RF LINK "]
ESP_NOW["ESP-NOW Protocol\nOrientationData Struct\n10 Hz · ~100 m range"]
end
subgraph RX[" RECEIVER "]
direction TB
MCU_RX["ESP32\nExp. Smoothing\nTimeout Detection"]
MAPPER["Servo Mapper\nYaw: 0–360° → 180–0°\nPitch: ±90° → 180–0°"]
SERVOS["Servo Motors\nYaw · GPIO 18\nPitch · GPIO 19"]
MCU_RX --> MAPPER --> SERVOS
end
TX ==> LINK ==> RX
style TX fill:#1e2d3d,stroke:#3d7ab5,stroke-width:2px,color:#dce8f5
style LINK fill:#162030,stroke:#2e5f8a,stroke-width:2px,color:#dce8f5
style RX fill:#1e2d3d,stroke:#3d7ab5,stroke-width:2px,color:#dce8f5
style IMU fill:#243449,stroke:#3d7ab5,stroke-width:1px,color:#b8cedf
style MCU_TX fill:#243449,stroke:#3d7ab5,stroke-width:1px,color:#b8cedf
style ESP_NOW fill:#1a2c3e,stroke:#2e6a9e,stroke-width:1px,color:#9fbdd1
style MCU_RX fill:#243449,stroke:#3d7ab5,stroke-width:1px,color:#b8cedf
style MAPPER fill:#243449,stroke:#3d7ab5,stroke-width:1px,color:#b8cedf
style SERVOS fill:#243449,stroke:#3d7ab5,stroke-width:1px,color:#b8cedf
The system uses a transmitter-receiver architecture where the transmitter continuously broadcasts orientation data, and the receiver listens and actuates the servos accordingly.
-
Sensor Initialization
- MPU6500 initialized at I2C address 0x69 (AD0 pin high)
- MPU6050 initialized at I2C address 0x68 (AD0 pin low)
- Both sensors share the I2C bus (SDA: GPIO21, SCL: GPIO22)
-
Gyroscope Calibration
- Collects 500 samples while sensor is stationary
- Calculates average offset for gyroscope Z-axis
- Warns if offset exceeds ±10°/s (indicates unstable environment)
-
Yaw Calculation (MPU6500)
- Reads gyroscope Z-axis angular velocity
- Subtracts calibrated offset
- Applies 5-sample moving average filter
- Integrates over time:
yaw += gyroZ_filtered × deltaTime - Normalizes to 0-360° range
- Validates data (rejects readings > 1000°/s)
-
Pitch Calculation (MPU6050)
- Reads 3-axis accelerometer data
- Converts to g-forces (±2g range, 16384 LSB/g)
- Calculates magnitude to validate data (0.5g - 1.5g expected)
- Computes pitch:
pitch = atan2(ay, sqrt(ax² + az²)) × 180/π
-
Wireless Transmission
- Packages yaw and pitch into struct
- Transmits via ESP-NOW to receiver MAC address
- Updates at 10Hz (100ms interval)
-
ESP-NOW Reception
- Listens for incoming orientation data packets
- Validates packet size matches OrientationData struct
-
Servo Mapping
- Yaw: Maps 0-180° input to 180-0° servo (inverted for mechanical correction)
- Pitch: Maps -90 to +90° input to 180-0° servo
- Constrains values to prevent servo damage
-
Servo Actuation
- Writes mapped values to servos (GPIO18 and GPIO19)
- Servos configured with 1000-2000μs pulse width range
Pin Connections:
- MPU6500: SDA → GPIO21, SCL → GPIO22, AD0 → VCC (address 0x69)
- MPU6050: SDA → GPIO21, SCL → GPIO22, AD0 → GND (address 0x68)
Pin Connections:
- Yaw Servo Signal → GPIO18
- Pitch Servo Signal → GPIO19
- Servo Power: Connect to adequate 5V supply (not USB power)
# Install Arduino IDE and add ESP32 board support
# In Arduino IDE: File → Preferences → Additional Board Manager URLs
# Add: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json- ESP32Servo
- MPU6050 (by Electronic Cats)
- MPU9250_asukiaaa
# In Arduino IDE: Tools → Manage Libraries
# Search and install each libraryBefore uploading transmitter code:
- Upload the receiver code first
- Open Serial Monitor (115200 baud)
- Note the displayed MAC address
- Update the MAC address in Transmitter/Transmitter.ino line 30:
uint8_t receiverAddress[] = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };- Upload
Receiver.inoto receiver ESP32 - Upload
Transmitter.inoto transmitter ESP32
The transmitter automatically calibrates on startup:
- Place the transmitter on a stable surface
- Keep it completely stationary
- Power on and wait for "Calibrating gyroscope..." message
- Calibration completes after ~2 seconds
- Check that offset is within ±10°/s
Servos automatically center at 90° during receiver initialization. Adjust mechanical mounting if needed to ensure proper range of motion.
-
Power On
- Power the receiver unit first
- Power the transmitter unit (triggers auto-calibration)
-
Verification
- Open Serial Monitor on receiver (115200 baud)
- Verify data reception: "Received -> Yaw: X | Pitch: Y"
- Check servo movement matches head orientation
-
Reset Yaw
- Connect to transmitter via Serial Monitor
- Send command:
reset - Yaw resets to 0°
-
Normal Operation
- Wear or mount transmitter on head
- Servos will replicate yaw and pitch movements
- Yaw: Transmitter tracks 0-360° continuously, servo replicates 0-180° mechanically
- Pitch range: ±90°
- Check I2C wiring (SDA, SCL, VCC, GND)
- Verify I2C addresses (use I2C scanner sketch)
- Ensure AD0 pins are correctly connected (high for 0x69, low for 0x68)
- Recalibrate in a more stable environment
- Check for vibrations or movement during calibration
- Verify gyro offset is within ±10°/s
- Verify receiver MAC address in transmitter code
- Check ESP-NOW initialization messages
- Ensure both devices are powered and within range (~100m line-of-sight)
- Check power supply (servos need adequate current)
- Verify servo connections to correct GPIO pins
- Ensure data validation isn't rejecting readings (check serial output)
- "Gyroscope data invalid": Excessive angular velocity detected, reduce movement speed
- "Accelerometer data invalid": Magnitude check failed, sensor may be loose or malfunctioning
- Camera Gimbals: FPV systems, cinema rigs
- Robotic Heads: Interactive robots, animations
- VR/AR Tracking: Head-mounted display orientation
- Remote Camera Control: Surveillance, telepresence
- Motion Capture: Animation reference, biomechanics
- Accessibility Devices: Head-controlled interfaces
- Gaming: Immersive head-tracking peripherals
This project was built by:
This project is licensed under the terms included in the LICENSE file.