FYI : Servo pulse timing measured

There were 2 or 3 recent queries about the Arduino servo pulses and their timing and control. I wasn’t sure what the answer was so I went off to look at the source code for the servo stuff. While I saw comments mentioning some refresh time it appeared to me that whenever the call for a servo.write happens, it immediately changes the timer and thus the resulting PW. Since I’m not familiar with all the ATMega registers I wasn’t sure whether this meant that a new output pulse would happen right then or wait until after the cycle running ran it’s course. So I set-up a simple sketch and used the Arduino to measure (grossly) the output PW and it’s timing. Specifically I output a servo pulse on pin 9 and wired that directly to pin 2. I then used the pulseIn() function to measure the PW for 2 pulses. Here’s the initial sketch (gaack) and a short sample of the output.

#include <Servo.h>

Servo myservo;  // create servo object to control a servo

int inPin = 2;
int PW = 0;
unsigned long time = 0;

void setup()
{
  Serial.begin(38400);
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object]
  Serial.println("Measuring servo PW");
}

void loop()
{
  time = millis();
  myservo.write(0);
  Serial.print("P1 = ");
  PW = pulseIn(inPin, HIGH);
  Serial.println(PW);
  Serial.println(millis()-time);
  myservo.write(180);
  Serial.print("P2 = ");
  PW = pulseIn(inPin, HIGH);
  Serial.println(PW);
  Serial.println(millis()-time);
}

  • P1 = 532

    17

    P2 = 2376

    40

    P1 = 532

    17

    P2 = 2370

    40

    P1 = 531

    17

    P2 = 2368

    40

    P1 = 532

    18

    P2 = 2370

    39

    P1 = 531

    19

    P2 = 2370

    40

    P1 = 531

    19

    P2 = 2370


  • The first thing that pops out is that the PW’s (P1 and P2, in usecs above) are different from my expectation. While I knew the Arduino servo function could output PWs shorter and longer than the usual 1 and 2 msec, I had expected that the defaults would be those limits. Turns outs, at least with IDE 1.01, that’s not the case. FYI … a command of 90 deg yielded a PW of ~ 1450 usec, close enough to the expected 1.5 msec. I also infer that the pulse happens as soon as the servo.write() executes and so the pulseIn() function, because of the delay in “printing” "Px = ", is actually measuring the PW of the 2’nd pulse output and thus the ~20 msec between pulses. That, BTW, is also good to confirm … that the servo.write() runs at the expected 50 Hz rate (20 msec period).

    I then ran the code below to confirm my belief that the pulse is output immediately upon executing the servo.write(). The slight difference below is that there’s a write(0) immediately followed by a write(180). The PW is then measured. Would it be the short PW or the long PW ?

    #include <Servo.h>
    
    Servo myservo;  // create servo object to control a servo
    
    int inPin = 2;
    int PW = 0;
    unsigned long time = 0;
    
    void setup()
    {
      Serial.begin(38400);
      myservo.attach(9);  // attaches the servo on pin 9 to the servo object]
      Serial.println("Measuring servo PW");
    }
    
    void loop()
    {
      time = millis();
      myservo.write(0);
      myservo.write(180);
      Serial.print("P1 = ");
      PW = pulseIn(inPin, HIGH);
      Serial.println(PW);
      Serial.println(millis()-time);
      myservo.write(180);
      Serial.print("P2 = ");
      PW = pulseIn(inPin, HIGH);
      Serial.println(PW);
      Serial.println(millis()-time);
    }
    

  • P1 = 2370

    20

    P2 = 2376

    40

    P1 = 2376

    20

    P2 = 2376

    40

    P1 = 2376

    20

    P2 = 2370

    40

    P1 = 2375

    20

    P2 = 2370

    40


  • The data shows it’s always the long PW and the timing btw pulses remains the expected 20 msec. In another sketch I measured the “low” PW for each of the commanded 0, 90 and 180 positions. As expected the HIGH and LOW durations add up to ~20 msec for each command (530/19324 us, 1450/18347 us, 2370/17445 us)

    So if you don’t want to confuse your servo, your code should ensure some minimum wait btw updating the servo commands. When the code calls for a servo.write(), the outgoing pulse happens right then.

    Good info, thanks Mac.