Links to stuff on this blog

Use the Site Index of Projects page link above for an easier way to find stuff on my blog that you might be looking for!

Saturday, October 3, 2009

Robotic Leg Testing with Python, Pololu and some good luck...

A day or so ago I got my Pololu USB 16 RC Servo Controller board in the mail. This is a USB or serial controlled RC Servo controller that can handle up to 16 RC Servo motors simultaneously. The board takes serial data from either the standard mini USB connection or a RS-232 connector and turns it into the pulse train necessary to position the RC servos. The handy thing about this board (and other like it) is that the board takes care of the pulse generating and all you have to do is sent it a serial string of data to tell it which motor goes to what position - the board takes care of the pulses.
  
For my initial mechanism testing I built a little test box that had an oscillator and three 'one shot' pulse stretchers that I could control with potentiometers to get the desired pulse train. That was good enough to test the mechanism one part at a time but for the coordinated motion required for exciting robotic action I need something like the Pololu USB 16. Because my robot has 3 servos per leg and a total of 4 legs I need to be able to control 12 servos and the Pololu handles 16... so far so good with 4 to spare....

My initial impression of the Pololu USB 16 is that it's small and only has one mounting hole to mount the board. The small size is great but the single mounting hole will make it an interesting challenge to mount it to the robot base. The other thing that I noticed about it is the servo power connector wasn't soldered to the board itself when I got it. I decided to solder it to the backside of the board since on the component side it will cover up the silkscreen on the board and make it hard to connect the servos to the header. Not a big deal I guess. I didn't bother to figure out a way to mount it just yet, I thought I'd better test it first. So I just set it on the robot base and hooked it all up.
 
Sorry about the fuzzy picture but you get the idea.

 
 
Another nice thing about the Pololu is it comes with a driver that once installed lets the USB connection to the Pololu board look like a standard serial COM port on your computer. That way controlling the Pololu is done by sending serial data out the COM port (really the USB). This is handy because most computers, especially laptops these days don't have an actual serial COM port.

The first thing that I did to make sure that this was all working was write a simple Jog test program in Python. I'll post the code for this at the end of this blog post. The code is mostly mine with a bit of the data conversion stuff from an example on the Pololu website. I used this jogger program to incrementally move the servos to their mechanical stops. I had to do this because the travel on each servo is 180 degrees but my robot leg mechanism doesn't use all 180, mechanically the linkages wont go that far. Each time I moved the servo with the jogger program it prints out the actual servo position and once I was at the mechanical stops I wrote down that position for each servo. As long as I don't tell the servo to go past that position I won't 'crash' the robot mechanism into it's hard mechanical stops.

Once I had all the mechanical stop positions written down I wrote a simple 'exerciser' script that moves the servos through their ranges. This was not only to test the mechanism but also to help me figure out how Python programming works (I'm not a programmer). Also this allowed me to see how well the Pololu handles coordinated motion of multiple servos. I made a 28 second grainy and dark video of the leg running this script.
 


It looks like the Python code talking to the Pololu USB 16 board works pretty good at getting everything running at the same time. All three servo's ran as expected without crashing into anything and the motors run at the same time as opposed to stepping through each motion one at a time.

The next immediate steps in the robot development are going to be:
1) figuring out a clean way to mount the Pololu board to the robot base with it's one mounting hole
2) cable management to make sure the servo wires don't get all tangled up while it's running
3) using the jog program to get the remaining leg hard stop values
4) hours of coding and testing to make this thing walk!!!

Here is the Python code of the Jogger program that I wrote. I want to say again that I am not a programmer and I have only been writing Python code for 4 days now so it probably isn't the best example of how to do this - but it woks. If you are a Python Guru please let me know what I can do to improve my code especially if it will make the next programming task (walking robot) a bit simpler and easier for me. In other words HELP!!!!   ;-)

- Python Pololu USB 16 Servo Jogger Program - 

Python needs to have everything indented correctly with spaces to run and the copy/past from Python IDLE seems to have removed some of those. You may have to tinker a bit to get it to work and look right in the Python editor but all of the code below works on my Windows Laptop running Python with the pySerial module loaded. PySerial gives you the serial commands to write out the virtual COM port (really a USB connection) that the Pololu USB driver sets up when you plug in the Pololu board.
   
# Pololu Motor Range Finder or Keyboard Jogger
# Written By Otto Belden Oct 2009
# http://ottobelden.blogspot.com/search/label/Robotics
#
import serial
import sys
#
#set com 3 up for communications Pololu defaults to com 3
ser=serial.Serial(2)
ser.baudrate=9600
# set the speed of Servo at something slow and reasonable with
# a varaible serstr = Serial String to write to com port
#           Start     DevID   Command  Servo     Data1
serstr = chr(0x80)+chr(0x01)+chr(0x01)+chr(0x02)+chr(0x10)
ser.write(serstr)
# set a default position at a mid range position for the servo 2750
# which breaks down in Pololu speak to 0x15 0x3E Data 1 and Data 2
# a varaible pos = position
# then build a new Serial String using that position and send it out
pos = 2750
#           Start     DevID   Command   Servo     Data1      Data2
serstr = chr(0x80)+chr(0x01)+chr(0x04)+chr(0x02)+chr(0x15)+chr(0x3e)
# define function newposition() that will calculate the 2 byte positions
# from the current position and assign those bytes to Data1 and Data 2
# then write out a new string
def newposition():
    if pos <=700 or pos >= 5300:
        print "******WARNING SLOW DOWN******"
    # get the data 1 byte (high byte)
    data1 = (pos-(pos&127))/128
    # get the data 2 byte (low byte)
    data2 = pos&127
    #           Start     DevID   Command    Servo     Data1      Data2
    serstr = chr(0x80)+chr(0x01)+chr(0x04)+chr(0x02)+chr(data1)+chr(data2)
    ser.write(serstr)
# print out to the console the instructions and keys to use then get keypresses
print "The servo should be on right now and in the middle of it's travel"
print "Use the '1' and '2' keys to jog the motor Forward and Reverse 100 counts"
print "Use the '3' and '4' keys to jog the motor Forward and Reverse 50 Counts"
print "Use the '5' and '6' keys to jog the motor Forward and Reverse 10 Counts"
print "Use the '7' and '8' keys to jog the motor Forward and Reverse 5 Counts"
print "Hit the '0' key to quit\n"
Input = 1
while Input != 0:
    Input = raw_input()
    Input = int(Input)
    if Input == 0:
        print "Now exiting last position was ",pos
        ser.close() # close the com port befor exiting
        print "Com port is open =",ser.isOpen() # make sure the port is closed
        break
    if Input == 1:
        pos = pos - 100
        newposition()     
    if Input == 2:
        pos = pos + 100
        newposition()
    if Input == 3:
        pos = pos - 50
        newposition()     
    if Input == 4:
        pos = pos + 50
        newposition()
    if Input == 5:
        pos = pos - 10
        newposition()     
    if Input == 6:
        pos = pos + 10
        newposition()
    if Input == 7:
        pos = pos - 5
        newposition()     
    if Input == 8:
        pos = pos + 5
        newposition()
    print "New Position  = ",pos



No comments:

Post a Comment