Team Sixteen/FinalPaper

From Maslab 2007

Jump to: navigation, search

Contents

Overall Strategy



As a team with limited resources (three freshmen, one clueless about coding), our goal was to complete a robot in general. So we kept things simple, and a simple physical robot gave us plenty of time for testing the code. As it turned out, this early decision to keep things simple was our team's key to um... success. We devoted a significant amount of time to testing possible scenarios, and it payed off. Our strategy was rather simple: we would start the round by scanning in a circle for red balls. If the bot saw a ball, it would go for it. If not, it would proceed to wall following until it saw a ball or a goal. However, our code ensured that the bot would go for a yellow goal only if it had at least two balls in possession. Likewise, it would not go for balls once it had seven in possession (the maximum capacity of the robot). Wall following allowed for exploration of the playing field with acceptable efficiency, while not being overly complex or computationally intensive. Our code also had provisions that would tell it to change which wall it was following - so as to allow for maximum exploration of the playing field.


Mechanical Design



Our initial brainstorming session resulted in about five design ideas for ball collecting, including an Archimedes' screw, the kind of mechanism used in tennis ball pitchers, conveyor belts, and spinning wheels to suck balls in and out. At the end of the “meeting” we quasi-agreed on a three part system consisting of a one-way gate/shovel combo feeding the ball into an Archimedes' screw, and finally storing the balls on a blocked incline plane. That was that. However, I'm really glad we came to our senses the next day, when we ditched the worm gear and plane in favor of a far simpler design. We kept the gate idea, but modified it so that it was controlled via servo to open and close the gate. To store the balls, we decided to trap the balls between the floor and vertical walls attached to the underside. We were all in agreement about one thing: the fewer moving parts the better. Remember we were (or rather, are) a team of freshmen who had often been told by evil-by-definition upperclassmen from other teams things like "Are you nuts... a team with only _freshmen_?" and our first priority was to make something that actually worked. (Well, may be it was not that bad... But you see, we have to grumble because tradition dictates that freshmen should consider upperclassmen to be intrinsically evil, just as uppertclassmen regard freshmen to be intrinsically clueless. My attitude will change when I become a sophomore. ;-) It is so uncool to add another parenthesis after a smiley, so I added this sentence.)

Having proper planning of mechanical design was always advantageous - we had even considered stuff like height of screw heads and it paid off because we _never_ had to rebuild anything because holes were not lining up or something stupid like that. This made it possible for us to have a completely built final robot ready in two weeks and we could extensively test and tweak code and hardware because of that.


For our chassis, we purchased and used 1/4” plexiglass from Central Machine Shop. Our pegbot ended up being double storied because we oriented it diagonally and were too lazy to try fitting everything neatly on one board, and this fluke design grew on us for the final bot. The sturdier battery and computer lives on the first story, with wires feeding through a central hole to the more delicate orcBoard, orcPad, sensors, and camera on the top floor. The whole chassis is circular with the front side cut flat to allow for our original idea of banging the bot into the goal to straighten itself for alignment (later, this changed due to a programming decision).


As for the gate, I tinkered in the shop for a few hours before realizing I could simplify everything. Initially I played around with attaching wheels to the servo with a fixed length of string connecting the wheel and a point on the gate. After I had made three cute wheels with funky drilling for fitting, what Sarang said days ago made sense: the hinge would not fall back on its own after the string was let out because it didn't weigh enough. Later, after plenty of WD40, the gate fell by itself, but was far from reliable. Went for the rod mechanism which would do the same thing, except it would actually push the gate back down. We used rod that we found in a bin, later simplified the borrowed rod mechanism for single piece of bent wire that hooks under the gate (using some funky bends).


The walls were made with *brass* sheet metal and bent by hand to fit properly under the chassis of the robot. So shiny. Copper spray paint on wheels. Shiny shiny.


For our sensors, we used the camera and short-range IR sensors. Both were mounted on the top layer by velcro (to allow us to make minor adjustments to camera and IR sensor angle, while remaining reasonably secure). We had two IR sensors facing forward and an additional two angled to the sides. The side-facing IR sensors were used primarily for wall following, while the forward-facing IR sensors were used to align properly with the goal during the robot's scoring routine.

Although we had originally planned to use bump sensors to detect when the robot was stuck, a gyro to allow precise turning, and some form of odometry, we found ourselves with no necessity for these things. Arguably, they would have been nice to use, but we decided to spend our time perfecting the simple system we designed rather than implement a more complex system poorly. In the end, we ended up employing a software solution to detect when the robot was stuck.

Software Design



For the software side of the robot, we decided early on that mapping the playing field, while certainly an elegant solution, was simply an unreasonable goal for us. We soon decided that a finite state machine was the best choice given our (limited) coding experience. Also, we decided that a multi-threaded program was in our future, as this would allow us to be continuously processing incoming images and updating sensor data.


Visuals Thread

All the image processing of the robot was handled in the Visuals thread. Ball and goal detection was done in RGB colorspace (we found this to be both more reliable as well as less processor-hungry than HSV colorspace) by calculating the ratio of red, green, and blue values of a certain pixel. If these ratios fell within defined thresholds, we considered the pixel red, or yellow, as the case may be--(if R/G > threshold && R/B > threshold && not too white && not too black then pixel is red). The 'not too white or too black' part is essential because colors close to white / black can have large R/G and R/B ratios and still not be the red we want. We spent about an hour and a half tinkering with the thresholds before we settled on our final value. We never touched the thresholds again--that's how reliable we found RGB colorspace to be. Another thing to note is that this worked well in 26-100 as well as in the lab. Changing light conditions was _never_ an issue. We had initially planned to put a light on our robot to control lighting, but we dropped it when we realized that RGB ratios were doing the trick well.

For both ball and goal detection, a simple center-of-mass calculation was performed to determine the position of the object in question. We found that we did not need to worry about multiple balls, since once the robot got close enough to a single ball, the center-of-mass of all the red pixels in the frame would be so far weighted to the nearest ball, that the robot performed as if it only saw the closest ball. Similarly, for goal detection, we found that a center-of-mass calculation was "good enough" to provide reasonable, reliable results.

We did not attempt to do blue line filtering because we thought of that as something that wasted CPU cycles. Yes, we tend to underestimate the power of our robot's computer. We positioned our camera and angled it in such a way that it could (physically) not see anything above the blue line. This is not a bad idea because after playing around a bit with the camera, we could find a position that allowed us to identify balls were as close as 8 inches as well as those that were as far as 8 feet, which we feel is a fairly good field of vision if we consider the size of the playing field.

Note: We later realized that the processor could have handled the extra processing required for dealing with multiple balls in a specialized manner. Heck, if it can handle diffing images and rendering derived images, it can surely deal with multiple balls. However we did not change our code because why would you want to change something that seems to be working? Even we "clueless" freshmen are not that stupid, you know... Really.

The visuals thread was also responsible for determining if the robot was stuck. We implemented a function provided by the Java Advanced Imaging (JAI) toolkit--the subtract method. Every ten frames, we subtracted the current frame from the one remembered from ten frames ago. If the resulting "difference" image showed little movement, we considered the robot stuck. We found this to be extremely reliable--in our hours of testing, we never encountered a false positive nor a false negative. In reality, this solution ended up being better than bump sensors, in which you must rely on one of the bump sensors actually being triggered. Unless you liberally coat all the external surfaces of the robot with bump sensors, the imaging solution will be more reliable. We wish to note that thresholds for this can be adjusted so that vibrations/slight 'non real' motions of the robot can all be differenciated from real motion.


Sensors Thread

The sensors thread had one simple job--continuously update all the sensor data. Originally, we expected this to include short- and long-range IR, a gyro, quad-phase encoders, and bump sensors. After all was said and done, we only used four short-range IR sensors, nothing else - no gyro, no quad-phase encoders etc. This thread updated their readings every 50 milliseconds. It did nothing more, nothing less.


Finite state machine arbiter thread

This thread held the bulk of the code and the majority of the "intelligence" of the robot. The possible states available to the robot were "wander", "retrieve red ball", and "score goal". Each of these states consisted of multiple actions. For example, in the "retrieve red ball" state, the robot would recursively center the red ball in the image and drive forward, until it got close, at which point it would open the gate and drive over the ball. We measured the maximum possible apparent area of a ball and used it along with the co-ordinates of the CM of red stuff to set some thresholds on when our gate should open, for how much time it should remain open etc. (This is necessary because after the ball gets too close, its area begins to decrease because it starts moving out of the robot's field of vision. Thus, the maximum detected apparent area of the ball is useful in estimating for how much time the ball will be in the robot's field of vision and how accurately should the robot align itself.) Scoring goals included centering the goal in the image and trying to approach it head-on, using a combination of strafing and aligning movements. and checking to see if the front IR sensors showed significant differences in their readings--this would indicate the robot was approaching the goal from and angle, and would adjust appropriately. The origin of this was in our idea of ramming (quite literally!) into the goal, raising motor speed to full thus leading to perfect ;-) aligning with the goal. Later on, we did the ramming virtually, with IR sensors. Essentially the same thing, but looks less stupid.

We also used IR for obstacle avoidance to avoid bumping into something while driving straight, say towards a ball. All this was with well defined levels of control within the code, so that we did not end up with situations with opposite instructions being sent to the motors at the same time/successively. For example, if there is a wall blocking only a part of the robot, and if the robot sees a ball on the other side, the camera will tell the robot to go straight while the IR will say do not. This will result in the robot moving ahead a bit, backing off again, then moving ahead again (because it is now not too close to the wall) and this will continue, leading to non-real motion, which means that effectively, the robot is stuck.

It is good to think of such situations before writing code and taking care of them in the very first piece of code. Also, it is good to have each method / loop / class /whatever begin with a line which outputs to BotClient stuff like "Finished followLWall. Executing alignBot. IR readings are:..." etc. It helps a lot in debugging / finding that small logical error which caused your robot to execute non-real motion etc.

We also put constraints on the availability of the states. For example, the robot would simply ignore a goal if it had fewer than two balls in its possession. Similarly, it would ignore red balls if it was already at maximum capacity (seven balls). This was designed to prevent unwanted and inefficient behavior.


Results



We did better than we had expected us to do. We scored 12 points (two goals, and four possessions), and if given an extra 30 seconds might have been able to score the four more goals off the balls the bot had in possession. Nonetheless, it was a good run. The robot displayed no surprising behavior, and performed as it had for the previous several days of testing. This is due in large part to the fact that we changed very little about the robot in the final days, and only tweaked thresholds whenever necessary.

Though we say we did better than we had expected to, we had a reason to believe that our robot could put up a decent performance. What we mean is we had expected a comparable score, but exceeded expectations place-wise. (Teams 1 and 14 were tied in the first place with 19 points and we were next.)


Pictures



Image:DSC00309 (Custom).JPG


Image:DSC00310 (Custom).JPG


Image:DSC00314 (Custom).JPG


For Maslab 2008


Keep your physical design simple or at least feasible. It was greatly to our advantage to have most of the final robot assembled within the first two weeks.

Test as often as possible. (After the actual contest, when we were to show demos of our robot to the general public to watch more closely, Sarang's instinctive, instantaneous reaction was "Shall we have a test run before that?")


Upload the correct version of the code onto the bot, and if you add a classpath declaration to the .bash_profile, make sure that the correct version is running (that is, the version as defined in the classpath). Really, annoying things like that do happen.

Make sure your loops aren't infinite if you don't want them to be and make sure that ou have timeouts for everything.

18.02A with maslab is fine. You may have to start psets at 1AM - 10 hours before they are due; but if that's when you normally start them anyways, you will feel absolutely no difference in your performance in 18.02A. The key is to not freak out before hand - it is manageable. Out of the three of us, two were taking 18.02A. With the co-operation of our third teammate (Andrew) and a plan which allowed the other two to skip alternate lectures - taking detailed notes so that anyone else can understand them, we both were fine. (Stephanie and Sarang)

Being freshmen is fine. :)

Be aware that--though extremely fun--all-nighters in the lab are not necessarily very productive. After a full ten hours of working on your robot during the day, you may be better off to take a break and get some sleep.

Avoid using glue. Proper mounts using bolts and rivets are awesome and are the way to go.

Nothing is intrinsically awesome. If it works, it is. If it does not, it is not. Do not be overly attached to an idea or be caught in the false awesomeness of something that doesn't work.


Make sure that everyone is fully committed from the start. MASLAB is a huge commitment (temporally, physically, emotionally); everybody must be sure they are up to the task. While deciding your team, make sure that your teammates are excited about maslab and they rwally want to do it, because they consider it to be fun.

Do not hesitate to help other people and to ask for help. Remember that maslab is fun. Do it for fun. Winning comes later.

HAVE FUN and GOOD LUCK! Thank you for reading our paper!