Toggle Nav

How To Interface Joystick Module with Arduino

Author

Category

Table of Contents

Overview

Controlling components of the project such as motors is an essential part of many projects in electronics and robotics. There are numerous methods for this such as using computers, smartphones, radio modules, push buttons, joysticks and, so on. In this article, you will get to know the joystick module and learn how to set it up with Arduino and optimize it.

What You Will Learn

  • How the joystick module works
  • How to set up a joystick module
  • How to optimize joystick data
  • Operate servo motor with a joystick
  • Connect to Processing and use the joystick

How 2-Axis Joystick Works?

Gamers are very well familiar with joysticks. A Joystick is a device translating your hand movements to electric signals. Its simplicity and ease of use help you feel like you are actually inside the game or the robot you control.

The structure of this joystick module is the same as a ‘PlayStation 2’ joystick. Module’s lever is usually at the center. The joystick moves smoothly to the side and the self-centering spring brings it back to the center once released. The module includes a push button.

Joystick operates based on the resistance change of two potentiometers (usually 10-kilo ohms). By changing resistance in x and y directions, Arduino receives varying voltages which are interpreted to x and y coordinates. The processor needs an ADC unit to change the joystick’s analog values into digital values and perform necessary processing.

Arduino boards have six 10-bits ADC channels. It means the Arduino’s reference voltage (5 volts) is divided to 1024 segments. When joystick moves along the x-axis, the ADC value rises from 0 to 1023, with the value 512 in the middle. The image below displays the ADC approximate value based on the joystick position.

Note
Due to environmental noise and production quality, ADC values might not be the same in different modules.
This module has 5 pins.

GND pin connects to the circuit’s ground.
Vcc pin is used to supply the 5-volt power to the module.
VRx pin is the analog output pin for X-axis (left and right).
VRy pin is the analog output pin for Y-axis (up and down).
SW pin is connected to the pull-up button. Once the button is pressed, SW pin outputs 0.

Required Materials

Hardware Components

Arduino UNO × 1
Dual-axis XY Joystick Module × 1
Male to Female jumper wire × 1
TowerPro Mini Servo SG-90 9G Servo** × 1

** Servo motor is used in “controlling servo motor with joystick” example.

Software Apps

Arduino IDE

Interfacing Joystick with Arduino

In order to use the joystick module with Arduino, you just need to read the ADC values from VRx and VRy pins.

Circuit

Connect the module to the Arduino according to the following circuit.

Code

Upload the following code to your Arduino board and view the output in the serial monitor window. No library is necessary to operate the joystick module.

/*
  Joystick and Arduino

  modified on 21 Jul 2019
  by Saeed Hosseini @ Electropeak
  https://electropeak.com/learn
*/

const int SW = 2; // SW
const int X = 0; // VRx
const int Y = 1; // VRy

void setup() {

  pinMode(SW, INPUT_PULLUP);
  Serial.begin(9600);

}

void loop() {

  Serial.print("Switch:  ");
  Serial.print(digitalRead(SW));
  Serial.print("\t\t");
  Serial.print("VRx: ");
  Serial.print(analogRead(X));
  Serial.print("\t\t");
  Serial.print("VRy: ");
  Serial.println(analogRead(Y));
  Serial.println("____________________________________________________________");
  delay(500);
}

Read the analog values using the analogRead(Pin) command and use those values.

How to Optimize the Joystick Data?

A major problem with joystick modules is the nonlinearity. ADC value does not change linearly with the joystick lever movement. This causes problems especially in projects requiring high precision, such as controlling flying robots.

Using the averaging techniques, you can make joystick data smoothen, so that nonlinearity wouldn’t be too problematic.

Upload the following code to your Arduino board. View the output in the Serial Monitor window and compare data with the initial simple setup.

Code

/*
  Joystick Smoothing

  modified on 21 Jul 2019
  by Saeed Hosseini @ Electropeak
  https://electropeak.com/learn
  This code is based on https://www.arduino.cc/en/Tutorial/Smoothing
*/

const int X = 0;
const int Y = 1;

const int MaxReadings = 10;

int Xreadings[MaxReadings];
int XreadIndex = 0;
int Xtotal = 0;
int X_Pos = 0;

int Yreadings[MaxReadings];
int YreadIndex = 0;
int Ytotal = 0;
int Y_Pos = 0;

void Smoother(int x_pin, int y_pin)
{
  Xtotal = Xtotal - Xreadings[XreadIndex];
  Ytotal = Ytotal - Yreadings[YreadIndex];
  delay(1);
  Xreadings[XreadIndex] = analogRead(x_pin);
  Yreadings[YreadIndex] = analogRead(y_pin);
  delay(1);
  Xtotal = Xtotal + Xreadings[XreadIndex];
  Ytotal = Ytotal + Yreadings[YreadIndex];
  delay(1);
  XreadIndex = XreadIndex + 1;
  YreadIndex = YreadIndex + 1;
  if (XreadIndex >= MaxReadings) XreadIndex = 0;
  if (YreadIndex >= MaxReadings) YreadIndex = 0;
  delay(1);
  X_Pos = Xtotal / MaxReadings;
  Y_Pos = Ytotal / MaxReadings;

}
void setup() {
  Serial.begin(9600);
  for (int i = 0; i < MaxReadings; i++) {
    Xreadings[i] = 0;
    Yreadings[i] = 0;
  }
}
void loop() {
  Smoother(X,Y);
  Serial.print("VRx: ");
  Serial.print(X_Pos);
  Serial.print("\t\t");
  Serial.print("VRy: ");
  Serial.println(Y_Pos);
  Serial.println("____________________________________________________________");
  delay(100);
}

The MaxReading variable sets the averaging count. Higher averaging count makes data smoother and more linear, but decreases module’s speed. You can choose the proper balance between precision and speed according to the project requirements.

Controlling a Servo Motor with Joystick

In order to better understand how the joystick module works, we are going to control a servo motor with this module.

Circuit

Code

/*
  Joystick and servo motor

  modified on 21 Jul 2019
  by Saeed Hosseini @ Electropeak
  https://electropeak.com/learn
  This code is based on https://www.arduino.cc/en/Tutorial/Smoothing
*/
#include 

Servo myservo;

const int X = 0;
const int Y = 1;

const int MaxReadings = 10;

int Xreadings[MaxReadings];
int XreadIndex = 0;
int Xtotal = 0;
int X_Pos = 0;

int Yreadings[MaxReadings];
int YreadIndex = 0;
int Ytotal = 0;
int Y_Pos = 0;

int Servo_Pos = 0, Pos = 0;

void Smoother(int x_pin, int y_pin)
{
  Xtotal = Xtotal - Xreadings[XreadIndex];
  Ytotal = Ytotal - Yreadings[YreadIndex];
  delay(1);
  Xreadings[XreadIndex] = analogRead(x_pin);
  Yreadings[YreadIndex] = analogRead(y_pin);
  delay(1);
  Xtotal = Xtotal + Xreadings[XreadIndex];
  Ytotal = Ytotal + Yreadings[YreadIndex];
  delay(1);
  XreadIndex = XreadIndex + 1;
  YreadIndex = YreadIndex + 1;
  if (XreadIndex >= MaxReadings) XreadIndex = 0;
  if (YreadIndex >= MaxReadings) YreadIndex = 0;
  delay(1);
  X_Pos = Xtotal / MaxReadings;
  Y_Pos = Ytotal / MaxReadings;

}


void setup() {

  Serial.begin(9600);
  myservo.attach(9);
  for (int i = 0; i < MaxReadings; i++) {
    Xreadings[i] = 0;
    Yreadings[i] = 0;
  }
}

void loop() {
  Smoother(X, Y);
  Servo_Pos = map(X_Pos, 0, 1023, 0, 180);
  myservo.write(Servo_Pos);
  Serial.println(Servo_Pos);
  delay(20);
}

We use the averaging method to receive the joystick data. Since servo motor position changes from 0 to 180 degrees, we need to convert joystick data which goes from 0 to 1023. We use map(X_Pos, 0, 1023, 0, 180) command for this purpose.

Joystick Communication with Processing

Processing is a set of Java libraries alongside a programming environment developed in 2001. It provides a visual interactive environment for education. Easy connection to boards such as Arduino and the graphical interactive environment has made Processing quite popular. Processing comes completely free of charge and can be downloaded here.

For more information on the Processing software, programming method, functions and so on, refer to the Processing software complete guide .

Processing can receive information from mouse, keyboard and serial ports. In this project, Processing joystick data goes through the computer’s serial port and Processing receives and processes these data.

Therefore we need two sets of codes for this part:

Extracting the joystick coordinates (x,y) and Sending it to Processing Using Arduino

Upload the following code to the Arduino:

/*
  Joystick and Processing

  modified on 21 Jul 2019
  by Saeed Hosseini @ Electropeak
  https://electropeak.com/learn
*/

const int X = 0;
const int Y = 1;


int b = 0;
int x = 0;
int y = 0;

const int MaxReadings = 10;

int Xreadings[MaxReadings];
int XreadIndex = 0;
int Xtotal = 0;
int X_Pos = 0;

int Yreadings[MaxReadings];
int YreadIndex = 0;
int Ytotal = 0;
int Y_Pos = 0;

void Smoother(int x_pin, int y_pin)
{
  Xtotal = Xtotal - Xreadings[XreadIndex];
  Ytotal = Ytotal - Yreadings[YreadIndex];
  delay(1);
  Xreadings[XreadIndex] = analogRead(x_pin);
  Yreadings[YreadIndex] = analogRead(y_pin);
  delay(1);
  Xtotal = Xtotal + Xreadings[XreadIndex];
  Ytotal = Ytotal + Yreadings[YreadIndex];
  delay(1);
  XreadIndex = XreadIndex + 1;
  YreadIndex = YreadIndex + 1;
  if (XreadIndex >= MaxReadings) XreadIndex = 0;
  if (YreadIndex >= MaxReadings) YreadIndex = 0;
  delay(1);
  X_Pos = Xtotal / MaxReadings;
  Y_Pos = Ytotal / MaxReadings;

}


void setup()
{
  Serial.begin(9600) ; 
  pinMode(2, INPUT_PULLUP) ; 
  for (int i = 0; i < MaxReadings; i++) {
    Xreadings[i] = 0;
    Yreadings[i] = 0;
  }
}

void loop()
{
  Smoother(X,Y);
  x = map(X_Pos, 0, 1023, 0, 512);
  y = map(Y_Pos, 0, 1023, 0, 512);
  b = digitalRead(2);

  Serial.print(x, DEC);
  Serial.print(",");
  Serial.print(y, DEC);
  Serial.print(",");
  Serial.print(!b);
  
  Serial.print("\n");

  delay(10);
}

You should separate the data with “,” and use “\n” to declare the ending for the Processing software.

Receiving Joystick Data via Serial Port and Processing Them

Copy the following code to the Processing software and execute the code:

/*
  Joystick and Processing
  modified on 21 Jul 2019
  by Saeed Hosseini @ Electropeak
  https://electropeak.com/learn
  Thanks to http://learningprocessing.com/examples/
*/
import processing.serial.*; 
Serial myPort;
int VRx;
int VRy; 
int but;
String val;
int maxImages = 5;
int imageIndex = 0;
int i = 1;
PImage[] img = new PImage[maxImages]; 
PImage image;
void setup() {
  size(512, 512);
  myPort = new Serial(this, "COM5", 9600);
  myPort.bufferUntil('\n'); 
  background(0);
}
void draw() {
  game();
}
void serialEvent( Serial myPort) 
{
  // read the data until the newline n appears
  val = myPort.readStringUntil('\n');
  if (val != null)
  {
    val = trim(val);

    // break up the decimal and new line reading
    int[] vals = int(splitTokens(val, ","));
    // we assign to variables
    VRx = vals[0];
    VRy = vals[1] ;
    but = vals[2];
  }
}
void game() {
  img[i] = loadImage( "p" + i + ".jpg" );
  image = img[i];
  loadPixels();
  img[i].loadPixels();
  for (int x = 0; x < image.width; x++ ) {
    for (int y = 0; y <image.height; y++ ) {

      // Calculate the 1D pixel location
      int loc = x + y*image.width;

      // Get the R,G,B values from image
      float r = red  (image.pixels[loc]);
      float g = green(image.pixels[loc]);
      float b = blue (image.pixels[loc]);

      // Calculate an amount to change brightness
      // based on proximity to the mouse
      float distance = dist(x, y, VRy, VRx);

      // The closer the pixel is to the mouse, the lower the value of "distance" 
      // We want closer pixels to be brighter, however, so we invert the value using map()
      // Pixels with a distance of 50 (or greater) have a brightness of 0.0 (or negative which is equivalent to 0 here)
      // Pixels with a distance of 0 have a brightness of 1.0.
      float adjustBrightness = map(distance, 0, 50, 1, 0);
      r *= adjustBrightness;
      g *= adjustBrightness;
      b *= adjustBrightness;

      // Constrain RGB to between 0-255
      r = constrain(r, 0, 255);
      g = constrain(g, 0, 255);
      b = constrain(b, 0, 255);

      // Make a new color and set pixel in the window
      color c = color(r, g, b);
      pixels[loc] = c;

      if (but == 1) i++;
      if (i>4) i = 1;
    }
  }

  updatePixels();
}

Pressing the center button displays the next image.

In the “float adjustBrightness = map(distance, 0, 50, 1, 0)” command, you can change the initial value (50) to make the game harder or easier.

Note

To establish the serial connection, disconnect and reconnect the Arduino board from the computer after making any changes in the program. Then run our code in the Processing.

What’s Next?

  • Try to make a gaming joystick using two joystick modules.
  • Try to use the NRF24L01 to make the gaming joystick wireless.

Liked What you see?

Get updates and learn from the best

More To Explore

Leave a Reply

Your email address will not be published. Required fields are marked *