Friday, February 1, 2008

SHOOT WE DONT PLAY!!!!


Yeah, we dont play!!!!




Team 10 after the tournament. From left: Dave Reens, Allen Yin, and Brandon Lew, with Allen holding Great Wall of Connecticut.


Here's a video of Great Wall performing:

It was an almost ideal performance by Great Wall (versus the placebot horse), too bad it didn't turn and score...thus lost.

video

The Competition and Robot Design

6.270 is a hands-on, learn-by-doing class open only to MIT students, in which participants design and build an autonomous robot that will play in a competition at the end of January. (from 6.270 website: http://web.mit.edu/6.270/www/)

This year's game is called the Oregon Trail (with a kinda lame story behind the title). Essentially, in each 60 seconds round, each robot starts with 6 balls and tries to shoot an appropriate number of balls into appropriate bins (3 bins total, with 1, 2, and 4 points value respectively) to achieve a desired point value. There's also a skunk ball that one robot can push to the other robot's starting zone to subtract point from its opponent.

All of the robots are constructed from lego pieces, motors, servos, LEDs, IRs, Gyros, Bump-sensors, encoders/breakbeam sensors, and sharp-distance sensors, and controlled by the microcontroller, not so happy "Happyboard", a custome MIT 6.270 board.


Below are some of the legos we got. The red vehicle-like thing was our first assignment- car of awesomeness.
In the second picture is our "unique" (as far as we know) way of organizing the lego pieces. Eventually entropy took over and we no longer have them organized anymore.


---------------------------------------------------------------------------------------------------------------------------------------- The Robot

Drivetrain:We've made a few differnt drivetrains, and eventually settled on this one:



It's a fairly symmetric drivetrain, with lots of braces near the gearboxes. The gear ratio is 45:1, one motor per side (which we eventually changed to two motors b/c the lack of torque later on). You may also notice that we dont have many long 16-length pieces in the frame. Thats because we've used most of them on our

Great Wall:














The picture at right's Dave Reens '11 holding the compressed form of the wall (his proud brain child). The wall's constructed by connecting many 16-length pieces together, similar to the structure of those toy boxing gloves one see in Looney Toons, with axels going through every pair. Then rubberbands are tied onto the axels, and other obstacles (like those yellow plates) are attached on as well. When compressed (like in the left), the rubberbands are stretched and thus store potential energy. During the match, our servo would hold the wall in until the release, at which point all potential energy is released, propelling the wall to the 2-point bin of our opponent on the other side of the court.
The picture above left shows the released version of the wall on the court (with the tether in the end attached to our robot).
----------------------------------------------------------------------------------------------------------------------------------------
Strategy/Code:

We have an incredibly simple but if executed consistently, effective strategy:
our robot starts at either the left (3 white squares with 1 black square), or right (3 black squares with 1 white square) corner of the court. At the beginning of each match, we figure out our position using three pairs of IR sensors directed at the board and orient ourself to face the 2-point bin of our opponent across the court (code's below:

//Sidedness: true implies the left side, when standing on the short side near both robots. //This is also the white square starting position. bool MIRROR; //Starting position /*Variable pos can take four values: *0: forward *1: outward *2: backward *3: inward */ uint8_t POSITION;

//Sets POSITION and MIRROR variables.
void orient(void)
{

uint8_t fl = ((analog_read(FRONT_LEFT)<100)?1:0); fr =" ((analog_read(FRONT_RIGHT)<100)?1:0);" br =" ((analog_read(BACK_RIGHT)<100)?1:0);" mirror =" (fl+fr+br">=2); //true if two+ are white

printf("\n%s",(MIRROR?"white":"black"));

if(MIRROR)
{
if(fl==0) //front_left is black
POSITION = 3; //inward
else if(fr==0)
POSITION = 0; //forward
else if(br==0)
POSITION = 1; //outward
else

POSITION = 2; //backward
} else {
if(fl==1) //front_left is white
POSITION = 0; //inward
else if(fr==1)
POSITION = 3; //inward

else if(br==1)
POSITION = 2; //backward
else
POSITION = 1; //outward
}

pause(500);
printf("\n%d",POSITION);
}

//turning function. Like others but based on the gyro.
void turn(int16_t deg,bool dir)
{

//reset doesn't work, but store starting values and track difference
uint16_t adjust_left = encoder_read(LEFT_ENCODER);
uint16_t adjust_right = encoder_read(RIGHT_ENCODER);

//encoder variables
uint16_t le = 0;

uint16_t re = 0;
int16_t error = 0;

//store starting degrees and measure with respect to this
int16_t starting_degrees = gyro_get_degrees();

//start motors moving slowly before we adjust for encoders
motor_set_vel(LEFT1,80*(dir?1:-1));
motor_set_vel(LEFT2,80*(dir?1:-1));
motor_set_vel(RIGHT1,90*(dir?-1:1));
motor_set_vel(RIGHT2,90*(dir?-1:1
));
pause(10);

//difference between starting degrees and current degrees
int16_t diff;

do{

//set diff, make sure its positive (cclock->gyro++)
diff = (starting_degrees - gyro_get_degrees())*(dir?1:-1);
diff = (diff<0?diff+360:diff); le =" encoder_read(LEFT_ENCODER)-adjust_left;" re =" encoder_read(RIGHT_ENCODER)-adjust_right;" error =" le" change =" (error">0?20:-20);

//keep it up.
motor_set_vel(LEFT1,(80-cha
nge)*(dir?1:-1));
motor_set_vel(LEFT2,(80-change)*(dir?1:-1));
motor_set_vel(RIGHT1,(90+chan
ge)*(dir?-1:1));
motor_set_vel(RIGHT2,(90+change)*(dir?-1:1));

}
while(diff<6>

Then we shoot the wall across by turning the servo holding it, which would enter and latch onto the 2-point bin, effectively trapping the other robot within its own corner.

We would then turn to be parallel to the longer wall near us (using the gyro mounted on the Happyboard), drive forward (rules says we cannot detach any part of the robot from itself, thus we connected the robot to the wall with a tether made from small links, which can be seen in the extended wall picture) a certain distance regulated by our two encoders mounted on each gearbox by specifying a specific encoder counts. At last, we turn at our own 2-point bin, and dump the balls from a hopper by gravity.

Our driving code:

//takes a distance and then drives based on it.
void drive(uint16_t distance)
{
uint16_t adjust_left = encoder_read
(LEFT_ENCODER);
uint16_t adjust_right = encoder_read(RIGHT_ENCODER);


//difference between encoder counts
int16_t error = 0;
uint16_t change = 0;
uint16_t count = 0;

motor_set_vel(LEFT1,-100);
motor_set_vel(LEFT2,-100);
motor_set_vel(RIGHT1,-100);

motor_set_vel(RIGHT2,-100);


//main loop; differentiates based on short and long distances
//long distance case. speed up to a given value,
//decrease when near to distance target.
while(encoder_read(LEFT_ENCO
DER)-adjust_left<10000)>e);
motor_set_vel(RIGHT2,-100-change);
error = encoder_read(LEFT_ENCODER) - encoder_read(RIGHT_ENCODER) - adjust_left + adjust_right;
change = (error<0?-5:5); i="2">


The bug that took us 10+ hours to figure out in this code was that we made the variable "error" an "uint" instead of "int", which caused our robot to drive in some sort of arc every time...be AWARE!!!!!















In the left picture above, our robot turns and accurately shoots the wall across the field, latching onto the 2-point bin.

In the right picture above, Great Wall sits at the corner before a round starts. Notice the compressed wall withing the robot. The blue-black box on top of the robot is the ball hopper, whose lower end can be opened and closed by a servo. The hopper's mounted high enough so the balls will roll and fall into the scoring bin over the field walls.

Also in the right picture, one can see the two motors protruding out of the gearboxes and the wires going up to the Happyboard.

----------------------------------------------------------------------------------------------------------------------------------------
Lessons Learned and Advices for Future 6.270-ers.

1) Plan Ahead!
All in all, we had a pretty solid robot and a fairly creative strategy. However, because of our poor planning, we did not start the real building process until the weekend before the competition. Furthermore, a finished robot's crucial to the testing of robot code, debugging takes an incredible amount of time (probably more than the actual building). We cannot stress more about the importance of planning ahead and actually following the plan (we had a timeline, but blew it off).

2) You're Not THAT Smart!
One of the reasons for our team's delayed efforts was that we thought it would be a piece of cake to design, build, and code a working lego robot. But clearly, we were wrong. Sure, we're all in MIT, but there are just so many things that can go wrong during those last hours of building: our gyroscope malfunctioned, happyboard malfunctioned, motor chips malfunctioned, IR sensors broke...you can never really predict that kind of events from happening.
When debugging code, always keep an open mind. Sometimes errors that one thinks he can never make can be his downfall (we're the perfect example).

3) Communicate!
Sure, everyone knows communication's important in teamwork, but we still forget that sometimes when caught up in exciting things. If, for example, the programmer's not updated in time with the design and strategy changes, it can really impede the team's progress. I spent 5 hours thinking and reading about multi-threading, and then after talking to Dave realized our strategy doesn't require that at all!

4) Always Have a Backup Plan!
You will always encounter unexpected situations that would render your original plan useless, be it a sudden diarrhea which prevents you from going to the lab in that last few hours, unexpected difficulty of an algorithm. Even the winning team had to change their original design after realizing the inconsistency of its original plan.
Our team spent 5+ hours writing a genuine PID control structure to drive straight, but it's nearly impossible to test and figure out the right constants for each component. Thus we fell back on constant adjustment (and many other methods along the way).

5) Sleep in the Lab!
It's very unfortunate that we never got to sleep (or work through the) the night before impounding...it could've been an awesome experience.





Tuesday, January 29, 2008

2008 MIT 6.270 Team 10

SHOOT WE DONT PLAY!!!!! team profile

Members: Allen Yin, Brandon Lew, Dave Reens. We're all freshmen living in Simmons Hall.

Robot: Great Wall of Connecticut.


-------------------------------------------------------------------------------------------------------------------------------------------
Competition Blog:

16 hours before impounding: Our wall and link all work really well, the other two teams all wowed at us. We were all set to test our PID control program when we realized that our robot's too fat and with a single-motor, 45 gear ratio gearbox, it can barely move....damn.
Major operation then follows, going to try to put in an extra motor per gearbox...or give it more torque.
Brandon's crying

1/30/08, 1:29 am
less than 16 hours before impounding:
Running into trouble putting on the extra motors, we dont have enough pieces for bracing and installation. Thus it's time to cannibalize other robot modules.

4 am:
Finished installing motors. Confused over how to make multithreading...then realized the need not to.

5am:
Brandon goes to sleep. Dave and I start to code. Tested the PID control structure(*insert code*). Constants are too hard to find, wrote and downloaded many different version of programs.

8am:
Allen = exhausted. Dave start to write the whole program from scratch, consulting other existing codes.

9am-12am:
Allen half-slept, half-awake.

12:30pm:
Wake up to test Dave's finished code. Driving function screwed up, doesnt drive straight no matter how we set the constants.

12:30- 3:00pm:
Testing on Kelly's court. Can turn, shoot the wall ("picture"), but refuses to go straight.

4:00pm:
we gave up and arrives at the lab, prepare for final try.

5:00pm:
turns out we can stay longer. Try more methods to tweak the drive.

7:00pm:
Gyro is screwed up, cant turn anymore. Get new one.

7:30pm:
New Happyboard, new motorchips...last push.

8:00 - 10:00pm:
We can turn now, still cant drive straight. Original Driving() function which used to work doesnt work now. Knight helps, with no avail.

11:00pm:
About to give up, but decide a last push to hardcode...use no correction factor depending on encoders.

12:00am, 1/31/08:
Find out error... apparently in the main code, we have error as an "uint" instead of "int"...solves problem.
Drives approximately straight, but had to get out of the lab. Fixes the wall and finally impounds.

10:30am, 1/31/08:
Seeding rounds, the robot suddenly cant turn. After inspection we realize a motor's unplugged. After fixing that and some other geartrain issues, the robot works decently. However, we also realized in a game against team13 that GWC has a knack for getting stuck on its own tether. Rewinded the tether in a new way to fix that.


10:00pm, 1/31/08:
Tournament ended. Great Wall did not score at all, but did make a splash with the wall and wowed quiet a few people. Sadly we did not advance past the second round.
Congrats to Team16's Matt and Olivia, whose robot was extremely reliable and robust and clearly deserved the win. There were so many other cool robots as well, and it's very unfortunate that the new playing board screwed up Team9's awesome distance sensor strategy.
Oh, and due to our team's tenaciousness and unwillingness to leave the lab last night, we won the Perseverance Prize (indeed!) which are 3 cool custom D.E.Shaw laptop bags, very nice!