Build Project

Robotics

ESP32 Educational Servo Arm Controller (3-DOF)

Build a small joystick-controlled 3-DOF servo arm on ESP32 with safe angle limits, incremental motion, and separate servo power.

IntermediateAges 13+90-120 minUnder 40 USDParent Safe
Project Mission

Build a 3-DOF Educational Servo Arm

The Story

The existing repository evidence describes three SG90-class servos, so this Golden page keeps the scope to 3 DOF and avoids industrial robot claims.

Explain Like I'm 12

Each joystick tells the ESP32 which way to move one joint. The ESP32 moves each servo a tiny step and keeps it inside safe angles.

Learning Support

  • Recommended ageAges 13+
  • Adult supervisionAdult supervision recommended for servo power wiring and first motion tests.
  • Classroom useUse it to discuss control loops and real robot safety standards without claiming certification.
  • Parent promptAsk why angle limits and separate servo power protect both electronics and fingers.
  • Screen-free activityMap each joint's safe angle range on paper before editing code limits.
  • Next challengeAdd a save-position button for a three-step playback sequence.
  • Skills practiced
    • Servo PWM
    • Joystick ADC
    • Angle constraints
    • Separate power domains
  • Learning outcomes
    • Control three SG90-class servos.
    • Use ADC1 joystick pins.
    • Constrain every servo write path.
    • Explain pinch hazards and external servo supply.
  • Mini experiments
    • Change incremental step size.
    • Test different dead-zone widths.
    • Record and replay a fixed sequence in a future extension.

Safety Standards

  • Unplug USB before changing jumper wires. Recheck 3.3 V, 5 V, and GND before reconnecting power.
  • Do not power motors, pumps, LED strips, or servos from the ESP32 3.3 V pin. Use a suitable external supply and common ground.
  • Breadboards are for low-current prototypes. Move high-current or unattended builds to proper terminals, enclosure, strain relief, and fusing.
  • Motors and servos can reset the ESP32 when they draw surge current. Use a separate motor supply, driver module, and flyback protection where needed.

What You Will Build

A small 3-DOF joystick-controlled servo arm with base, shoulder, and elbow joints.

Learning Objectives

  • Control three SG90-class servos.
  • Use ADC1 joystick pins.
  • Constrain every servo write path.
  • Explain pinch hazards and external servo supply.

Components List

  • ESP32 DevKit boardMain 3.3 V logic controller.
  • Three SG90-class micro servosBase, shoulder, and elbow.
  • Separate regulated 5-6 V servo supplyDo not power servos from ESP32 regulator.
  • 470 uF or larger electrolytic capacitorAcross servo supply near servos.
  • Two analog joystick modulesUse three axes for base/shoulder/elbow.
  • SSD1306 OLED displayOptional I2C display on GPIO21/GPIO22.

Bill of Materials

PartQtyEstimated CostNotes
ESP32 DevKit board1VariesMain 3.3 V logic controller.
Three SG90-class micro servos1VariesBase, shoulder, and elbow.
Separate regulated 5-6 V servo supply1VariesDo not power servos from ESP32 regulator.
470 uF or larger electrolytic capacitor1VariesAcross servo supply near servos.
Two analog joystick modules1VariesUse three axes for base/shoulder/elbow.
SSD1306 OLED display1VariesOptional I2C display on GPIO21/GPIO22.

Wiring

Servo signals use GPIO13, GPIO16, and GPIO17 to avoid boot-sensitive pins. Joystick axes use ADC1 GPIO34/GPIO35/GPIO36. Servo power is separate with common ground.

Wiring Diagram ESP32 Educational Servo Arm Controller (3-DOF) wiring diagram
  1. 1

    Unplug USB and servo supply before wiring.

  2. 2

    Connect servo signal wires to GPIO13, GPIO16, and GPIO17.

  3. 3

    Connect servo red/brown power leads to the separate 5-6 V supply, not the ESP32 regulator.

  4. 4

    Connect servo supply ground to ESP32 GND.

  5. 5

    Place a 470 uF or larger capacitor across the servo supply rail.

  6. 6

    Connect joystick axes to GPIO34, GPIO35, and GPIO36 with joystick VCC at 3.3 V.

GPIO Mapping

SignalESP32 PinDirectionNotes
Base servo signalGPIO13PWM outputSafe output pin for servo signal.
Shoulder servo signalGPIO16PWM outputAvoids boot strap pins.
Elbow servo signalGPIO17PWM outputAvoids boot strap pins.
Joystick base axisGPIO34ADC1 inputInput-only ADC pin.
Joystick shoulder axisGPIO35ADC1 inputInput-only ADC pin.
Joystick elbow axisGPIO36ADC1 inputInput-only ADC pin.
Servo powerExternal 5-6 V / GNDPowerCommon ground with ESP32.

Circuit Explanation

The ESP32 sends servo control pulses while joystick axes are read on ADC1. Servos draw power from a separate supply.

Engineering Explanation

Every angle update passes through explicit constrain functions. Movement is incremental to reduce sudden jumps.

Libraries

  • ESP32ServoInstall ESP32Servo; standard Servo library is not the right ESP32 choice.

Code

Copy into Arduino IDE. Install any libraries noted in the component guides first.

esp32-robot-arm-controller.ino
// ESP32 educational 3-DOF servo arm controller
// Uses separate 5-6 V servo supply, common ground, and constrained incremental motion.
#include <ESP32Servo.h>

const int SERVO_BASE_PIN = 13;
const int SERVO_SHOULDER_PIN = 16;
const int SERVO_ELBOW_PIN = 17;
const int JOY_BASE_PIN = 34;
const int JOY_SHOULDER_PIN = 35;
const int JOY_ELBOW_PIN = 36;

Servo baseServo;
Servo shoulderServo;
Servo elbowServo;

int baseAngle = 90;
int shoulderAngle = 90;
int elbowAngle = 90;
int baseCenter = 2048;
int shoulderCenter = 2048;
int elbowCenter = 2048;

const int BASE_MIN = 20;
const int BASE_MAX = 160;
const int SHOULDER_MIN = 35;
const int SHOULDER_MAX = 145;
const int ELBOW_MIN = 25;
const int ELBOW_MAX = 155;
const int DEAD_ZONE = 220;

int constrainBase(int a) { return constrain(a, BASE_MIN, BASE_MAX); }
int constrainShoulder(int a) { return constrain(a, SHOULDER_MIN, SHOULDER_MAX); }
int constrainElbow(int a) { return constrain(a, ELBOW_MIN, ELBOW_MAX); }

void writeServos() {
  baseAngle = constrainBase(baseAngle);
  shoulderAngle = constrainShoulder(shoulderAngle);
  elbowAngle = constrainElbow(elbowAngle);
  baseServo.write(baseAngle);
  shoulderServo.write(shoulderAngle);
  elbowServo.write(elbowAngle);
}

int axisStep(int raw, int center) {
  if (raw < 20 || raw > 4075) return 0; // hold last safe position if disconnected or stuck
  int delta = raw - center;
  if (abs(delta) < DEAD_ZONE) return 0;
  return delta > 0 ? 1 : -1;
}

int readAverage(int pin) {
  long sum = 0;
  for (int i = 0; i < 16; i++) sum += analogRead(pin);
  return sum / 16;
}

void setup() {
  Serial.begin(115200);
  analogReadResolution(12);
  baseServo.attach(SERVO_BASE_PIN, 500, 2500);
  shoulderServo.attach(SERVO_SHOULDER_PIN, 500, 2500);
  elbowServo.attach(SERVO_ELBOW_PIN, 500, 2500);

  baseCenter = readAverage(JOY_BASE_PIN);
  shoulderCenter = readAverage(JOY_SHOULDER_PIN);
  elbowCenter = readAverage(JOY_ELBOW_PIN);

  for (int a = 60; a <= 90; a++) {
    baseAngle = constrainBase(a);
    shoulderAngle = constrainShoulder(a);
    elbowAngle = constrainElbow(a);
    writeServos();
    delay(20);
  }
  Serial.println("Servo arm ready. Keep fingers clear of pinch points.");
}

void loop() {
  baseAngle = constrainBase(baseAngle + axisStep(analogRead(JOY_BASE_PIN), baseCenter));
  shoulderAngle = constrainShoulder(shoulderAngle + axisStep(analogRead(JOY_SHOULDER_PIN), shoulderCenter));
  elbowAngle = constrainElbow(elbowAngle + axisStep(analogRead(JOY_ELBOW_PIN), elbowCenter));
  writeServos();
  Serial.printf("Base %d Shoulder %d Elbow %d\n", baseAngle, shoulderAngle, elbowAngle);
  delay(20);
}

Code Explanation

The code calibrates joystick centers, checks implausible ADC extremes, constrains each joint, and writes incremental servo angles.

Expected Output

Moving each joystick axis changes one joint smoothly inside its limits. Reset returns the arm gradually toward home.

Troubleshooting

  • Servo jitter Check separate supply, common ground, and bulk capacitor.
  • Arm moves unexpectedly Increase dead zone and recalibrate joystick center.
  • One joint binds Tighten that joint's min/max constraints before testing again.

Common Mistakes

  • Powering servos from ESP32 5 V/3.3 V pins.
  • Using boot-sensitive pins for servo outputs.
  • Writing unconstrained angles.
  • Calling this an industrial robot or certified emergency stop system.

Testing Checklist

  • Test each servo alone.
  • Verify no joint binds at min/max limits.
  • Keep fingers clear during first powered motion.

Engineering Tips

  • Start with horns disconnected.
  • Label each servo cable.
  • Use conservative angle ranges first.

Upgrade Ideas

  • Add save-position button.
  • Add gripper only after power budget is checked.
  • Add OLED angle display.

Real-World Applications

  • Servo control lesson
  • Joystick mapping demo
  • Mechanical constraint exercise

FAQs

How many DOF?

This implementation uses three servos: base, shoulder, and elbow.

Why separate servo power?

Servo surge current can reset or damage the ESP32 supply path.

Is this an emergency stop?

No. It has cautious startup and limits, not certified safety hardware.

Review, Testing, and References

Author: Abdul Mubeen and the ESP32 Engine editorial team. Last updated: 2026-06-27. Reviewed: wiring logic, Arduino code structure, beginner safety, and learning sequence.

Educational level: Intermediate. Estimated completion time: 90-120 min. This project is for learning and prototyping; production or unattended hardware needs additional engineering review.

Project Complete!

You completed ESP32 Educational Servo Arm Controller (3-DOF) with matching wiring, code, tests, and limitations.

  • Servo PWM
  • Joystick ADC
  • Angle constraints