Skip to content
Buy 10+ on select items — save 10% auto-applied
Free US shipping on orders $35+
Order by 3pm ET — ships same-day from the US
Skip to main content

Arduino Uno Analog Joystick: Control a Pan-Tilt Servo Mount | ShillehTek

September 05, 2026 10 views

Arduino Uno Analog Joystick: Control a Pan-Tilt Servo Mount | ShillehTek
Project

Build an Arduino Uno pan-tilt servo mount controlled by an analog joystick with proportional speed, dead zone, and click-to-recenter using ShillehTek parts.

45 min Beginner7 parts

Project Overview

Joystick-Controlled Pan-Tilt Servo Mount with Arduino: Use an Arduino Uno with an analog joystick module (KY-023 style) to drive a two-axis pan-tilt servo mount with smooth proportional speed and a click-to-recenter button.

The original project drove the two servos from a four-way switch joystick. This version uses the common analog thumbstick module, which gives you variable speed and diagonal movement from the same two servo outputs. It is the control scheme behind camera gimbals, turret toys, and remote inspection rigs.

  • Time: ~45 minutes
  • Skill level: Beginner
  • What you will build: A two-axis servo mount steered by a joystick, with a dead zone, proportional speed, travel limits, and a recenter button.
Arduino Uno controlling a pan-tilt servo bracket using an analog joystick module
Two axes on the stick, two servos on the mount.

Parts List

From ShillehTek

External

  • An analog joystick module (KY-023 style: VRx, VRy, SW)

Note: A joystick is two potentiometers at right angles plus a button. At rest each axis reads about 512, but never exactly, and it wobbles. The dead zone in the code ignores small deviations so the mount does not creep when your hand is off the stick.

Step-by-Step Guide

Step 1 - Center and Assemble the Servos

Goal: Full travel in both directions.

What to do: Plug each servo into the servo tester and set it to the center position, then attach the horns and build the bracket so the platform is level and facing forward at 90°. Skipping this is how people end up with a mount that can only look left.

Expected result: A pan-tilt mount that is square at its midpoint.

Step 2 - Wire Joystick and Servos

Goal: Two analog inputs, one button, two PWM outputs.

What to do: Joystick: VCC to 5V, GND to GND, VRx to A0, VRy to A1, SW to D2. Servos: pan signal to D9, tilt signal to D10. Power the servos from the MB102 5 V rail (or the Arduino 5V pin for a single SG90 pair), with all grounds tied together.

Arduino Uno wiring diagram showing analog joystick to A0/A1 and two servos on D9/D10 with a shared ground and external 5V supply
Servos on D9/D10 with their own 5 V supply; the joystick's two pots feed A0/A1.

Expected result: Everything shares a ground and the servos have real current available.

Step 3 - Upload the Sketch

Goal: Read the joystick, apply a dead zone, and move pan and tilt with proportional speed.

What to do: Paste the sketch below into the Arduino IDE and upload it to your Arduino Uno.

Code:

#include <Servo.h>

Servo pan, tilt;
const int JOY_X = A0, JOY_Y = A1, JOY_SW = 2;
const int CENTER = 512, DEAD = 60;      // ignore stick wobble near the middle
const int MAX_STEP = 3;                 // degrees per update at full deflection
int panPos = 90, tiltPos = 90;

int stepFor(int raw) {                  // returns -MAX_STEP..+MAX_STEP, 0 in the dead zone
  int d = raw - CENTER;
  if (abs(d) < DEAD) return 0;
  return map(d, -512, 511, -MAX_STEP, MAX_STEP);
}

void setup() {
  pan.attach(9); tilt.attach(10);
  pinMode(JOY_SW, INPUT_PULLUP);
  pan.write(panPos); tilt.write(tiltPos);
}

void loop() {
  panPos  += stepFor(analogRead(JOY_X));           // push further = move faster
  tiltPos += stepFor(analogRead(JOY_Y));
  panPos  = constrain(panPos, 0, 180);
  tiltPos = constrain(tiltPos, 20, 160);           // keep the bracket off its mechanical stops

  if (digitalRead(JOY_SW) == LOW) { panPos = 90; tiltPos = 90; }   // click = recenter

  pan.write(panPos);
  tilt.write(tiltPos);
  delay(15);                                       // ~66 updates per second
}

Expected result: Upload and nudge the stick. A light push creeps; a full push sweeps. Click the stick to snap back to center. Control should feel smooth and not drift at rest.

If an axis moves the wrong way, swap the sign in that line (or swap A0/A1 if pan and tilt are crossed).

Step 4 - Tune the Feel

Goal: Make it pleasant to drive.

What to do: Raise DEAD if it creeps, lower it if the center feels mushy. Lower MAX_STEP for fine camera framing or raise it for a snappy turret. For an "absolute" mode where stick position equals mount position (like the original switch-based build's direct control), replace the increment with panPos = map(analogRead(JOY_X), 0, 1023, 0, 180).

Expected result: Control tuned for your mount and your thumb.

Step 5 - Put Something on It

Goal: Turn the mount into a useful rig.

What to do: Mount a phone or small camera and you have a manual gimbal for time-lapses. Add a laser pointer for a cat toy. Swap the joystick for two pots at the end of a long cable, or for an HC-05 Bluetooth module reading the same two axes from a phone app, and it becomes a remote inspection head.

Expected result: A pan-tilt platform that does a job you care about.

Conclusion

Read two axes, apply a dead zone, scale to a step size, clamp to limits, and you have a simple recipe for smooth manual control of servo motion. With an Arduino Uno, an analog joystick module, and two servos, you now have a proportional pan-tilt mount with travel limits and a click-to-recenter control.

Want the exact parts used in this build? Grab them from ShillehTek.com. If you want help customizing this project or building something for your product, check out our IoT consulting services.

Credits: All photos and images in this tutorial are credited to ejshea on Hackster.io. The original guide by ejshea served as the reference for this ShillehTek version.