EasyJoystick is a lightweight Arduino library for reading analog joystick modules (such as the KY-023) and converting their input into simple directional states.
Instead of working directly with raw analog values, this library interprets the joystick position as one of five states:
- Up
- Down
- Left
- Right
- Middle (center)
This makes it easy to handle joystick input in games, menus, and navigation systems without writing your own thresholding or state detection logic.
- Works with any 2-axis analog joystick (two potentiometers)
- Converts analog input into discrete directional states
- Removes the need for manual analog thresholding and debounce logic.
- Built-in state change detection (
changed(),newUp(), etc.) - Axis flipping and rotation support
- Simple and beginner-friendly API
- Any analog joystick module (e.g., KY-023)
- Arduino board with at least 2 analog input pins
- This library does not handle the joystick’s built-in push button.
- If you need button support, use a dedicated button library (e.g., OneButton, ezButton).
#include <EasyJoystick.h>
EasyJoystick joystick;
void setup() {
joystick.begin(A1, A2, true, true);
Serial.begin(115200);
}
void loop() {
joystick.loop();
if (joystick.newUp()) {
Serial.println("Moved up!");
}
}joystick.begin(xPin, yPin, flipX, flipY);- Must be called once in setup().
- xPin and yPin must be analog pins (A0, A1, etc.).
- To rotate the joystick 90°, swap xPin and yPin.
- If left/right movement is reversed, toggle flipX (switch between true and false).
- If up/down movement is reversed, toggle flipY.
joystick.loop();Call this function repeatedly in your main program loop (or within blocking loops) to update the joystick state.
This function reads the joystick input and updates the internal state. Most other functions simply return this stored state.
joystick.getState();Returns the current state of the joystick as one of the constants: UP, DOWN, LEFT, RIGHT, or MIDDLE.
See the getState example.
joystick.changed();Returns true if the joystick state has changed since the last call to loop().
Otherwise returns false.
See the getState example.
joystick.isUp();
joystick.isDown();
joystick.isLeft();
joystick.isRight();
joystick.isMiddle();Each function returns true if the joystick is currently in the corresponding state.
See the isUp example.
joystick.isUDLR();Returns true if the joystick is in any directional state (up, down, left, or right), and false if it is in the middle.
Equivalent to:
(isUp() || isDown() || isLeft() || isRight())joystick.newUp(); // same as (joystick.isUp() && joystick.changed())
joystick.newDown(); // same as (joystick.isDown() && joystick.changed())
joystick.newLeft(); // same as (joystick.isLeft() && joystick.changed())
joystick.newRight(); // same as (joystick.isRight() && joystick.changed())
joystick.newMiddle(); // same as (joystick.isMiddle() && joystick.changed())Returns true if the joystick has just moved into that state.
See the newUp example.
joystick.newUDLR();Returns true if the joystick has just moved into a directional state (up, down, left, or right).
Equivalent to:
(joystick.isUDLR() && joystick.changed())Additional examples can be found in the examples folder:
- Basic state detection (
isUp,isDown, etc.) - Change detection (
newUp,newDown, etc.) - State polling (
getState,changed) - Wireless transmission using NRF24L01
- Wireless reception using NRF24L01
Wiring diagrams for each example are available in the docs folder.
The joystick provides two analog values (X and Y), which represent its position.
EasyJoystick processes these values as follows:
- Reads the analog inputs
- Optionally flips axes (
flipX,flipY) - Centers the values around (0, 0)
- Determines one of five states:
- Up
- Down
- Left
- Right
- Middle
At any given time, the joystick is always in exactly one state.
Instead of using time-based debouncing, this library uses positional hysteresis.
Rather than a single boundary between states, it defines two:
- An inner boundary (normal zone)
- An outer boundary (exit threshold)
This prevents rapid state switching when the joystick is near a boundary.
For example:
- Moving from middle → up requires passing a higher threshold
- Returning from up → middle requires dropping below a lower threshold
This creates a "dead zone gap" that eliminates jitter without sacrificing responsiveness.
