PS2 Joystick with Arduino Uno: Centre Calibration, Circuit, Wiring and Code
Review draft — incomplete: the store does not identify the joystick manufacturer, potentiometer values or current rating. Confirm the supplied revision and pin labels before approval. A downloadable code attachment is pending hosting. The complete copyable sketch is included; compilation and hardware testing remain pending.
Turn a PS2 joystick module into a two-axis input monitor with an Arduino Uno R3. This project displays raw X/Y readings, measures the resting centre and filters small centre variations with a dead band. Pressing the stick lights the Uno built-in LED after button-bounce filtering.
What you will build
You will connect five wires and observe the controls in Serial Monitor. It is a starting point for a menu input or robot controller; this sketch only monitors the inputs and does not move a motor. Allow about 30 minutes. No extra library, cloud service or account is needed.
Contents
- How the joystick works
- Parts and purchase links
- Circuit and wiring
- Assembly and setup
- Complete code and explanation
- Upload and test
- Troubleshooting and FAQs
How the joystick works
Two potentiometers act as adjustable voltage dividers. Their wipers provide the VRx and VRy signals; the push switch provides SW. The Joy-IT KY-023 reference documents this five-pin interface. It is a comparison reference, not evidence that the Anu Electronics item is made by Joy-IT.
The Uno reads each axis with its ADC. The raw result is a count from 0 to 1023, not an angle or a calibrated distance. At rest the reading is often near the middle, but the exact centre varies. This sketch measures each resting centre and subtracts it from subsequent readings. Differences within ±40 counts become zero. Outside that band, the original signed difference is reported.
SW connects to ground when pressed on the reference circuit. The Uno internal pull-up holds it HIGH when released. The code waits for a stable level for 30 ms before updating the LED. The reference PDF contains a contradictory switch-polarity sentence and a variable-name error in its example; the original sketch below uses separate fixed pin names and state variables.
Parts and purchase links
| Component | Required | Specification / pack |
|---|---|---|
| PS2 joystick module | 1 | SKU SEN000056; store lists 3.3–5 V operation, two analog axes and one push switch. Use 5 V here. Resistance and current ratings are not specified. |
| Arduino Uno R3 | 1 | 5 V ATmega328P board with analog inputs A0/A1, built-in LED and USB-B socket. |
| Male-to-female jumper wires | 5 leads | 20 cm; sold in a pack of 40. Female ends at joystick header, male ends at Uno sockets. |
| USB A-to-B data cable | 1 | USB-B at Uno; USB-A at computer. A computer adapter may be needed. |
Also have a computer ready. This build uses the module header and Uno sockets, so a breadboard is optional. No external pull-up or indicator resistor is required. Do not infer a current rating from a similar-looking module. For two purely resistive axes, supply current would be 5/Rx + 5/Ry amperes, with resistance in ohms, plus any other board loads; the actual values must be confirmed.
Connection table
| Joystick label | Uno connection | Function |
|---|---|---|
| +5V / VCC | 5V | Module supply |
| GND | GND | Common ground |
| VRx | A0 | X-axis analog input |
| VRy | A1 | Y-axis analog input |
| SW | D2 | Button input with internal pull-up |
Functional circuit schematic

Visual module wiring

Follow printed pin labels, not drawing positions. The wiring illustration is symbolic, and the schematic shows the expected potentiometer/switch arrangement rather than a verified PCB layout. Inspect the actual module before connecting it. If labels differ or are unclear, obtain its matching pinout.
Disconnect USB before wiring. Use 5V, not VIN, and connect common ground. The analog signals can approach the module supply: this 5 V wiring is for Uno R3 and must not be copied directly to a 3.3 V-only input. Do not connect a motor or other load to VRx, VRy or SW.
Assembly and setup
- Place the module on an insulating surface and check its header labels. With USB unplugged, make the five connections in the table.
- Install Arduino IDE from the official Arduino website. In Boards Manager install Arduino AVR Boards if needed, then select Arduino Uno and its port.
- Create a sketch named
uno_joystick. Copy the complete program below. No additional library is required. - Connect the USB data cable. Leave the stick centred and released whenever the board starts or resets. The sketch waits two seconds, then averages 64 samples per axis.
Complete Arduino sketch
Copy this entire program. Downloadable hosting is pending.
// Anu Electronics: original PS2 joystick + Arduino Uno R3 monitor.
// +5V->5V, GND->GND, VRx->A0, VRy->A1, SW->D2.
const byte X_PIN = A0, Y_PIN = A1, SW_PIN = 2;
const int DEAD_BAND = 40;
const unsigned long DEBOUNCE_MS = 30, REPORT_MS = 100;
int centreX, centreY;
bool calibrationOK = false;
int lastRaw = HIGH, stableSwitch = HIGH;
unsigned long changedAt = 0, reportedAt = 0;
int centred(int raw, int centre) {
int delta = raw - centre;
return (delta >= -DEAD_BAND && delta <= DEAD_BAND) ? 0 : delta;
}
void setup() {
pinMode(SW_PIN, INPUT_PULLUP);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
Serial.begin(9600);
Serial.println(F("Leave joystick centred and released. Calibrating..."));
delay(2000);
long sumX = 0, sumY = 0;
for (byte i = 0; i < 64; ++i) {
sumX += analogRead(X_PIN);
sumY += analogRead(Y_PIN);
delay(10);
}
centreX = sumX / 64;
centreY = sumY / 64;
calibrationOK = centreX >= 128 && centreX <= 895 &&
centreY >= 128 && centreY <= 895;
Serial.print(F("Centres: X=")); Serial.print(centreX);
Serial.print(F(" Y=")); Serial.println(centreY);
if (!calibrationOK) {
Serial.println(F("Centre out of range. Check wiring, release stick, reset."));
}
lastRaw = digitalRead(SW_PIN);
changedAt = millis();
}
void loop() {
if (!calibrationOK) return;
unsigned long now = millis();
int rawSwitch = digitalRead(SW_PIN);
if (rawSwitch != lastRaw) {
lastRaw = rawSwitch;
changedAt = now;
}
if ((unsigned long)(now - changedAt) >= DEBOUNCE_MS) {
stableSwitch = rawSwitch;
}
digitalWrite(LED_BUILTIN, stableSwitch == LOW ? HIGH : LOW);
if ((unsigned long)(now - reportedAt) >= REPORT_MS) {
reportedAt = now;
int x = analogRead(X_PIN), y = analogRead(Y_PIN);
Serial.print(F("X=")); Serial.print(x);
Serial.print(F(" Y=")); Serial.print(y);
Serial.print(F(" dX=")); Serial.print(centred(x, centreX));
Serial.print(F(" dY=")); Serial.print(centred(y, centreY));
Serial.print(F(" SW="));
Serial.println(stableSwitch == LOW ? F("PRESSED") : F("RELEASED"));
}
}
Key code sections
- The 64-sample sums use
long: 64 × 1023 = 65,472 exceeds the Uno signed 16-bit integer range. - The centre check rejects grossly off-centre values outside 128–895. It does not detect every wiring fault or prove the stick was untouched.
-
centred()returns zero inside an inclusive ±40-count band. For a centre of 512, raw 552 yields zero while 553 yields +41. This is a dead band, not a smooth scaling function. - The button must stay unchanged for 30 ms. A short glitch restarts the stability timer instead of immediately changing the LED.
- Serial output is limited to about ten lines per second. Button sampling continues between reports; there is no long loop delay.
- Unsigned timer subtraction handles the millis counter wrapping. Resetting the Uno deliberately repeats centre calibration.
Upload and test
- Click Verify, then Upload. Open Serial Monitor at 9600 baud. Release the stick and press Reset to repeat calibration if needed.
- Note the printed centres. If the program reports an out-of-range centre, unplug USB, check the wiring, release the stick and try again.
- At rest, expect dX and dY to stay near zero. If they repeatedly leave the band, inspect connections and measure the actual resting variation before adjusting DEAD_BAND.
- Move one axis slowly through its travel. Raw values should change substantially. Record which physical direction gives positive and negative differences; direction depends on mounting orientation.
- Try diagonal movement and check both axes. Release the stick and confirm it returns near the calibrated centre. Do not force it against the mechanical stops.
- Press and hold the stick. Expect SW=PRESSED and the built-in L LED on; release for SW=RELEASED and LED off. Very brief presses may fall between printed reports.
Illustrative output

The GIF uses invented example counts to explain the program. It is labelled simulated and does not demonstrate physical accuracy or testing.
Troubleshooting
| Problem | Check |
|---|---|
| One axis stays near 0 or 1023 | Inspect the matching VR lead and power/ground. Unplug power before correcting connections. |
| Centred output is biased | Reset with the stick untouched. A displaced stick during startup creates a wrong centre even when the range check passes. |
| Button always reads pressed | Check SW for a short to ground and verify the module pinout. Confirm the sketch uses INPUT_PULLUP. |
| X and Y seem swapped | Check A0/VRx and A1/VRy, then consider the physical mounting orientation. |
| Readings jump slightly | Small noise and mechanical variation are normal. Keep leads short; increase the dead band only after observing the resting range. |
| No upload or serial data | Use a data cable, select Uno and the correct port, and set Serial Monitor to 9600 baud. |
FAQs
Is this a USB game controller?
This sketch sends serial text. It does not make the Uno appear as a USB gamepad.
Does the joystick use the PlayStation 2 communication protocol?
The store name describes this thumbstick module. This build uses separate analog outputs and a switch, not a console controller protocol.
Can I assume the centre is exactly 512?
No. The program calibrates the resting value. Endpoints, mechanical travel and centre position can vary between modules.
Can I connect it to a Raspberry Pi?
A standard Raspberry Pi computer needs an external ADC to read these analog axes. This tutorial is for Uno R3; it is not a direct Pi GPIO wiring guide.
Related learning and purchase links
Explore another analog input with the LDR calibration tutorial, and learn button event counting in the push-button debounce project.
Get the PS2 joystick module and Arduino Uno R3, along with the compatible wires and USB cable in the parts table.
Sources and testing limits
- Joy-IT KY-023 interface reference
- Joy-IT module manual — reference only; not the verified manufacturer of the stocked item.
- Arduino analogRead reference
- Arduino debounce explanation
Original writing, sketch and diagrams; CircuitDigest informed the tutorial structure only. The cover uses the store photo as a visual reference. Software logic is checked with simulated inputs. Arduino compilation and physical testing have not been performed. Confirm exact module current, resistance, pinout and switch operation before approving this draft.