Building a Micro Servo Robotic Arm with a Servo Motor Driver

DIY Robotic Arm with Micro Servo Motors / Visits:8

There’s something deeply satisfying about watching a tiny robotic arm pick up a paperclip, rotate it 90 degrees, and drop it exactly where you intended. When I first started experimenting with micro servo motors, I was hooked by the combination of precision, affordability, and the sheer number of possibilities they unlock. A micro servo motor isn’t just a component—it’s the muscle behind countless DIY robotics projects, from animatronic eyes to miniature pick-and-place machines.

In this guide, I’ll walk you through building a fully functional micro servo robotic arm using a dedicated servo motor driver. We’ll cover everything from selecting the right hardware to writing the control code, with a strong emphasis on the unique characteristics of micro servo motors that make them both powerful and challenging to work with.

Why Micro Servo Motors Are the Perfect Choice for a Robotic Arm

Before we dive into the build, let’s talk about what makes micro servo motors stand out. Unlike standard servos, micro servos are smaller, lighter, and often operate at lower voltages—typically 4.8V to 6V. This makes them ideal for desktop-scale robotic arms where weight and power consumption matter.

Key Characteristics of Micro Servo Motors

  • Compact Form Factor: Most micro servos measure around 23mm x 12mm x 29mm, allowing you to build a multi-joint arm that fits in the palm of your hand.
  • High Torque-to-Weight Ratio: Despite their size, many micro servos deliver 0.5 to 1.5 kg·cm of torque. That’s enough to lift lightweight payloads like a pen cap or a small gear.
  • Positional Feedback: The built-in potentiometer provides continuous feedback, so your arm knows exactly where each joint is at all times.
  • PWM Control: You can control them with any microcontroller that outputs a 50Hz PWM signal. No complex communication protocols needed.

The trade-off? Micro servos are more sensitive to electrical noise and mechanical binding. A poorly tuned PID loop or a jammed joint can cause them to jitter or overheat. But with the right driver and code, these issues are easily managed.

Selecting Your Components

A successful robotic arm starts with the right parts. Here’s what I used for my build, along with reasoning for each choice.

The Micro Servo Motors

I chose MG90S micro servos for all five joints. These are metal-gear servos, which means they’re more durable than plastic-gear alternatives like the SG90. For a robotic arm, metal gears are a must—plastic gears strip easily under load, especially when the arm is moving a payload near its maximum torque.

| Joint | Servo Model | Torque | Notes | |-------|-------------|--------|-------| | Base rotation | MG90S | 1.8 kg·cm | Needs to handle the moment arm of the entire structure | | Shoulder | MG90S | 1.8 kg·cm | Highest load, consider a stronger servo if payload exceeds 50g | | Elbow | MG90S | 1.8 kg·cm | Similar load to shoulder | | Wrist pitch | SG90 (plastic) | 1.2 kg·cm | Lower load, plastic gears are acceptable here | | Gripper | SG90 (plastic) | 1.2 kg·cm | Only needs a few grams of force to close |

The Servo Motor Driver

A standard microcontroller can’t directly power five servos without risking voltage drops or timing issues. That’s where a dedicated servo motor driver comes in. I used the PCA9685 16-channel PWM driver for several reasons:

  • It generates stable 50Hz PWM signals without relying on the microcontroller’s internal timers.
  • It has a built-in 25MHz oscillator, so the pulse width is precise down to about 4 microseconds.
  • It communicates over I2C, meaning you only need two wires (SDA and SCL) to control up to 16 servos.
  • It can output up to 5V on each channel, which matches the operating voltage of most micro servos.

If you’re on a budget, a simpler driver like the Adafruit 16-channel servo shield also works, but the PCA9685 gives you more flexibility with address selection and output enable.

The Microcontroller

Any board with I2C support will do. I used an Arduino Nano because it’s small, cheap, and has enough GPIO for additional sensors or buttons. If you want wireless control, an ESP32 is a great alternative—just make sure you level-shift the I2C lines if the ESP32 operates at 3.3V.

Additional Hardware

  • Power Supply: A 5V, 2A USB power supply is sufficient for five micro servos under light load. For heavier tasks, use a 5V 5A adapter or a 2S LiPo battery with a 5V BEC.
  • Structural Components: I 3D-printed the arm segments from PLA. You can also use laser-cut acrylic, but PLA is easier to modify. The design should have mounting holes for the servos and bearings at the joints.
  • Bearing and Fasteners: Use M2 or M3 bolts and nylon lock nuts. For rotating joints, add a small ball bearing to reduce friction—this dramatically improves positional accuracy.
  • Wiring: 22 AWG silicone wire for power, 26 AWG for signal. Servo connectors are standard 3-pin Dupont headers.

Mechanical Design Considerations

Building a robotic arm isn’t just about bolting servos together. The geometry of the arm determines its reach, payload capacity, and stability. Here are the design principles I followed.

Joint Configuration

A 5-DOF (degrees of freedom) arm is a good balance between complexity and capability. My configuration is:

  1. Base rotation (yaw): Rotates the entire arm 180 degrees.
  2. Shoulder (pitch): Lifts the upper arm.
  3. Elbow (pitch): Lifts the forearm.
  4. Wrist pitch: Tilts the gripper up and down.
  5. Gripper: Opens and closes.

This setup allows the arm to reach any point within a hemispherical workspace, but it does have a singularity when the wrist is fully extended. Avoid operating near that point unless you have a robust control algorithm.

Center of Gravity and Counterbalancing

Micro servos have limited torque, so you need to minimize the moment arm. Keep the upper arm and forearm as short as possible—mine are 100mm and 80mm respectively. The gripper should be lightweight; I used a 3D-printed parallel-jaw gripper with a rubber pad for grip.

If you find the shoulder servo struggling to lift the arm, add a counterweight at the base of the upper arm. A small brass or steel weight (20-30 grams) can reduce the torque required by up to 40%.

Bearing Integration

At the base rotation joint, the entire weight of the arm rests on the servo shaft. This is a common failure point. I added a 608ZZ ball bearing between the base plate and the rotating platform. The bearing carries the axial load, while the servo only handles rotational torque. This simple addition extended the lifespan of my base servo from weeks to months.

Wiring and Power Distribution

Proper wiring is critical for micro servo motors. A single servo can draw up to 500mA under stall current, and five servos running simultaneously can exceed 2A. If your power supply can’t handle that, you’ll see voltage drops that cause servos to twitch or reset.

The Power Bus

I built a dedicated power distribution board using a strip of perfboard. The positive rail connects to the 5V input from the power supply, and the negative rail connects to ground. Each servo’s red wire goes to the positive rail, and the brown wire goes to the negative rail. The orange (signal) wires go to the PCA9685 output channels.

Never power servos through the microcontroller’s 5V pin. The voltage regulator on an Arduino Nano can only supply about 500mA—nowhere near enough for five servos.

I2C Wiring

The PCA9685 connects to the Arduino Nano as follows:

  • VCC → 5V (from the same power supply, not the Arduino’s 5V pin)
  • GND → Common ground
  • SDA → A4 (or pin 20 on Mega)
  • SCL → A5 (or pin 21 on Mega)
  • OE (Output Enable) → Connect to GND to enable outputs, or to a GPIO pin for software enable/disable

If you’re using multiple PCA9685 boards, set different I2C addresses by soldering the A0, A1, A2 pins. The default address is 0x40.

Decoupling Capacitors

Micro servos create electrical noise on the power line. To filter this, place a 470µF electrolytic capacitor between 5V and GND near the power input. Add a 0.1µF ceramic capacitor close to each servo’s power pins. This reduces jitter and prevents the microcontroller from reseting.

Programming the Servo Motor Driver

Now for the fun part—making the arm move. I’ll use the Adafruit PWM Servo Driver Library for Arduino, which abstracts the I2C communication and lets you control servos with simple commands.

Library Installation

Open the Arduino IDE, go to Sketch → Include Library → Manage Libraries. Search for “Adafruit PWM Servo Driver” and install it. This library handles all the register writes to the PCA9685.

Basic Control Code

Here’s a minimal sketch that sweeps all five servos from 0 to 180 degrees and back.

cpp

include <Wire.h>

include <Adafruit_PWMServoDriver.h>

AdafruitPWMServoDriver pwm = AdafruitPWMServoDriver();

// Define servo pulse width limits (in microseconds)

define SERVOMIN 150 // 0 degrees

define SERVOMAX 600 // 180 degrees

// Servo channels on the PCA9685 int servoChannels[] = {0, 1, 2, 3, 4};

void setup() { Serial.begin(9600); pwm.begin(); pwm.setPWMFreq(60); // 60Hz is standard for analog servos delay(10); }

void loop() { // Sweep all servos from 0 to 180 degrees for (int angle = 0; angle <= 180; angle += 1) { int pulse = map(angle, 0, 180, SERVOMIN, SERVOMAX); for (int ch = 0; ch < 5; ch++) { pwm.setPWM(servoChannels[ch], 0, pulse); } delay(15); }

// Sweep back for (int angle = 180; angle >= 0; angle -= 1) { int pulse = map(angle, 0, 180, SERVOMIN, SERVOMAX); for (int ch = 0; ch < 5; ch++) { pwm.setPWM(servoChannels[ch], 0, pulse); } delay(15); } }

Calibrating Pulse Widths

Not all micro servos respond the same way to PWM signals. The MG90S typically uses a pulse width range of 500µs to 2500µs, but I’ve seen variations of ±50µs between individual units. To calibrate:

  1. Attach a single servo to channel 0.
  2. Set SERVOMIN to 100 and SERVOMAX to 700.
  3. Upload a sketch that sets the servo to SERVOMIN and measure the angle with a protractor.
  4. Adjust SERVOMIN until the servo is at exactly 0 degrees.
  5. Repeat for SERVOMAX at 180 degrees.

Once calibrated, you can use the map() function to convert angles to pulse widths. For better accuracy, create a lookup table that maps every degree to a specific pulse width, accounting for any nonlinearities in the servo’s response.

Implementing Inverse Kinematics

Moving individual joints is fine for testing, but to make the arm useful, you need to control the end effector (gripper) position in 3D space. That’s where inverse kinematics (IK) comes in.

The Geometry of a 2-Link Arm

For simplicity, I’ll focus on the shoulder and elbow joints, which form a 2-link planar arm. The base rotation and wrist pitch are handled separately.

Let: - L1 = length of upper arm (100mm) - L2 = length of forearm (80mm) - x, y = desired position of the wrist joint (relative to the shoulder) - θ1 = shoulder angle - θ2 = elbow angle

From the law of cosines:

cos(θ2) = (x² + y² - L1² - L2²) / (2 * L1 * L2) θ2 = acos(cos(θ2))

Then:

θ1 = atan2(y, x) - atan2(L2 * sin(θ2), L1 + L2 * cos(θ2))

Arduino Implementation

cpp

include <math.h>

float L1 = 100.0; // mm float L2 = 80.0; // mm

void inverseKinematics(float x, float y, float &theta1, float &theta2) { float cosTheta2 = (xx + yy - L1L1 - L2L2) / (2 * L1 * L2); // Clamp to [-1, 1] to avoid NaN from acos if (cosTheta2 > 1.0) cosTheta2 = 1.0; if (cosTheta2 < -1.0) cosTheta2 = -1.0;

theta2 = acos(cosTheta2); theta1 = atan2(y, x) - atan2(L2 * sin(theta2), L1 + L2 * cos(theta2));

// Convert radians to degrees theta1 = theta1 * 180.0 / MPI; theta2 = theta2 * 180.0 / MPI; }

Handling Singularities

When the arm is fully extended (θ2 = 0), the IK solution becomes degenerate. In that case, you have infinite solutions for θ1. I handle this by checking if the distance to the target is greater than L1 + L2. If so, I set the arm to its maximum reach and move the target along the line of sight.

Also, micro servos have limited range. The MG90S can typically rotate from 0 to 180 degrees. If the IK solution gives an angle outside this range, you need to either clamp it or choose a different arm configuration (e.g., elbow-up vs. elbow-down).

Advanced Control Techniques

Once you have basic movement working, you can add features that make the arm feel responsive and intelligent.

Trapezoidal Motion Profiles

Abrupt starts and stops cause the arm to jerk, which can destabilize the payload or damage the servos. A trapezoidal velocity profile accelerates the arm smoothly, maintains a constant speed, then decelerates.

cpp void moveToAngle(int servoChannel, int targetAngle, int durationMs) { int currentAngle = getCurrentAngle(servoChannel); // You need to track this int steps = 50; // Number of intermediate positions int delayPerStep = durationMs / steps;

for (int i = 0; i <= steps; i++) { float t = (float)i / steps; // S-curve easing: 3t² - 2t³ gives smooth acceleration/deceleration float easedT = 3.0 * t * t - 2.0 * t * t * t; int angle = currentAngle + (targetAngle - currentAngle) * easedT; int pulse = map(angle, 0, 180, SERVOMIN, SERVOMAX); pwm.setPWM(servoChannel, 0, pulse); delay(delayPerStep); } }

Feedback and Error Correction

Micro servos don’t report their actual position—they just try to hold the commanded position. If the arm hits an obstacle, the servo will stall and draw high current. To detect this, monitor the current draw using an INA219 sensor. If current exceeds a threshold (e.g., 400mA per servo), stop the movement and reset the arm to a safe position.

Alternatively, you can add external position sensors like potentiometers or magnetic encoders. This turns your micro servo arm into a closed-loop system, which is more accurate but adds complexity.

Multi-Joint Coordinated Motion

For smooth pick-and-place operations, you need all joints to reach their target angles at the same time. This requires synchronizing the PWM updates. The PCA9685 makes this easy because you can write all 16 channels in a single I2C transaction, and the outputs update simultaneously when you write to the ALL_LED register.

cpp void setAllServos(int angles[5]) { for (int ch = 0; ch < 5; ch++) { int pulse = map(angles[ch], 0, 180, SERVOMIN, SERVOMAX); pwm.setPWM(ch, 0, pulse); } // The PCA9685 updates all channels on the next PWM cycle }

Testing and Troubleshooting Common Issues

No build goes perfectly the first time. Here are the problems I encountered and how I solved them.

Jittery Servos

If your servos twitch or oscillate around the target position, the most likely cause is power noise. Add more decoupling capacitors. Also check that your PWM frequency is exactly 60Hz. The PCA9685’s oscillator can drift slightly—if you have a scope, measure the PWM period and adjust the setPWMFreq() value accordingly.

Overheating Servos

A micro servo that’s too hot to touch is drawing too much current. This usually happens when the arm is holding a position against gravity without a mechanical lock. In software, reduce the holding torque by lowering the PWM pulse width to the minimum required to maintain position. Alternatively, add a servo saver—a clutch mechanism that slips under excessive load.

Inaccurate Positioning

If the arm doesn’t go to the expected position, recalibrate the pulse widths. Also check for mechanical slop. The 3D-printed joints might have 1-2 degrees of play, which adds up over multiple joints. Use tighter tolerances or add anti-backlash springs.

Communication Errors

I2C can fail if the bus is too long or if there’s too much noise. Keep the wires from the Arduino to the PCA9685 under 30cm. Add 4.7kΩ pull-up resistors on the SDA and SCL lines if your board doesn’t have them built in.

Expanding the Project

Once you have a working arm, the possibilities are endless. Here are a few directions you can take.

Adding a Camera

Mount a small OV2640 camera above the workspace. Use OpenMV or a Raspberry Pi to detect colored objects and send their coordinates to the Arduino. The arm can then pick up objects autonomously.

Wireless Control

Replace the USB cable with an HC-05 Bluetooth module. Send angle commands from a smartphone app or a game controller. For longer range, use an ESP32 with WiFi and a web interface.

Force Feedback

Attach a force-sensitive resistor (FSR) to the gripper. When the gripper touches an object, the resistance changes. Use this to control the grip force—tight enough to hold the object, but not so tight that it crushes it.

Multi-Arm Coordination

Use two PCA9685 boards to control two arms. Synchronize their movements so they can pass objects between them. This is a great way to explore collaborative robotics on a small scale.

Building a micro servo robotic arm with a dedicated servo motor driver is one of the most rewarding projects you can tackle. It teaches you about mechanics, electronics, control theory, and software—all in one compact package. The micro servo motor, despite its small size, is capable of remarkable precision when treated with respect. By understanding its limitations and leveraging a proper driver like the PCA9685, you can create a arm that moves smoothly, responds accurately, and opens the door to countless experiments.

So grab a handful of MG90S servos, fire up your 3D printer, and start building. The only limit is your imagination—and maybe the torque of your shoulder servo.

Copyright Statement:

Author: Micro Servo Motor

Link: https://microservomotor.com/diy-robotic-arm-with-micro-servo-motors/servo-driver-micro-servo-arm.htm

Source: Micro Servo Motor

The copyright of this article belongs to the author. Reproduction is not allowed without permission.

About Us

Lucas Bennett avatar
Lucas Bennett
Welcome to my blog!

Tags