---

Thursday, July 26, 2012

Raspberry Pi GPIO driving Servo

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.





                                                                                                                           

Tuesday, July 3, 2012

Raspberry Pi meets Arduino - part 2

I gave a short talk and demonstration yesterday evening at the #raspberryjam event in Preston. I demonstrated the Pi raising some servo driven flags attached to an Arduino. I would have demonstrated communication in the other direction using a ultrasonic rangefinder, but I ran out of time. That can be my next post.

Here is the code and details of the electronics for all this.

Flags



First of all the electronics. Here is a wiring diagram for the servos. 


The servo control pins are wired to D2 and D3.

The Arduino is powered by a separate power supply into its DC power socket. I used a 9V 1.5A power supply. The USB lead is connected from the Arduino to the Pi. I was running tightVNC on the Pi, so I could remote control it from my Mac without having to attache keyboard mouse and TV.

Arduino

Here is the Arduino sketch.
#include <Servo.h>

#define MIN_ANGLE 30
#define MAX_ANGLE 160

#define SERVO_1_PIN 3
#define SERVO_2_PIN 2

Servo servo1;
Servo servo2;
int servo1pos = MIN_ANGLE;
int servo2pos = MIN_ANGLE;

void setup()
{
  servo1.attach(SERVO_1_PIN);
  servo2.attach(SERVO_2_PIN);
  Serial.begin(9600);
}

void loop()
{
  if (Serial.available())
  {
    char ch = Serial.read();
    if (ch == 'a')  servo1pos = MAX_ANGLE;
    else if (ch == 'A')  servo1pos = MIN_ANGLE;
    else if (ch == 'b')  servo2pos = MAX_ANGLE;
    else if (ch == 'B')  servo2pos = MIN_ANGLE;

  }
  servo1.write(servo1pos);
  servo2.write(servo2pos);
  delay(20);
}

All nice standard stuff. It listens on the serial connection for one of the single character commands 'a', 'A', 'b' or 'B' and when it gets one it raises or lowers the appropriate flag.

Python

The Python script from the Raspberry Pi end is equally simple. However you will need to install the pyserial library.

Step 1. If you are not reading this page on your Pi, then switch now, so you can copy and paste.

Step 2. Browse to here and download pyserial-2.5.tar.gz (106.3 kB) and save it somewhere convenient like the Desktop.

Step 3. This is a gziped tar file. Which needs unzipping and untaring. To unzip it open a Terminal, which you will find from the 'start menu' under 'accessories'. Now paste the following commands into it.
cd /home/pi/Desktop/other
gunzip pyserial-2.5.tar.gz
tar - xvf pyserial-2.5.tar

Step 4. Install pySerial, by typing these lines in your terminal window:
cd pyserial-2.5
sudo python setup.py install



Startup IDLE (use Python 2 NOT 3) and open a new file, pasting the following code into it:


from Tkinter import *
import serial
import time

DEVICE = '/dev/ttyACM0'
BAUD = 9600
ser = serial.Serial(DEVICE, BAUD)

root = Tk()

def aUp() :
    ser.write('a')
    return

def aDown() :
    ser.write('A')
    return

def bUp() :
    ser.write('b')
    return

def bDown() :
    ser.write('B')
    return

Button(text='A up', command=aUp).pack()
Button(text='A down', command=aDown).pack()
Button(text='B up', command=bUp).pack()
Button(text='B down', command=bDown).pack()


root.mainloop()


Then run the script and the four buttons should appear.

Here is a short video showing the flags in action.






About the Author
These are my books. Click on the image below to find out more about them.