This site was created to share some experiences with the nice little
Orangutan controller from Pololu corp. The Pololu folks are great engineers but despite
enthusiastic promises of examples to come, they do not seem to be able to
provide software support for their products. They need help
from their users!
I'll be happy to post code/links/comments from others here. For example,
Cathy Saxton of Idle Loop Software Design has posted an extensive C++
code
example
for the Orangutan that is well worth studying. Here, I provide some
vanilla C examples.
The Orangutan is based on the ATmega8 controller from Atmel, which is great because of the availability of excellent free development software -- especially WinAVR. I use PIC processors when I can because the instruction set and hardware is so simple, but usually program them with MPLAB in assembler. PIC C compilers are expensive, and not as flexible as the fine gcc compiler.
The down side is that the built-in hardware of the ATmega chips is extremely flexible and the documentation is very hard to read. So, just getting a simple pulse-width modulated motor controller working can be difficult hard unless you have examples to follow. Read on:
I use a laptop running WinXP Pro connected to the AVRISP programmer via a USB serial cable adapter. The USB serial port ends up being different COMn ports depending on which USB port it is plugged in to, so the makefile often has to be edited. The makefile that I'm currently using is here. I have the Atmel development software installed but I've only used it once for a medium-sized assembly language project. C is certainly less work, but quirky and less intimate.
"WheelWatcher" modules (WW-01) from Nubotics,
attached to the servo bodies, were used to measure the wheel rpms.
The code examples provided by Nubotics were useful to figure out how to
use the modules, but the examples are very complex--far more complex than
they need to be to get the basic job done. I monitored only the right
wheel in my tests. The clock output of the WW-01 (purple lead) was
connected to INT0 (PORTD.2), which unfortunately is required as an output
to the Orangutan LCD module. An INT0 interrupt routine counts segment
ticks and measures the period of wheel rotation (time between segment
ticks), accumulating average values. The direction of wheel rotation and
total travel distance was monitored by the same routine, with the WW-01
direction bit (orange wire) connected to PORTC.5. The distance and
direction information were not used in my example, but could be used for
dead reckoning. This setup was later used to implement error-correcting
proportional (PID) speed control, as PWM alone is insufficient for robust
speed control. See below.
My opinion of the WheelWatcher? Glad you asked! A good idea, but
too expensive and too limited in mounting flexibility for different
motor/wheel configurations--I now have a spare set that won't fit my other
applications.
Also, if you make a mistake applying the black-and-silver reflective
wheel sticker, the replacement cost is outrageous -- $5.00 plus shipping
at one supplier.
The wheel speed is measured by computing the period between segment ticks. Timer0 increments at 3.9 kHz and when it overflows, an interrupt causes a counter to be incremented, extending the resolution to 24 bits. As each wheel tick occurs, a time stamp is saved and used to compute the period after the next tick. This approach fails when the wheel is stalled, so a more complete routine (see PID code below) should include a timeout to indicate zero velocity.
The LCD display on the Orangutan is good for accumulating the information on the wheel rotational period as a function of the PWM setting, but care has to be taken to disable the INT0 interrupt and reinitialize the LCD output bit on PORTD, as they can't be used by the two routines simultaneously. The actual test code, not cleaned up for publication, is WW_pwm_test.c, which requires routines to run the LCD display lcd_or.c (modified from an example posted on the Polulo user forum) and one of the PWM modules mentioned below. This program steps through a series of PWM settings, measures the wheel rotational period, and outputs the period and PWM setting on lines 1 and 2 of the LCD display, respectively. The wheel speed is calculated in arbitrary units as 1/(period*0.256E-3)--see graphs below.
The on-board LB1836M dual H-bridge has four modes of operation (taken from the data sheet, available from Pololu, or here.)
IN1/3 | IN2/4 | OUT1/3 | OUT2/4 | Mode |
H | L | H | L | Forward |
L | H | L | H | Reverse |
H | H | L | L | Brake |
L | L | Off | Off | Coast |
Forward and reverse modes are obvious, however the difference between the "brake" and "coast" or output-off modes is less obvious. Brake mode is in principle supposed to stop the motor quickly by acting as a short circuit across the motor terminals, but the current must flow through one of the output surge suppressor diodes as well as an output transistor, depending on the direction of motor rotation. The forward voltage drop across these components limits the effectiveness of the braking action Conversely, in "output off" mode the outputs do not conduct current and the motor coasts or freewheels. Either mode can be used for PWM control but the results are quite different (see below).
In my implementation, three interrupt service routines are required (TCNT1 Overflow, Compare matches TCNT1=OC1A and TCNT1=OC1B). The basic routines pwm_brake.c and pwm_coast.c were written to implement this approach and to study current draw and wheel rotational period (converted into robot forward speed) as a function of the PWM settings. Hopefully this example will be useful to others. Please feel free to offer corrections or suggestions. The example driver program pwm_modetest.c can be used to call one of the two PWM routines and exercise the motors.
If the foregoing is not completely clear, well, there is always the ATmega8 chip documentation...
I measured the overall current draw of the entire robot (Orangutan plus motor controller plus WheelWatcher) by a multimeter in series with the battery leads. With the motors off in "coast mode" about 60 mA was consumed. With motors off in "brake mode" about 120 mA was consumed, due to ~60 mA base current for the output transistors in the motor driver chip. Maximum current draw for "free air" rotation (right wheel only) was around 250 mA in brake mode PWM. The current draw is of course higher if the robot is running on the ground.
For brake mode, the wheel speed is very linear with the PWM
setting but the current consumption is generally high and very nonlinear
with the PWM setting. Graphs of the results are posted below. As you can
see, the current draw is highest when the motor is running at about half
speed. This makes perfect sense: for half of the PWM cycle, the rotational
energy is being dissipated by the braking action. However, the speed
setting is quite robust, that is, low speed performance is good, and the
robot maintains its speed rather well if a bit of resistance is applied to
the wheel. Why this should be so is less obvious, and it is not true
for coast mode.
.
For coast mode, the wheel speed is a nonlinear function of the PWM setting, and tops out at well below PWM setting=255. The current draw at low to intermediate speeds is quite a bit lower than with brake mode, but about the same when both are maxed. However, at intermediate speeds, the wheel rotational rate is not robust and slight resistance applied to the wheel causes it to slow down rather quickly. In the graphs at right, wheel speed is in arbitrary units (AU).
The algorithm is proportional/differential (PD) with an additional low-pass filter. I found it was not necessary to include an integral term.
Works great! Take a look at the all-in-one example pid_kd_all.c.
Tuning means to determine the mysterious constants Kp and Kd, which in turn will depend on the system: motor gear ratio, battery voltage, overall weight, friction, phase of moon, etc. There are entire web sites (plus thick, four-color, expensive, dense & excruciatingly boring undergraduate engineering texts) devoted to the process. Sadly, no standard notation seems to have arisen, not even the sign of the error term seems to be standard! It is easiest to start with floating point calculations and then convert to integer math for speed. You will probably need 8 MHz CPU clock or higher.
The basic operation of tuning is fairly simple: you begin with small Kp and Kd=0, and increase Kp until first the system response (e.g. motor speed) stabilizes, then further increase Kp until the response starts to oscillate. Back off Kp a bit, then, increase Kd in order to damp down the oscillations. In theory, there should at most one overshoot in response to a step change in speed.
For more detail, one place to start is the WikiPedia entry.
However, Parallax Inc. has a great example of PID process control using
the Basic Stamp.
Finally, there is always Jeff Bachiochi's lovely example of magnetic
levitation in Circuit Cellar
(Issue 18, Dec-Jan 90-91), in which only 15 lines of BASIC code were
required to levitate a steel sphere with an electromagnet. For another
amusing example, see the PID-Pong levitating ping-pong ball challenge by
Tom Cantrell in issue #50 of the same publication.
To facilitate tuning, you should have a means of studying the
operation of
the algorithm at fairly high speed. Following an example C program posted
by
Nubotics,
I used high speed RS232 output
(38400 baud) using the built-in UART to capture the action of the PD
algorithm at 0.1 second intervals on a PC. All that is needed is a time
stamp, the
current speed and PWM settings, which is all the main loop of the test
program does after posting a requested speed. The output was captured by
HyperTerm and loaded into a spreadsheet for plotting. I found that
the values for Kp and Kd were not critical, with Kp in the range of 0.1 to
0.2 while Kd needed to be about 0.4 to 0.6. After an evening of
experimentation, I settled on Kp=0.15 and Kd=0.40. See the plots below for
some examples, with comments.
The graphs below show the speed and
PWM setting for about 30
seconds. The horizontal axis is clock ticks.
Note:I
physically grabbed
the wheel at two points during each test (for a few seconds) to slow it
down or stop it, so that I could observe the response.
The RS232 AVR to PC transmit-only interface is port-powered from the PC DTR, pin 4 (or RTS, pin 7) and it worked well at 38400 baud using a USB to serial adapter. Similar designs can be found in many places on the web, see for example the PICList site. A schematic diagram is available here. The diode is probably necessary as on my adapter, the RTS and DTR pins swing from about +8V when the port is open to -8V when the port is closed, which could damage the transistor. I built the circuitry into a D9 subminiature shell as shown above.
Feel free to
email
me with comments, questions or suggestions.
last update: 10/1/2006
Copyright (C) 2006 by S. James Remington. All rights reserved.