Using a joystick sensor on an Arduino

How it works, and how to connect and use it on an Arduino

Melanie Chow
6 min readJun 17, 2019

For class I was handed two mystery sensors, and was given the vague instructions to figure them out and create a demo. One of the sensors that I easily recognized was a joystick, and I thought I would share the demo and tutorial here. (Our other sensor was a rotary encoder, and that tutorial can be found here.)

Analog Joystick Sensor: Image credit to MakerFabs

The following article is structured like so:

  1. Overview: Input & Output pins of the joystick
  2. Understanding a Joystick: How a joystick works
  3. Connecting it to an Arduino: Step-by-step wiring
  4. Demo + How to Code: Creating the demo

(Disclaimer: These tutorials were made by my wonderful team and I. The following has been edited slightly for sharing.)

Overview

The joystick is useful for reading and interpreting 2D motion through two analog variables, which represent the position of the sensor on a 2D plane. The joystick can also be pressed inwards like a button, which is useful for functions such as selecting items in menus.

  • Input 1: Moving the stick
  • Output 1: position of handle relative to its center, X and Y axis
  • Input 2: Pressing the button
  • Output 2: Whether the button is pressed or not

Understanding a Joystick

Before we go in to how to connect a sensor and use it in code, it is important to understand how a joystick works internally.

The analog joystick has a handle and two slotted shafts around the handle (along the x-axis and y-axis). The handle can be pushed to any point in a plane, which will cause one or both of the slotted shafts to pivot. Each slotted shaft is attached to a potentiometer on the side, which converts the angular displacement of the shaft to an analog signal.

The data for each axis is determined in analog using a potentiometer, communicating position in the form of voltage. This is possible because the shaft is connected to a wiper and resistive strip inside the potentiometer.

Resistive strip controlling output voltage

As the wiper moves further along the resistive strip, more current passes through the strip to complete the circuit, thereby increasing the total resistance of the circuit.

Therefore, twisting the potentiometer will change the voltage of its output. In its default position along an axis, the joystick will output half the voltage input. As we move along an axis, the voltage of the output will move either to the maximum inputted voltage, or to zero, signaling how far we have moved the shaft of the joystick.

Connecting it to an Arduino

Here are what the 5 pins of the analog joystick mean:

  • GND: Ground
  • +5V: 5V power source
  • VRx: X-direction reading (Analog)
  • VRy: Y-direction reading (Analog)
  • SW: Button press (Digital)

VRx and VRy should be connected to analog pins on the Arduino, and SW should be connected to a digital pin. As usual, +5V should be connected to 5V, and the GND pin should be connected to GND.

Step by Step Instructions

1. GND: Place one end of a wire at the GND pin on the joystick to the GND pin on the arduino (Black Wire)

2. +5V: Place one end of a wire at the 5V source pin on the joystick (+5V) to the 5V pin on the arduino (Red Wire)

3. VRx: Place one end of a wire at the VRx pin on the joystick to any analog pin on the arduino (Orange Wire — We connected it to pin A3)

4. VRy: Place one end of a wire at the VRy pin on the joystick to any analog pin on the arduino (Yellow Wire — We connected it to pin A1)

5. SW: Place one end of a wire at the SW pin on the joystick to any digital pin on the arduino. (Sky Blue Wire — We connected it to pin D5)

Vertical view of the arduino setup
Side angle of the arduino setup

Demo + How to Code

This code moves the servo hand in X degree intervals based on Joystick positioning. For example, if joystick is held to the left continuously, the servo hand will move in 180 degree intervals.

Here is a demo video where I describe how it works:

What you will need:

  • Analog joystick sensor
  • Arduino
  • LED pin
  • Continuous servo motor
  • Wires

For this demo, we used a continuous servo motor. Ideally we would use a non-continuous servo motor for this demo since it works with degree coordinates. However, since we only had a continuous servo, we had to use delays in the code to control movement. Although a delay of 500ms may theoretically be correct based on the speed of servo movement, 600ms worked better after experimentation.

/* Setup */
#include <math.h>
#include <Servo.h>
/* Pins */
int servo_pin = 3;
int joyPin1 = 1; // slider variable connected to analog pin 1
int joyPin2 = 3; // slider variable connected to analog pin 3
int led = 2; // led light connected to digital pin 2

int SW_pin = 5; // digital pin connected to switch output
int y = 0; // variable to read the value from the analog pin 0
int x = 0; // variable to read the value from the analog pin 1
Servo servo_motor;void setup() {
pinMode(SW_pin, INPUT);
digitalWrite(SW_pin, HIGH);
Serial.begin(9600); //Start printing to the console
servo_motor.attach(servo_pin);
pinMode(led, OUTPUT);
}
int getDegree(int raw_x, int raw_y) {
raw_x = (raw_x - 2457);
raw_y = (raw_y - 2541);

/* Convert Raw Values to Degree */
//convert radians to degree
double val = atan2(raw_y, raw_x) * 180/3.14159265358979;
if (val < 0) {
val += 360;
}

//convert to a double
double new_x = raw_x / 100.0;
double new_y = raw_y / 100.0;
double distance = sqrt((new_x * new_x) + (new_y * new_y));

//15 is a distance threshold that determines when to move the servo
if (distance > 15) {
return val;
}
return -1; // joystick has not moved far enough to move servo
}
void loop() { /* Get x and y raw values*/
y = (analogRead(joyPin1) * 4.9);
delay(50); // small pause needed between reading
x = (analogRead(joyPin2) * 4.9 );
delay(50);

/* Print Raw Coordinates */
Serial.print(y);
Serial.print('-');
Serial.print(x);
Serial.print("-");
Serial.println(digitalRead(SW_pin));

/* If pressed down, light up pin */
if (digitalRead(SW_pin) == 0) { // when pressed, SW_pin returns 0
digitalWrite(led, HIGH);
}
else {
digitalWrite(led, LOW);
}

/* Translate x and y into a degree */
int deg = getDegree(x, y);
Serial.print("Degree");
Serial.println(deg);

/* If deg is -1, don't move */
if (deg == -1) {
servo_motor.write(90);
}
/* If deg is not -1, move that # of degrees*/
else {
Serial.println("move");
servo_motor.write(0); //Move servo at maximum speed
delay(600 * (deg/360.0)); //Experimental value
servo_motor.write(90); //Stop servo movement after delaying a certain amount of time
}
}

I hope you enjoyed this tutorial and found it thorough and useful!

--

--

Melanie Chow

Computer Science student at the University of Chicago, interested in a bunch of random things.