ESP32 S3 UNO - DIYables Bluetooth App Joystick

Overview

This ESP32 S3 Uno Bluetooth joystick tutorial shows you how to turn your phone into a wireless 2D controller for the ESP32 S3 Uno form board. The DIYables Bluetooth STEM app sends live X and Y values from -100 to +100 over BLE, so you can steer a robot, aim a pan-tilt servo mount or drive motors from your phone.

In this tutorial, you will:

  1. Install the DIYables Bluetooth library in the Arduino IDE
  2. Upload a BLE joystick sketch to the ESP32 S3 Uno
  3. Connect the DIYables Bluetooth App from Android or iOS
  4. Read X/Y joystick values in the Serial Monitor
  5. Use the values to control motors, servos and LEDs

※ NOTE THAT:

The ESP32 S3 Uno supports only BLE (Bluetooth Low Energy). It has no Classic Bluetooth radio, so the BluetoothSerial version of this example does not work on it. The good news: BLE works with the DIYables Bluetooth App on both Android and iOS, and you do not need to pair the board first.

ESP32 S3 Uno Bluetooth joystick

Features

The joystick app gives you a simple way to send two values at the same time. This makes it a natural fit for anything that moves in two directions.

Two Axes

You get an X axis and a Y axis. Each one goes from -100 to +100, and the center is (0, 0).

Live Updates

While you drag your finger, the app keeps sending new positions over Bluetooth. Your sketch gets each one right away.

Auto-Return and Sensitivity

You can make the stick jump back to the center when you let go. You can also set a minimum movement, so tiny finger shakes do not flood your code with updates.

Android and iOS, No Pairing

Because the ESP32 S3 Uno uses BLE, the same sketch works with both phone systems. You just scan and connect inside the app. BLE also uses less power than Classic Bluetooth.

Hardware Preparation

1×ESP32 S3 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×Breadboard
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 .

ESP32 S3 Uno Pinout

The main example needs no wiring, but the project examples below use the Uno header pins. This pinout diagram shows each header pin (D2, D9, A0…) and its GPIO number.

ESP32 S3 Uno pinout diagram

ESP32 S3 Uno Code

The sketch below sets up a BLE server on the ESP32 S3 Uno and adds the joystick app to it. You do not need to wire anything for this first test. The board only needs the USB cable.

Detailed Instructions

  1. New to the ESP32 S3 Uno? Follow ESP32 S3 Uno - Getting Started first.
  2. Connect the board to your computer with a USB Type-C cable.
  3. Open Arduino IDE, choose the ESP32S3 Dev Module board and the correct COM port.
  4. Set the partition scheme. Go to Tools > Partition Scheme and pick "Huge APP (3MB No OTA/1MB SPIFFS)". The Bluetooth library is large and does not fit in the default app space.
  5. Open Library Manager. Click the Libraries icon on the left bar of the Arduino IDE.
  6. Find the library. Search "DIYables Bluetooth" and look for the DIYables Bluetooth library by DIYables.
  7. Install it. Click the Install button.
  • Search for DIYables Bluetooth created by DIYables and click the Install button.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32S3 Dev Module
Library Manager
Type:
All
Topic:
All
DIYables Bluetooth by DIYables
A comprehensive Bluetooth library that connects Arduino to the DIYables Bluetooth STEM mobile app (Android & iOS) via BLE and Classic Bluetooth. Features 11 built-in apps: Monitor, Chat, Digital Pin Control, Joystick, Sliders, Plotter, Analog Gauge, Rotator, Temperature, RTC, and Data Table. Clean architecture with platform abstraction. Works with Arduino Uno R4 WiFi, Arduino Nano 33 BLE, ESP32, and other BLE-capable boards. No mobile coding required. More info
1.0.1
INSTALL
Newbiely.ino
···
1 void setup() {
Output
Serial Monitor
Ln 1, Col 1
ESP32S3 Dev Module on COM15
1
  1. Install the dependencies. When the IDE asks about other libraries, click Install All.
  2. Tip: If the upload does not start, hold the BOOT button, press RESET, then release BOOT and try again.

ESP32 S3 Uno BLE Code (works with the app on Android and iOS)

This sketch creates a BLE device named ESP32BLE_Joystick and waits for the app. Each time you move the joystick, the callback saves the X and Y values and prints them. When the app opens the joystick screen, the onGetConfig() callback sends the last saved position back, so the app shows the right place.

  1. Load the example. In the Arduino IDE, go to File Examples DIYables Bluetooth Esp32BLE_Joystick, or copy the code below into the editor.
/* * This ESP32 S3 Uno code was developed by newbiely.com * * This ESP32 S3 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-s3-uno/esp32-s3-uno-diyables-bluetooth-app-joystick */ /* * DIYables Bluetooth Library - ESP32 S3 Uno BLE Joystick Example * Works with DIYables Bluetooth STEM app on Android and iOS * * This example demonstrates the Bluetooth Joystick feature: * - Interactive joystick control via Bluetooth Low Energy (BLE) * - Real-time X/Y coordinate values (-100 to +100) * - Control pins based on joystick position * * Board: ESP32 S3 Uno form board (BLE only, no Classic Bluetooth) * * Note: Select "Huge APP (3MB No OTA/1MB SPIFFS)" partition scheme * in Arduino IDE: Tools > Partition Scheme * * Setup: * 1. Upload the sketch to your ESP32 S3 Uno * 2. Open Serial Monitor (115200 baud) to see connection status * 3. Use DIYables Bluetooth App to connect and control the joystick * * Tutorial: https://diyables.io/bluetooth-app * Author: DIYables */ #include <DIYables_BluetoothServer.h> #include <DIYables_BluetoothJoystick.h> #include <platforms/DIYables_Esp32BLE.h> // BLE Configuration const char* DEVICE_NAME = "ESP32BLE_Joystick"; const char* SERVICE_UUID = "19B10000-E8F2-537E-4F6C-D104768A1214"; const char* TX_UUID = "19B10001-E8F2-537E-4F6C-D104768A1214"; const char* RX_UUID = "19B10002-E8F2-537E-4F6C-D104768A1214"; // Create Bluetooth instances DIYables_Esp32BLE bluetooth(DEVICE_NAME, SERVICE_UUID, TX_UUID, RX_UUID); DIYables_BluetoothServer bluetoothServer(bluetooth); // Create Joystick app instance DIYables_BluetoothJoystick bluetoothJoystick(false, 5); // Variables to store current joystick values int currentJoystickX = 0; int currentJoystickY = 0; void setup() { Serial.begin(115200); delay(1000); Serial.println("DIYables Bluetooth - ESP32 S3 Uno BLE Joystick Example"); // Initialize Bluetooth server with platform-specific implementation bluetoothServer.begin(); // Add joystick app to server bluetoothServer.addApp(&bluetoothJoystick); // Set up connection event callbacks bluetoothServer.setOnConnected([]() { Serial.println("Bluetooth connected!"); }); bluetoothServer.setOnDisconnected([]() { Serial.println("Bluetooth disconnected!"); }); // Set up joystick callback for position changes bluetoothJoystick.onJoystickValue([](int x, int y) { currentJoystickX = x; currentJoystickY = y; Serial.print("Joystick - X: "); Serial.print(x); Serial.print(", Y: "); Serial.println(y); // TODO: Add your control logic here based on joystick position }); bluetoothJoystick.onGetConfig([]() { bluetoothJoystick.send(currentJoystickX, currentJoystickY); Serial.print("App requested values - Sent: X="); Serial.print(currentJoystickX); Serial.print(", Y="); Serial.println(currentJoystickY); }); Serial.println("Waiting for Bluetooth connection..."); } void loop() { bluetoothServer.loop(); delay(10); }
  1. Upload. Click the Upload button to send the code to the ESP32 S3 Uno.
  2. Open the Serial Monitor and set it to 115200 baud.
  3. Check the output. You should see:
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32S3 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32S3 Dev Module' on 'COM15')
New Line
9600 baud
DIYables Bluetooth - ESP32 S3 Uno BLE Joystick Example Waiting for Bluetooth connection...
Ln 11, Col 1
ESP32S3 Dev Module on COM15
2

Mobile App

Now the board is waiting, and your phone becomes the controller. With BLE there is no pairing step in the phone settings. You connect from inside the app.

  1. Install the app on your phone: Android | iOS
  2. Open the DIYables Bluetooth App.
  3. Allow the permissions the first time you open it:
  • Nearby Devices (Android 12+) or Bluetooth (iOS) - needed to scan and connect
  • Location (Android 11 and below only) - older Android versions need it to scan for BLE devices
  1. Turn on Bluetooth on your phone.
  2. Scan. On the home screen, tap the Connect button. The app looks for nearby BLE devices.
DIYables Bluetooth App - Home Screen with Scan Button
  1. Connect. Tap "ESP32BLE_Joystick" in the scan list.
  2. Open the Joystick app. After it connects, the app returns to the home screen. Tap Joystick in the app menu.
DIYables Bluetooth App - Home Screen with Joystick App

※ NOTE THAT:

You can tap the settings icon on the home screen to hide or show apps. For more details, read the DIYables Bluetooth App User Manual.

  1. Move the joystick in any direction.
DIYables Bluetooth App - Joystick Screen
  1. Watch the Serial Monitor. The X/Y values show up in real time:
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32S3 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32S3 Dev Module' on 'COM15')
New Line
9600 baud
Bluetooth connected! Joystick - X: 50, Y: 0 Joystick - X: 75, Y: -30 Joystick - X: 0, Y: 100 Joystick - X: -60, Y: 45 Joystick - X: 0, Y: 0
Ln 11, Col 1
ESP32S3 Dev Module on COM15
2

Creative Customization - Adapt the Code to Your Project

The basic sketch only prints numbers. The parts below show the library functions you will use to turn those numbers into real actions on the ESP32 S3 Uno.

Configure Auto-Return and Sensitivity

The constructor takes two settings. The first one turns auto-return on or off. The second one is the smallest change (in percent) that sends a new update. You can also change both while the sketch runs and read them back.

// Create Joystick app instance // Parameters: autoReturn (bool), sensitivity (float - minimum % change to trigger update) DIYables_BluetoothJoystick bluetoothJoystick(false, 5); // Or change at runtime: bluetoothJoystick.setAutoReturn(true); // Enable auto-return to center bluetoothJoystick.setSensitivity(10.0); // Only send updates when joystick moves >10% // Read current configuration: bool autoReturn = bluetoothJoystick.getAutoReturn(); float sensitivity = bluetoothJoystick.getSensitivity();

Handle Joystick Position Changes

All your control code goes into the onJoystickValue() callback. It gets X (left to right) and Y (down to up) each time the stick moves.

bluetoothJoystick.onJoystickValue([](int x, int y) { // x ranges from -100 (left) to +100 (right) // y ranges from -100 (down) to +100 (up) Serial.print("X: "); Serial.print(x); Serial.print(", Y: "); Serial.println(y); // TODO: Add your control logic here });

Handle Configuration Request from App

When the app opens the joystick screen, it asks the ESP32 S3 Uno for the current values. Answer in onGetConfig() so the app draws the stick in the right place.

bluetoothJoystick.onGetConfig([]() { // This is called when the app requests joystick configuration // Send current joystick values so the app displays them correctly bluetoothJoystick.send(currentJoystickX, currentJoystickY); Serial.println("App requested config - sent current values"); });

Send Values to App

Data can also go the other way. The ESP32 S3 Uno can push a position or a short text message to the app at any time.

// Send X/Y coordinate values to the app bluetoothJoystick.send(currentJoystickX, currentJoystickY); // Send a text message bluetoothJoystick.send("Joystick calibrated");

Handle Connection Events

It is smart to know when the phone connects or leaves. For a moving robot, the disconnect event is the right place to stop the motors.

// Called when the app connects to the ESP32 S3 Uno bluetoothServer.setOnConnected([]() { Serial.println("Bluetooth connected!"); bluetoothJoystick.send(currentJoystickX, currentJoystickY); }); // Called when the app disconnects from the ESP32 S3 Uno bluetoothServer.setOnDisconnected([]() { Serial.println("Bluetooth disconnected!"); // Stop motors when connection is lost stopAllMotors(); }); // Check connection status anywhere in your code if (bluetoothServer.isConnected()) { // Do something only when connected }

How to Use the Joystick

Knowing the value range helps you map the joystick to your hardware. Here is what the app shows and what the numbers mean.

App Interface Controls

The screen has a round joystick pad that you touch and drag. Under it, the app shows the current X value and Y value, each from -100 to +100.

Value Ranges

Axis Minimum Center Maximum
X -100 (full left) 0 +100 (full right)
Y -100 (full down) 0 +100 (full up)

When you do not touch the stick (or when auto-return is on and you let go), the position is (0, 0).

Programming Examples

These short examples show common ways to use the joystick values. All pins use the Uno header positions, with the ESP32 S3 Uno GPIO number in the code.

Basic Joystick Handler

This is the smallest useful handler. It saves the latest position and prints it.

void setup() { bluetoothJoystick.onJoystickValue([](int x, int y) { currentJoystickX = x; currentJoystickY = y; Serial.print("Joystick - X: "); Serial.print(x); Serial.print(", Y: "); Serial.println(y); }); }

Two-Wheel Robot Control

A two-wheel robot turns by running its wheels at different speeds. The code mixes X (turn) and Y (speed) into a left and a right speed. Each motor gets one PWM pin for speed and one pin for direction: left PWM on D9 (GPIO46), right PWM on D10 (GPIO10), left direction on D7 (GPIO14) and right direction on D8 (GPIO21).

const int LEFT_MOTOR_PIN = 46; // D9 (GPIO46) - left motor speed (PWM) const int RIGHT_MOTOR_PIN = 10; // D10 (GPIO10) - right motor speed (PWM) const int LEFT_DIR_PIN = 14; // D7 (GPIO14) - left motor direction const int RIGHT_DIR_PIN = 21; // D8 (GPIO21) - right motor direction void setup() { pinMode(LEFT_MOTOR_PIN, OUTPUT); pinMode(RIGHT_MOTOR_PIN, OUTPUT); pinMode(LEFT_DIR_PIN, OUTPUT); pinMode(RIGHT_DIR_PIN, OUTPUT); bluetoothJoystick.onJoystickValue([](int x, int y) { // Differential drive: mix X (turn) and Y (speed) int leftSpeed = constrain(y + x, -100, 100); int rightSpeed = constrain(y - x, -100, 100); // Set direction digitalWrite(LEFT_DIR_PIN, leftSpeed >= 0 ? HIGH : LOW); digitalWrite(RIGHT_DIR_PIN, rightSpeed >= 0 ? HIGH : LOW); // Set speed (PWM) analogWrite(LEFT_MOTOR_PIN, map(abs(leftSpeed), 0, 100, 0, 255)); analogWrite(RIGHT_MOTOR_PIN, map(abs(rightSpeed), 0, 100, 0, 255)); Serial.print("Left: "); Serial.print(leftSpeed); Serial.print("%, Right: "); Serial.print(rightSpeed); Serial.println("%"); }); }

WARNING

D9 (GPIO46) is a boot strapping pin on the ESP32 S3 Uno. If the motor driver pulls this pin HIGH while the board starts, the board may not boot or may not accept new code. If you have upload or boot problems, unplug the wire from D9, then upload or reset again.

Pan-Tilt Servo Control

The X value turns the pan servo and the Y value moves the tilt servo. The map() function changes -100..+100 into 0..180 degrees. On the ESP32 S3 Uno, use the ESP32Servo library (by Kevin Harrington) instead of Servo.h. The pan servo signal goes to D9 (GPIO46) and the tilt servo signal goes to D10 (GPIO10).

#include <ESP32Servo.h> Servo panServo; // Horizontal (X axis) Servo tiltServo; // Vertical (Y axis) const int PAN_PIN = 46; // D9 (GPIO46) const int TILT_PIN = 10; // D10 (GPIO10) void setup() { panServo.attach(PAN_PIN); tiltServo.attach(TILT_PIN); panServo.write(90); // Center position tiltServo.write(90); bluetoothJoystick.onJoystickValue([](int x, int y) { // Map joystick values (-100 to +100) to servo angles (0 to 180) int panAngle = map(x, -100, 100, 0, 180); int tiltAngle = map(y, -100, 100, 0, 180); panServo.write(panAngle); tiltServo.write(tiltAngle); Serial.print("Pan: "); Serial.print(panAngle); Serial.print("°, Tilt: "); Serial.print(tiltAngle); Serial.println("°"); }); }

WARNING

The pan servo uses D9 (GPIO46), a boot strapping pin. Power the servos from their own 5V supply (with a shared GND), and keep the signal wire off D9 while you upload if the board will not boot. The ESP32 S3 Uno sends a 3.3V signal, which most hobby servos accept.

LED Matrix Direction Indicator

Four LEDs show which way the stick points. An LED turns on only when the value goes past a threshold of 30, so small moves near the center do nothing. The LEDs connect to D2 (GPIO18), D3 (GPIO17), D4 (GPIO19) and D5 (GPIO20), each through a 220 ohm resistor.

// 4 directional LEDs const int LED_UP = 18; // D2 (GPIO18) const int LED_DOWN = 17; // D3 (GPIO17) const int LED_LEFT = 19; // D4 (GPIO19) const int LED_RIGHT = 20; // D5 (GPIO20) const int THRESHOLD = 30; // Minimum joystick value to activate LED void setup() { pinMode(LED_UP, OUTPUT); pinMode(LED_DOWN, OUTPUT); pinMode(LED_LEFT, OUTPUT); pinMode(LED_RIGHT, OUTPUT); bluetoothJoystick.onJoystickValue([](int x, int y) { // Light up LEDs based on joystick direction digitalWrite(LED_UP, y > THRESHOLD ? HIGH : LOW); digitalWrite(LED_DOWN, y < -THRESHOLD ? HIGH : LOW); digitalWrite(LED_RIGHT, x > THRESHOLD ? HIGH : LOW); digitalWrite(LED_LEFT, x < -THRESHOLD ? HIGH : LOW); // Show direction in Serial String direction = ""; if (y > THRESHOLD) direction += "UP "; if (y < -THRESHOLD) direction += "DOWN "; if (x > THRESHOLD) direction += "RIGHT "; if (x < -THRESHOLD) direction += "LEFT "; if (direction == "") direction = "CENTER"; Serial.println("Direction: " + direction); }); }

Advanced Programming Techniques

Raw joystick values are fine for a test. For a real machine, you usually want smoother and safer control. These three tricks help.

Dead Zone Filter

A finger never rests exactly at the center. The dead zone treats any value close to zero as zero, so motors do not creep.

const int DEAD_ZONE = 15; // Ignore joystick values within ±15 bluetoothJoystick.onJoystickValue([](int x, int y) { // Apply dead zone filter int filteredX = (abs(x) > DEAD_ZONE) ? x : 0; int filteredY = (abs(y) > DEAD_ZONE) ? y : 0; // Use filtered values for control controlMotors(filteredX, filteredY); });

Speed Ramping

A sudden jump from 0 to full speed can make a robot jerk or tip over. Here the callback only stores a target, and loop() moves the real value toward it a little at a time.

int targetX = 0, targetY = 0; int currentX = 0, currentY = 0; const int RAMP_RATE = 5; // Max change per update void setup() { bluetoothJoystick.onJoystickValue([](int x, int y) { targetX = x; targetY = y; }); } void loop() { bluetoothServer.loop(); // Gradually ramp to target values if (currentX < targetX) currentX = min(currentX + RAMP_RATE, targetX); else if (currentX > targetX) currentX = max(currentX - RAMP_RATE, targetX); if (currentY < targetY) currentY = min(currentY + RAMP_RATE, targetY); else if (currentY > targetY) currentY = max(currentY - RAMP_RATE, targetY); controlMotors(currentX, currentY); delay(20); }

Magnitude and Angle Calculation

Sometimes you want "how far" and "which way" instead of X and Y. The distance from the center gives a speed, and atan2() gives the angle in degrees.

bluetoothJoystick.onJoystickValue([](int x, int y) { // Calculate magnitude (distance from center, 0-100) float magnitude = sqrt(x * x + y * y); magnitude = constrain(magnitude, 0, 100); // Calculate angle in degrees (0° = right, 90° = up) float angle = atan2(y, x) * 180.0 / PI; Serial.print("Magnitude: "); Serial.print(magnitude, 1); Serial.print(", Angle: "); Serial.print(angle, 1); Serial.println("°"); // Use magnitude for speed and angle for direction int speed = map((int)magnitude, 0, 100, 0, 255); // Apply to your hardware... });

Hardware Integration Examples

These two examples show bigger builds. They are starting points; add your own motor driver code where needed.

Mecanum Wheel Robot

A mecanum robot has four wheels and can slide sideways. Each wheel gets its own mix of X and Y. Here the four motor PWM signals use D2 (GPIO18), D3 (GPIO17), D4 (GPIO19) and D5 (GPIO20).

// Mecanum wheel robot requires 4 motors const int MOTOR_FL = 18; // Front-Left - D2 (GPIO18) const int MOTOR_FR = 17; // Front-Right - D3 (GPIO17) const int MOTOR_BL = 19; // Back-Left - D4 (GPIO19) const int MOTOR_BR = 20; // Back-Right - D5 (GPIO20) void setupMecanumRobot() { bluetoothJoystick.onJoystickValue([](int x, int y) { // Mecanum wheel kinematics int fl = constrain(y + x, -100, 100); int fr = constrain(y - x, -100, 100); int bl = constrain(y - x, -100, 100); int br = constrain(y + x, -100, 100); setMotor(MOTOR_FL, fl); setMotor(MOTOR_FR, fr); setMotor(MOTOR_BL, bl); setMotor(MOTOR_BR, br); }); } void setMotor(int pin, int speed) { // Map -100..100 to PWM with direction analogWrite(pin, map(abs(speed), 0, 100, 0, 255)); }

Stepper Motor Position Control

With the AccelStepper library, the joystick sets the speed of two stepper motors, one per axis. The X driver uses STEP on D2 (GPIO18) and DIR on D3 (GPIO17). The Y driver uses STEP on D4 (GPIO19) and DIR on D5 (GPIO20).

#include <AccelStepper.h> AccelStepper stepperX(AccelStepper::DRIVER, 18, 17); // STEP D2 (GPIO18), DIR D3 (GPIO17) AccelStepper stepperY(AccelStepper::DRIVER, 19, 20); // STEP D4 (GPIO19), DIR D5 (GPIO20) void setup() { stepperX.setMaxSpeed(1000); stepperX.setAcceleration(500); stepperY.setMaxSpeed(1000); stepperY.setAcceleration(500); bluetoothJoystick.onJoystickValue([](int x, int y) { // Map joystick to stepper speed (-1000 to +1000 steps/sec) int speedX = map(x, -100, 100, -1000, 1000); int speedY = map(y, -100, 100, -1000, 1000); stepperX.setSpeed(speedX); stepperY.setSpeed(speedY); }); } void loop() { bluetoothServer.loop(); stepperX.runSpeed(); stepperY.runSpeed(); }

Why BLE Only on the ESP32 S3 Uno?

Some boards offer two Bluetooth modes: BLE and Classic Bluetooth. The ESP32 S3 Uno chip has only BLE, so this page uses only the Esp32BLE_Joystick example. The table shows what this means for your project.

Feature BLE on the ESP32 S3 Uno
iOS support Yes
Android support Yes
Power use Low
Range about 30-100 m in open space
Pairing Not needed, connect inside the app
Best for Battery projects and cross-platform control

The Classic Bluetooth sketch (Esp32Bluetooth_Joystick, which uses BluetoothSerial) will not compile or run on this board. Always pick the BLE example.

Project Ideas

A joystick fits any project that moves in two directions. Here are some ideas to try with the ESP32 S3 Uno.

Robotics Projects

Build a Bluetooth differential drive robot, a mecanum or omni-wheel robot, a robotic arm joint controller or a simple drone ground station.

Camera Projects

Control a pan-tilt camera mount, a motorized camera slider or a remote security camera.

Game Projects

Make a Bluetooth game controller, a maze game or an LED matrix game like Snake or Pong.

Industrial Projects

Try a CNC jog controller, a motorized stage or a small crane or winch.

Integration with Other Bluetooth Apps

The joystick works well together with other apps from the same library. You add more than one app to the same Bluetooth server.

Combine with Bluetooth Slider

The joystick sets the direction, and a slider sets the top speed.

int maxSpeed = 100; bluetoothSlider.onSliderValue([](int slider1, int slider2) { maxSpeed = slider1; // Slider controls max speed }); bluetoothJoystick.onJoystickValue([](int x, int y) { // Scale joystick by slider-controlled speed limit int scaledX = map(x, -100, 100, -maxSpeed, maxSpeed); int scaledY = map(y, -100, 100, -maxSpeed, maxSpeed); controlRobot(scaledX, scaledY); });

Combine with Bluetooth Monitor

The joystick drives the motors, and the monitor shows live data on your phone.

bluetoothJoystick.onJoystickValue([](int x, int y) { controlMotors(x, y); // Send telemetry to monitor bluetoothMonitor.send("X=" + String(x) + " Y=" + String(y) + " Speed=" + String(sqrt(x*x + y*y), 0)); });

Next Steps

When the joystick works well, try these other DIYables Bluetooth App examples on the ESP32 S3 Uno:

  1. Bluetooth Slider - for exact analog value control
  2. Bluetooth Digital Pins - for simple on/off control
  3. Bluetooth Monitor - for watching joystick values on your phone
  4. Multiple Bluetooth Apps - for mixing the joystick with sliders and other controls

Support

If you get stuck, these places can help:

  1. Read the library API reference
  2. Ask in the Arduino community forums

FAQ

Does the ESP32 S3 Uno support Classic Bluetooth for this joystick example?

No. The ESP32 S3 Uno has only BLE (Bluetooth Low Energy). Sketches that use BluetoothSerial, like Esp32Bluetooth_Joystick, will not work. Use the Esp32BLE_Joystick example, which works with the app on both Android and iOS.

Can I use the DIYables Bluetooth joystick on an iPhone with the ESP32 S3 Uno?

Yes. iOS supports BLE, and the ESP32 S3 Uno uses BLE. Install the DIYables Bluetooth App from the App Store, tap Connect and pick ESP32BLE_Joystick. No pairing in the phone settings is needed.

Why do I need the "Huge APP" partition scheme?

The BLE stack and the DIYables Bluetooth library make the sketch large. The default partition gives only about 1.2 MB for your program, so the upload can fail with a "sketch too big" error. "Huge APP (3MB No OTA/1MB SPIFFS)" gives about 3 MB, but you lose over-the-air updates.

Is the UNO R4 code the same as the ESP32 S3 Uno code?

The joystick logic is the same, but the setup is different. The UNO R4 WiFi uses the DIYables_ArduinoBLE.h platform and 9600 baud. The ESP32 S3 Uno uses DIYables_Esp32BLE.h and 115200 baud. For servos, the ESP32 S3 Uno needs the ESP32Servo library instead of Servo.h.

Can I connect 5V motor drivers and servos to the ESP32 S3 Uno pins?

The ESP32 S3 Uno pins work at 3.3V and are not 5V tolerant. Sending 3.3V signals out to a 5V motor driver or servo usually works. But never send a 5V signal back into an ESP32 S3 Uno pin. Use a level shifter or a voltage divider for that.

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

The ESP32 S3 Uno has two extra rows of holes with more GPIOs: GPIO15 and GPIO16 (I/O, PWM, analog), GPIO45 and GPIO35 to GPIO42 (I/O, PWM), and GPIO47/GPIO48 (output only, PWM). Solder pin headers to them and write the GPIO number in your code. For extra motor PWM or direction pins, GPIO35 to GPIO42 are a good choice. Be careful with two groups of pins. First, GPIO47 and GPIO48 may run at 1.8V instead of 3.3V on some modules (mostly ones with "V" in the name, like R8V or R16V), so 3.3V devices can be damaged or act strangely. Second, GPIO0, GPIO3 (D6), GPIO45 and GPIO46 (D9) are boot strapping pins, and a wrong connection can stop the board from booting or uploading code. Use the other extra pins first.

Troubleshooting

Problem Possible Cause Solution
No COM port shows up in Arduino IDE USB driver missing or charge-only cable Install the CP210x or CH340 driver, use a data USB cable, or hold BOOT while you press RESET
"Sketch too big" error when compiling Default partition scheme is too small for the Bluetooth library Set Tools > Partition Scheme to "Huge APP (3MB No OTA/1MB SPIFFS)"
Compile error about BluetoothSerial Classic Bluetooth example was used Use the Esp32BLE_Joystick example because the ESP32 S3 Uno has BLE only
App cannot find ESP32BLE_Joystick Sketch not running, phone Bluetooth off or missing permission Check the Serial Monitor for "Waiting for Bluetooth connection...", turn on Bluetooth, allow Nearby Devices, and on Android 11 or older turn on Location
Joystick moves but nothing happens Callback not set or Serial Monitor at wrong baud Check that onJoystickValue() is set in setup() and set the Serial Monitor to 115200 baud
Values jump or look erratic Sensitivity too low or no dead zone Call setSensitivity(10.0) and add a dead zone filter in the callback
Connection drops often Too far away, BLE interference or weak power Move the phone closer, turn off other BLE devices nearby and use a good USB cable or power supply
Motors keep running after release Auto-return off or no stop on disconnect Call setAutoReturn(true), add a dead zone and stop the motors in setOnDisconnected()
Board does not boot or upload with motors or servos wired Wire on D9 (GPIO46) holds the boot strapping pin at the wrong level Unplug the D9 wire while you upload or reset, then plug it back in
Board resets when motors start Motors take power from the board Power motors and servos from a separate supply and connect all GND wires together

Debug Tips

Add this helper to your sketch and call it from the joystick callback. It prints the raw values, the distance from the center and the angle, so you can see what the app really sends.

void debugJoystickValues(int x, int y) { float magnitude = sqrt(x * x + y * y); float angle = atan2(y, x) * 180.0 / PI; Serial.println("=== Joystick Debug ==="); Serial.println("X: " + String(x) + ", Y: " + String(y)); Serial.println("Magnitude: " + String(magnitude, 1)); Serial.println("Angle: " + String(angle, 1) + "°"); Serial.println("======================"); }

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