When I started this project, I literally did not know what I was getting into. My mindset was, "It has to work because I have all these bits and pieces, see?" My ignorance about everything I was going to build and program was an advantage. Because I had no idea how much work it would entail, I therefore had no reason to feel discouraged by the task ahead. All I knew was that I wanted to build a turret that scanned for intruders and, with that in mind, I started building.
The Rig
I built the rig, a kind of squat gantry turret with a rotating piece at the top (Figure 1), over the course of several days, scavenging from a set of beams and gears I had obtained from a Kickstarter project reward, an old Arduino set of sensors, a decommissioned webcam, and several bits of cardboard and Blu-Tack®.
Figure 1: My surveillance rig, made of pieces scavenged from a construction kit, old hardware, cardboard, and Blu-Tack.
I figured I'd solve each problem as I came across it, and I'd learn about each piece separately, before moving it into the final setup and going on to the next bit.
Because I wanted a moving turret, the first thing I needed to learn about was motors.
And Yet It Moves
My main reason for wanting a rotating turret was it would be waaaaay cooler than a static one. The hitch was that it had to move precisely to cover certain areas to scan the room, and that meant servos.
A word of warning: Be careful what you plug into your Pi in the way of motors and servos. One false step and you can irreparably kill your Pi. Why? Because physics, that's why. To rotate a spool of copper wire, you need to run an electric current through an electromagnet (which is in essence how an electric motor works). When you cut off the electric current, the spool does not stop rotating immediately – and what does a rotating spool of copper create between the two poles of an electromagnet? An electric current, that's what – an electric feedback from the motor that rushes back to whatever was powering it in the first place.
So, if you have a motor connected directly to your Pi, and that motor is powerful enough, the moment you shut it down, an electric current will surge from the motor toward your Pi. If it's strong enough, it can fry your computer.
You have two ways of avoiding this: (1) you can protect your board with a controller of some kind [1], which puts up a barrier between your Pi and the motor (as well as allows you to control 16 servos in one go); (2) you can do what I did: Check that the servo you're going to use only takes (and returns) a maximum of 5V, plug it in, and cross your fingers.
I picked a servo like the one in Figure 2 (see it mounted in Figure 3). The HS-311 is weak enough not to damage the Raspberry Pi but still strong enough to rotate the gears with ease.
Figure 2: The HS-311 can be connected directly to your Pi without the risk of frying it.
Figure 3: The servo mounted in the rig drives the rotating turret.
That said, although you can control the servo from the Pi (more about this later), the power the Pi outputs from the pin labeled "5V" is not going to be enough to move the servo. If you try (I did), the servo will vibrate a bit, and that's it.
You're going to need an external power source. I went for a battery holder that can hold six AA batteries (Figure 4). Plenty of these are available on the Internet, but I salvaged this one from a broken toy. Was I afraid six batteries would burn my servo? Sure. I plugged it in anyway. Fortune favors the brave! (It worked fine.)
Figure 4: Six AA batteries mounted in a salvaged battery holder from an old toy supplied juice to the servo.
The servo setup is shown in Figure 5. Note that you have to connect the servo's ground both to the battery holder's ground AND to one of the Raspberry Pi's ground pins; otherwise, the servo will work erratically.
Figure 5: Connection diagram for the servo. The ground cable of the servo must connect to the battery holder ground and to one of the Pi's ground pins.
Now comes the tricky bit about controlling the servo's movement. Servos are really old technology, dating back at least to WWII, when they were first used on a massive scale to control the precise movement of radar and anti-aircraft artillery. Because servos can move to more than two positions, sending a 1 or a 0 (i.e., HIGH
or LOW
signal) through a digital pin is not going to cut it. What you do is send a pulse: a quick sequence of 1s and 0s. The frequency of the pulse determines the position of the servo.
The HS-311 has a range of about 180º (i.e., it can rotate in a semicircle). Experimenting with different frequencies, I determined that a frequency of about 550 rotated the servo to 0º, and a frequency of about 2,450 rotated the servo to the 180º position. The middle position is halfway between those two numbers (i.e., 1,500).
You could use the standard GPIO Python library to control the servo, pushing out a 1, then sleeping for a fraction of a second, before sending out a 0, pausing, and then repeating everything all over again, gradually building a pulse. But this way of doing things is very error-prone, as explained in the "Why You Should Not Use the GPIO for Servos" box.
Why You Should Not Use the GPIO for Servos
The reason you should not use the regular GPIO library provided by default with Raspbian is because servos use pulses of highs and lows to move to a certain position. An exact timing of these pulses is fundamental to get a smooth and accurate positioning. The GPIO module cannot guarantee the precision of the pulses you push out from Python using a for
loop. The result is a jitter or trembling when moving the servo.
Try running the code in Listing 1 (as root), and you'll see what I mean.
Fortunately, there's a Python module specifically designed to control servos on the Pi. It's called RPIO, and if you compare Listing 1 (which uses the standard GPIO module) and Listing 2 (RPIO-based) [2], you'll see how easy RPIO makes things. Both programs do the same thing in theory: move the servo all the way one way, then all the way in the opposite direction, and finally moving the servo to its central position.
import RPi.GPIO as GPIOimport time
pin = 2
refresh_period = 0.02
GPIO.setup(pin, GPIO.OUT)
GPIO.output(pin, True)
for i in range(1, 100):
GPIO.output(pin, False)
time.sleep(0.001)
GPIO.output(pin, True)
time.sleep(refresh_period)
time.sleep(1)
for i in range(1, 100):
GPIO.output(pin, False)
time.sleep(0.002)
GPIO.output(pin, True)
time.sleep(refresh_period)
time.sleep(1)
for i in range(1, 100):
GPIO.output(pin, False)
time.sleep(0.0015)
GPIO.output(pin, True)
time.sleep(refresh_period)
time.sleep(1)
01 from RPIO import PWM
02 import time
03
04 servo = PWM.Servo()
05 pin=2
06
07 servo.set_servo(pin, 550)
08 time.sleep(1)
09
10 servo.set_servo(pin, 2450)
11 time.sleep(1)
12
13 servo.set_servo(pin, 1500)
14 time.sleep(1)
15
16 # Clear servo on GPIO
17 servo.stop_servo(2)
Apart from being much shorter, RPIO allows you to send a much more accurate pulse – no jitter!
Note the pauses (time.sleep(1)
) between positions. When working in the real world, you have to allow time for physical objects to reach their destination. Without a pause, the servo would move to position 550 and then start rotating toward 2,450, but before it got there, it would receive the message to move to 1,500, so it would never actually reach 2,450. Pausing the program for 1 second between movement instructions, gives the servo time to get where it needs to go.
RPIO does not come preinstalled by default in Raspbian, nor is it in the repositories. To install RPIO, first install the Python setup tools, using:
$ sudo apt-get install python-setuptools
Then, enter
$ sudo easy_install -U RPIO
to download and install the module from the Python repositories.