Example: Joystick Mouse

This circuit uses an Adafruit joystick breakout to read movements to control the mouse.  The joystick has a pushbutton switch built-in that simulates the mouse left-click.  An external pushbutton (shown on the breadboard) enables and disables the mouse control which is useful when you want the project to not read mouse control (if you have two mice, it allows the other mouse to resume full control).  One push enables, another disables.

The mouse uses some exponential math to give non-linear movement - the harder you lean on the joystick, the faster it will go.   Also the switch is debounced to prevent spurious mouse clicks.  

/*
 Joystick Mouse Control
 
 Controls a PC mouse from a joystick on an Adafruit Pro Trinket.
 Uses the joystick pushbutton to click the left mouse button
 
 Hardware:
 * 2-axis joystick connected to pins A0 and A1 with pushbutton on D10
 * Pushbutton enable/disable the mouse entirely on D9 (optional)
 
 The mouse movement is always relative. 
 
 The sketch assumes that the joystick resting values are around the 
 middle of the range, but that they vary within a threshold.
 
 WARNING:  When you use the new mouse, the Arduino takes
 over your mouse!  Make sure you have control before you use the project.
 This sketch includes a pushbutton to toggle the mouse on and off.
 
Based on software on arduino.cc by Tom Igoe placed in the public domain

Version 1.0  Initial version for Adafruit Pro Trinket by Mike Barela
 
 */
#include <ProTrinketMouse.h>  // include mouse library for Pro Trinket (3V or 5V)

// set pin numbers for switch, joystick axes, and LED
const int switchPin   =  9;   // switch to turn on and off mouse control
const int mouseButton = 10;   // input pin for the mouse pushButton
const int xAxis  = 1;         // joystick X axis to A1 
const int yAxis  = 0;         // joystick Y axis to A0
const int ledPin = 13;        // Mouse control LED 

// parameters for reading the joystick
int range = 12;               // output range of X or Y movement (zero to range)
int responseDelay = 5;        // response delay of the mouse, in ms
int threshold = range/4;      // resting threshold
int center = range/2;         // resting position value
const float powerValue = 1.4; // for exponential behavior, 1 < value < 2

boolean mouseIsActive = false;      // whether or not to control the mouse
int lastSwitchState = LOW;          // previous switch state
boolean mouseButtonPressed = false; // whether or not mouse button pressed
int  lastReading = 1;       // last joystick/mouse button reading
long debounceTime = 0;      // last time the mouse button was toggled
long debounce = 50;         // debounce time, increase if the mouse clicks rapidly

void setup() {
  pinMode(switchPin,   INPUT_PULLUP);   // the switch pin
  pinMode(mouseButton, INPUT_PULLUP);   // mouse button on joystick
  pinMode(ledPin, OUTPUT);              // the LED pin  
  TrinketMouse.begin();                 // initialize the mouse library
}

void loop() {
  int switchState;  // State of the mouse enable/disable button
  int buttonState;  // State of the mouse left button switch on joystick
  int xReading, yReading; // readings of the joystick movements
  int buttonReading;      // reading of the joystick (left mouse) button
  
  switchState = digitalRead(switchPin);  // read the mouse disable switch
  // if it's changed and it's high, toggle the mouse state
  if (switchState != lastSwitchState) {
    if (switchState == HIGH) {
      mouseIsActive = !mouseIsActive;
//      digitalWrite(ledPin, mouseIsActive);   // toggle LED to indicate mouse state
    } 
  }
  lastSwitchState = switchState;    // save switch state for next comparison

  // read and scale the two joystick readings, one for each axis
  xReading = readAxis(xAxis);
  yReading = readAxis(yAxis);

  // This code gives the mouse a nonlinear acceleration 
  //   These 8 lines may be commented out to have linear acceleration
  if(xReading > 0)
     xReading =  (int)pow(powerValue,xReading);
  else if(xReading < 0)
     xReading = -(int)pow(powerValue,-xReading);
     
  if(yReading > 0)
     yReading =  (int)pow(powerValue,yReading);
  else if(yReading < 0)
     yReading = -(int)pow(powerValue,-yReading);  // end nonlinear acceleration code

  // Read the joystick button as the left mouse button.  Debounce per 
  //   Ladyada code at https://learn.adafruit.com/tilt-sensor/using-a-tilt-sensor
  buttonReading = digitalRead(mouseButton);  // read the mouse left button (push joystick)
  if(buttonReading != lastReading) {         // switch changed
     debounceTime = millis();                // reset debounce timer
  }
  if((millis() - debounceTime) > debounce) {
     buttonState = buttonReading;
     if(buttonState == LOW) {
        mouseButtonPressed = true;
     }
     else {
        mouseButtonPressed = false;
     }
  } 
  lastReading = buttonReading;
  digitalWrite(ledPin, mouseButtonPressed);  // toggle LED to indicate button state
  
  // if the mouse control state is active, move the mouse:
  if (mouseIsActive) {
      if (mouseButtonPressed) {  // if joystick pressed down, indicate that too
         TrinketMouse.move(xReading, yReading, 0, MOUSEBTN_LEFT_MASK);
      }
      else {
         TrinketMouse.move(xReading, yReading, 0, 0);  // move, no mouse button press
      }
  }  
  delay(responseDelay);  // wait between mouse readings
}

// Reads a joystick axis (0 or 1 for x or y) and scales the 
//  analog input range to a range from 0 to <range>
int readAxis(int thisAxis) { 
  int reading = analogRead(thisAxis);  // read the analog input

  // map the reading from the analog input range to the output range
  reading = map(reading, 0, 1023, 0, range);

  // if the output reading is outside from the rest position threshold, use it
  int distance = center - reading;

  if (abs(distance) < threshold) { // if distance not to threshold, no move
    distance = 0;                  // prevents tiny jitters due to readings
  } 
  return distance;   // return the distance for this axis
}

Use

The single button enables and disables the mouse.  The joystick moves the mouse cursor in all 4 directions with acceleration for bigger movements. The joystick push down button is the mouse left button.  The Pro Trinket onboard red LED indicates the left button press but can be changed to the on/off state by changing the two lines with a digitalWrite to ledPin.

Wiring

Solder the joystick to its breakout board and small piece of male header shown in the product page. Solder headers (included) onto the Pro Trinket.  I stripped and cut my own wires from the nice Adafruit hookup wire selection but you can use premade wires for prototyping.

The completed breadboard is shown below.  There is a ground wire from the joystick ground to the top ground line that is obscured by the joystick circuit board.

If you would like to make a more permanent project, you can transfer the parts to an Adafruit half Perma-Proto board.  See the next project, the accelerometer mouse for how using a Perma-Proto looks.

Last updated on 2015-05-04 at 04.27.32 PM Published on 2015-01-25 at 08.25.22 PM