Published 2026-04-02
This guide explains how to control a standardservomotor using Pulse Width Modulation (PWM) signals. You will learn the exact PWM parameters (period, pulse width,duty cycle) needed to set aservoto any angle from 0 to 180 degrees. The instructions are based on widely available microcontroller platforms and have been verified with common 50Hz analog and digitalservos used in hobby robotics. By following the step‑by‑step code examples and calibration methods, you can reliably position a servo without jitter or drift.
A standard servo motor expects a PWM signal with the following fixed characteristics:
Signal period: 20 ms (milliseconds), which equals a frequency of50 Hz.
Pulse width (high time): varies between1.0 msand2.0 ms.
Duty cycle= (pulse width / 20 ms) × 100%.
Note: Some servos may accept 0.5 ms to 2.5 ms for extended range, but the standard 1.0–2.0 ms works for nearly all common servos.
The following code structure works on any platform that provides hardware PWM (e.g., Arduino, STM32, ESP32, Raspberry Pi with hardware PWM). We use generic pseudocode so you can adapt it to your specific microcontroller.
Choose a PWM‑capable pin.
Set PWM frequency to50 Hz(period = 20 ms).
Set resolution to at least 8‑bit (0–255) or 16‑bit for finer control.
For an 8‑bit PWM (0 = 0% duty, 255 = 100% duty):
Duty cycle for 1.0 ms = (1.0 / 20.0) × 255 = 12.75 → round to13
Duty cycle for 1.5 ms = (1.5 / 20.0) × 255 = 19.125 → round to19
Duty cycle for 2.0 ms = (2.0 / 20.0) × 255 = 25.5 → round to26
General formula for any angle (0–180°):
pulse_width_ms = 1.0 + (angle / 180.0)(2.0 - 1.0) duty_value = (pulse_width_ms / 20.0)(2^resolution - 1)
Example for 8‑bit resolution and 45°:
![]()
pulse_width_ms = 1.0 + (45/180)1.0 = 1.25 ms
duty_value = (1.25/20)255 = 15.9375 → integer16
// Pseudocode pwm_set_frequency(PWM_PIN, 50); // 50 Hz pwm_set_resolution(PWM_PIN, 8); // 8-bit int angle = 90; // target angle int duty = map(angle, 0, 180, 13, 26); // using pre‑computed min/max duty pwm_write(PWM_PIN, duty);
Because no two servos are exactly identical, always measure the actual pulse width limits:
1. Write a 1.0 ms pulse – observe the servo position. If it does not reach the physical stop, increase pulse width in 0.05 ms steps until it stops moving (record asmy_pulse).
2. Write a 2.0 ms pulse – similarly find the maximum pulse width that gives full rotation (max_pulse).
3. Use these measured values in your code instead of the theoretical 1.0/2.0 ms.
Common case: A typical Tower Pro SG90 micro servo requiredmin_pulse = 0.9 msandmax_pulse = 2.1 msfor a true 0–180° range. Always calibrate per servo model.
// Servo control using PWM – no external libraries required // Works on any board with hardware PWM (e.g., Uno, Nano, Mega, ESP32) const int servoPin = 9; // PWM pin const int freq = 50; // 50 Hz const int resolution = 8; // 8-bit (0-255) // Pre‑calibrated pulse limits (in microseconds) const int minPulseUs = 1000; // 1.0 ms = 1000 µs const int maxPulseUs = 2000; // 2.0 ms = 2000 µs void setup() { // Configure PWM ledcSetup(0, freq, resolution); // channel 0 ledcAttachPin(servoPin, 0); } void setServoAngle(int angle) { // Constrain angle to 0-180 angle = constrain(angle, 0, 180); // Convert angle to pulse width (microseconds) int pulseUs = minPulseUs + (angle(maxPulseUs - minPulseUs)) / 180; // Convert pulse width to duty cycle (0-255) int duty = (pulseUs255) / 20000; // 20000 µs = 20 ms period ledcWrite(0, duty); } void loop() { setServoAngle(0); // move to 0° delay(1000); setServoAngle(90); // move to 90° delay(1000); setServoAngle(180); // move to 180° delay(1000); }
1. Always calibrate each servo individually– even two servos of the same model can have ±0.1 ms variation. Write a simple test sketch that sweeps from 0.5 ms to 2.5 ms and note the exact pulse widths for 0° and 180°.
2. Use a separate power supply– never power a servo directly from your microcontroller’s 5V pin (current spikes can reset the board). A 5V/2A regulated supply or 4×NiMH batteries (4.8V) works reliably.
3. Add a 100–470 µF electrolytic capacitoracross the servo’s power terminals close to the servo. This absorbs voltage dips caused by sudden motor starts.
4. Avoid software delayswhile the servo is moving. Use non‑blocking timing (e.g., millis()‑based state machines) so your program can handle other tasks.
5. For high‑precision applications (e.g., robotic arms), use a 16‑bit PWM timer and linear interpolation between calibrated points. Also consider adding a 10‑bit analog feedback potentiometer to close the loop.
Core takeaway: Controlling a servo with PWM is straightforward once you fix the frequency at 50 Hz and map the angle to a 1.0–2.0 ms pulse width. However, real‑world reliability comes from proper calibration, adequate power, and using measured limits rather than theoretical values. Apply the calibration method described in section 2.4 to every new servo you integrate, and your projects will achieve smooth, accurate motion every time.
Update Time:2026-04-02
Contact Kpower's product specialist to recommend suitable motor or gearbox for your product.