We’re pretty sure we violated every single principle of traditional good project management in existence. We formed a team of all math majors/double majors, we all lived in the same floor of the same
dorm, we were all either freshmen or sophomores, we took longer than the recommended time to complete our robot’s mechanical construction, we scored 0 points on the Mock Contest held three days before the real one, and we made many major revisions to our software in the last 48 hours before the robot impounding deadline as opposed to debugging existing code. Yet when the contest day came, our robot, Archimedes Pi, somehow scored the most points.
Early on, we decided we wanted to score field goals—a reasonable decision, as it would yield the most points and, with a lifting device, ought to be just as easy as going through the mousehole, but the decision that would alter our destiny the most drastically. We were also influenced by our lack of mechanical experience to try to design something that would not be too mechanically complicated; gripping arms and the like were right out. We were also ambitious enough to want to map the playing field in the exploration round, though we ran out of time to implement it.

A rectangular platform, supported by four pillars at its corners, somewhat more than 12 inches above the ground, is tilted so that balls roll toward its front. It has a capacity of about 10 to 12 balls, assuming random packing, and does not funnel down at its opening because we feared that balls might become jammed against each other.
A lot of teams independently thought of the Archimedes’ screw to lift balls since it’s a compact mechanism and it can be run continuously without giving attention to individual balls. Only one other team besides us actually implemented an Archimedes’ screw since it is hard to make the actual screw and there are difficulties loading and unloading balls. We made our loading mechanism robust by building two screws, which are mounted at the rear of the robot. We constructed the screws using the amazing power of low-tech tools: since helices are geodesics on a cylinder, we used a string to measure around a PVC pipe and traced the pipe so we could cut it with a simple hacksaw. We succeeded in cutting two screws of opposite chirality, each about 15 inches long.

The Archimedes Screws are connected to two 18" shafts by a series of bolts. The bolts actually wound up being troublesome to us because if they extend too far through the shaft they can lead to jamming; altogether, too much time was spent on readjusting these bolts. The bottom of each shaft has a small hole cut into it and a screw sticks up from the bottom of the casing, sliding into this hole. The bottom of the casing rests 1/4"-3/8" above the floor. The center of the bottom casing is hollowed out and a metal strip lies there which gives the ball its initial lift. A pole is attached to the back center of the casing, and as the ball travels up it is always adjacent to the pole. Gears are on the top of the casing and a gear train leads to the side where a high-torque motor is attached with an inverted universal joint. The casing is mounted on the back of the wooden base, behind the wheels. It would have looked cooler in all of the pictures if we had made our ball storage area and all sides of the screw casing out of polycarbonate, but everything was already cut well and working fine and time was an issue so we only made the casing back see-through and stuck with our wooden prototypes for the rest. Special thanks to Ross Hatton for giving us good mechanical engineering input on how to make the gears. We were a bunch of mathematicians who hadn’t realised that gears involved attention when we made our design.
The bottom “gate” consists of duct tape covering PVC foam held up by reinforced wire attached to joints that pivot one way only. The underside of our robot guides balls to the rear screw assembly. The gate rests between two wheels that are giant ball bearings (the robot has rear-wheel drive).
The top gate is hinged at the bottom and has a servo mounted to a piece of wood that rotates pulling a piece of wire reinforced with hollow copper cylinder to open and close the gate. The hinged front wall swings open. We actually stop just in front of the field goal and swing the hinge open rather than running all the way up against the mouse hole wall so that we have a larger margin of error allowed for our goal alignment (even though our field goal aligning algorithm gave us remarkably good results as long as the field goal was visible).
We have an IR sensor mounted 9 inches above the ground on a front pillar on each side of the bot, facing forward, to provide information about the nearness of walls; it is at that height to avoid being confused by the mouseholes.
Our camera was intentionally placed at the height of blue tick marks, about 9 inches above the ground, so that we could ignore anything above the horizon. The disadvantages were having to tilt the camera down to see anything useful, which we compensated for (see More Math), and even then we were unable to see anything between the front of the bot and about 1 foot futher away.
We took pictures with our camera in the appropriate playing fields (using the mock contests to get pictures in the lighting of 26-100) of various features and separated the colors in each picture into one of 7 designations: white (walls), blue (wall tops and tick marks), yellow (goals), red (balls), black (barcodes), green (barcodes), and floor-grey. Using random distortions to run this through a “voting” program yielded a 16×16×16 lookup table, mapping the most significant bits of any color to one of these 7 colors. While this training method was somewhat time-consuming, it yielded fairly good and very fast results as long as the lighting conditions weren’t too different from that of the sampled pictures; the lab and 26-100 had similar enough lighting for our purposes.
We also used some trigonometry to map pixel coordinates in camera images to coordinates in the reference frame of the bot, with x axis horizontal, y axis depth, and z axis vertical, with the bot at the origin facing the positive y axis. Eventually, using odometry and the knowledge of our current position and orientation contained therein, we turned these into absolute positions, with the origin at the start position.
Early on, we decided that if at all possible, we should be efficient in driving the bot. Better than attempting to turn precisely and drive exactly straight was driving in a continuous arc, using feedback from the camera to improve our course as we approached. The arc driving algorithm is used to both chomp balls and score goals.
When we see a goal we go for it if (0) we think we have at least 6 balls, (1) we think we have at least 4 balls and there are 105 or fewer seconds remaining, (2) we think we have at least 1 ball and there are 75 or fewer seconds remaining, or (3) there are 30 or fewer seconds remaining. To dock we find a point 27 inches from the front of the goal, drive in an arc to it, turn toward the goal, and then drive in an arc toward the goal, using feedback from the IR sensors when it gets close enough. Our front gate is 7 inches wide, and the goal posts are 10 inches wide. We’ve programmed the robot so that it stops with enough clearance that the front of the front gate stops just before the goal posts rather than sticking out between them (see picture in Results section). This way we allow for error in the docking procedure in position and angle. The hinges, as an unexpected benefit, also wind up funneling balls to the center.
We didn’t finish docking until Wednesday at 9pm of the last week (robots were called for the impounding deadline started Thursday at 5, which was 6:30 when they came to us) and during the day Wednesday we were a bit uneasy that we wouldn’t have time to debug all of our existing code because we were writing new procedures, but getting good docking was absolutely essential in the contest. You can’t win with just possession points, so we figured that even if we had a less than 50% chance of it working that it was the right thing to go for. It turned out that our docking code worked beautifully so we were happy.
We set our time cutoffs somewhat arbitrarily, but we’re glad that we did it this way. A couple other teams missed their chance to dock early because they wanted to wait until closer to the end and dock once (which theoretically is better) and got single digit scores when they really had nice robots. Given the facts that (1) the need for the mechanical construction of complex lifting devices this year slowed all the teams down considerably and (2) there was a three minute time limit this year, not a four minute limit, docking when you had just a few balls and sealing your position instead of being greedy actually made a lot of sense this year even though I would have been reluctant to do so at first.
We kept track of our bot’s location using an Extended Kalman Filter on out data from the wheel encoders and the gyro. We assumed that all of the error from the encoders came from the encoders being at some fractional number of ticks of which we know only the integer part (though we later increased this assumed error after discovering that our encoders were highly biased towards even values). We kept track of the variables x and y for position, th for orientation, two variables el and er for the fractional parts on our left and right encoders, and two variables go and gr which tracked the calibration error of the gyro.
We realized during the mock contests that the shadows cast by the lights on the playing field make it impossible for our camera to tell the walls apart from the floor, significantly dampening our interest in trying to map the playing field. Given that we nearly ran out of time as it is, maybe that’s a good thing. But hopefully, next year’s floor will have a more distinguishable color.
We make no effort to use the mapping round or to record the long-term positions of objects. We did use our odometry and knowledge of positions in 3-space to keep track of the absolute position of our bot, as well as the ball or goal we’re tracking.
We used our odometry to come up with a wandering program that attempts to explore new areas without using direct wall following. We imagined our robot dropping invisible “force fields” at locations where it has been and at locations where it detected walls. We programmed the robot to travel in the arc that causes the direction that the front of the robot travels in to be in the same direction as the gradient of the total force field at that point, albeit giving precedence to avoiding walls. We didn’t have enough time to fully understand the ideas needed to make this method work optimally, but noticed a few things. For example, we needed to implement a forward bias to prevent a problem that caused our robot to get stuck in a loop of travelling back and forth. We also needed to make the strength of the force fields decay exponentially with time to prevent excessive buildup and to compensate for inaccurate odometry. We programmed all of the force field stuff in the last 24 hours before the Thursday night impounding deadline. We wish we could have tweaked the parameters a bit more since there are situations where we know that the robot doesn’t do as well, but the robot did its job on contest day.
Our robot spits out text messages and channel names that are all titles of puzzles, taken from the
2005 MIT Mystery Hunt. We have a vector graphics rendering of our local map which shows the robot’s orientation, field of view, IR sensor ranges, spotted goals or balls, and force fields. We also mark many of these items on our video channel when they’re in view.
On contest day, our USBMOD had several pins break off after we tried to hotglue it into place. After some onerous minutes of last-minute debugging, the USBMOD was replaced and all was well.
Our robot did not use its exploration round. In the scoring round, it wandered through only about the half of the playing field in which it started, picking up balls as it went along. It was fortunate that as it picked up the 5th ball, a goal was directly in its view. The field goal docking mechanism worked successfully, as did the waiting until 25 seconds after the last ball was picked up; the last ball escaped the shaft and rolled into the goal just before the gate closed. Then, less than 30 seconds remained in the round; the bot had already picked up all the nearby balls and scored no more points. This total of 25 points wound up being the high score. MASLab was a lot of fun. We really didn’t expect to win.

By Murphy’s Law, things will break at the last minute, so do as few things as possible at the last minute. But for the next to last minute, do a lot:
email us all or obtain our individual email addresses by the usual MIT ways. Just don’t expect a fast reply if you email us during Mystery Hunt…