Controlling a servo using raspberry pi PWM generator is not a trivial task since PWM period cannot be defined by the user. To overcome this issue we will use wiringPi C library in order to create a software generated pulse. Of course the generated pulse will not be as accurate as a hardware generated pulse but will be sufficient for simple tasks involving servo control.
In the following picture we can see how PWM is used to control the position of a servo. We need a period of about 20 ms and an on duration that varies between 1 ms (minimum) and 2 ms (maximum).
WiringPi library allows us to use one (in our case pin 0) or more pins of Raspberry pi as PWM outputs by using the following code.
if (wiringPiSetup () == -1)
exit (1) ;//we set GPIO pin0 as output. Don't forget that pin number in wiringPi is different that the actual pin
//number on the gpio header of raspberry pi
pinMode (0, OUTPUT) ;
//and set its value to 0
digitalWrite (0, LOW) ;//The the parameters of softPwmCreate function represent gpio pin number, initial value and range.
//The smallest period that we can achieve is 100μs (with a range of 1). In order to generate the
//needed 20ms period pulse we need to multiply 100μs by 200 so we set our range to 200.
softPwmCreate(0,0,200);//softPwmWrite takes two parameters, the output pin and the value (which has to be in the range we //defined before
Theoreticaly, if we wanted to generate a pulse with “on duration” of 2ms (duty cycle 10%) the value we should set to softPwmWrite would be 20. However, it seems that values in softPwm functions define the “off duration” so we would need a value of 180. Practically, after doing a few experiments the range of acceptable values for my mini servo was between 180 and 194.
The complete code is included in hellosoftpwm.c file.
To compile the code use
gcc -o hellosoftpwm hellosoftpwm.c -lwiringPi
and to run
We are also going to use a transistor as a buffer for protection of the GPIO and transformation of 3V GPIO output to 5V, which is the pulse voltage expected by the servo. To do this you can use a BC548 or 2N2222 or other NPN transistor. In my case the only available transistor was a BC547 with 6V emitter-base voltage which worked like a charm.
(I have tried to use the servo directly on the GPIO but didn't work, I guess because of the 3V output)
In the following diagram you can see the needed connections.