ESP32 UNO - Joystick

Want to steer a robot, a game or a camera with your thumb? Hook an ESP32 Uno joystick module to three pins and your sketch gets the stick position as two numbers plus a click. The ESP32 Uno form board reads each axis of the thumb joystick from 0 to 4095, so even small moves show up. With a few lines of Arduino code, you turn the 2-axis joystick into LEFT, RIGHT, UP and DOWN commands.

What you will do:

  1. Learn what the five joystick pins carry
  2. Connect an analog joystick to the A1, A0 and D2 headers
  3. Read the X and Y positions with analogRead()
  4. Detect the thumb-stick click with the ezButton library
  5. Turn stick moves into direction commands in Arduino IDE
ESP32 Uno joystick

Components You Need

1×ESP32 Uno-form Board
1×USB Cable Type-A to Type-C (for USB-A PC)
1×USB Cable Type-C to Type-C (for USB-C PC)
1×Joystick
1×Jumper Wires

Or you can buy the following kits:

1×DIYables Sensor Kit (18 sensors/displays)
Disclosure: Some of the links provided in this section are Amazon affiliate links. We may receive a commission for any purchases made through these links at no additional cost to you.
Additionally, some of these links are for products from our own brand, DIYables .

The Thumb Joystick at a Glance

By the end of this part, you know what the module sends to the board.

Joysticks sit on game pads, RC toy remotes and the control levers of heavy machines such as diggers. The small module used here packs two potentiometers, mounted at 90 degrees to each other, and one push switch under the stick.

Output Signal Type Value on ESP32 Uno
Horizontal position (X) Analog 0 to 4095
Vertical position (Y) Analog 0 to 4095
Stick click (SW) Digital HIGH (free) or LOW (pressed)

Put X and Y together and you get a 2-D point. A spring pulls the stick back to the middle, so at rest both numbers sit near the center of the range. The first sketch below shows you which side is left, right, up and down on your module. A project may use all three outputs or only one or two of them.

Pinout

Match these five pins before you plug in any jumper wire.

Pin Role Connect To
GND Ground (0V) GND
VCC Power for the two potentiometers 3.3V on the ESP32 Uno
VRX Analog voltage for the X axis An analog input
VRY Analog voltage for the Y axis An analog input
SW Push switch, normally open A digital input with pull-up

With a pull-up resistor on SW, the pin stays HIGH until you press the stick, then drops to LOW.

Joystick Pinout

Good to know: feed the module from 3.3V. The axis pins output a voltage between 0V and VCC, and ESP32 Uno pins are NOT 5V tolerant.

How It Works

Here you see how a stick position becomes a number in your code.

Stick Action Pin That Changes Voltage Reading
Full left VRX 0V about 0
Full right VRX 3.3V about 4095
Full up VRY 0V about 0
Full down VRY 3.3V about 4095
Released (center) VRX and VRY about 1.65V roughly 1800 to 2100
Pressed down SW 3.3V to 0V HIGH to LOW

Each axis is a voltage divider. Moving the stick slides the wiper, and the ESP32 Uno ADC converts that voltage to a 12-bit number. A diagonal push changes VRX and VRY at the same time, each one by how far the stick traveled on its own axis. Pressing the stick closes the internal switch, so SW is pulled to ground and reads LOW.

Good to know: the ESP32 Uno ADC is 12-bit, so the scale ends at 4095, not 1023.

ESP32 Uno Pinout

Your sketch never uses the printed label (A1, A0, D2); it uses the GPIO number behind it. Find those three headers in the diagram below first.

ESP32 Uno pinout diagram

How to Connect the Joystick

By the end of this part, the joystick is wired and powered.

The wiring diagram between ESP32 Uno Joystick

This image is created using Fritzing. Click to enlarge image

Joystick Pin ESP32 Uno Pin
GND GND
VCC 3.3V
VRX A1 (GPIO4)
VRY A0 (GPIO2)
SW D2 (GPIO26)

WARNING

A0 (GPIO2) is a boot strapping pin. GPIO2 must be LOW or floating when the board enters upload mode. At rest, the VRY pin sits at about 1.65V, which can block an upload ("Failed to connect" or "Waiting for download"). If that happens, unplug the VRY wire during the upload and plug it back after.

WARNING

A1 (GPIO4) and A0 (GPIO2) are ADC2 pins. analogRead() on ADC2 does not work while WiFi is on. This page uses no WiFi, so the wiring is fine here. For a WiFi version, read the axes on A2 to A5 (GPIO35, 34, 36, 39) instead.

Good to know: never connect the joystick VCC to 5V. At 5V the axis pins can push 5V into the ESP32 Uno analog inputs and damage them.

Reading a Joystick in Code

By the end of this part, you know the two tools each sketch below uses.

Step 1 — The two axes

Read each axis with analogRead(). Pass the GPIO number of the header, not its label.

int xValue = analogRead(4); // A1 (GPIO4) carries VRX int yValue = analogRead(2); // A0 (GPIO2) carries VRY

Step 2 — The stick click

The SW pin is just a push button. The ezButton library switches on the internal pull-up of D2 (GPIO26) and filters contact bounce. More button details are in ESP32 Uno - Button.

Raw readings are rarely the final goal. The examples below turn them into values your project can act on.

ESP32 Uno Code

Pick the sketch that matches your goal. Start with the first one, since it shows how your module is turned.

Example What You Get
Read analog values X and Y numbers every 200 ms
Read analog values and the button X, Y, button level and press/release messages
Direction commands COMMAND LEFT, RIGHT, UP and DOWN text
Two servo motors Angles for a pan-tilt mount (separate tutorial)

Sketch 1 — Print the X and Y Numbers

This sketch samples both axes five times per second and prints them.

/* * This ESP32 Uno code was developed by newbiely.com * * This ESP32 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-uno/esp32-uno-joystick */ #define VRX_PIN 4 // A1 (GPIO4) gets the joystick VRX signal #define VRY_PIN 2 // A0 (GPIO2) gets the joystick VRY signal int xValue = 0; // last X axis reading int yValue = 0; // last Y axis reading void setup() { Serial.begin(9600) ; // set the ADC attenuation to 11 dB (up to ~3.3V input) analogSetAttenuation(ADC_11db); } void loop() { // sample both axes (0 to 4095 on the ESP32 Uno) xValue = analogRead(VRX_PIN); yValue = analogRead(VRY_PIN); // show the two numbers in the Serial Monitor Serial.print("x = "); Serial.print(xValue); Serial.print(", y = "); Serial.println(yValue); delay(200); }

Good to know: the analogSetAttenuation(ADC_11db) line in setup() lets the ESP32 Uno analog pins measure the full swing, from 0V up to about 3.3V. Without a wide range, the readings hit 4095 when the stick is only half way, and the joystick values look wrong.

Upload and Test

  1. First time with this board? Set it up with ESP32 Uno - Getting Started before you continue.
  2. Build the circuit by following the wiring table above.
  3. Plug in the USB Type-C cable between the ESP32 Uno and your computer.
  4. Select the board in Arduino IDE: pick ESP32 Dev Module and the COM port of the board (CH340).
  5. Paste the sketch into a new Arduino IDE window.
  6. Send the sketch to the board with the Upload arrow. If it stops at "Connecting...", pull the VRY wire for a moment.
  7. Push the stick to its edge and sweep it around in a full circle, either way.
  8. Open the Serial Monitor at 9600 baud and watch the numbers.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32 Dev Module' on 'COM15')
New Line
9600 baud
x = 1912, y = 1876 x = 0, y = 1840 x = 1427, y = 0 x = 4095, y = 2233 x = 2603, y = 4095 x = 1909, y = 1881
Ln 11, Col 1
ESP32 Dev Module on COM15
2
  1. Pro tip: put a small piece of tape on the module and mark the side where X shows 0 as "L" and the side where Y shows 0 as "U". The opposite edges are right and down.

Sketch 2 — X, Y and the Stick Click

This sketch adds the stick click. It prints X, Y and the button level each loop, plus one line on every press and release.

/* * This ESP32 Uno code was developed by newbiely.com * * This ESP32 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-uno/esp32-uno-joystick */ #include <ezButton.h> #define VRX_PIN 4 // A1 (GPIO4) gets the joystick VRX signal #define VRY_PIN 2 // A0 (GPIO2) gets the joystick VRY signal #define SW_PIN 26 // D2 (GPIO26) gets the joystick SW signal ezButton button(SW_PIN); int xValue = 0; // last X axis reading int yValue = 0; // last Y axis reading int bValue = 0; // last button level void setup() { Serial.begin(9600) ; // set the ADC attenuation to 11 dB (up to ~3.3V input) analogSetAttenuation(ADC_11db); button.setDebounceTime(50); // ignore contact bounce shorter than 50 ms } void loop() { button.loop(); // keep this call at the top of loop() // sample both axes (0 to 4095 on the ESP32 Uno) xValue = analogRead(VRX_PIN); yValue = analogRead(VRY_PIN); // get the debounced button level bValue = button.getState(); if (button.isPressed()) { Serial.println("The button is pressed"); // TODO put your press action here } if (button.isReleased()) { Serial.println("The button is released"); // TODO put your release action here } // show axes and button in the Serial Monitor Serial.print("x = "); Serial.print(xValue); Serial.print(", y = "); Serial.print(yValue); Serial.print(" : button = "); Serial.println(bValue); }

Upload and Test

  1. Open Library Manager from the left sidebar (the Libraries icon).
  2. Search for “ezButton”; the right one is made by ArduinoGetStarted.com.
  3. Hit Install and wait for it to finish.
  • Search for ezButton created by ArduinoGetStarted.com and click the Install button.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32 Dev Module
Library Manager
Type:
All
Topic:
All
ezButton by ArduinoGetStarted.com
Button library supports debounce, pressed/released events and the press counting. It is easy to use with multiple buttons. The library can be used for push-button, momentary switches, toggle switch, magnetic contact switch (door sensor)... It is designed for not only beginners but also experienced users. More info
1.0.6
INSTALL
Newbiely.ino
···
1 void setup() {
Output
Serial Monitor
Ln 1, Col 1
ESP32 Dev Module on COM15
1
  1. Paste the sketch into Arduino IDE.
  2. Upload it to the ESP32 Uno.
  3. Tilt the stick in each direction.
  4. Click the stick straight down, then let go.
  5. Read the Serial Monitor.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32 Dev Module' on 'COM15')
New Line
9600 baud
x = 1915, y = 1873 : button = 1 x = 3988, y = 1862 : button = 1 The button is pressed x = 1917, y = 1870 : button = 0 The button is released x = 1911, y = 52 : button = 1
Ln 11, Col 1
ESP32 Dev Module on COM15
2
  1. Pro tip: this sketch prints with no delay, so the monitor scrolls fast. Turn off autoscroll in the Serial Monitor to read one line at a time.

Sketch 3 — Turn Stick Moves into Direction Commands

This sketch checks each axis against a low and a high limit. The limits 1600 and 3200 match the 12-bit scale, so the rest zone near the middle sends nothing.

/* * This ESP32 Uno code was developed by newbiely.com * * This ESP32 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-uno/esp32-uno-joystick */ #define VRX_PIN 4 // A1 (GPIO4) gets the joystick VRX signal #define VRY_PIN 2 // A0 (GPIO2) gets the joystick VRY signal #define LEFT_THRESHOLD 1600 #define RIGHT_THRESHOLD 3200 #define UP_THRESHOLD 1600 #define DOWN_THRESHOLD 3200 #define COMMAND_NO 0x00 #define COMMAND_LEFT 0x01 #define COMMAND_RIGHT 0x02 #define COMMAND_UP 0x04 #define COMMAND_DOWN 0x08 int xValue = 0 ; // last X axis reading int yValue = 0 ; // last Y axis reading int command = COMMAND_NO; void setup() { Serial.begin(9600) ; // set the ADC attenuation to 11 dB (up to ~3.3V input) analogSetAttenuation(ADC_11db); } void loop() { // sample both axes (0 to 4095 on the ESP32 Uno) xValue = analogRead(VRX_PIN); yValue = analogRead(VRY_PIN); // build the command bits from the two readings // start from "no command" each round command = COMMAND_NO; // X axis: far left or far right? if (xValue < LEFT_THRESHOLD) command = command | COMMAND_LEFT; else if (xValue > RIGHT_THRESHOLD) command = command | COMMAND_RIGHT; // Y axis: far up or far down? if (yValue < UP_THRESHOLD) command = command | COMMAND_UP; else if (yValue > DOWN_THRESHOLD) command = command | COMMAND_DOWN; // NOTE: ZERO, ONE OR TWO COMMAND BITS CAN BE SET AT THE SAME TIME // print each active command and run its task if (command & COMMAND_LEFT) { Serial.println("COMMAND LEFT"); // TODO: your left action } if (command & COMMAND_RIGHT) { Serial.println("COMMAND RIGHT"); // TODO: your right action } if (command & COMMAND_UP) { Serial.println("COMMAND UP"); // TODO: your up action } if (command & COMMAND_DOWN) { Serial.println("COMMAND DOWN"); // TODO: your down action } }

Upload and Test

  1. Paste the sketch into Arduino IDE.
  2. Upload it to the ESP32 Uno.
  3. Push the stick to each side and to a corner.
  4. Read the Serial Monitor.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32 Dev Module' on 'COM15')
New Line
9600 baud
COMMAND RIGHT COMMAND RIGHT COMMAND DOWN COMMAND LEFT COMMAND UP COMMAND LEFT COMMAND UP
Ln 11, Col 1
ESP32 Dev Module on COM15
2
  1. Pro tip: the loop has no delay, so one push prints many lines. Add delay(100); at the end of loop() while you test.

※ NOTE THAT:

One reading can give zero, one or two commands. A corner push, for example, prints both COMMAND LEFT and COMMAND UP.

Sketch 4 — Aim Two Servos with the Stick

Map each axis to an angle and you can aim a pan-tilt bracket with two servos. That build has its own page: ESP32 Uno - Joystick controls Servo Motor.

Video Tutorial

See the ESP32 Uno build in action in the video below.

Code Explanation

This part maps each key line to its job.

Code Part What It Does
#define VRX_PIN 4 / #define VRY_PIN 2 Names GPIO4 (A1) and GPIO2 (A0), the two axis inputs
analogSetAttenuation(ADC_11db) Opens the ADC range to about 0 to 3.3V
analogRead(VRX_PIN) Returns the X position as 0 to 4095
button.loop() and button.isPressed() Debounces SW on GPIO26 and flags a fresh click
COMMAND_LEFT and the other flags One bit per direction, so two can be active at once
command & COMMAND_UP Tests if the UP bit is set before printing

The result is a clean set of direction flags that you can hook to motors, a cursor or a game.

ESP32 Uno vs UNO R4 for This Project

This shows what changes when you move this joystick project from the UNO R4 to the ESP32 Uno.

Item Arduino UNO R4 ESP32 Uno
Logic voltage 5V 3.3V
Joystick VCC 5V 3.3V
VRX / VRY pins in code A1 / A0 4 / 2 (A1 = GPIO4, A0 = GPIO2)
SW pin in code 2 26 (D2 = GPIO26)
ADC range 0 to 1023 0 to 4095
Command thresholds 400 and 800 1600 and 3200
Extra setup line none analogSetAttenuation(ADC_11db)

The header positions are the same, so the same wiring works as long as you move the joystick VCC wire to 3.3V. Watch the A0 boot pin during uploads.

Go Wireless: Joystick Position on Your Phone

By the end of this part, you have an idea for a wireless joystick build.

The ESP32 Uno has WiFi and Bluetooth (Classic and BLE) on board. Stream the X and Y numbers to a phone and watch them move on a live plot, or send direction commands to a robot across the room. If you use WiFi, move VRX and VRY to A2 and A3 (GPIO35 and GPIO34) first, because A0 and A1 are ADC2 pins and stop reading while WiFi runs. You can also skip the hardware stick and use an on-screen joystick in the phone app.

Try These Next

  • Add a dead zone around the center so tiny hand shakes give no command.
  • Use the stick click to switch between "slow" and "fast" mode.
  • Drive two servos with the axes, as in the servo page linked above.

Troubleshooting

Problem Possible Cause Solution
No COM port in Arduino IDE CH340 driver missing or a charge-only USB cable Install the CH340 driver and use a USB data cable
Upload stops at "Failed to connect" or "Waiting for download" VRY holds A0 (GPIO2) above 0V, and GPIO2 is a boot strapping pin Unplug the VRY wire while uploading, or hold the BOOT button as the upload starts
Board does not boot or upload with the joystick connected Boot strapping pin A0 (GPIO2) pulled the wrong way Unplug the joystick during upload, or use another analog pin and change VRY_PIN
X and Y both read 0 all the time No power on the module or a loose GND Check that VCC goes to 3.3V and GND goes to GND
Readings reach 4095 at half travel ADC range is too small Keep analogSetAttenuation(ADC_11db) in setup()
Analog values freeze after adding WiFi code A0 and A1 are ADC2 pins, blocked while WiFi runs Move VRX and VRY to A2 to A5 and update the pin numbers
Button level never changes SW wired to a different header than the code expects Wire SW to D2 and keep SW_PIN at 26
ezButton.h no such file Library not installed Install ezButton from Library Manager
Commands fire with the stick at rest Center value drifts outside the 1600 to 3200 band Widen the band, for example 1400 and 3400

FAQ

How does a 2-axis thumb joystick sense position?

It holds two potentiometers, one per axis. The stick turns both wipers, so each one outputs a voltage between 0V and VCC. The ESP32 Uno converts each voltage to a number from 0 to 4095.

Is 3.3V enough to run the joystick module?

Yes. The module is only two potentiometers and a switch, so it works at any voltage. At 3.3V, the full stick travel still gives the full 0 to 4095 scale, and the ESP32 Uno inputs stay safe.

Do I need a resistor on the SW pin?

No. The ezButton library turns on the internal pull-up of D2 (GPIO26). The pin reads 1 when the stick is free and 0 when you click it.

Why are my joystick numbers four times bigger than in older Uno sketches?

The ESP32 Uno ADC is 12-bit (0 to 4095), while the UNO R4 uses 10-bit (0 to 1023) by default. Multiply old thresholds by 4. That is why this page uses 1600 and 3200 instead of 400 and 800.

What is the analogSetAttenuation(ADC_11db) line in the joystick code for?

This line widens what the ESP32 Uno analog pins can measure to roughly 0 to 3.3V, so stick edge to stick edge spans the whole 0 to 4095 scale. Leave it out and the numbers top out long before the edge. Sketches for the UNO R4 never have this line, because only the ESP32 Uno family needs it. Never let VRX or VRY go above 3.3V.

Can I read the joystick while the ESP32 Uno is on WiFi?

Not on A0 and A1. They are ADC2 pins (GPIO2 and GPIO4), and ADC2 cannot be read while WiFi is on. Move VRX and VRY to A2 to A5 (GPIO35, 34, 36, 39) or to GPIO32/33, and change the pin numbers in the code.

Can the SW pin go on A2 to A5?

Only with an extra part. A2 to A5 (GPIO35, 34, 36, 39) are input only and have no internal pull-up. Add a 10kΩ resistor from SW to 3.3V, or keep SW on a normal digital header like D2.

How do I connect two joysticks to one ESP32 Uno?

Give the second stick two more analog pins (for example A2 and A3) and one more digital pin for its click. Copy the reading lines with new pin names, and make a second ezButton object.

What if my joystick project needs more pins than the Uno headers give?

The ESP32 Uno has a few extra holes near the power header. GPIO32 and GPIO33 offer I/O, PWM and analog on ADC1, so they also read while WiFi is on. GPIO15 offers I/O, PWM and analog on ADC2. Add a short pin header to the holes you need, then use the plain GPIO number in your sketch. For a second joystick or a WiFi build, put the axes on GPIO32 and GPIO33. Two warnings: (1) GPIO15 and GPIO0 (the IO0 pin at the unused Uno NC position) are boot strapping pins, and a wrong connection can stop the board from booting or uploading code, so use GPIO32/33 first; (2) never use the six holes under the digital header (SD0 to SD3, CMD, CLK = GPIO6 to GPIO11), because they connect to the flash chip and using them crashes the board.

Do UNO joystick shields fit the ESP32 Uno?

Most of them fit, because the header layout is the same. Check that the shield powers its sticks from 3.3V, or that its analog outputs never go above 3.3V. Then map each shield pin to its GPIO with the pinout diagram.

Can I control a servo or a robot car with this joystick?

Yes. Use map() to turn 0 to 4095 into 0 to 180 degrees for a servo, or use the direction commands to drive motors. The ESP32 Uno servo page uses the ESP32Servo library.

※ OUR MESSAGES

  • As freelancers, We are AVAILABLE for HIRE. See how to outsource your project to us
  • Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!