The idea for our lego holonomic base came from www.visi.com/~dc, a page containing many interesting lego technic ideas. After discussing holonomic and nonholonomic robots in class one day, Prof. Dodds showed a Lego holonomic base (from this page) as an example. The specific base modeled a Killough Platform, a sample of which is shown below. We decided to try and build our own Lego Killough Platform, similar to the one we had seen but built from scratch.
The key component of such a base is a set of semi-spherical wheels, since the driving force from each set of wheels comes from turning them perpendicular to their normal direction of rotation. If of one the Killough Platform's wheels were mounted as if on a car, then it would be free to spin along its normal axis, but would be forcibly rotated around an axis through the center of the wheel and parallel to a line between the front and rear of the car. Thus the spinning wheel would start to push the car sideways. By mounting a pair of semi-spherical wheels 90 degrees out of phase and spinning them together, you can ensure that one of the two is always touching the ground, and thus always providing some sideways force. By taking three such pairs and fixing them each 120 degrees apart, you can sum the forces from different wheel pairs to move instantly in and direction in the plane. This is how a Killough Platform works.
Of course, the wheels themselves proved difficult. You don't have to use spherical wheels, and in fact the tiny design below actually uses flat-bottomed wheels (though you can't see them). But flat bottomed wheels have eight definite equilibrium points around their 360-degree field of motion, and thus give you a very bumpy ride, as well as requiring a lot more torque.
Unfortunately, the spherical Lego wheels we had proved too small in diameter for their width; when we built brackets to hold them and tried to rotate them, the brackets hit the ground and stopped the wheels. We knew it was possible to build such brackets around Lego wheels, since one page online had a diagram (below) of how it might be done. In the meantime, we constructed an unpowered prototype using tall, thin wheels, to see how the platform might fit together. To our dismay, our prototype used nearly all the Legos in the lab, yet was hardly even big enough to fit motors into. In addition, it was incredibly bumpy when moved around by hand, and obviously wouldn't work too well if we tried to control it with an RCX.
On examining the diagram closer and peering through Lego catalogs, we discovered that there was another size of Lego semi-spherical wheels, much larger (and much rarer). We special-ordered these from Lego and, on receiving them, set to work. This time our platform was better built and sturdier, and much smoother when pushed across the ground, due to the new wheels. We took three of the new model Technic motors (already geared down 1:20 (?) internally for more torque) and geared them down further, then attached each to a rotation sensor and a pair of wheels. After hooking the RCX up, we were done!
Above you can see the whole Killough Platform, as it still stands. Three identical wheel assemblies were made, each consisting of two wheels in brackets, geared 90 degrees out of phase and set inside a rectangular Lego frame. Below is a closer shot of a single wheel assembly.
This frame was then braced, and a motor and rotation sensor were attached. Then hinged pieces were used to connect the corners of the three wheel frames together. As any geometry teacher knows, fixing the lengths of all three sides of a triangle uniquely determines the triangle; and with three equal- length sides connected at the corners, our wheel assemblies were rigidly in place.
For additional strength, the wheel assemblies were also connected to a single, circular center section, which supported the middle of the platform to prevent sagging. This was also the section to which we attached the RCX. Below is a somewhat blurry shot of the botom of this central section, attached to which you can see bits of all three wheel assemblies.
After doing some work with the RCX and the supplied software from Lego, it became apparent that these tools would not provide the amount of low level control that we desired for the robot. To that end, we began looking for other sources that could provide low level control and a C/C++ environment. LegOS provides both of these features, giving relatively unrestricted access to the core of the RCX, and providing a version of the GNU compiler geared for the h8300 processor. Using this cross compiler combined with a set of standard GNU tools, it is possible to write C programs and download them to the RCX unit. LegOS is available as open source at legos.sourceforge.net. The tools to download code and firmware to the RCX are available as precompiled binaries for Windows 95/98/NT, and the source code for these tools are available and compile under Linux. The precompiled binaries do not run under Windows 2000.
LegOS provides for quasi C and C++ support, memory allocation through
free, and multiple processes through
semaphores. Motor speed can be set by an 8-bit wide byte, and sensor input is
stored in both raw and processed form via 16-bit integers. Unfortunately the
LegOS project does not supply precompiled libraries giving standard C functions,
and only a very small subset are supported directly by the API. One notable
shortcoming of the firmware is lack of support for memory management via
delete, as well as the lack of a
sizeof function which supports classes, making it very difficult to
program under C++. In order to install LegOS on an RCX unit, one must first
install the software on a PC by getting the compiler, and some basic tools such
as make and a native compiler. These can all be found on the LegOS page. The
next step is to build the LegOS kernel, which can be done very easily with the
configuration script supplied with the software. Once the kernel is built, it
can be downloaded to the RCX unit via the IR tower with the supplied tool called
firmdl3. Once this is done, one can use the supplied example makefile to build
programs for the RCX, compile them as a standard program via make, and download
them using the dll tool. The RCX unit can support 5 programs, numbered 0-4. As
long as one follows the supplied instructions very carefully, it is not very
difficult to compile the software. The only difficulties come from interfacing
with the IR tower. The error messages returned by firmdl3 and dll are not
helpful for determining what the problem is should something go wrong. Also,
external IR sources such as optical mice and remote control keyboards can
interfere with the IR tower making transmissions impossible. Specifications for
the API can be found at http://legos.sourceforge.net/docs.
Also at this site one can find information about the specifics of the RCX and
how the LegOS kernel itself works.
The first attempt to program our robot was to create movement at any arbitrary direction without turning the base. LegOS provides a byte to specify motor speed. So in theory, it should have been possible to work some trigonometry and vector addition over the power on all three motors to make the base move in any direction. Unfortunately, in practice this proved impossible to accomplish. LegOS provides for 256 possible motor speeds, but the motors themselves do not respond as one might expect to the speed commands. For one thing, these speed numbers represent voltages, not actual axle speeds. As the motor voltages decreased, so too did their torque. Low values for motor speeds, between 0 and about 100, did not provide enough torque to move the base. 100-200 provided enough torque to move the base, but not to move it in a straight line. Even restricting the speed to 255 did not solve the problem, as the design of the base provided a few problems. If the wheels were perfectly spherical, then they would be in contact with the ground at all times. We discovered short periods where a pair of wheels would not provide any torque, and the base could roll along the axis of those wheels. As such, the base would tend to rotate while it moved, causing the robot to get off course. It was possible to experimentally determine a correction factor for each of the motors to produce the desired motion, but this correction factor needed to be calculated individually for every wheel.
If we could have found a better way to control the motor speed through the low regions, perhaps running them at the highest speed, but only for short periods of time, it may have been possible to correct for the rotation of the robot. Still, we would have needed to devise some method to control the spin of the wheels along both their axes, as they allowed for tangential rotation, as well as radial rotation. We had no way to control or to correct for the radial rotation of the wheels.
The second attempt to program the robot was to allow for a person to push the robot around for 20 seconds, and then have the robot return to the original spot by ordering the motors to mirror the captured rotational sensor data. Here again we ran into the problem with how motor speed is specified. It was possible to create a scenario where two of the sensors would record an order of magnitude of rotations over the third sensor. When the robot attempted to return to its original location, the torque produced by two of the motors would overpower the third, thus causing the robot to rotate in a circle as opposed to returning to its original spot. Likewise, it was possible to move the robot beyond the maximum speed the motors would handle.
Also, the amount of execution space available to a program is very limited. When we attempted to record sensor data for 100ms time periods for 20 seconds, we overflowed the amount of stack space LegOS provided. In fact we overran the stack space by enough that we wrote over the kernel and the RCX locked up. None of the forced power off methods worked in fixing the RCX, and the only solution was to remove the batteries, and reload all the software back into the RCX. When we lowered the amount of sampling done on the sensors to a point that would not crash the RCX, we did not have enough resolution to deal with situations where a user pushed the robot extremely quickly. This, combined with the torque problems from the motor, made this project a failure. The timing required to make the robot return to its original position is not possible due to motor controls. If there were a way to provide torque at low speeds, then perhaps this project would work.
Another idea with using the robot's sensors to measure the distance moved involved devising a coordinate system for robot's RCX. Moving the robot would rotate the sensors, allowing the program to translate those into a coordinate system. The robot could then try to take the most direct route after a series of rotations and trnaslations, i.e. figure out where it ultimately wound up. However, one problem that arose was the lack of trigonometric functions, decimals from the sensors and, sometimes, negative numbers, in LegOS. Among other things, this required an upload of trigonometric tables, taking up precious memory and limiting the amount of "recording time". While not difficult, precision would become a problem because of both discrete sensor readings and slippage in wheels and gears. And again, the lack of precision in movement would make the final "return" movement only an approximation. Since this project's problems were so similar to those of the other two ideas, we abandoned it.
This project broke down into two pieces, a logo interpreter running on a Windows-based PC, and low level motor controls on the robot itself. The basic idea was to create a system that would take a raw logo command file, translate it low level motor controls on the robot, compile that code, and then download it to the RCX. The two pieces will be explained in more detail below.Low Level Commands
For our purposes, logo breaks down into 4 basic commands: move forward, move backward, rotate right, and rotate left. Most logos also allow for things like repeat and function call, but that was handled at a higher level by our logo interpreter; all these eventually translate to a series of the four basic commands. Our controllers for each of the four commands ran all the motors at the maximum speed, as those speeds provided for the least noticeable slippage on the robot wheels. By reading values off the rotational sensors, the robot can avoid problems of varying voltages, and always produce similar results. The user can specify turning by degrees. The error margin on the turn is approximately plus/minus 5 degrees. Forward and backward movement is defined in arbitrary units of approximately 1 unit equating to 1 centimeter. This doesn't hurt us, since most logos use their own arbitrary units for linear motion, generally 1 unit = 1 pixel onscreen. The 3 rotation encoders provide for a relatively decent degree of control. As always, the slippage problem comes into play, and during a rotation, the center of the robot will tend to move a little bit, but within the constraints of what the Lego Mindstorm pieces are able to provide, the controls do pretty well.Logo Interpreter
The LOGO interpreter reads LOGO programs from standard input and outputs a C++ program that will drive the holonomic base correctly so that it acts like the "turtle." The actual control of the base here is very easy since all LOGO programs (that we can parse at least) eventually break down into the four statements FD, BK, LT and RT. If we always fix FD and BK in the same dircetions relative to the RCX, then we can use all three wheels to spin the robot for RT and LT and we're done. Thus the C++ code outputted is actually a simple (though slightly long) header to define these four functions in terms of actual motor and sensor control, following by a main function which calls the four commands repeatedly. The whole skeleton is available here.
The LOGO interpretation is fairly robust (we think :) ). In addition to direct mappings of the FD, BK, LT, and RT commands, it can support several important features of LOGO:
REPEAT, for looping a string of commands
MAKE"name and :name)
TOname params body
The following example program may make things clearer. This is designed to
demonstrate the various supported features (not to be a great program); for
readability, we've spaced it out on multiple lines, though this wouldn't be
possible in the real interpreter.
repeat 3 [fd 6 rt 120]
to square :size
repeat 4 [bk :size rt 90]
to flower :petals :ctrsize
make "ang 360/:petals
make "half ctrsize/2
repeat :petals [fd :half-3 triangle fd :half+3 lt :ang]
repeat 4 [square 5 lt 90]
flower 5 10
We've provided a couple more sample programs with our code: one draws a simple square, one a star, and one some mysterious initials. All of these have also been compiled and loaded on the RCX as well, and can be run by selecting the various numbered programs.
Our original plan was to have the entire interpreter run on the RCX, and
store the desired program in a string at the top of the code. However, after
spending two hours trying to get code (which already compiled on Win32) to work
with the silly broken LegOS compiler, we found that neither the new operator nor
taking sizeof a class were implemented, making memory allocation difficult (to
say the least). So we gave up and modified our program to get the code
generator. Usage is very simple from DOS; typing
logo < input.lgo
generally suffices, then (assuming we have the LegOS Makefile for logo.c in that directory) we can simply make and download the code to the RCX, and we're ready.
As far as getting things to actually draw went, our luck was fairly poor. We couldn't find a working whiteboard marker, for one thing, and we found it was basically impossible to modify the robot to accept a marker directly in the center anyway (at least, without rebuilding it from scratch, with a lot more pieces). We tried taping a marker on the side, but the output was pretty lousy. We eventually gave up and just imagined the "turtle" leaving a trail behind as the robot ran :).
The big problem with our LOGO interpreter is that since there's no way to pull the "pen up" (even if one did exist), errors accumulate. Repeating a square over and over rapidly covers the paper with scribbles, since the robot tends to under-turn fairly consistently when given RT or LT. Though this error may be only 5 degrees per turn, after only a few turns we're noticeably out of true. Thus the program to draw "initials" makes some interesting (and curvy!) letters where there were supposed to be straight. This error is difficult to fix; the Lego motors need a lot more torque and a better drivetrain (with less slippage in the gears). Really it's about as good as Legos can do.
Our code is provided in the separate files logo.cpp, fun.cpp, fun.h, token.cpp, token.h, var.cpp, and var.h. Sample programs are in alph.lgo, square.lgo, and star.lgo. logo.exe is the compiled Win32 console application.