MG996R Servo
The MG996R is a high-torque servo motor ideal for robotics and demanding DIY projects. Operating on 4.8V to 7.2V, it delivers up to 11 kg·cm torque at 6V, with a ~120° rotation range controlled via PWM signals. Weighing 55g, its durable metal gears and dimensions (40.7mm x 19.7mm x 42.9mm) make it suitable for heavy-duty applications requiring strength and reliability.

On this page
mg996r pinout
The MG996R is a high-torque 3-wire servo motor with GND (brown), +5V (red), and DATA (orange) wires.
| Pin | Type | Description | Notes |
|---|---|---|---|
| GND | Power | Ground connection. Connect to ESP32 GND and external power supply ground. | Essential for both power and signal reference. |
| +5V | Power | Power supply input (4.8V-7.2V). Requires external power supply capable of 2.5A peak. | DO NOT power from ESP32 5V pin - insufficient current capacity. |
| DATA | PWM | PWM control signal. Pulse width: 1ms (0°), 1.5ms (midpoint), 2ms (max). | Connect to a PWM-capable GPIO pin (e.g., GPIO 18). |
Operating voltage: 4.8V-7.2V
Torque: Up to 11 kg·cm at 6V
Angular range: ~120° (60° each direction)
High current draw: up to 2.5A during stall
Metal gears for heavy-duty applications
Wiring the mg996r to ESP32
To control the MG996R servo with an ESP32, connect the brown wire to GND, red wire to an external 5-7.2V power supply (NOT ESP32), and orange wire to a PWM GPIO pin.
| mg996r pin | ESP32 pin | Purpose |
|---|---|---|
| GND (brown) | GND + External Supply GND | Common ground for ESP32 and external power supply. |
| +5V (red) | External 5-7.2V Supply | Dedicated power supply (2.5A+ capacity). DO NOT use ESP32 5V pin. |
| DATA (orange) | GPIO 18 | PWM control signal (50Hz, 1-2ms pulse width). |
CRITICAL: Use external power supply - ESP32 cannot provide sufficient current
Recommended: 6V 3A regulated power supply
PWM frequency: 50Hz (standard servo)
Peak current: up to 2.5A during stall conditions
Add 470µF-1000µF capacitor across power supply to reduce voltage spikes
Connect all grounds together (ESP32 + power supply + servo)
mg996r code examples
mg996r Arduino example
Copy// Requires library: "ESP32Servo"
#include <ESP32Servo.h> // The classic Arduino Servo library does not support the ESP32
Servo myServo; // Create a Servo object
void setup() {
myServo.attach(18); // Servo signal on GPIO18, matches the wiring above
}
void loop() {
myServo.write(0); // Move the servo to 0 degrees
delay(1000);
myServo.write(90); // Move the servo to 90 degrees
delay(1000);
myServo.write(180); // Move the servo to 180 degrees
delay(1000);
}On the ESP32 the classic Arduino Servo library does not work - install ESP32Servo instead, which provides the same familiar attach()/write() API on top of the ESP32's LEDC PWM hardware. The servo's signal wire connects to GPIO18 as shown above, and the sketch sweeps between 0, 90 and 180 degrees. Power the servo from 5V (or an external supply for stronger servos) - not from the 3.3V pin. The MG996R is a high-torque servo: power it from an external 5-7.2V supply that can source several amps at stall - never from the ESP32 board's regulator - and tie the grounds together.
mg996r ESP-IDF example
Copy#include "driver/ledc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_err.h"
#define SERVO_PIN GPIO_NUM_18 // GPIO pin for the servo signal
#define SERVO_MIN_PULSEWIDTH 500 // Minimum pulse width in microseconds (0°)
#define SERVO_MAX_PULSEWIDTH 2500 // Maximum pulse width in microseconds (180°)
#define SERVO_MAX_DEGREE 180 // Maximum angle in degrees
// Convert an angle to an LEDC duty value: pulse width in us -> timer ticks
// (16-bit resolution at 50 Hz means the 20000 us period spans 65535 ticks)
uint32_t calculate_duty(uint32_t angle) {
uint32_t pulse_us = SERVO_MIN_PULSEWIDTH + ((SERVO_MAX_PULSEWIDTH - SERVO_MIN_PULSEWIDTH) * angle) / SERVO_MAX_DEGREE;
return (uint32_t)((uint64_t)pulse_us * 65535 / 20000);
}
void app_main() {
// Configure the LEDC timer
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.timer_num = LEDC_TIMER_0,
.duty_resolution = LEDC_TIMER_16_BIT,
.freq_hz = 50, // Frequency for servos
.clk_cfg = LEDC_AUTO_CLK
};
ledc_timer_config(&ledc_timer);
// Configure the LEDC channel
ledc_channel_config_t ledc_channel = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = LEDC_CHANNEL_0,
.timer_sel = LEDC_TIMER_0,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = SERVO_PIN,
.duty = 0, // Initial duty cycle
.hpoint = 0
};
ledc_channel_config(&ledc_channel);
while (1) {
// Move servo to 0°
uint32_t duty = calculate_duty(0);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
vTaskDelay(pdMS_TO_TICKS(1000));
// Move servo to 90°
duty = calculate_duty(90);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
vTaskDelay(pdMS_TO_TICKS(1000));
// Move servo to 180°
duty = calculate_duty(180);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}This code controls a servo using ESP-IDF's LEDC PWM driver. The calculate_pulse_width function computes the pulse width for a given angle (0° to 180°). The LEDC timer is set to 50 Hz, and the GPIO pin (e.g., GPIO_NUM_18) is configured as the output for the PWM signal. The servo's position is adjusted by updating the PWM duty cycle in the loop. The MG996R is a high-torque servo: power it from an external 5-7.2V supply that can source several amps at stall - never from the ESP32 board's regulator - and tie the grounds together.
mg996r ESPHome example
Copyoutput:
- platform: ledc
id: pwm_output
pin: GPIO18 # servo signal, matches the wiring above
frequency: 50 Hz
servo:
- id: my_servo
output: pwm_output
number:
- platform: template
name: "MG996R Position"
min_value: -100
max_value: 100
step: 1
optimistic: true
set_action:
- servo.write:
id: my_servo
level: !lambda 'return x / 100.0;'On the ESP32 the PWM output platform is ledc (the esp8266_pwm platform seen in older examples is ESP8266-only). The servo consumes the 50 Hz LEDC output on GPIO18, and the template number entity maps -100..100 to the servo range so you can slide it from Home Assistant; servo.write takes -1.0..1.0. The MG996R is a high-torque servo: power it from an external 5-7.2V supply that can source several amps at stall - never from the ESP32 board's regulator - and tie the grounds together.
mg996r PlatformIO example
Copy[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
lib_deps =
madhephaestus/ESP32Servo @ ^3.0.5#include <Arduino.h>
#include <ESP32Servo.h> // The classic Arduino Servo library does not support the ESP32
Servo myServo; // Create a Servo object
void setup() {
myServo.attach(18); // Servo signal on GPIO18, matches the wiring above
}
void loop() {
myServo.write(0); // Move the servo to 0 degrees
delay(1000);
myServo.write(90); // Move the servo to 90 degrees
delay(1000);
myServo.write(180); // Move the servo to 180 degrees
delay(1000);
}This code demonstrates how to control a servo in PlatformIO using the Arduino framework. The servo is connected to GPIO 18, and its position is controlled using PWM signals generated by the myServo.attach() and myServo.write() methods. No additional libraries are needed as the Arduino Servo library is built into the framework. The setup() function initializes the servo, while the loop() moves it between 0°, 90°, and 180° with delays. The MG996R is a high-torque servo: power it from an external 5-7.2V supply that can source several amps at stall - never from the ESP32 board's regulator - and tie the grounds together.
mg996r MicroPython example
Copyfrom machine import Pin, PWM
from time import sleep
# Configure PWM on GPIO18
servo = PWM(Pin(18))
servo.freq(50) # Set frequency to 50 Hz
# Function to move the servo to a specific angle (0° to 180°)
def set_servo_angle(angle):
# Convert angle to duty cycle (pulse width in microseconds)
duty = int(40 + (angle / 180) * 115) # Duty cycle range: 40-155 (approx. 500-2500 μs)
servo.duty(duty)
# Main loop
while True:
set_servo_angle(0) # Move to 0°
sleep(1) # Wait 1 second
set_servo_angle(90) # Move to 90°
sleep(1) # Wait 1 second
set_servo_angle(180) # Move to 180°
sleep(1) # Wait 1 secondThis MicroPython code controls a servo motor using PWM on GPIO 18. The PWM object sets a 50 Hz frequency for the servo. The function set_servo_angle(angle) converts an angle (0° to 180°) into a duty cycle to position the servo. In the loop, the servo moves between 0°, 90°, and 180° with a 1-second delay between movements. The MG996R is a high-torque servo: power it from an external 5-7.2V supply that can source several amps at stall - never from the ESP32 board's regulator - and tie the grounds together.
mg996r specifications
About the mg996r
The MG996R is a standard-size metal-gear servo, a step up in every dimension from the micro servos on this site: about 55g, 41 x 20 x 43mm, and enough torque for robotic arms, pan-tilt rigs, and steering linkages that would strip an SG90 or MG90S in minutes. TowerPro’s own figures put stall torque at 9.4 kg-cm at 4.8V and 11 kg-cm at 6V - worth stating plainly because online listings for this exact part are all over the place, with some sellers advertising 13 kg-cm or more. Treat any number above the manufacturer’s own 9.4/11 kg-cm as marketing rather than measurement.
Current draw scales with that torque. The datasheet-quoted stall current reaches 2.5A at 6V, and while a moving load rarely sits at full stall for long, informal side-by-side testing against similar standard servos has recorded peak draws close to 1A even under moderate load - enough on its own to overwhelm the regulator on an ESP32 dev board. This is not a servo to power from the board’s 5V pin: it needs its own external 5-7.2V supply rated for at least a couple of amps, with its ground tied back to the ESP32’s ground and only the PWM signal wire going to a GPIO.
Control is the same 50Hz pulse-width signal as every other servo here, so the general PWM servo wiring and ESP32Servo code apply unchanged - only the power budget is different. For driving several MG996R-class servos at once, a PCA9685 PWM controller with its own dedicated servo power rail is a cleaner setup than trying to fan out several GPIOs and hoping one 5V rail keeps up.
mg996r troubleshooting
Servo Not Responding or Moving Erratically
›
Issue: The MG996R servo does not move as expected or exhibits erratic behavior.
Possible causes include insufficient power supply, incorrect wiring, or incompatible control signals.
Solution: Ensure the servo is powered by an adequate external power source, as it can draw up to 2.5A at stall. Verify that the control signal is connected to a PWM-capable pin on the microcontroller, and that the signal parameters match the servo's specifications.
Servo Overheating
›
Issue: The MG996R servo becomes excessively hot during operation.
Possible causes include overloading the servo, continuous operation under high torque, or inadequate power supply.
Solution: Avoid stalling the servo for extended periods, as this can lead to overheating. Ensure that the load applied to the servo is within its torque specifications. Use a stable and adequately rated power supply to prevent voltage drops that could cause the servo to overheat.
Servo Jittering or Twitching
›
Issue: The MG996R servo exhibits jittery or twitchy movements during operation.
Possible causes include electrical noise, insufficient power supply, or signal interference.
Solution: Ensure a stable and adequate power supply to the servo, as voltage fluctuations can cause erratic behavior. Implement proper grounding and consider adding decoupling capacitors to filter out electrical noise. Check for any sources of signal interference and ensure that control signals are clean and within the appropriate voltage levels.
Servo Not Centering Correctly
›
Issue: The MG996R servo does not return to its neutral position accurately.
Possible causes include calibration issues, mechanical wear, or internal potentiometer faults.
Solution: Perform a calibration by sending a neutral position command (typically 1500µs pulse width) and adjust as necessary. Inspect the servo for signs of mechanical wear or damage. If the problem persists, the internal potentiometer may be faulty, and replacing the servo could be necessary.
Where to buy the mg996r

Resources
Similar sensors





