Project 3 - Building the Holonomic Base

Michael Chan, Ben Hulse, Peter Kasting

Part I - Hardware

The idea for our lego holonomic base came from, 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.

A real Killough Platform

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.

A tiny Lego Killough Platform

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.

Blueprint for Lego wheel brackets

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!

The finished product

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.

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.

Central supporting section

Part II - Firmware

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 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 malloc and 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 new and 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 Also at this site one can find information about the specifics of the RCX and how the LegOS kernel itself works.

Project 4 - Programming the Holonomic Base

Michael Chan, Ben Hulse, Peter Kasting, Katie Ray

Failed Idea 1: Arbitrary movement

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.

Failed Idea 2: The Boomerang

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.

Failed Idea 3: Robot Coordinates

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.

Successful Idea: Logo

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:

There are some expectations about input format: tokens are passed on a single line of input, separated by exactly one space. Arithmetic expressions have no spaces and no parentheses, though correct order of operations is supported. The bracketed bodies of REPEAT statements must not have a space immediately inside either end bracket, but must have one OUTSIDE the brackets. An arbitrary number of functions and variables may be defined and used; the most recent definition of a variable will be visible over all others until the end of the variable's scope. However, using too many REPEATS and function calls may eat stack space quickly (it's not a very OPTIMIZED interpreter...). All input is converted to lowercase, so case is unimportant.

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.

to triangle
        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]
to ctrsquare
        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 > logo.c
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.