Understanding the outputs of analogWrite and Servo.write

Hello to all!

I am quite new to arduino and I am trying to understand some of the basics yet. The big issue I had in the past few days was about reading values from these two functions: analogWrite and Servo.write. I would like to write some words about my encounter with these functions and receive some feebacks about the conclusions.

Fist of all I am reading data from an Arduino UNO and from a kk2.1.5 board hacked into an Arduino (as done by Arduino on the KK2 Multicopter controller - RCHacker.com - Radio Control for Engineers, Hackers and the advanced Hobbyist).

I am using an USBasp cable to program and supply power to both Arduino and kk boards, as well as a breadboard and a cheap multimeter.
So lets go…

The first thing I wanted was read what values my kk board output with the analogWrite, so I did this code.

const byte outsignal = X; //change X to the different pin numbers
int i=0;

void setup() {
  pinMode(outsignal, OUTPUT);
}

void loop() {
  analogWrite(outsignal, i);
  delay(2000);
  i = i+20;
}

I know the maximum value for i will be 255, but I would like to test with higher number too to see what happens.

My result:

  1. From pin 5 to pin 8, I read 0V in the multimeter until i is around 128, when it suddenly rised to 5V and stayed there forever;
  2. Pins 9 and 10 gave me 0V for all values of i;
  3. From pin 11 to pin 12, I read 0V in the multimeter until i is around 128, when it suddenly rised to 5V and stayed there forever.

After that, I implemented the same code in Arduino UNO and my results were:

  1. In no PWM pins, I read 0V in the multimeter until i is around 128, when it suddenly rised to 5V and stayed there forever;
  2. In PWM pins (pins 3, 5, 6, 9, 10, 11), I read, as expected, an increasing in voltage, step by step, until i = 255, where I reached the maximum voltage (5V). For i higher than 255, the function started again from 0, reaching maximum voltage when i = 510, and so on.

What did I realize from that:
A. Although the ATmega644PA (used by kk2.1.5) datasheet tell us that it has 6 PWM channels, they are not in the pins meant to be output of the kk board. People say that “The PWM pins seem to be wasted on the buttons and LCD interface.” (http://www.rcgroups.com/forums/showthread.php?t=2061620&page=94)… I don’t know;

B. I have no idea why pins 9 and 10 do not work. Probably some issue with the hacking… don’t know;

C. analogWrite(outsignal, 128) gives full voltage in non PWM pins. That was very unexpected!


After that, I wanted to know more about the Servo.write, so I begin again with the kk board with the following code.

#include <Servo.h>

const byte outsignal = X; //change X to the different pin numbers
int i=0;

Servo out;

void setup() {
  out.attach(outsignal);
}

void loop() {
  out.write(i);
  delay(2000);
  i = i+20;
}

My result:

  1. Again pins 9 and 10 did not work;
  2. All other output pins in the kk board gave me 0.12V when i=0 and raised, step by step, up to 0.58V (when i=180). For i higher than 180, the output value remained 0.58V;

Implementing the same code in Arduino UNO, I had the same result for all output pins:

  1. All output pins gave me 0.12V when i=0 and raised, step by step, up to 0.58V (when i=180). For i higher than 180, the output value remained 0.58V.

What did I realize from that:
At first, I was expecting 0V when the angle is 0 and 5V when the angle is 180. As my results showed very different numbers, I did some research and I concluded the following… Please correct me if I am wrong.

analogWrite outputs some PWM signal, with fixed duty cycles (2ms in a 500hz PWM pin, 1ms in a 1khz PWM pin). The value I set for i represents the width of the signal “inside” this duty cycle. In other words, if I set 0, means that the pin outputs 5V during zero ms inside the 2ms cycle. If I set 255, means that the pin outputs 5V during 2ms inside a 2ms cycle. The numbers in between represent a percentage of the duty cycle in which the pin is “on” (outputs 5V). After i=255, it starts again and the number 256 is equal to zero and so on. If I set i=127, means that half of the time (1ms in a 2ms duty cycle) the pin is “on”, which, in the average, outputs 2.5V (half of 5V).

— In a no PWM pin, 50% duty cycle is enough to let it outputs the full 5V. Unexpected to me!! I do not know how to explain this.

Servo.write seems that works pretty the same as analogWrite, with a little conceptual difference in the modulation. As far as I understood, Servo.write produces a fixed duty cycle of 20ms (50hz) and there is no way to increase or reduce this cycle. Inside this 20ms duty cycle, the function will create a pulse of 0.5ms up to 2ms. In other words, if I set the angle equal to 0, it means that the function is producing a 0.5ms 5V pulse inside a 20ms cycle (2.5% of the cycle, which means 2.5% of 5V, which is 0.12V (checked with my results!!)). If I set the angle 180, the function is producing a 2ms 5V pulse inside a 20ms cycle, which gives 0.5V. As I found 0.58V, I think the maximum pulse width is slightly higher than 2ms.
Lastly, I was wondering… If I have a servo that operates with more than 5V, I cannot drive him with Arduino UNO, right?

I hope the experts here can validate what I just said or correct me if I am wrong or misunderstood some point! If someone has answers to my doubts, I would really appreciate to read it!!
Thanks!!

If I told you that analogWrite doesn't write an analogue voltage but a PWM waveform, would that help you understand what you're seeing?

A servo signal is just a low duty-cycle PWM waveform Maximum 2ms out of 20ms, minimum. 1ms, so 5 to 10%)

. analogWrite(outsignal, 128) gives full voltage in non PWM pins. That was very unexpected!

You have the source of analogWrite - you can look at it and find out why you observe that.

AWOL: A servo signal is just a low duty-cycle PWM waveform Maximum 2ms out of 20ms, minimum. 1ms, so 5 to 10%)

If my results are ok, I think the minimum is 0.5ms pulse width in a 20ms cycle for a servo signal. With a minimum of 1ms, my minimum reading in the multimeter would have to be 0.25V, not 0.12V, right? I am missing something?

I'd ignore anything your multimeter tells you, unless it relates to a known DC voltage. It simply doesn't convert fast enough to give sensible results.

The “apparent” voltage on a servo signal is irrelevant: the servo looks for the width of the pulse. The only way you can see what’s going on is to use an oscilloscope, which will let you see the pulses and their interval.

You can change the following values in servo.h:

#define MIN_PULSE_WIDTH       544     // the shortest pulse sent to a servo  
#define MAX_PULSE_WIDTH      2400     // the longest pulse sent to a servo 
#define DEFAULT_PULSE_WIDTH  1500     // default pulse width when servo is attached
#define REFRESH_INTERVAL    20000     // minumim time to refresh servos in microseconds

Here is a servo trace for the default interval and another for when I made it 10000.

servo attached.jpg

10ms servo refresh.jpg

Then, as far as pure PWM is concerned, the following trace may be of interest to you. As you can read here, there are two different PWM frequencies depending on which pins you use.

This shows two traces, both for a 50% duty (analogWrite of 128), but for pins using different frequencies.

pwm hi and low freq with labels.jpg

Jabba_Joe:
If I have a servo that operates with more than 5V, I cannot drive him with Arduino UNO, right?

I may be wrong here but I think the control voltage will still be 5V, even if the power voltage is say 7. The servo still sees 5V as high on the signal wire.

Reading between the lines though, I’m wondering if you’re talking about powering (as distinct from controlling) a servo from Arduino… you really don’t want to do that. Power servos from their own supply, thus:

servo power.png

Jabba_Joe: If my results are ok, I think the minimum is 0.5ms pulse width in a 20ms cycle for a servo signal.

That's roughly correct. A servo should only require pulses from 1000us to 2000us in a perfect world, but unfortunately this isn't a perfect world, and servo specs vary considerably. As such, to cater to out-of-spec servos. the "Servo" library defaults to pulse widths between 544us and 2400us when 0 to 180 respectively are written using Servo.write(), as shown in JimboZA's code excerpt from the library:-

#define MIN_PULSE_WIDTH       544     // the shortest pulse sent to a servo  
#define MAX_PULSE_WIDTH      2400     // the longest pulse sent to a servo

Thank you very much for the answers! I didn't have realized that I could just go to the source code of the functions for understand some of my doubts!! Reading the analogWrite I understood why after 128 is always high and I saw the pulse widths in servo.h.. Next time for sure I will pay more attention to the sources!

JimboZA: I may be wrong here but I think the control voltage will still be 5V, even if the power voltage is say 7. The servo still sees 5V as high on the signal wire.

Yehh that's my doubt too. I don't mean to power the servo with the microcontroller, but I was wondering if a 7V servo for example needs a 7V signal or if a 5V is the standard for the signal, regardless of the power voltage.