Team #20: Space Oddity

MARVIN: Welcome to my home page. I hope you like it. Though you probably won't. This will all end in tears, I just know it.

Electronics


Comments

We originally designed the front chain bumper as an improvement on simple corner sensors in order to detect pressure at any point along the front of our robot. It soon became apparent, however, that in most cases the robot was more likely to encounter obstacles at an angle rather than parallel to its drive axis. We later added whisker-style sensors on the left and right, positioned so as to detect collisions which would otherwise be absorbed by the bumper's mounting frame. Smooth 1x8 plates were glued to the whiskers to extend their reach, a connection which proved both strong and flexible enough to survive repeated impacts. Bump sensors were attached with a combination of foam tape and hot glue. The last touch sensor, in the rear of the robot, has lego plates glued across it to widen its area of sensitivity and ensure that it would detect the skunk ball, triggering the rear grabber mechanism to close.

The three floor-facing IR LED/phototransistor pairs were angled so as to maximize the specular reflection from the emitter onto the detector at roughly table level. We recalibrated these sensors every round by placing the robot on white and black, then used a threshold at the averege of the two measurements to decide which color was visible in each detector in the starting position. In practice, white would always produce readings around 40 and black would always produce readings around 700-800. These sensors were highly reliable.

The gyroscope was very challenging to use. We modified ours to remove the injected noise, finding that there were still a few millivolts of noise even without the 555 timer oscillating. It seemed like the noise was sufficient We also rewrote the gyro integration code in JoyOS to use integer math rather than floating point, removing the issue of accuracy loss which we observed during calibration, and to measure time in microseconds rather than milliseconds, improving the device's stability during multithreaded operation. We added a phase to usetup calibration whereby the operator could manually dial in a correction to the gyroscope zero-offset via the frob knob. This seemed to work well, but during the excitement of the actual contest, it was difficult to tune accurately. The screen continuously displayed delta theta as the knob was adjusted, so it was simply a matter of zeroing the display and pressing "go". Ultimately, it proved too difficult to avoid accumulation of gyroscope error during periods of heavy motor load, and so the gyroscope was only used for turning in place, a case for which the shaft encoders were too difficult to manage.

The servo and drive motors worked beautifully. We calibrated the dispensor's "up" and "down" positions during usetup via the frob knob since the chain link between the servo and the actuator was prone to slippage. The drive motors were driven according to a constant forward speed and a "turn" parameter proportional to the difference between accumulated left encoder counts and accumulated right encoder counts. The rear claw motor was theoretically capable of capturing the skunk ball, but we ran out of time to debug this behavior. The claw gear train was motor -> 16-tooth gear -> chain -> 16-tooth gear -> worm gear -> 40-tooth gear -> claw. This configuration was extremely fast and had just barely enough torque to shut the claw. It tended to sieze at the extremes of travel, requiring manual adjustment before the motor could turn again. This was mainly due to the high friction inherent in the worm drive, but was actually desirable for holding the skunk ball firmly in place. The main drive trains were geared at 45:1, with a gear branching off for the shaft encoders at 90 beam-breaks per wheel-revolution. This gave us plenty of torque for navigation, and excellent speed. Substantial differences in base motor speed were noted between the left and right drives. This was attributed to variability in motor position due to human error in foam tape application, and as a result some grinding between the motor's 8-tooth gear and a nearby structural beam. The gear was modified slightly to reduce grinding by lathing it with a knife while the motor was running. The remaining difference was easily corrected using the shaft encoders.

Some code was written to orient towards the skunk ball using the distance sensor, but without time for testing this code was ultimately not used. The procedure called for the robot to approach the skunk backwards, occasionally stopping, turning 20 degrees to the side, and then turning in the opposite direction until the distance sensor registered a sharp jump and then a decline corresponding to passing the center of the skunk ball.

A substantial amount of time went into the optical mouse sensor. We started by disassembling a mouse we already owned and examining the sensor chip. After some research, it was determined that the chip was an Agilent ADNS-3060 instead marked "2020". After obtaining a datasheet for the part, we carefully examined the mouse circuit board and severed the connections between the optical sensor and the USB controller. The relevant connections were the four-pin SPI bus (MOSI, MISO, SCK, NCS) and the two additional pins NPD and RESET. One teammember had prior experience with a very similar data bus, and we were confident that we would be able to implement the required interface to the HappyBoard. We learned that the HappyBoard still has solder pads for the RF part used for location last year, and that this part was controlled by the AVR via SPI, so we had a perfect place to attach the first four pins. On Greg Belote's recommendation, we used the AVR's unused I2C port to control the other two pins. Holes were pre-drilled into the HappyBoard for an I2C header, so we just soldered on a 4-pin female header at that location. Some problems were encountered later on with these pins being reset by the LCD driver. It turned out that the LCD driver overwrites the entire PORTD register rather than changing only the high six bits (those associated with the actual LCD), so we corrected it.

The ADNS-3060 is a 3.6V part, while the mouse LED, the USB bus, and the USB controller chip run at 5V. The ATmega128 on the HappyBoard runs at 3.6V, but the sensor power rails are at +5V. To keep things simple, we soldered VCC and GND wires to the mouse's USB port and plugged them into a sensor port on the HappyBoard. The mouse's on-board regulator produced 3.6V for the optical sensor, the LED used the full 5V, and digital control signals between the optical sensor and the AVR did not require voltage dividers, so everyone was happy, and the rest was software. After we had tracked down the LCD driver bug mentioned above, the mouse powered on and the red LED shone whenever the RESET and NPD lines were set appropriately. Success!

Adapting code from existing JoyOS device drivers produced a prototype driver that clearly didn't work. It took a bit of poking around with the oscilloscope to determine the cause: first, the SPI clock signal sense had to be inverted and the clock phase had to be altered (both easily-accesible configuration bits of the AVR's SPI port); and second, delays had to be inserted between sending the "read" command to the ADNS-3060 and retrieving its response. Once these changes were made, we got X and Y data from the mouse, as well as dots-per-inch info and diagnostic data.

A test "drag" of the mouse across the contest table for calibration was our first indication that all was not well. Instead of the correct value of ~100 inches, the mouse counted only 63. We figured that linear calibration should be able to take care of the difference. However, our robot chassis was already built, and we discovered that keeping the mouse flush with the surface without creating a lot of drag was going to be problematic. To make matters worse, it appeared for a time that the addition of balsa-wood strips to the table would force us to raise the mouse up a few millimeters - far enough to make the imaging sensor stop working. At the same time, we were struggling with gyroscope drift issues exacerbated by current draw from the motors and timing variations introduced by adding a mouse-tracking thread. Several days of intense frustration and continuous effort yielded only a routine that could turn to a specified angle accurately and a drive-straight routine that waddled like a penguin. The contest date was approaching, and we still had no way to implement or test our strategy.

After many false starts, we finally decided to add the shaft encoders. Within a day or two, we got the robot to drive straight, but we were now struggling with making accurate turns. The day of the impounding, we realized that we could use the old (working) turn routine with the new (working) drive straight routine to put together a qualifying program. To remove the effects of gyro drifts over long periods of time, we compute all of our turns as if our orientation had not changed at all since the end of the last turn. This meant that our robot slowly lost track of its orientation during the round as it bumped into walls and other robots. There was no time to get the mouse debugged and calibrated, so, to our great chagrin, we ended up removing it from our robot.


Construction

Chassis

We started with a chassis design very similar to that in Assignment 1. After a brief experiment with a larger design, we decided to go back to a small, heavily-reinforced, wide-body structure. With larger wheels doubled up for traction and a single caster in the back (after much experimentation with skids), we had a very sturdy robot. Each new addition was carefully reinforced. The claw was a bit of a challenge since it had an odd width instead of an even width due to the constraints of the 40-tooth gears. We ended up attaching it satisfactorally with a pair of LEGO rods passing through two pairs of beams with yellow spacers in between. The bumper mounts were supported and made rigid by locking together the two 24-tooth geared axles. This put them under some compression. The drive trains were designed so that nothing would rattle or come loose over time, and they held up very well.

Where vertical bracing was not feasible, we found diagonal bracing using the Pythagorean Theorem extremely useful.

The battery and HappyBoard were held in place by black bent beams and pegs in a symmetric and rear-heavy position. This kept weight on the caster to prevent the robot from tipping, and kept the drag on the left and right sides even. Later additions, like the ball dispenser, shaft encoders, and whiskers, were attached in a more ad-hoc fashion. Typically, we would foam-tape and hot-glue sensors to a 2 x 4 plate and then attach that plate to the desired location. If a sensor were misplaced, only the 2 x 4 plate had to be removed, rather than prying the sensor off the robot chassis. Perhaps the most precarious attachment was the servo, which was simply foam-taped to a 6 x 6 plate. There were instances in which the servo would come off, causing the chain link to fall off and altering the position of the servo and releasing implement. When disconnection occurred (which was only a few times), the servo and 24-tooth gear had to be reset. In the end our robot was easily able to smack into walls or other robots (or be smacked into) without any significant harm. Two vertical beams anchored deep in the chassis provided a place to wrap extra wire length as well as a structural support for the HappyBoard and the ball dispensor. We were very pleased with our robot's structural performance. It experienced bone-crushing collisions yet escaped injury. Perhaps the years of self-pity that Marvin the Manically Depressed Robot inflicted on himself built up an extra tough exterior.

We drilled holes through the mouse housing of the correct diameter to pop in black pegs and bind the mouse to LEGO beams. These beams were then supported on deep stacks of foam tape (as much as ~1/3 inch deep) to serve as shock absorbers and to keep the mouse on the table surface. This idea was the suggestion of a TA, as was the use of meshing 24-tooth gears to anchor the ends of the bumper chain.

The front bumper was structurally augmented with wire. This kept it from going anywhere if it broke, which happened occasionally when handling the robot. We hoped that the wire would also keep the bumper usable during a match if it broke, but in practice the bumper never worked right if the chain was broken.

Strategy

Original
  1. Pause in front of opponent's 4-point bin
  2. Capture Skunk Ball
  3. Go to our 4-point bin
  4. Unload balls
  5. Proceed to opponent's square.

By bringing our table score to the nearest multiple-of-four to the target score, we were guaranteed not to accumulate more than 2 penalty points (since no number is more than 2 away from the nearest multiple of four). Holding the skunk ball in the opponent's starting square brings their penalty score up to at least 4, so we would win the match. Since our robot depends on speed, its ability to reach the skunk ball before the other robot would be an excellent heuristic for whether it is in fact faster than that robot. Since this is our first action in the round, it will allow us to react if we are out-maneuvered by e.g. scoring more precisely and attempting to keep our starting square clear of the skunk ball.

Final
  1. Dial in target bin.
  2. Go to our 2 point bin and dump x number of balls.
  3. Go to our 4 point bin and dump y number of balls.
  4. Go to our 1 point bin and dump z number of balls.
  5. 2x + 4y + 1z = target score

We adopted a new scoring strategy because we were unable to create and debug a program to execute the old strategy in time for the impounding. We had many good ideas that did not make it in the end. The original plan of dead reckoning via the gyroscope and optical mouse sensor was replaced by the use of shaft encoders. Distressingly, the shaft encoders did a better job of going straight after a few hours' tinkering than the gyroscope and optical mouse combo did in a week. The control system was simply too complicated to tune. The time constraints of team members, the limitations of the electronic components, and the magnitude of the undertaking led to the disintegration of the original plan. Even after the switch to shaft encoders, we struggled for several hours trying to tune a PID control system. Four hours before impound, Team Space Oddity realized that simpler equals better. A minimalist function for driving straight was created, and the claw, back bump sensor, side bumpers, and distance sensor were forsaken. The final product was Marvin the Manically Depressed Robot. We made these decisions too late to debug our code for the competition, and our robot was only marginally working when it was impounded late Wednesday night.

Concluding Remarks

It was a tough four weeks, but we survived with nothing worse than a pain in all the diodes down our left legs. What began as an interesting excursion into the world of HappyBoard and LEGO ended at the impact point between two onrushing trains. The abandoned plans of the optical mouse and gyro drained a lot of time and energy, but in the end, we were able to seed relatively well and hold our heads high during the competition. We would like to thank our parents for their unwavering support. We would also like to thank our Organizer and TA Bin and Rajeev for being so very patient with us. We would like to extend our thanks to the entire 6.270 staff for a great experience, a helpful environment, a constructive atmosphere, and for the new friends we made.

I would like to thank my partner Peter for reflecting Buddha's patience with me as I filled my other obligations as a fraternity pledge. The stressful combination of both left me harried, but I have come away with a greater appreciation for the essential things in life, namely Anna's burritos and programming languages. - Sun

I would like to thank Sun for staying patient with me when contrary circumstances were driving me batty and technical challenges stymied our progress. He never refused to offer his help, and never lost his temper. - Peter