Introduction: How to Make an Autonomous Basketball Playing Robot Using an IRobot Create As a Base

This is my entry for the iRobot Create challenge. The hardest part of this whole process for me was deciding what the robot was going to do. I wanted to demonstrate the cool features of the Create, while also adding in some robo flair. All of my ideas seemed to either fall in the category of boring but useful, or cool and impractical. In the end cool and impractical won out and the basketball playing robot was born. After some thought I realized that could be practical. Suppose that you use orange paper, and that all of your trash cans have green backboards...

Step 1: Aquire Parts

Because of the time limit of the contest, most of the parts I used were "off the shelf".

"Stock" Robot Parts Used:
Create (x1) -- from iRobot www.irobot.com
XBC V.3.0 (x1) -- from Botball www.botball.org
Create-Roomba cable (x1) -- from Botball www.botball.org
Servo (x2) -- from Botball www.botball.org
Sharp rangefinder (x1) -- from Botball www.botball.org
Assorted LEGO bricks -- from LEGO www.lego.com
6-32 machine screws (x4) -- from McMaster www.mcmaster.com

"Created" Robot Parts Used:
3/8" thick extruded PVC sheet -- this stuff is awesome, but I can't remember where I got it from, but it is just like this stuff http://www.lynxmotion.com/Category.aspx?CategoryID=62

Other parts:
Orange "POOF" ball -- from WalMart
Basketball goal looking trash can -- from Lowes
Green "backboard" -- extra PVC painted bright green

Step 2: Create the Unique Part

The only part that I had to fabricate was a plate that bolted to the Create and offered LEGO spacing. The spacing of the LEGO brick holes is 8mm apart, but I did a double spacing to save time. The extruded PVC is a breeze to work with. It can be cut with a utility knife, but is rigid and strong. I often pick up the robot by this plate and I have not had a problem yet.

Step 1:
Cut the sheet to 3.5" x 9.5", you can cut this with a utility knife.

Step 2:
Drill the holes for the create screws. The create screws make a box that is 2 and 5/8" by 8 and 5/8".

Step 3:
Drill the LEGO brick spaced holes. Use a 3/16" drill bit and I spaced the holes 16mm apart.

Tip:
I laid out the sheet in a CAD program, printed it out full size and taped it to the sheet. Then I used this as a guide for cutting and drilling.

Step 3: Assembling the Robot

I enjoy building things as simply as possible, that way when they jump off of the table you don't have to rebuild as much!

1. Screw the newly fashioned plate to the top of the Create
2. Build an arm to grab the ball
3. Build an arm to hold the camera
4. Build a mount for the rangefinder
5. Mount the XBC and connect all of the cables

Step 4: Programming the Robot

I decided to use the XBC as my controller mainly because of its built in color tracking. Because I decided to with the XBC as the brains of the operation I programmed my robot in Interactive C, or as I call it IC. IC is free to use and can be downloaded at www.botball.org. IC is very similar to C++, but has several built in libraries. As it turns out, David Miller from the University of Oklahoma has written a library for the Create which can be downloaded from his page at http://i-borg.engr.ou.edu/~dmiller/create/.

With those resources and the manuals for the create I was ready to program. But the next big challenge was what did I want it to do? I wanted a robot that could go and pick up orange balls and score them in a basket. My goal sounded simple, and probably could have been simple, but the more I got into what the Create could do, the more i wanted it to do. My final list looked like this:

1. Find orange ball
2. Pick up orange ball
3. Locate basket
4. Put ball in basket

While

1. Avoiding objects
2. Not falling off anything(like a table)
3. Detecting the charge of the battery and docking with the home base when low

Oh, and all of this is completely autonomous, meaning that it is all preprogrammed.

Step 5: Code

It may be messy, but it works.

#use "createlib.ic"
#use "xbccamlib.ic"

#define cam 0//camera servo port
#define arm 3//arm servo port
#define et (analog(0))//et port

/*The create cable also needs to be plugged in. The power jack,
the 3 pronged plug into port 8 and the one labeled U X into JP 28
(next to the USB port) with the U towards the camera*/

#define c_down 5//camera servo down
#define a_down 17//arm servo down
#define hold 50//servo hold ball
#define caught 27//arm servo position to keep from getting caught on table
#define shoot 150//servo throw ball
#define track_c 25//camera servo track close position
#define track_f 45//camera servo track far position

#define center 120//center of camera vision
#define inrange 30//track_y coordinate when ball is in claw
#define ball 0//channel of orange ball
#define ball_x (track_x(ball,0))//x coordinate of ball
#define ball_y (track_y(ball,0))//y coordinate of ball

#define slow 100//speed of slow motor
#define fast 175//speed of fast motor

#define clear 0.2//sleep to back away from obstacles
#define time 0.5 //1.0 is a 90 degree right turn
#define rest 0.05//time to sleep while tracking blobs

#define speeda 175//speed of avoid turn
#define back_s -200//speed to back away from bumped object
#define straight 32767//drive in a straight line

#define backb 2//channel of backboard main color
#define square 1//channel of backboard accent color
#define track_d 250//camera position for tracking goal
#define track_find 70//camera position for long tracking
#define reverse 2.25//sleep time for a 180
#define back_f -150//back fast speed
#define back_sl -125//back slow speed
#define center_x 178//true x center of cam
#define center_y 146//true y center of cam

int pida;//avoid process
int pidb;//track process
int pidc;//score process
int have_ball = 0;//tells which function we are in

void main(){
long ch;
enable_servos();//enable servos
init_camera();//start camera
cconnect();//connect to create with full controll
start_a();//start avoid function
start_b();//start ball_tracking function
while(1){
if(r_button()||gc_ldrop||gc_rdrop){//if picked up or r shoulder button
kill(pida);
kill(pidb);
kill(pidc);
disable_servos();
disconnect();
break;}
create_battery_charge();
display_clear();
printf("charge = %l\n", gc_battery_charge);
if(gc_battery_charge<1200l||b_button()){
kill(pida);
kill(pidb);
kill(pidc);
throw();
have_ball=0;
create_demo(1);
while(b_button());
while(gc_battery_charge<2800l&&!b_button()){
create_battery_charge();
display_clear();
printf("charge = %l\n", gc_battery_charge);
sleep(1.0);}
cconnect();
back();
sleep(2.0);
start_a();
start_b();}
}

}

void avoid(){

while(1){//repeat forever

create_sensor_update();//update all sensor values
//create_drive (speeda,straight);
if(gc_lbump==1){//left bump
avoid_right();}//turns right to avoid
else if(gc_rbump==1){//right bump
avoid_left();}//turns left to avoid
else if(gc_lfcliff==1){//left front cliff
avoid_right();}
else if(gc_rfcliff==1){//right front cliff
avoid_left();}
else if(gc_lcliff==1){//left cliff
avoid_right();}
else if(gc_rcliff==1){//right cliff
avoid_left();}
}
}

void track_ball(){

kill(pidc);

while(!have_ball){//repeat until get ball

track_update();
far();//sets the camera
ready();//sets the arm

while(et<255){//until max value happens when ball is caught

track_update();//update camera picture

if(ball_x<=(center-5)){//if the ball is left
track_update();
create_drive_direct(slow,fast);//turn left
sleep(rest);}

else if(ball_x>=(center+5)){//if the ball is right
track_update();
create_drive_direct(fast,slow);// turn right
sleep(rest);}

else if(ball_x<(center+5)&&ball_x>(center-5)){// if the ball is centered
track_update();
create_drive_straight(fast);//go straight
sleep(rest);}
}
grab();//grab ball
beep();//make noise
stop();//stop driving
have_ball=1;//make a note that I have ball
}
start_c();//find the basket
sleep(1.0);//sleep so that I'm not doing anything when I get killed
}

void find_basket(){

kill(pidb);//kill ball tracking process
find();//put camera up
track_set_minarea(1000);//the backboard is large, so only look for large blobs

while (have_ball){//while I have the ball

track_update();
while(track_x(backb,0)<=(center_x-20)||track_x(backb,0)>=(center_x+20)){//while not centered
track_update();

if(track_x(backb,0)>=(center_x+20)){//if the backboard is left
track_update();
create_spin_CCW(100);}//turn left

else if(track_x(backb,0)<=(center_x-20)){//if the backboard is right
track_update();
create_spin_CW(300-center_x);}// turn right slowing as the center approaches
}
stop();

while(track_size(backb,0)<=(6000)){//while the target is less than 6000 pixels in size
track_update();
if(track_x(backb,0)<=(center_x-5)){//if the target is left
track_update();
create_drive_direct(slow,fast);//turn left
sleep(rest);}

else if(track_x(backb,0)>=(center_x+5)){//if the target is right
track_update();
create_drive_direct(fast,slow);// turn right
sleep(rest);}

else if(track_x(backb,0)<(center+5)&&track_x(backb,0)>(center_x-5)){// if the target is centered
track_update();
create_drive_straight(fast);//go straight
sleep(rest);}
}
stop();
//create_drive_straight(fast);// get a little bit closer
//sleep(1.0);
//stop();
sleep(1.0);
create_spin_CW(speeda);//spin right
sleep(reverse);//sleep long enough for a 180 turn
stop();
down();//put camera down to track backboard
sleep(1.0);
track_set_minarea(200);//use a smaller min size, since we are pointed at it and going to get closer

while(track_y(backb,0)>=(center_y-140)){//while the target is less than the y coordinate
track_update();
if(track_x(backb,0)<=(center_x-5)){//if the target is left
track_update();
back_right();//turn left
sleep(rest);}

else if(track_x(backb,0)>=(center_x+5)){//if the target is right
track_update();
back_left();// turn right
sleep(rest);}

else if(track_x(backb,0)<(center+5)&&track_x(backb,0)>(center_x-5)){// if the target is centered
track_update();
back();//go straight
sleep(rest);}

}
stop();
beep();
throw();//shoot
sleep(1.0);
have_ball=0;//reminder I threw ball and don't have it
}
start_b();//back to ball tracking
sleep(1.0);//don't do anything until this process dies
}

void cconnect(){
create_connect();
create_full();//for full controll of ledge sensors
create_power_led(0,255);}//green power led

void disconnect(){
stop();//stop moving
create_disconnect();}

void back_away(){
back();
sleep(clear);
stop();}

void rotate_l(){
create_spin_CCW(speeda);
sleep(time);
stop();}

void rotate_r(){
create_spin_CW(speeda);
sleep(time);
stop();}

void stop(){
create_drive(0,straight);}

void back(){
create_drive(back_s,straight);}

void ready(){
set_servo_position(arm, a_down);}

void check(){
set_servo_position(cam, track_c);}

void far(){
set_servo_position(cam, track_f);}

void ledge(){
set_servo_position(arm, caught);}

void throw(){
int a;
for(a=50; a>=30; a-=1){//get ready
set_servo_position(arm, a);}
set_servo_position(arm, shoot);}

void grab(){
int a;
for(a=0; a<=hold; a+=1){//raise the arm smoothly
set_servo_position(arm, a);}}

void down(){
set_servo_position(cam, track_d);}

void find(){
set_servo_position(cam, track_find);}

void start_a(){
pida = start_process(avoid());}

void start_b(){
pidb = start_process(track_ball());}

void start_c(){
pidc = start_process(find_basket());}

void kill(int pid){
CREATE_BUSY;//wait for current create process to finish, and take priority
kill_process(pid);
CREATE_FREE;//i'm done
stop();}

void avoid_left(){
kill(pidb);//stop everything else
kill(pidc);
ledge();//pick up claw so it does not get caught on the table
back_away();//back away
rotate_l();//rotate away from obstacle
ready();//put claw back down
if(have_ball){//if i have the ball
start_c();}//start goal tracking
else if(!have_ball){//if i don't have the ball
start_b();}//start ball tracking
}

void avoid_right(){
kill(pidb);
kill(pidc);
ledge();
back_away();
rotate_r();
ready();
if(have_ball){
start_c();}
else if(!have_ball){
start_b();}
}

void back_left(){
create_drive_direct(back_f,back_sl);}

void back_right(){
create_drive_direct(back_sl,back_f);}

Step 6: Was It Worth It?

The costs were:

Create + battery+ doc = $260
XBC starter kit (xbc, cam, LEGO bricks, sensors) = $579
PVC + paint + screws = about $20
Total cost = $859

I already had the XBC starter kit from Botball, so the cost to me was the cost of the Create.

I think that it was worth it, and the best part is that all of the parts I used are reusable, if I could bring myself to part out this bot.

This video shows the avoid sub routine, on a table top.


This video shows the robot scoring 5 orange balls in a goal. I only assisted to speed the process along, it would have found ball 5 eventually on it's own.


Step 7: Conclusion

The final result is a robot that can pick up and score orange balls in a goal all on its own.

I loved working on this project. The more I worked on this robot the more attached I became to it. I now talk to it as if it were a pet. I hope that this has helped you on your next project. There are lots of people that I need to thank, but there are too many.

Like Bernard of Chartres so elegantly stated:

"we are like dwarfs on the shoulders of giants, so that we can see more than they, and things at a greater distance, not by virtue of any sharpness on sight on our part, or any physical distinction, but because we are carried high and raised up by their giant size."

The Instructables Book Contest

Participated in the
The Instructables Book Contest