Using Arduino to Control the Rotation Angle of a Micro Servo Motor
Why Micro Servo Motors Are the Unsung Heroes of DIY Robotics
If you’ve ever built a robot arm, a pan-tilt camera gimbal, or even a tiny animatronic puppet, you already know the truth: the micro servo motor is the muscle behind the magic. These palm-sized powerhouses—typically the SG90, MG90S, or TowerPro variants—pack enough torque to move lightweight mechanisms with astonishing repeatability, all while drawing less than 500mA at stall. But here’s the kicker: unlike DC motors that spin endlessly, a micro servo gives you absolute positional feedback through a built-in potentiometer and a closed-loop control circuit. All you need to do is send a specific pulse width, and the servo snaps to a precise angle—usually 0° to 180°.
In this deep-dive guide, we’re going beyond the basics. We’ll explore not just how to wire up an Arduino to a micro servo, but how to think about pulse-width modulation (PWM), timing jitter, power stability, and even software-based smoothing. By the end, you’ll be able to command a micro servo with sub-degree accuracy, handle multiple servos without frying your board, and debug the classic “twitching servo” nightmare.
The Anatomy of a Micro Servo: What Makes It Tick
Before we touch a single jumper wire, let’s dissect the humble micro servo. Inside that plastic casing (usually 22mm x 11.5mm x 27mm for an SG90) you’ll find:
- A DC gear motor – high-speed, low-torque, but geared down to deliver ~1.8 kg-cm at 4.8V.
- A feedback potentiometer – attached to the output shaft, this variable resistor tells the control board the current angle.
- A control board – compares the incoming signal pulse to the pot’s voltage and drives the motor forward or backward until they match.
- A 3-wire pigtail – typically brown/black (ground), red (5V), and orange/yellow (signal).
The critical spec is the pulse width range. Most analog micro servos expect a 50Hz refresh rate (20ms period), with a 1ms pulse commanding 0°, 1.5ms commanding 90°, and 2ms commanding 180°. However, not all servos are created equal. Some MG90S variants might respond to 0.5ms–2.5ms for a wider 180° sweep, while high-voltage digital servos like the DS3218 can run at 333Hz with narrower pulses.
The “Dead Band” and Why It Matters
Every micro servo has a tiny dead band—a range of pulse width changes that produce no physical movement. For cheap SG90s, this might be ±5µs. That means if you send 1.500ms and then 1.502ms, the servo might ignore the change. This is why naive delay()-based sweeping looks jerky: you’re stepping outside the dead band in coarse jumps. To get smooth motion, you need to interpolate between angles in micro-steps that are larger than the dead band but smaller than what the eye perceives (about 1° per 10ms).
Hardware Setup: Wiring a Micro Servo Without the Smoke
Here’s the part where most beginners fry their Arduino. A micro servo on stall can draw up to 800mA. The Arduino Uno’s 5V regulator can only supply ~500mA from USB, and even less from a 9V battery. Never power a servo directly from the Arduino 5V pin. Instead:
- Use an external 5V 2A power supply (a phone charger or a UBEC) for the servo’s red and brown wires.
- Connect the Arduino GND to the external supply GND – this creates a common reference.
- Connect the servo signal wire to any PWM-capable pin – on a Uno, that’s pins 3, 5, 6, 9, 10, or 11.
The Classic “Brownout” Trap
If you see the Arduino resetting every time the servo moves, that’s a brownout. The servo pulls the shared 5V rail below 4.5V, and the ATmega328P’s brown-out detector trips. The fix is twofold: add a 1000µF electrolytic capacitor across the servo power pins (close to the servo), and keep the servo’s ground wire as short and thick as possible. For multi-servo projects, consider a separate servo shield with its own DC-DC buck converter.
Wiring Diagram (Mental Model)
[External 5V 2A] ---> Servo RED [External GND] ---> Servo BROWN ---> Arduino GND (common) [Arduino Pin 9] ---> Servo ORANGE (signal)
That’s it. No magic, no optocouplers needed for a single servo. For two or more, add a 470µF cap per servo.
Software Control: Beyond Servo.h – The Raw PWM Approach
The Arduino Servo library is great for beginners, but it has limitations: it uses Timer1 on the Uno, which disables analogWrite() on pins 9 and 10. Also, its default pulse range (544µs–2400µs) is not calibrated to your specific servo. To truly master angle control, you have two paths:
Path 1: The Servo Library (Good for 90% of Projects)
cpp
include <Servo.h>
Servo myServo; int angle = 0;
void setup() { myServo.attach(9, 500, 2500); // custom pulse range myServo.write(90); // center }
void loop() { for (angle = 0; angle <= 180; angle++) { myServo.write(angle); delay(15); // 15ms per degree = ~66°/sec } for (angle = 180; angle >= 0; angle--) { myServo.write(angle); delay(15); } }
This works, but the delay(15) is blocking. If you want to read a sensor while the servo moves, you need non-blocking timing.
Path 2: Direct Register-Level PWM (For the Perfectionist)
By writing directly to the ATmega328P’s Timer1 registers, you can generate a 50Hz signal with 1µs resolution. This gives you the ability to calibrate the exact pulse widths for your servo’s 0° and 180° positions. Here’s a minimal example:
cpp void setServoPulse(int micros) { // Assuming Timer1 is in phase-correct PWM mode, prescaler=8, TOP=39999 (50Hz) OCR1A = micros * 2; // because each tick = 0.5µs at 16MHz/8 }
void setup() { DDRB |= (1 << PB1); // Pin 9 as output TCCR1A = (1 << COM1A1) | (1 << WGM11); TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); ICR1 = 39999; // 20ms period }
void loop() { setServoPulse(1500); // 90° delay(1000); setServoPulse(1000); // 0° delay(1000); }
Why bother? Because you can now calibrate the min/max pulse widths by trial and error. For example, your SG90 might hit 0° at 540µs and 180° at 2410µs, not the textbook 1000µs–2000µs. Using the library’s default 544–2400 might leave you 2° short of full travel.
Calibrating Your Micro Servo: The 3-Point Method
No two micro servos are identical. The potentiometer tolerance alone can shift the zero point by ±5°. Here’s how to find your servo’s true range:
- Attach a long horn (arm) to the servo and mark a reference line.
- Send a 1.5ms pulse (or
write(90)). Measure the angle with a protractor. If it’s not 90°, note the offset. - Send 1.0ms and 2.0ms pulses. Measure the actual angles. You’ll likely see 0° and 180° only if you’re lucky.
- Adjust your pulse limits in code until you get exactly 0° and 180°. Store these as constants.
For the Servo library, use myServo.attach(pin, minPulse, maxPulse). For register-level, just adjust the micros values.
A Pro Tip: The “Soft Limits” Trick
If you’re using a servo with a plastic gearbox (like the SG90), slamming it into the end stops at full speed will eventually strip teeth. In software, always clamp your angle request to a safe range, e.g., constrain(angle, 5, 175). This leaves a 5° buffer on each side, drastically extending the servo’s lifespan.
Smooth Motion: The S-Curve and Easing Functions
Linear sweeping (write(angle) with equal delays) causes sudden acceleration and deceleration, which looks robotic and stresses the gears. For a professional feel, implement an easing function. The most popular is the S-curve (sigmoid):
cpp float easeInOutQuad(float t) { return t < 0.5 ? 2 * t * t : 1 - pow(-2 * t + 2, 2) / 2; }
void smoothMove(int targetAngle, int durationMs) { int startAngle = currentAngle; int steps = 50; // 50 intermediate positions for (int i = 1; i <= steps; i++) { float t = (float)i / steps; float eased = easeInOutQuad(t); int newAngle = startAngle + (targetAngle - startAngle) * eased; myServo.write(newAngle); delay(durationMs / steps); } currentAngle = targetAngle; }
This produces a motion profile where the servo accelerates gently, cruises, then decelerates—just like a real industrial robot. For even smoother results, increase steps to 100 and reduce the delay accordingly.
The “Jitter” Problem and How to Kill It
If your servo shivers at rest, it’s usually one of three things:
- Power noise: Add a ferrite bead or a 100nF ceramic cap across the signal and ground.
- Timer drift: The
Servolibrary uses interrupts that can be delayed by other ISRs. Switch to register-level PWM. - Mechanical backlash: The gear train has play. Add a small rubber band load to preload the gears.
For a rock-solid hold, some servos support digital mode with a higher refresh rate (e.g., 300Hz). If your servo is digital, you can use the Servo library’s writeMicroseconds() at 50Hz, but digital servos actually prefer 200–333Hz. You’ll need to write a custom PWM generator for that.
Multi-Servo Coordination: The Power of a Servo Driver
Controlling 6 micro servos directly from an Arduino Uno is a recipe for timing headaches. Each Servo object uses an interrupt timer, and the Uno only has 3 timers. The practical limit is about 12 servos with the Servo library, but the CPU becomes a bottleneck. The clean solution is the PCA9685 16-channel PWM driver over I2C.
cpp
include <Wire.h> include <Adafruit_PWMServoDriver.h>
AdafruitPWMServoDriver pwm = AdafruitPWMServoDriver();
define SERVOMIN 150 // ~0° (calibrated) define SERVOMAX 600 // ~180° (calibrated)
void setup() { pwm.begin(); pwm.setPWMFreq(50); // analog servos }
void setServoAngle(uint8t channel, float angle) { uint16t pulse = map(angle, 0, 180, SERVOMIN, SERVOMAX); pwm.setPWM(channel, 0, pulse); }
With the PCA9685, the Arduino just sends I2C commands and can sleep. The driver board handles the 50Hz refresh for all 16 channels simultaneously. This is how you build a hexapod or a robotic hand without losing your sanity.
A Word on Servo Stalls
If you push a micro servo against a hard stop, it draws maximum current and heats up. The internal control board doesn’t have over-current protection. In software, always check if the servo has reached its target within a timeout. If not, cut power to that channel via a MOSFET or use a servo with stall detection (like the Feetech FS90R, though that’s continuous rotation).
Advanced Angle Feedback: Closed-Loop with an External Pot
Sometimes you need to know exactly where the servo is, not just where you commanded it. Micro servos don’t have a digital encoder, but you can hack it: attach a 10kΩ linear potentiometer to the output shaft (coaxially), and read its voltage with an Arduino analog pin.
cpp int readServoAngle() { int raw = analogRead(A0); // Map raw (0-1023) to 0-180 based on your pot's range return map(raw, potMin, potMax, 0, 180); }
Then, in your loop, you can implement a simple PID controller to correct for any missed steps. This is especially useful for robot arms that carry variable loads. The servo’s internal pot is not accessible externally, but an external pot glued to the shaft works fine for prototyping.
The “Stall Detection” Hack
By monitoring the current draw through a low-side sense resistor (0.1Ω) and an op-amp, you can detect when the servo is stalled (current spikes). This allows your Arduino to abort a motion and save the servo from burnout. It’s overkill for most hobby projects, but it’s a fun weekend build.
Real-World Example: A Pan-Tilt Camera Gimbal
Let’s tie everything together. You want a two-axis gimbal (pan on Y-axis, tilt on X-axis) using two MG90S micro servos. The tilt servo carries the camera, so it needs more torque. The pan servo only needs to swing the whole assembly.
Hardware: - Arduino Nano - 2x MG90S servos (or one SG90 for pan, one MG90S for tilt) - 5V 3A UBEC (battery eliminator circuit) - 1000µF capacitor across the power rails
Software: - Use the Servo library for simplicity. - Implement a smoothMove() function for both axes. - Read a joystick (analog) to set targets, with a dead zone to prevent drift.
cpp
include <Servo.h>
Servo panServo; Servo tiltServo;
int panAngle = 90; int tiltAngle = 90;
void setup() { panServo.attach(9, 500, 2500); tiltServo.attach(10, 500, 2500); panServo.write(panAngle); tiltServo.write(tiltAngle); }
void loop() { int x = analogRead(A0); // joystick X int y = analogRead(A1); // joystick Y
// Dead zone if (abs(x - 512) > 50) panAngle = constrain(panAngle + (x - 512) / 100, 0, 180); if (abs(y - 512) > 50) tiltAngle = constrain(tiltAngle + (y - 512) / 100, 10, 170);
// Smoothly move smoothMove(panServo, panAngle, 100); smoothMove(tiltServo, tiltAngle, 100); }
This is a robust base for a webcam tracker, a laser turret, or a solar panel alignment system. The key is the constrain() on the tilt axis to avoid flipping the camera.
Troubleshooting Common Micro Servo Failures
Even with perfect code, hardware can misbehave. Here’s a quick checklist:
- Servo twitches but doesn’t rotate: Signal wire not connected, or ground missing. Check with an oscilloscope that you’re seeing a 50Hz square wave.
- Servo rotates in one direction only: The pot is dirty or the control board is failing. Replace the servo.
- Servo gets hot: It’s fighting a mechanical bind. Loosen the linkage or reduce the load.
- Servo moves to wrong angles: The pulse range is miscalibrated. Re-run the calibration routine.
- Arduino resets when servo moves: Power starvation. Add the big capacitor and use an external supply.
The “Humming” Servo Fix
If your servo hums at rest, it’s oscillating around the target. This is often because the dead band is too small for the mechanical load. Increase the dead band in your code by adding a tiny tolerance:
cpp if (abs(targetAngle - currentAngle) < 2) { // do nothing, servo is close enough }
Or, better yet, power down the servo via a MOSFET when idle. For battery-powered projects, this saves a surprising amount of energy.
Final Thoughts on Pushing Micro Servos to Their Limits
Micro servo motors are deceptively simple. A beginner can blink one with three lines of code, but a master can coax sub-degree precision, silent motion, and years of reliable service from a $3 part. The secrets are:
- Respect the power budget – always use a separate supply.
- Calibrate, don’t assume – every servo has its own pulse-to-angle curve.
- Smooth is strong – easing functions reduce gear wear.
- Monitor and protect – soft limits and stall detection save hardware.
Now go build something that spins, points, or waves. And when someone asks how you got that micro servo to move so gracefully, you can smile and say, “It’s all in the pulses.”
Copyright Statement:
Author: Micro Servo Motor
Source: Micro Servo Motor
The copyright of this article belongs to the author. Reproduction is not allowed without permission.
Recommended Blog
- How to Connect a Micro Servo Motor to Arduino MKR IoT Bundle
- How to Connect a Micro Servo Motor to Arduino MKR Zero
- Using Arduino to Control the Rotation Angle and Speed of a Micro Servo Motor
- Using Arduino to Control the Angle, Speed, and Direction of a Micro Servo Motor
- Creating a Servo-Controlled Automated Plant Watering System with Arduino
- Using Arduino to Control the Angle, Speed, and Direction of a Micro Servo Motor
- How to Connect a Micro Servo Motor to Arduino MKR NB 1500
- How to Connect a Micro Servo Motor to Arduino Due
- Using Arduino to Control the Position, Speed, and Direction of a Micro Servo Motor
- How to Connect a Micro Servo Motor to Arduino MKR IoT Bundle
About Us
- Lucas Bennett
- Welcome to my blog!
Hot Blog
- Diagnosing and Fixing RC Car ESC Throttle Limiting Issues
- How to Use Raspberry Pi to Control Servo Motors in CNC Machines
- Getting Started with Micro Servo Motors and Raspberry Pi
- Building a Servo-Powered Automated Sorting Robot with Raspberry Pi and Sensors
- Smart Shelf Displays using Servo-Controlled Tilt Mechanics
- Micro Servos with Minimal Dead Band
- Troubleshooting Signal Loss in RC Cars
- The Role of Thermal Management in Motor Cost Reduction
- Building a Micro Servo Robotic Arm with a Custom PCB
- Micro Servos in RC Boats: Handling Wave Impacts & Shock Loads
Latest Blog
- Exploring the SG90 Micro Servo Motor: Features and Specifications
- Using Arduino to Control the Rotation Angle of a Micro Servo Motor
- Designing a Modular Micro Servo Robotic Arm
- The Role of Gear Materials in Servo Motor Performance Under Varying Signal Longevity
- How to Design Motors for Optimal Heat Distribution
- The Best Micro Servo Motors for Educational Robotics Kits
- How to Control Servo Motors Using Raspberry Pi and the RPi.GPIO Library for Beginners
- How to Find Quality Micro Servo Motors on a Budget
- The Importance of Thermal Modeling in Motor Design
- The Role of PWM in Signal Modulation: Applications and Techniques
- Micro Servo Motors in Environmental Monitoring: Applications and Benefits
- Best Practices for Securing Micro Servos in RC Boats to Prevent Water Ingress
- Advanced Servo Control Techniques Using Raspberry Pi
- How to Connect a Servo Motor to Raspberry Pi Using Jumper Wires
- Wire Length & Connector Type: Micro Servo Wiring in RC Boats
- Which Servo Offers Better Resolution: Micro or Standard?
- How PWM Shapes Define Micro Servo Motor Behavior
- Micro Servo Motors in Smart Financial Systems: Applications and Benefits
- The Evolution of Micro Servo Motors: Top Brands Over the Years
- The Importance of Gear Ratio in Servo Motor Performance