Arduino UNO Q - Joystick

A joystick lets you detect 2-axis movement and a button press — just like a game controller thumb stick. In this tutorial, you will learn how to connect a joystick to Arduino UNO Q, read its X/Y axis values and button state, convert them into direction commands, and check joystick readings remotely via Telegram.

※ NOTE THAT:

Arduino UNO Q ADC difference: The STM32 MCU on Arduino UNO Q has a 12-bit ADC (values 0–4095, center ~2048), compared to 10-bit (0–1023) on many other Arduino boards. The reference voltage is 3.3V. Always use these values when mapping joystick positions.

Arduino UNO Q - Joystick

Hardware Preparation

1×Arduino UNO Q
1×USB Cable for Arduino Uno Q
1×Joystick
1×Jumper Wires
1×Recommended: Screw Terminal Block Shield for Arduino Uno
1×Recommended: Sensors/Servo Expansion Shield for Arduino Uno
1×Recommended: Breadboard Shield for Arduino Uno
1×Recommended: Enclosure for Arduino Uno
1×Recommended: Prototyping Base Plate & Breadboard Kit for Arduino UNO

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 .

Overview of 2-Axis Joystick

You may have encountered a joystick in game controllers, toy controllers, or industrial machines. A joystick combines two potentiometers and a pushbutton to produce three outputs:

  • VRX: Analog value (0–4095 on Arduino UNO Q) corresponding to horizontal position (X-axis)
  • VRY: Analog value (0–4095 on Arduino UNO Q) corresponding to vertical position (Y-axis)
  • SW: Digital signal from the built-in pushbutton (LOW when pressed with pull-up)

Pinout

A joystick module has 5 pins:

  • GND pin: Connect to GND (0V)
  • VCC pin: Connect to 3.3V (Arduino UNO Q MCU operates at 3.3V)
  • VRX pin: Horizontal axis — analog output connected to an analog input pin
  • VRY pin: Vertical axis — analog output connected to an analog input pin
  • SW pin: Pushbutton output — connect to a digital input pin (use internal pull-up)
Joystick Pinout

How It Works

  • Moving the thumb left/right varies the VRX voltage from 0V to 3.3V → ADC reads 0 to 4095
  • Moving the thumb up/down varies the VRY voltage from 0V to 3.3V → ADC reads 0 to 4095
  • At center/resting position, both VRX and VRY read approximately 2048 (mid-range)
  • Pressing the thumb down closes the internal button — with pull-up enabled, SW reads LOW

※ NOTE THAT:

Run the first code example below before wiring anything to confirm which direction gives low/high values on your specific joystick, as axis orientation can vary by manufacturer.

Wiring Diagram

The wiring diagram between Arduino UNO Q Joystick

This image is created using Fritzing. Click to enlarge image

Joystick PinArduino UNO Q Pin
GNDGND
VCC3.3V
VRXA0
VRYA1
SWD2

How To Program For Joystick

  • For the analog axes (VRX, VRY), read the ADC value with analogRead():
int value_X = analogRead(A0); // 0 to 4095 on Arduino UNO Q int value_Y = analogRead(A1);
  • For the button (SW), use the ezButton library for built-in debounce and pull-up support:
#include <ezButton.h> ezButton button(2); button.loop(); int state = button.getState(); // LOW = pressed, HIGH = released
  • To convert analog values to direction commands, compare against thresholds. On Arduino UNO Q with a 12-bit ADC, use ~1600 / ~2400 as the low/high thresholds (center is ~2048):
if (value_X < 1600) // LEFT else if (value_X > 2400) // RIGHT

MCU Code

The Arduino UNO Q has two processors: the STM32 MCU (handles real-time hardware control) and the Qualcomm MPU (runs Debian Linux). In this section, only the STM32 MCU is programmed — the Linux side stays idle. A later section will show how both processors work together.

Example 1: Read X and Y Analog Values

/* * This Arduino UNO Q code was developed by newbiely.com * * This Arduino UNO Q code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-uno-q/arduino-uno-q-joystick */ #define VRX_PIN A0 // Arduino UNO Q pin connected to VRX #define VRY_PIN A1 // Arduino UNO Q pin connected to VRY int value_X = 0; // stores X-axis ADC value (0 to 4095) int value_Y = 0; // stores Y-axis ADC value (0 to 4095) void setup() { // nothing to set up — analog pins are inputs by default } void loop() { // read 12-bit ADC values from joystick axes (0 to 4095 on Arduino UNO Q) value_X = analogRead(VRX_PIN); value_Y = analogRead(VRY_PIN); // TO DO: use value_X and value_Y in your logic here // Example: map X to a percentage // int x_percent = map(value_X, 0, 4095, 0, 100); delay(200); }

Detailed Instructions

  • First time with Arduino UNO Q? Follow the Getting Started with Arduino UNO Q tutorial to get your development environment ready before proceeding.
  • Wire the joystick: Connect GND to GND, VCC to 3.3V, VRX to A0, VRY to A1 according to the wiring diagram.
  • Connect: Plug the Arduino UNO Q into your computer with a USB-C cable.
  • Open Arduino App Lab: Launch Arduino App Lab and wait until it detects your Arduino UNO Q.
  • Create a new App: Click the Create New App button.
Create New App in Arduino App Lab on Arduino UNO Q
  • Give the App a name, for example: DIYables_Joystick
  • Click Create to confirm.
  • You will see a set of folders and files generated inside your new App.
Arduino App Lab App folders and files on Arduino UNO Q
  • Find the sketch/sketch.ino file — this is where you will paste the MCU sketch.
  • Paste the sketch: Copy the MCU code above and paste it into the sketch file. Keep other files as default.
    • Install the library: Click the Add sketch library button (the open book icon with a + sign) in the left sidebar.
    Add sketch library in Arduino App Lab on Arduino UNO Q
    • Search for Arduino_RouterBridge created by Arduino and click the Install button.
    My Apps / DIYables Apps
    Run
    Bricks
    No bricks added...
    Sketch Libraries
    No sketch libra...
    Files
    python
    sketch
    .gitignore
    README.md
    app.yaml
    sketch.ino
    Add sketch library
    Arduino_RouterBridge Arduino

    This library provides a simple RPC bridge for Arduino UNO Q boards, allowing communication between the board and other devices using MsgPack serialization.

    0.4.1
    Install
    More Info
    • Search for ezButton created by ArduinoGetStarted.com and click the Install button.
    My Apps / DIYables Apps
    Run
    Bricks
    No bricks added...
    Sketch Libraries
    No sketch libra...
    Files
    python
    sketch
    .gitignore
    README.md
    app.yaml
    sketch.ino
    Add sketch library
    ezButton 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.

    1.0.6
    Install
    More Info
    • Upload: Click the Run button in Arduino App Lab to compile and upload to the STM32.
    Click Run button in Arduino App Lab on Arduino UNO Q
    • Move the joystick — observe behavior by extending the code with TO DO logic, or proceed to the Bridge section to see live readings.
    • Pro Tip: Move the joystick fully left, right, up, and down to find the actual min/max values — they may not reach exactly 0 or 4095 depending on your joystick.

    Example 2: Read X, Y Values and Button State

    /* * This Arduino UNO Q code was developed by newbiely.com * * This Arduino UNO Q code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-uno-q/arduino-uno-q-joystick */ #include <ezButton.h> #define VRX_PIN A0 // Arduino UNO Q pin connected to VRX #define VRY_PIN A1 // Arduino UNO Q pin connected to VRY #define SW_PIN 2 // Arduino UNO Q pin connected to SW ezButton button(SW_PIN); // create ezButton with internal pull-up int value_X = 0; // stores X-axis ADC value (0 to 4095) int value_Y = 0; // stores Y-axis ADC value (0 to 4095) void setup() { button.setDebounceTime(50); // set debounce time to 50 milliseconds } void loop() { button.loop(); // MUST call the loop() function first // read 12-bit ADC values from joystick axes value_X = analogRead(VRX_PIN); value_Y = analogRead(VRY_PIN); if (button.isPressed()) { // TO DO: handle button press here } if (button.isReleased()) { // TO DO: handle button release here } // TO DO: use value_X and value_Y in your logic here delay(200); }

    Detailed Instructions

    • Use the same App from Example 1.
    • Replace the sketch with the code above.
    • Also connect SW to pin D2 (if not already).
    • Upload and move the joystick and press the button.
    • Pro Tip: The TO DO sections are where you add your own logic — for example, toggle an LED on button press.

    Example 3: Convert to Direction Commands

    /* * This Arduino UNO Q code was developed by newbiely.com * * This Arduino UNO Q code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-uno-q/arduino-uno-q-joystick */ #define VRX_PIN A0 // Arduino UNO Q pin connected to VRX #define VRY_PIN A1 // Arduino UNO Q pin connected to VRY // 12-bit ADC on Arduino UNO Q: center ~2048, range 0-4095 #define LEFT_THRESHOLD 1600 #define RIGHT_THRESHOLD 2400 #define UP_THRESHOLD 1600 #define DOWN_THRESHOLD 2400 #define COMMAND_NO 0x00 #define COMMAND_LEFT 0x01 #define COMMAND_RIGHT 0x02 #define COMMAND_UP 0x04 #define COMMAND_DOWN 0x08 int value_X = 0; int value_Y = 0; int command = COMMAND_NO; void setup() { // nothing to set up } void loop() { // read 12-bit ADC values from joystick axes value_X = analogRead(VRX_PIN); value_Y = analogRead(VRY_PIN); // convert analog values to direction commands command = COMMAND_NO; if (value_X < LEFT_THRESHOLD) command = command | COMMAND_LEFT; else if (value_X > RIGHT_THRESHOLD) command = command | COMMAND_RIGHT; if (value_Y < UP_THRESHOLD) command = command | COMMAND_UP; else if (value_Y > DOWN_THRESHOLD) command = command | COMMAND_DOWN; // NOTE: AT A TIME, THERE MAY BE NO COMMAND, ONE COMMAND, OR TWO COMMANDS if (command & COMMAND_LEFT) { // TO DO: add your left task here } if (command & COMMAND_RIGHT) { // TO DO: add your right task here } if (command & COMMAND_UP) { // TO DO: add your up task here } if (command & COMMAND_DOWN) { // TO DO: add your down task here } }

    Detailed Instructions

    • Use the same App, replace the sketch with the code above.
    • Upload and move the joystick in all four directions.
    • Add your own logic to each TO DO block (e.g., digitalWrite(LED_PIN, HIGH) when left command is active).
    • Pro Tip: At any moment there can be no command, one command, or two simultaneous commands (e.g., UP and LEFT at the same time) — your code must handle all cases.

    Linux + MCU Bridge Programming

    The Arduino UNO Q has two processors that work together: the MPU (Qualcomm, runs Debian Linux) and the MCU (STM32, runs Zephyr OS with your Arduino sketch). They communicate using RPC via the Arduino_RouterBridge library — never via raw serial ports.

    • The joystick is connected to the MCU (STM32) — VRX is wired to A0, VRY to A1, SW to D2. The MCU reads the analog values and button state.
    • The MPU cannot read the joystick directly — it must request the reading from the MCU via Bridge.call(). The MCU responds with the current X, Y values and button state.
    • The MPU has Wi-Fi — because the MPU runs full Debian Linux with Wi-Fi, it can report joystick readings via Telegram on demand.
    • Communication: Bridge.call() on the Linux side invokes Bridge.provide() functions on the MCU side
    • ⚠️ Reserved: /dev/ttyHS1 (Linux) and Serial1 (MCU) are used by the Arduino Router — never open them directly

    In short: MPU requests joystick reading → MCU reads X, Y, button → MCU reports values → MPU logs or forwards it.

    MCU sketch — joystick with Bridge and Monitor output:

    /* * This Arduino UNO Q code was developed by newbiely.com * * This Arduino UNO Q code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-uno-q/arduino-uno-q-joystick */ #include "Arduino_RouterBridge.h" #include <ezButton.h> #define VRX_PIN A0 #define VRY_PIN A1 #define SW_PIN 2 ezButton button(SW_PIN); void get_joystick() { button.loop(); int x = analogRead(VRX_PIN); int y = analogRead(VRY_PIN); const char* btn_state = (button.getState() == LOW) ? "PRESSED" : "RELEASED"; Monitor.print("x = "); Monitor.print(x); Monitor.print(", y = "); Monitor.print(y); Monitor.print(", button = "); Monitor.println(btn_state); } void setup() { Bridge.begin(); Monitor.begin(); button.setDebounceTime(50); Bridge.provide("get_joystick", get_joystick); Monitor.println("Joystick Bridge ready"); } void loop() {}

    Python script (Arduino App Lab) — poll joystick from Linux:

    /* * This Arduino UNO Q code was developed by newbiely.com * * This Arduino UNO Q code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-uno-q/arduino-uno-q-joystick */ from arduino.app_utils import * import time def loop(): while True: Bridge.call("get_joystick") time.sleep(0.5) App.run(user_loop=loop)
    • Note: Make sure Bridge.begin() is called in the MCU sketch and the sketch is uploaded before running the Python script on the Linux side.
    • ⚠️ Warning: Never directly open /dev/ttyHS1 (on Linux) or use Serial1 (on MCU) in your code — these are reserved by the Arduino Router and accessing them will break the Bridge.

    Detailed Instructions

    • Upload the MCU sketch: Open Arduino App Lab, create a new App, paste the Bridge MCU sketch above into sketch/sketch.ino, install ezButton and Arduino_RouterBridge libraries, and click Run.
    • Add the Python script: Paste the Python code above into the Python tab of the same App.
    • Run the App: Click Run — the Python side polls the joystick every 500 ms.
    • Move the joystick and press the button — watch the X, Y, and button state update in the console.
    • Check the console: Open the Console tab → MCU Monitor subtab.

    App Lab Console Output

    DIYables_Apps
    Stop
    sketch.ino
    1#include "Arduino_RouterBridge.h"
    Serial Monitor
    Python
    Message (Enter to send a message to "Newbiely" on usb(2820070321))
    New Line
    9600 baud
    Joystick Bridge ready x = 2048, y = 2048, button = RELEASED x = 512, y = 2048, button = RELEASED x = 512, y = 200, button = RELEASED x = 2048, y = 2048, button = PRESSED

    Telegram Integration

    Read the current joystick position and button state remotely from anywhere via Telegram.

    If you do not have a Telegram bot yet, see How to Create a Telegram Bot to get your bot token before continuing.

    MCU sketch: Keep the same MCU sketch from the previous Bridge section — no changes needed. Make sure it is already uploaded and running on the STM32 before proceeding.

    Python script (Arduino App Lab) — Telegram bot for joystick reading:

    /* * This Arduino UNO Q code was developed by newbiely.com * * This Arduino UNO Q code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-uno-q/arduino-uno-q-joystick */ from arduino.app_utils import * import requests import time BOT_TOKEN = "YOUR_BOT_TOKEN" API_URL = f"https://api.telegram.org/bot{BOT_TOKEN}" last_update_id = 0 def send_message(chat_id, text): requests.post(f"{API_URL}/sendMessage", json={"chat_id": chat_id, "text": text}) def get_updates(): global last_update_id resp = requests.get(f"{API_URL}/getUpdates", params={"offset": last_update_id + 1, "timeout": 5}) return resp.json().get("result", []) def loop(): global last_update_id updates = get_updates() for update in updates: last_update_id = update["update_id"] msg = update.get("message", {}) chat_id = msg.get("chat", {}).get("id") text = msg.get("text", "").strip() if text == "/read": result = Bridge.call("get_joystick") send_message(chat_id, result) else: send_message(chat_id, "Commands:\n/read — read joystick X, Y position and button state") time.sleep(1) App.run(user_loop=loop)
    • Note: Replace YOUR_BOT_TOKEN with the token obtained from @BotFather on Telegram.
    • Send /read to get the current X, Y position and button state.

    Detailed Instructions

    • Upload the MCU sketch: Use the Bridge MCU sketch from the previous section (upload it first if not already done).
    • Paste the Telegram script: Copy the Python code above into the Python tab of your App in Arduino App Lab.
    • Set your token: Replace YOUR_BOT_TOKEN in the script with your actual bot token.
    • Run the App: Click Run — the bot starts listening for Telegram messages.
    • Test it: Move the joystick, send /read — the bot replies with the X, Y values and button state.

    App Lab Console Output

    DIYables_Apps
    Stop
    sketch.ino
    1#include "Arduino_RouterBridge.h"
    Serial Monitor
    Python
    [2026-04-29 12:00:01] Telegram: /read [2026-04-29 12:00:01] x = 2048, y = 2048, button = RELEASED [2026-04-29 12:02:10] Telegram: /read [2026-04-29 12:02:10] x = 512, y = 200, button = RELEASED [2026-04-29 12:04:05] Telegram: /read [2026-04-29 12:04:05] x = 2048, y = 2048, button = PRESSED
    Telegram
    Telegram 12:45
    Welcome to Telegram!
    ArduinoBot 10:19
    Chatting with Arduino...
    telegram-botfather
    BotFather Yesterday
    Your bot has been created.

    ArduinoBot

    bot
    Today
    /read
    10:15 AM ✓✓
    x = 2048, y = 2048, button = RELEASED
    10:16 AM
    /read
    10:17 AM ✓✓
    x = 512, y = 200, button = RELEASED
    10:18 AM

    OpenClaw Integration

    OpenClaw integration for Arduino UNO Q joystick reading is coming soon.

    • Coming Soon: OpenClaw support for reading a joystick on Arduino UNO Q will be covered in a future update.

    Application/Project Ideas

    • Remote robot control: Use joystick X/Y values sent via Telegram to steer a robot's direction and speed
    • Pan-tilt camera: Map X to pan servo angle and Y to tilt servo angle for camera positioning
    • Game controller: Build a simple 2-player game where joystick position is read over the network
    • Crane control: Use joystick direction commands to lift, lower, and swing a model crane arm
    • Cursor control: Map joystick values to cursor movement on an OLED or TFT display

    Challenge Yourself

    • Easy: Add a /button Telegram command that reports only whether the joystick button is currently pressed or released
    • Medium: Map the X and Y values to direction labels (LEFT, RIGHT, UP, DOWN, CENTER) and send the label instead of raw numbers via Telegram
    • Advanced: Build a 2-axis servo pan-tilt system where the joystick position sets the servo angles in real time via the Bridge

    Learn More

    ※ 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!