I recently bought a couple of cheap MG996R high-torque servos on ebay, and I want to use them with my Arduino.

Arduino + MG996 + Dusty Breadboard

These have the "JR" servo pinout, so orange = signal, red = V+, brown = V-.

You control these servos by sending a 50Hz pulse width modulated signal. The pulse width determines the position of the servo. Arduino wraps this in a nice Servo library. So you can just use servo.write(<angle>) to set the servo to a certain angle. Cool!

The servo library defaults to pulsing 544ms to 2400ms for angles zero to 180. This is too wide for the MG996R, the servo only moves when you write angles through 20-150 or so. Setting the value outside this range stresses the servo and can wear it out!

I wrote a quick sketch to interactively find the real minimum and maximum values: . You just watch the serial port and follow simple prompts:

Download the sketch here.

Servo Range Sketch (running)

Using that sketch, I found my MG996R servos to have minimum pulse width around 771 and maximum around 2193 when running off 5v1. The full sweep is approximately 0-130 degrees.

So, to use the servo library with correct angles the sweep will be 771 to 27402. So I can call:

servo.attach(servopin, 771, 2740);
servo.write(0); // Min
servo.write(65); // Midpoint
servo.write(130); // Max

Note: If setting up the Servo range like this, it's important not to drive the servo past 130 degrees - which corresponds to pulse width 2193 and the maximum position of the servo.

EDIT 2018: Fixed a nine year old bug in the formula above, thanks Dillon and Stavros for pointing it out.

Yay Arduino!

  1. While the servo is unloaded I'm powering it from the Arduino via USB, but this won't supply enough current for a loaded servo. []
  2. The adjusted max of 2740 is calculated as ( (MaxPW - MinPW) * (180 / MaxAngle) ) + MinPW, ie ( (2193 - 771) * (180 / 130) ) + 771 []

16 thoughts on “Servo pulse width range with Arduino

  1. Great info on how to find the min and max on my servo as the mfg’s docs do not seem to be accurate.

    I’ll give this a try tonight.

  2. Marius – the 0 and 180 are arbitrary, they get mapped to the pulse width values min and max that you provide. So if your servo can move further than 180 when running the test sketch, you should be able to map it. If it doesn’t move further thne it’s probably incapable, at least with the voltage & PWM frequency that the Arduino is providing.

    Hope this makes some sense. :)

  3. Hi this would be a great help to me but the when I try to download it appears to be missing. If you still have that code handy would you be able to re-post or email to me?

    Thank you!

  4. Hey! I am having the same problem. I would like to get accurate values for the pulse width of my servo and I believe that your software is perfect for that purpose, but unfortunately it is not there. Could you please email me the code?
    Thanks a lot!

  5. I downloaded the sketch & ran it. I get a continuous run from one extreme to the other on the servo. It starts moving almost at the very beginning of the output from the Arduino, but when the serial monitor is asking to hit any character when the servo stops – does this mean the far end of the sweep, or when all motion literally comes to a stop? I am powering the servo with a MA7805 regulator, not using the Arduino as its power source – only the signal source.

  6. Hi JMorton,

    I’m not sure exactly what you mean, sorry. It should be to stop when the servo arm stops moving – the motor might still be trying to drive it further but it might have stalled against its endstop.

    You might have to do some manual experiments with driving the servo to particular pulse widths (just manually writing them into the code) to see exactly what’s happening.


  7. Hey Angus, for the longest time I have been using 996R. But I have been really puzzled by some of its behaviors,
    I stumbled on your article by googling. WHAT A HELFULY ARTICLE!! :) THANK YOU VERY MUCH!!

  8. looking at your code there – when you set a new max pulse for the servo library – that corresponds to “180 deg” in the servo library

    so if your pulse 771 – 2193 corresponds to 0 – 130deg, then you need to set the max pulse (180deg) to something higher than 2193 ie (2193 * 180)/130 or 3036 – then in your code make sure you never ask it to go over 130 deg


  9. Hello,
    In your code (Servo_Range_Find.pde) at the end you write:
    myservo.write (180);
    delay (4000);
    For a 360 ° servo, is this code suitable?
    myservo.write (360);
    delay (4000);
    Is this correct?
    If no, can you help me?

Leave a Reply

Your email address will not be published.