Brushless Motor, Servo Library and AnalogWrite

Good Night,

My question is actually really simple. What does the servo Library ".write" does, that analogWrite doesn't?

I have 4 brushless motors, each connected to an individual ESC. I'm trying to change their speeds using analogWrite. This doesn't work.

However, when I instantiate 4 servo variables to handle the motors, using both attach and write servo library functions, they do work.

Any thoughts?

Thank you in advance.

1 Like

I believe the basic difference between analogWrite() and servo.write is that the servo library is using clock interrupts so that is basically works in the background without you having to constantly manually do analog writes to keep the servos (or ESCs) positioned.

You can run an ESC by analogWrite, but basically you need to control the timing by hand, so a 1-2ms high pulse, total frame width of 20ms, so like

loop()
{
analogWrite(escPin, High);
delay(1000);
analogWrite(escPin, Low);
delay(19000);
}

Would be zero throttle

loop()
{
analogWrite(escPin, High);
delay(2000);
analogWrite(escPin, Low);
delay(18000);
}

would be high throttle. The servo library is taking care of all of the delays for you, and is allowing you to run your code as if servos are a background task that you do not have to account for timing using. Additionally the servo library will maintain the position of the last write until told otherwise, if you do it by hand you pretty much need to do an analogWrite every time through loop.

Edit: Note, if you hand control more than 1 servo you can combine the delays

loop()
{
analogWrite(esc1Pin, High);
delay(2000);
analogWrite(esc1Pin, Low);
analogWrite(esc2Pin, High);
delay(2000);
analogWrite(esc2Pin, Low);
delay(16000);
}

Also the "16000" in not a critical value, if you start to exceed 20ms frame width by a long ways your servos will be slow and not hold position well, you can drive them faster, but there is a mathmatical limit to how fast they can possibly go (for instance at high throttle 500 cycles a second would be the limit... 2ms*500 = 1 Second), in reality most ESCs get grouchy above around 400hz.

BH72, thank you for your answer.

However, as it is of my understanding, the analogWrite allows one to output values between 0-255, if dealing with a PWM pin, which is the case.
That being said, why can't I output a value between those min and max to my motors by simply using analogWrite, and with the servo library I actually can?!

So sorry, do not know what I was thinking there for a minute, replace everything above with digitalWrite.

With the servo library you are telling it to write to an angle, lets say 90 for instance, the library converts that angle to a pulse 1.5ms wide and pulses the servo at the proper frequency. It is the width of the pulse that is important to a servo or esc. Trying to PWM a servo will not get you the correct pulse width nor frequency.

Doing servo.writeMicroseconds(1500) should produce the same result as servo.write(90).

So, if I understood you correctly, when using servo.write(), the inputted values can vary between 0 and 360 is that correct? Being 180 the highest possible value.

That being said, is there any way of outputting ranging values from 0 to 255, using analogWrite, to the motors?

Once again, thank you for your help.

Technically in order to use analog write you would have to manually adjust the PWM frequency to match what would be within specification for the servo (or esc), and then set the PWM value (which would be duty cycle), for instance if you set the PWM frequency to 50HZ an analogWrite of 25 should set ESC to 0 throttle, 50 to high (you would need to actually do the math for this, these are just example values), but there are significant penalties that you must accept if you mess with the PWM frequency.

With servo.write, you can input values from 0-180 that correspond to angle of servo (90 being center), the servo library will map those value to a range of 1000-2000 (actually it is not exactly 1000-2000, and it is adjustable, but 1000-2000 will suffice for our conversation). The 1000-2000 value is the high on time of the pulse sent to the servo (or esc).

DigitalWrite with delays is the most realistic way to hand control these if you do not desire to use the servo library. If you are really wanting to use 0-255 you can map these values to 1000-2000...

esc1Output = map(myZerotoTwoFifyFiveValue, 0, 255, 1000, 2000);
digital(esc1Pin, high);
delay(esc1Output);
digital(esc1Pin, low);
delay(20000-esc1Output)

This would be the idea of how the servo library does it, except it uses timer interrupt so that your code does not block on delay() and instead of 0 and 255 the map values would be 0 and 180.

If you do not want to manually do all of these delays (as your code will stop for these delays) you probably want to use a timer interrupt, but if you are going to do that might as well use the servo library.

EDIT: You would have to check out your PWM frequency for your particular board, but on most pins I think it is 490hz, meaning that a value of like 125 should correspond to low throttle and maybe 250 would correspond to high throttle, but it is not likely your ESC would accept this high of a frequency.

BH72,

Thank you so much for your through explanation.

I will use the servo library, i have nothing against it. I solely wanted to understand the difference between both approaches and why it wouldn't work the way I was doing it.

Have a nice evening!

You can set up a 16 bit timer in a 16 bit PWM mode and then get a proper servo signal from it,
(50 Hz with resolution of 1us). The Uno only has one 16-bit timer though.

The Servo library is smarter, it uses one 16 bit counter to drive upto 12 servos in turn by reprogramming
the timer repeatedly and driving a different output pin (all in an ISR). 20ms is plenty of time for 12 1.5ms
pulses.

Some people have been having trouble using the Servo library for quadcopters. It simply isn't fast enough, only updates at 50Hz.

I

Isaac96:
Some people have been having trouble using the Servo library for quadcopters. It simply isn't fast enough, only updates at 50Hz.

True, although it does appear that it could be made to update faster by altering servo.h

#define REFRESH_INTERVAL 20000

And you can change the timer that the library uses. I had to do that once when I was using the servo library with IRRemote. It is pretty easy.