Skip to content

support@quartzcomponents.com

Free Shipping Over INR 500

Electronics Projects

DIY Wireless Mouse using MPU6050 & ESP32-C3

by RISHABH JANGID 01 May 2026 0 Comments

Turn simple hand gestures into seamless control with this DIY Wireless Air Mouse using MPU6050 & ESP32-C3. In this project, you’ll build a compact motion-controlled mouse that translates real-time orientation and movement data from the MPU6050 gyroscope and accelerometer into cursor actions via ESP32-C3 Development Board built-in Bluetooth Low Energy (BLE). Ideal for presentations, media control, and interactive setups, this air mouse offers a fun and practical way to explore motion sensing, wireless communication, and embedded programming. Whether you're a beginner or an electronics enthusiast, this project combines hardware and software to create an intuitive, gesture-based interface without the need for traditional peripherals.

Components Required

About the Components

ESP32-C3 Super Mini

Ultra-compact WiFi + BLE microcontroller used as the brain of the system.

  • ESP32-C3 (RISC-V, up to 160 MHz)
  • WiFi + Bluetooth 5 LE
  • 4MB Flash
  • USB-C programming
  • 3.3V logic
  • Supports I2C, SPI, UART, PWM, ADC

Handles sensor data and sends BLE mouse signals.

MPU6050 IMU Sensor

The MPU6050 is a low-cost motion sensor combining a 3-axis accelerometer and 3-axis gyroscope on a single chip. It measures movement, orientation, and rotation, making it suitable for motion-based control systems.

  • 3-axis accelerometer + 3-axis gyroscope
  • Communication: I2C
  • Power Supply: 3V–5V
  • 16-bit ADC for high accuracy
  • Built-in Digital Motion Processor (DMP)
  • Configurable I2C address
  • Auxiliary I2C pins for additional sensors (e.g., magnetometer)
  • Integrated temperature sensor

In this project, it tracks hand motion and provides real-time data used to control the cursor movement.

 

Circuit Connection

Fig. Circuit Diagram

Fig. Schematic Diagram

MPU6050 to ESP32-C3

  • VCC → 3.3V
  • GND → GND
  • SDA → GPIO 4
  • SCL → GPIO 5

Buttons

  • GPIO 2 → Button → GND
  • GPIO 4 → Button → GND

(INPUT_PULLUP configuration)

Code Explanation

Libraries Used

Arduino · C++
#include <Wire.h>
#include <HijelHID_BLEMouse.h>

Purpose of Library

#include <Wire.h> → Handles I2C communication with MPU6050.
#include <HijelHID_BLEMouse.h> → Enables ESP32 to act as a BLE mouse.

Pin Definitions

Arduino · C++
#define MPU_ADDR 0x68
#define LEFT_BTN 3
#define RIGHT_BTN 10

#define MOUSE_LEFT MouseButton::Left
#define MOUSE_RIGHT MouseButton::Right
  • MPU_ADDR → I2C address of MPU6050
  • LEFT_BTN / RIGHT_BTN → Button inputs
  • MOUSE_LEFT / MOUSE_RIGHT → BLE mouse button mapping

I2C Configuration

Arduino · C++
Wire.begin(8, 9);

Initializes I2C using GPIO 8 (SDA) and GPIO 9 (SCL).

BLE Connection Handling

The system checks if BLE is paired before sending data. If not paired, it pauses execution and prints status messages for debugging.

Sensor Data Reading

Arduino · C++
Wire.beginTransmission(MPU_ADDR);
Wire.write(0x43);
Wire.endTransmission(false);
Wire.requestFrom(MPU_ADDR, 6);

Reads gyroscope values (gx, gy, gz). Includes error handling if data is not received.

Motion Conversion

Arduino · C++
float dx = -gy * sensitivity;
float dy = -gx * sensitivity;

Maps rotational motion to cursor movement axes.

Noise Filtering

Arduino · C++
if (abs(dx) < 0.5) dx = 0;
if (abs(dy) < 0.5) dy = 0;

smoothed_dx = smoothed_dx * 0.7 + dx * 0.3;
smoothed_dy = smoothed_dy * 0.7 + dy * 0.3;
  • Deadzone removes small unintended movements
  • Smoothing stabilizes cursor motion

Button Control

Arduino · C++
bool leftPressed = (digitalRead(LEFT_BTN) == LOW);
bool rightPressed = (digitalRead(RIGHT_BTN) == LOW);

Button states are read and mapped to BLE mouse click events.

Cursor Output

Arduino · C++
mouse.move(move_x, move_y);

Sends processed cursor movement to the connected device via BLE.

Debug Output

Serial output prints sensor values, computed movement, and button states at controlled intervals. Also reports BLE connection status and MPU read errors.

Sends cursor movement to the connected device via BLE.

Working of Loop

  • Reads gyroscope data continuously from MPU6050.
  • Converts motion into cursor movement.
  • Applies deadzone and smoothing for stability.
  • Checks button states for clicks.
  • Sends movement and click data over BLE.

System Summary

The ESP32-C3 continuously reads motion data from the MPU6050 sensor using I2C. This data is processed into smooth cursor movement and transmitted via Bluetooth Low Energy as a HID mouse. Button inputs allow full mouse interaction including left and right clicks.

Why this Architecture Works

  • Direct sensor → ESP32-C3 → BLE pipeline eliminates intermediate latency.
  • Gyroscope enables continuous motion tracking without external reference.
  • BLE HID allows plug-and-play usage without additional drivers.
  • Compact ESP32-C3 design enables handheld implementation.
  • Minimal hardware reduces complexity and improves reliability.

Real-Life Applications

  • Presentation Control: Navigate slides using hand gestures.
  • Smart TV Control: Replace traditional remotes with motion input.
  • Gaming: Use motion for aiming and interaction.
  • Assistive Technology: Enable touchless computer control.
  • Interactive Systems: Gesture-based control for installations.

Result

The system successfully converts hand motion into cursor movement using the MPU6050 sensor. The ESP32-C3 processes this motion data and transmits it wirelessly via Bluetooth as a HID mouse. Cursor movement is smooth, and both left and right click functions operate reliably. The device works without any surface, demonstrating a fully functional wireless air mouse system.

Code

Complete sketch
#include <Wire.h>
#include <HijelHID_BLEMouse.h>

#define MPU_ADDR 0x68
#define LEFT_BTN 3
#define RIGHT_BTN 10

#define MOUSE_LEFT MouseButton::Left
#define MOUSE_RIGHT MouseButton::Right

HijelBLEMouse mouse("MPU_Mouse", "Hijel");

int16_t gx, gy, gz;

float smoothed_dx = 0;
float smoothed_dy = 0;

unsigned long lastPrint = 0;

void setup() {
    Serial.begin(115200);

    Wire.begin(8, 9);

    pinMode(LEFT_BTN, INPUT_PULLUP);
    pinMode(RIGHT_BTN, INPUT_PULLUP);

    Wire.beginTransmission(MPU_ADDR);
    Wire.write(0x6B);
    Wire.write(0);
    Wire.endTransmission();

    mouse.setBatteryLevel(100);
    mouse.begin();

    Serial.println("INIT DONE");
}

void loop() {

    if (!mouse.isPaired()) {
        if (millis() - lastPrint > 1000) {
            Serial.println("BLE NOT PAIRED");
            lastPrint = millis();
        }
        delay(100);
        return;
    }

    if (millis() - lastPrint > 1000) {
        Serial.println("BLE CONNECTED");
        lastPrint = millis();
    }

    bool leftPressed = (digitalRead(LEFT_BTN) == LOW);
    bool rightPressed = (digitalRead(RIGHT_BTN) == LOW);

    if (leftPressed)
        mouse.press(MOUSE_LEFT);
    else
        mouse.release(MOUSE_LEFT);

    if (rightPressed)
        mouse.press(MOUSE_RIGHT);
    else
        mouse.release(MOUSE_RIGHT);

    Wire.beginTransmission(MPU_ADDR);
    Wire.write(0x43);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU_ADDR, 6);

    if (Wire.available() == 6) {
        gx = Wire.read() << 8 | Wire.read();
        gy = Wire.read() << 8 | Wire.read();
        gz = Wire.read() << 8 | Wire.read();
    } else {
        Serial.println("MPU READ ERROR");
        return;
    }

    float sensitivity = 0.003;

    float dx = -gy * sensitivity;
    float dy = -gx * sensitivity;

    if (abs(dx) < 0.5) dx = 0;
    if (abs(dy) < 0.5) dy = 0;

    smoothed_dx = smoothed_dx * 0.7 + dx * 0.3;
    smoothed_dy = smoothed_dy * 0.7 + dy * 0.3;

    int move_x = constrain((int)smoothed_dx, -20, 20);
    int move_y = constrain((int)smoothed_dy, -20, 20);

    mouse.move(move_x, move_y);

    if (millis() - lastPrint > 200) {
        Serial.print("GX: "); Serial.print(gx);
        Serial.print(" GY: "); Serial.print(gy);
        Serial.print(" DX: "); Serial.print(dx);
        Serial.print(" DY: "); Serial.print(dy);
        Serial.print(" MX: "); Serial.print(move_x);
        Serial.print(" MY: "); Serial.print(move_y);
        Serial.print(" L: "); Serial.print(leftPressed);
        Serial.print(" R: "); Serial.println(rightPressed);
        lastPrint = millis();
    }

    delay(10);
}
Prev Post
Next Post

Leave a comment

Please note, comments need to be approved before they are published.

Thanks for subscribing!

This email has been registered!

Shop the look

Choose Options

Edit Option
Back In Stock Notification
is added to your shopping cart.
this is just a warning
Login