Today I set up the Raspberry Pi to control a servo motor.
For the hardware setup, I referred to chapter 10 from the
Raspberry Pi Cookbook. Aside from the Pi, I only used the Pi Cobbler, a 1k resistor, and a 4AA battery pack. I didn't use any other special components. In the future, I'll consider getting a specialized breakout board for controlling servos.
For the software, I started with the code from this blog post:
http://www.doctormonk.com/2012/07/raspberry-pi-gpio-driving-servo.html
Note that in Simon Monk's post, he uses a transistor in his circuit that I didn't use based on the circuit in the book.
My first attempt didn't work well. The servo would turn very slowly, arriving at the 180 degree position, and stay there. I could feel the motor working but there was little to no movement.
After further research, I made some modifications to the starting code including changing the order of the True and False statements and playing with the timing. Things started to work. I was reading that servos needed between a .001 and .002 second pulse to move between 0 and 180 degrees respectively. I was finding those to be too long. For my servo, the range was between .00055 and .002. I don't know if that is a servo thing or if that helps to compensate for a delay from the RPi itself.
Finally, I added some code to accept an angle 0-180 as input and convert that angle into the appropriate timing of the pulses. I also had that input affect the number of loops because for shorter angle changes, a greater number of loop iterations would result in the motor jumping around slightly after reaching the desired angle. Now I can probably convert this to a function and use with other programs.
I had been reading about others experiencing a jittery movement when only using GPIO to control the servo but once I figured out the appropriate timing and loops, I found that it moved very smoothly. I don't know if there are other factors that I'm not experiencing that could affect the performance.
The Code:
import RPi.GPIO as GPIO
import time
import math
pin = 18
refresh_period = 0.02
prev_angle = 90 #initiate previous angle
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin, GPIO.OUT)
GPIO.output(pin, False)
while True:
angle = int(input('Angle: '))
# convert degrees (0-180) to the servo pulse (.00055 to .002ms)
pulse = (angle * .00000805555) + .00055
# determine the number of loops based on degrees needed to travel, a shorter distance (degrees) to travel = fewer loops
loops = math.ceil(math.fabs(prev_angle - angle) * .135) + 2
prev_angle = angle
# move the servo arm
for i in range(1, loops):
time.sleep(refresh_period)
GPIO.output(pin, True)
time.sleep(pulse)
GPIO.output(pin, False)
The circuit:
The servo I used:
The servo specs:
Years ago, I created a very simple robotic arm that waves and was able to revive it once again with the RPi!