I have experimented with GPIO on the Raspberry Pi, just turning an LED on and off here. But since then Ben Croston has improved the RPi GPIO Python library to do most of the work in C and I can confirm that it is a lot faster. Driving servo motors requires precise timing, so I decided to see how the Pi would perform this task.
Here is a video of the servo in action. It is set to stay on the left for a few seconds, then move to the middle position, then swing all the way to the right, then scoot back to the left.
As you can see it works, but is rather jittery. This would make it okay for some applications.
Here is what I did, for anyone wishing to try it for themselves.
Schematic
I did not like the idea of using the GPIO pin to directly drive the control signal for the servo. You may get away with it, but I wouldn't risk it, and it may not work as the GPIO pins are 3V where as the servo expects a 5V control signal.
The transistor I used was a BC548, but any similar NPN transistor (like the 2N2222) should do the trick.
Breadboard
To build this prototype, I used Adafruit's Cobbler. This very handy little gadget allows you to link the GPIO connector to breadboard.
Here is the breadboard layout:
You might want to open this up to full size to see what's going on.
The transistor is in the bottom three rows. The bottom most row being connected to GND on the cobbler, the base connection (second row up) is linked by a 1kΩ resistor to #17 on the cobbler.
An external 5V power supply was used to provide the power to the servo. I tried using the 5V connection from the servo, but even with big (2200µF) and small capacitors across the supply, the load from the servo was enough to crash the Pi. This external power supply was connected to the red and green jumper leads to the left.
A second 1kΩ resistor is connected from the external +5V to the collector of the transistor (third row up) using another 1kΩ resistor.
The connections to the servo are GND, +5V (from the external supply) and the control signal from the collector of the transistor (yellow lead).
Software
You will need to install the new version of the RPi.GPIO library from here. I used version 0.3.1a.
It requires you install python3-dev by entering the following from the terminal:
sudo apt-get install python3-dev
To install the library itself, fetch the archive from the link above, unpack into a directory and then run the command:
sudo python3 setup.py install
If you need more instructions on this, see my earlier post here. This part of the installation is the same, except I am now using python3 instead of python.
Here is the Python program to generate the pulses.
import RPi.GPIO as GPIO
import time
pin = 17
refresh_period = 0.02
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin, GPIO.OUT)
GPIO.output(pin, True)
while True:
for i in range(1, 100):
GPIO.output(pin, False)
time.sleep(0.001)
GPIO.output(pin, True)
time.sleep(refresh_period)
for i in range(1, 100):
GPIO.output(pin, False)
time.sleep(0.0015)
GPIO.output(pin, True)
time.sleep(refresh_period)
for i in range(1, 100):
GPIO.output(pin, False)
time.sleep(0.002)
GPIO.output(pin, True)
time.sleep(refresh_period)
This has to be run as root, so save it in a file called 'servo_test.py' and then run it with the command:
sudo python3 servo_test.py
The program generates pulses for the servo that look like this:
The pulses need to be about 20 mS apart, and the length of each pulse determines the servo position. A pulse of 1.5mS puts it in the middle position, 1.0mS one side and 2.0mS the other side.
Conclusion
The Pi can generate pulses fast enough to control a servo, but the operating system means that the pulses are not terribly reliable. The process may get interrupted at any time, lengthening the pulses, resulting in the jitter that you see.
If you want true accurate control, then you probably need to have the Pi delegate looking after the servos to an Arduino, as I do in my Pi with Arduino over USB blog post.
About the Author
These are my books. Click on the image below to find out more about them.
Here is a video of the servo in action. It is set to stay on the left for a few seconds, then move to the middle position, then swing all the way to the right, then scoot back to the left.
As you can see it works, but is rather jittery. This would make it okay for some applications.
Here is what I did, for anyone wishing to try it for themselves.
Schematic
I did not like the idea of using the GPIO pin to directly drive the control signal for the servo. You may get away with it, but I wouldn't risk it, and it may not work as the GPIO pins are 3V where as the servo expects a 5V control signal.
The transistor I used was a BC548, but any similar NPN transistor (like the 2N2222) should do the trick.
Breadboard
To build this prototype, I used Adafruit's Cobbler. This very handy little gadget allows you to link the GPIO connector to breadboard.
Here is the breadboard layout:
You might want to open this up to full size to see what's going on.
The transistor is in the bottom three rows. The bottom most row being connected to GND on the cobbler, the base connection (second row up) is linked by a 1kΩ resistor to #17 on the cobbler.
An external 5V power supply was used to provide the power to the servo. I tried using the 5V connection from the servo, but even with big (2200µF) and small capacitors across the supply, the load from the servo was enough to crash the Pi. This external power supply was connected to the red and green jumper leads to the left.
A second 1kΩ resistor is connected from the external +5V to the collector of the transistor (third row up) using another 1kΩ resistor.
The connections to the servo are GND, +5V (from the external supply) and the control signal from the collector of the transistor (yellow lead).
Software
You will need to install the new version of the RPi.GPIO library from here. I used version 0.3.1a.
It requires you install python3-dev by entering the following from the terminal:
sudo apt-get install python3-dev
To install the library itself, fetch the archive from the link above, unpack into a directory and then run the command:
sudo python3 setup.py install
If you need more instructions on this, see my earlier post here. This part of the installation is the same, except I am now using python3 instead of python.
Here is the Python program to generate the pulses.
import RPi.GPIO as GPIO
import time
pin = 17
refresh_period = 0.02
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin, GPIO.OUT)
GPIO.output(pin, True)
while True:
for i in range(1, 100):
GPIO.output(pin, False)
time.sleep(0.001)
GPIO.output(pin, True)
time.sleep(refresh_period)
for i in range(1, 100):
GPIO.output(pin, False)
time.sleep(0.0015)
GPIO.output(pin, True)
time.sleep(refresh_period)
for i in range(1, 100):
GPIO.output(pin, False)
time.sleep(0.002)
GPIO.output(pin, True)
time.sleep(refresh_period)
This has to be run as root, so save it in a file called 'servo_test.py' and then run it with the command:
sudo python3 servo_test.py
The program generates pulses for the servo that look like this:
The pulses need to be about 20 mS apart, and the length of each pulse determines the servo position. A pulse of 1.5mS puts it in the middle position, 1.0mS one side and 2.0mS the other side.
Conclusion
The Pi can generate pulses fast enough to control a servo, but the operating system means that the pulses are not terribly reliable. The process may get interrupted at any time, lengthening the pulses, resulting in the jitter that you see.
If you want true accurate control, then you probably need to have the Pi delegate looking after the servos to an Arduino, as I do in my Pi with Arduino over USB blog post.
About the Author
These are my books. Click on the image below to find out more about them.
8 comments:
You should check out emc2, former linuxcnc. They use software timing for running stepper motors from a paralell port. I built a 3axis mill using that. Emc2 and raspberry pi would be a match made in heaven.
What is your servo motor model?
How do we calculate the needed pulse of a servo motor?
@amento, Pretty much any sevo will do. pulse is between 1ms and 2 ms, each pulse about 20ms apart. 1ms left 2 ms right 1.5ms in the middle.
The motor runs at 50kHz. If you add a 20ms delay after a 2ms pulse you are at about 45.45kHz not 50khz. So the delay has to be 20ms minus the pulse time. Also I would put the pulse at the end of the cycle, not the beginning. So it should look something more like this
Delay = 19ms
Pulse = 1ms
Delay = 18.5ms
Pulse = 1.5ms
Delay = 18ms
Pulse = 2ms
Delay = 19ms
Pulse = 1ms
python says "expected an indented block"
All the contents you mentioned in post is too good and can be very useful. I will keep it in mind, thanks for sharing the information keep updating, looking forward for more posts. Thanks
Router Mill
Thanks for this post, Simon. Between this and the newly purchased Raspberry Pi Cookbook (ebook), I was able to get things working!
http://kj-til.blogspot.com/2013/12/rpi-controlling-servo-motor.html
Servo-Blaster Raspberry:
https://github.com/richardghirst/PiBits/tree/master/ServoBlaster
Post a Comment