ESP32 Joystick Simulator: Wiring, Code and a Live Circuit
This is a two-axis joystick module wired to an ESP32 DevKit, read live: the serial monitor prints both axes, the direction the stick points and the word pressed while the button is down.
- 3.3 V logic
- No library: analogRead()
- X on GPIO 34 (D34), Y on GPIO 35 (D35)
- Button on GPIO 4 (D4)
Wiring the Joystick to the ESP32
Five wires: 3V3, GND, VRX to GPIO 34 (D34), VRY to GPIO 35 (D35) and SW to GPIO 4 (D4). In the editor, drag the stick on the drawing and press it.
Every connection in the circuit above, with the board’s own pin names.
| Joystick pin | ESP32 pin | Why |
|---|---|---|
| VCC | 3V3 | The stick’s two tracks span 0 to 3.3 V. |
| GND | GND | The other end of both tracks. |
| VRX | GPIO 34 (D34) | The X wiper, an analog input. |
| VRY | GPIO 35 (D35) | The Y wiper, an analog input. |
| SW | GPIO 4 (D4) | Shorts to GND when the stick is pressed; the sketch turns on the internal pull-up. |
Power
Power the module from 3V3, never from VIN (5 V from USB): pushed to the end of its travel, a wiper would put 5 V on an analog pin rated for 3.3 V. Both axis pins here are input-only pins with an ADC. The ESP32’s ADC is twelve bits, 0 to 4095, and at the default attenuation it saturates at about 3.1 V, so a pot across the 3.3 V rail reaches 4095 a little before the end of its travel and reads about 1890 in the middle.
Pins to leave alone on the ESP32
GPIO 34, 35, 36 (VP) and 39 (VN) are input only: they cannot drive a pin or take an internal pull-up. GPIO 0, 2, 5, 12 and 15 are strapping pins, read at power-on, and GPIO 6 to 11 are the flash chip.
On a real bench
The thirty-pin DevKit straddles a breadboard with one row of holes free on each side, which is where the Joystick’s jumpers go. Many ESP32 boards are wider and cover both rows; then use two breadboards side by side. Hold BOOT while uploading if the IDE cannot connect.
The code, and what it does.
The sketch the circuit above runs. Open it in the editor, change a line and press Run: it compiles in your browser.
const int X_PIN = 34; // VRX, GPIO 34 (D34)
const int Y_PIN = 35; // VRY, GPIO 35 (D35)
const int SW_PIN = 4; // the button, GPIO 4 (D4)
void setup() {
Serial.begin(115200);
pinMode(SW_PIN, INPUT_PULLUP); // LOW while the stick is pressed
}
void loop() {
int xr = analogRead(X_PIN); // 0 to 4095
int yr = analogRead(Y_PIN);
bool pressed = digitalRead(SW_PIN) == LOW;
const char* dir = "Center";
if (xr < 4095 / 4) dir = "Left";
else if (xr > 4095 / 4 * 3) dir = "Right";
else if (yr < 4095 / 4) dir = "Up";
else if (yr > 4095 / 4 * 3) dir = "Down";
Serial.print("X: ");
Serial.print(xr);
Serial.print(" Y: ");
Serial.print(yr);
Serial.print(" ");
Serial.print(dir);
Serial.println(pressed ? " pressed" : "");
delay(250);
}
Each axis is a potentiometer with its ends on VCC and GND, so analogRead() gives about half of 4095 with the stick centered and nears 0 or 4095 at the ends of travel. Real sticks rest a few counts off center, so the sketch uses wide bands (a quarter and three quarters of the range) rather than an exact middle.
The button is a plain switch to ground, so INPUT_PULLUP makes it read HIGH at rest and LOW while the stick is pressed down.
Serial.begin(115200) opens the serial monitor. Serial is UART0 on the USB bridge. ESP32 sketches usually run it at 115200 baud, which this one does.
Common mistakes with the Joystick on the ESP32
No pull-up on the button
Without INPUT_PULLUP the SW pin floats and reports presses nobody made. Most modules have no resistor of their own.
Expecting an exact center
The rest position is a few counts either side of the middle and differs per axis. Use a dead zone, or read the rest position at startup and measure from it.
An axis that runs backwards
Modules are mounted in different directions. Swap the two pins in the code, or flip a reading with 4095 - reading.
Questions and answers
Can I simulate a joystick with an ESP32 DevKit?
Yes. The circuit at the top of this page is an ESP32 DevKit with a joystick module, running in your browser on a simulated ESP32 (Xtensa LX6). Drag the stick on the drawing and both axes change; press it and the button line goes low. Press Run it in the editor to change the wiring or the code; it is free and needs no account.
What values does the joystick give on the ESP32?
The ESP32’s ADC is twelve bits, 0 to 4095, and at the default attenuation it saturates at about 3.1 V, so a pot across the 3.3 V rail reaches 4095 a little before the end of its travel and reads about 1890 in the middle. The button reads LOW when pressed.
Is it a real analog stick?
Yes, in the sense that matters: two variable voltages and a switch. Under the cap is a pair of 10 k potentiometers, so any code that reads two analog pins reads it.
How do I move a servo with the stick?
Read an axis and call servo.write(map(reading, 0, 4095, 0, 180)). The Servo page on this site has the wiring.
Build your own Joystick project
Open this circuit in the editor, change the wiring or the code, and keep your version in a free account.