The Story

Hello !

I have a MacBook laptop with a finicky mouse that doesn't work very well.  So, I thought of ideas to fix it.  I suddenly thought of an awesome idea; a gesture mouse! I have thought of this project before, but didn't have the time to make it, so now I just dove in headfirst.


How it Works

This mouse utilizes an Atmega32u4 microcontroller and a MPU-6050 accelerometer and gyroscope.

The microcontroller gathers the data from the accelerometer / gyroscope, and uses it to move and control the mouse on your personal computer!


Wiring / Schematic

The wiring is simple; only 4 wires.

Atmega32u4   -   MPU-6050

VCC  -  VCC

GND  -  GND

2    -    SDA

3    -    SCL

The I2C is unusual on the Atmega32u4 microcontroller, with the I2C pins being pin 2 and 3, vs. the normal A4 and A5.


The Code

Code link: https://github.com/Kgray44/Gesture-Mouse

WARNING:  This code will take over control of your mouse and keyboard!  The mouse and keyboard built-in to your computer will still work though at the same time.

#include <MPU6050_light.h>
#include <Wire.h>
#include <Mouse.h>
#include <Keyboard.h>

First we include the libraries needed; Wire.h and MPU6050_light.h for the gyroscope / accelerometer, and mouse.h and keyboard.h for controlling the computer.

float Ythreshhold = 5.00; //degrees; for mouse
float Xthreshhold = 5.00; //degrees; for mouse
float Xthreshholdtop = 30.00; //degrees; for mouse
float Ythreshholdtop = 40.00; //degrees; for mouse
float clickThreshhold = 1.65; //accel value; for clicking
float scrollthreshhold = 30.00; //degrees; same as Xangle; i.e. Xthreshholdtop
float switchdesktopthreshhold = 350.00; //gyro value; swiping between desktops

These are all the adjustable variables for controlling the mouse.  Each is explained beside it.

int clickcounter;
boolean isClicked = false;

float gyroZ;
float accelZ;
float Xangle, Yangle, Zangle;

int timer;

These are the rest of the variables we need, to store the incoming data, and for a couple other things.

MPU6050 mpu(Wire);

Here, a library instance is declared for the MPU6050.

void setup(){
  Mouse.begin();
  Keyboard.begin();

  Serial.begin(115200);
  delay(1000);

  Wire.begin();
  
  byte status = mpu.begin();
  Serial.print(F("MPU6050 status: "));
  Serial.println(status);
  mpu.calcOffsets(true,true); // gyro and accelero
}

In void setup(), first, the mouse and keyboard are started.  Then the serial port; useful for debugging.  Then Wire is started (used for the MPU6050), and the MPU6050 is started and calibrated. 

  mpu.update();

  Xangle = mpu.getAngleX();
  Yangle = mpu.getAngleY();
  Zangle = mpu.getAngleZ();
  accelZ = mpu.getAccZ();
  gyroZ = mpu.getGyroZ();
  
  Serial.println("Xangle: " + String(Xangle) + " Yangle: " + String(Yangle) + " Zangle: " + String(Zangle) + " AccelZ: " + String(accelZ) + " gyroZ: " + String(gyroZ));

First, in void loop(), the mpu is updated, and the data gathered and stored.  The last line prints all of the incoming data to the serial monitor on 115200baud (useful for debugging).

  if ((abs(Xangle) > Xthreshhold && abs(Xangle) < Xthreshholdtop) || (abs(Yangle) > Ythreshhold && abs(Yangle) < Ythreshholdtop)){
    Mouse.move(map(Yangle,5,15,0,2),map(Xangle,5,12,0,2));
  }

This first if statement controls the mouse.  The absolute of the Xangle and Yangle variables is checked to make sure they are within our threshold values.  If so, the mouse is moved with mapped Yangle and Angle values.  You can adjust the map values to fine tune the mouse to your desires.

  if (abs(Xangle) > scrollthreshhold){
    if (Xangle < -scrollthreshhold){
      Mouse.move(0,0,-1);
      delay(map(Xangle,-scrollthreshhold,-45,85,45));//65
    }
    else {
      Mouse.move(0,0,1);
      delay(map(Xangle,scrollthreshhold,45,85,45));//65
    }
  }

The second if  statement controls the scrolling.  Because...

Read more »