Motor control with the Raspberry Pi and Pololu Qik

20130915-035623.jpg

The last piece of electronics to add to my project was the motor controller. After doing some digging, I decided to get a Pololu Qik Dual Serial Motor Controller to power a Tamiya Double Gearbox. Pololu is actually recommending a different (older) motor controller to go with the gearbox. So I did some research, and the only advantage the older motor controller has over the Qik, as far as I can tell, is that the older version supports up to 10A of current vs the Qik’s 1A (3A peak). But according to the specs, the FA-130 motor that comes with the gearbox has a stall current of 2.2A, so I think the Qik should be sufficient. Also, the motor controller they’re recommending is slightly more expensive and is in the “old and discontinued” section, so there’s that too.

Hooking up the Qik to the Raspberry Pi is pretty straight forward, except you first have to re-configure the Pi’s serial port so that it’s not being used for console logins (I followed these directions for this step). The only thing that might be a bit confusing (it was for me) is that with the serial port, you hook up TX to RX and RX to TX. This makes sense when you consider that you want the writes to go to reads, and reads to writes, but this is different to i2c where you want SCL to connect with SCL and SDA with SDA.

On the software side of things, you just need the Python serial package (sudo apt-get install python-serial), and you’re good to go. The following code will turn on motor 0 at full speed for 1 second, pause 1 second, then reverse for 1 second.

s = serialport = serial.Serial("/dev/ttyAMA0", 9600, timeout=0.5)
s.write( chr(0xAA) + chr(0x09) + chr(0x08) + chr(127) )  # motor 0 full speed forward
time.sleep(1)
s.write( chr(0xAA) + chr(0x09) + chr(0x08) + chr(0) )    # motor 0 speed to 0
time.sleep(1)
s.write( chr(0xAA) + chr(0x09) + chr(0x0A) + chr(127) )    # motor 0 full speed reverse
time.sleep(1)
s.write( chr(0xAA) + chr(0x09) + chr(0x0A) + chr(0) )      # motor 0 stop

The short version of the command is that the first byte is a starter byte, the next byte is the device ID (you can have multiple), the 3rd byte is the command, and then parameters follow (in this case, 1 byte containing the motor speed). More information on these commands can be found in the docs, and the Qik also has some other nifty features, so it’s definitely worth reading the manual if you get one. For the most part, as has generally been the case so far, I was surprised by how easy it was to get set up. I also like the serial interface because it’s dead simple to use, but once I get to more powerful motor controllers, I’m probably going to need to do PWM without a handy dandy serial interface.

Now that all the electronics are working, the next step is to put it all together, so stay tuned.

Advertisements

IRDAR- Infrared Detection and Ranging with the Raspberry Pi

Having figured out how to set the angle of a servo, I was ready to start working on the next mini-porject: the IRDAR. IRDAR stands for InfraRed Detection And Ranging, and is similar in concept to RADAR (RAdio Detection And Ranging). The basic idea is simple: Mount an IR distance sensor to a servo, then continuously move the sensor back and forth while getting distance measurements. The end result is that I will be able to detect objects, and determine how far away they are.

While a similar device could be created using an acoustic sensor, I decided to use an IR sensor for a few reasons:

  • IR sensors supposedly have a narrower beam than sonar sensors
  • IR sensors are a bit cheaper than sonar sensors (~$15 vs $25+)
  • IR travels faster than sound! (more on this later)

The basic setup is quite simple. For the IR sensor, I replicated the setup described in Jeremy Blythe’s blog post. You just need a Sharp IR sensor (model GP2Y0A02YK) and a MCP3008 chip, and he has another post describing how to hook up the MCP3008 to the Raspberry Pi. He also has some code on his GitHub for reading values from the chip and calculating distances, but the code I wanted was combined with some code I didn’t want, so I refactored the code to get a function that just returns the distance. Once I confirmed that the IR sensor was working and the code was returning sensible values, I taped the sensor onto a servo.

The last step was to write some more code to continuously move the servo, record the distance, and repeat (the code is on GitHub). To show what the IRDAR was seeing, the program prints out a crude text-based visualization to the console. The image below is a screen shot of the text output. The vertical axis is the angle, and the horizontal axis is the distance. In this image, you can see 3 objects being picked up by the IRDAR; 2 of them at about 20cm away, and another at about 60cm. The IRDAR code also stores historical data, and in the screen shot below, the ‘@’ symbols show readings from the most recent scan, while the ‘#’ symbols show readings from the scan before that. In the video, you can see how displaying historical data can sort of visualize movement as well.

Screen Shot 2013-09-13 at 1.37.03 AM

While the early results are promising, there’s more work to be done before it’s really usable. In the video, I have the IRDAR scanning at full speed, and I found that there are significant problems with accuracy when it’s moving that fast. On the other hand, scanning slowly makes it less useful in tracking objects that move. In the next post, I’ll talk about strategies to address these issues.

Setting the servo angle with a Raspberry Pi and Adafruit 16-channel servo controller

Servo hooked up to a Raspberry Pi

Controlling a servo from the Raspberry Pi isn’t hard, except for one minor point of confusion, which I’ll get to in a bit. 

But, first some background. A servo is basically a geared motor specifically designed for fine control. If you imagine a typical remote control car, a servo is what makes the front wheels turn left and right, while a motor provides propulsion (e.g. forward and backwards movement). Standard servos generally also only rotate around a 170 degree arc (although you can also get continuous rotation servos that can keep spinning like a regular motor). Servos are designed to accept Pulse Width Modulation signals, and based on this signal, a servo will either change position or change its speed. 

The Raspberry Pi has a pin that can be used to send PWM signals (here’s a nice tutorial) but if you want to control more than one device using PWM, you’ll need to use something more. I decided to use Adafruit’s 16-channel driver, which as the name implies, allows you to control up to 16 servos from one board. The Raspberry Pi talks to the controller board over a serial protocol called I2C, and the cool thing about I2C is that you can chain multiple devices, so it won’t prevent me from also using some I2C sensors or motor controllers in the future.

The Adafruit website has a great tutorial (with code!) for using the servo driver, but there’s one thing that isn’t entirely obvious: how to set the servo to a specific angle of rotation. Although it’s not clear from the tutorial and sample code, the servoMin and servoMax values actually represent pulse widths that will set standard (i.e. non-continuous) servos to the extremes of their range of motion (i.e. “far left” and “far right”). If you set the pulse to half way between servoMin and servoMax, the servo will be more or less centered. From there, you can calculate the pulse width required to rotate the servo to either direction in any angle you desire.

Long story short, I wrote a quick ‘n dirty function like this:

def setAngle(channel, angle, delta=170):
    """
        Sets angle of servo (approximate).
        :param channel: Channel servo is attached to (0-15)
        :param angle:   off of center, ( -80 through 80)
        :param delta:   Angle changed from past position. Used to calculate
                        delay, since rotating thru a larger arc takes longer
                        than a shorter arc.
    """
    delay = max(delta * 0.003, 0.03)        # calculate delay
    zero_pulse = (servoMin + servoMax) / 2  # half-way == 0 degrees
    pulse_width = zero_pulse - servoMin     # maximum pulse to either side 
    pulse = zero_pulse + (pulse_width * angle / 80)
    print "angle=%s pulse=%s" % (angle, pulse)
    pwm.setPWM(channel, 0, int(pulse))
    time.sleep(delay)  # sleep to give the servo time to do its thing

It works pretty well for the servo I have, but YMMV. One thing to note, also, is the delay. Servos rotate at different speeds, and is usually given in “seconds to rotate 60 degrees”. If you look at the technical specs of servos, this should be represented in a number that looks like “0.07 sec/60°”. Based on that, you can calculate how long it should take the servo to change its position. The function shown above is hard-coded to work for a servo that takes 0.15 seconds for 60 degrees of motion. I’ll write up some better code someday, but for now, this’ll get me to the next step.