Roborodentia 2011
Team Members: Dennis Cagle, Justin Kenny, Zach Negrey
Introduction
Roborodentia is a robotics competition held annually at Cal Poly SLO. The 2011 Roborodentia competition resembled a game of soccer. There were two sides to a playing field with a net on each end and troughs on the sides to hold ping-pong balls (Figure 1). The goal of the contest is to create an autonomous robot capable of scoring the most ping-pong balls into an opponent’s net.
Strategy
Our overall plan was to stay simple. Past experience has taught us that a really well working simple design is better then a not working complex one. We decided to make a basic robot that would go around in a square collecting balls and shooting as it went. In retrospect from past competitions, we decided to go with a mechanical switch-based location system, as opposed to an optical or line following approach. We have noticed that IR dependent sensors may vary dramatically based on different lighting and environments, whereas touch is easy to implement and almost perfectly reliable. In order to score, we would only go after the main balls and shoot them as we picked them up (rather then storing them for later).
Design
The plans for Marvin can be seen in Figure 2. Marvin is made of plexiglass with a square base. Marvin was designed to fit within the 12x12x12 inch box requirements of the competition, but allow enough room for additions or changes to the design. We ended up trimming the base down so we could have the “scoopers” (see below), but the base still had enough room for a stray ping pong ball to fit between a wall and the wheels. This was to prevent the bot from getting “stuck” because we could not hit a wall (and prevent the touch sensors from knowing we reached the wall). On top of the base is a vertical piece of plexiglass to hold our Xiphos board (Atmel AVR based microcontroller board), and to add some defense/blocking capability to the bot. The shooter is at the front of the robot, and the servos on the sides were for picking up the balls. Each of the individual portions of the robot is explained below. A picture of Marvin on competition day can be seen in Figure 3.
Base:
We decided to go with a tried and true square platform using four omniwheels as shown in Figure 4. Two motors/wheels are configured diagonally from each other facing the same direction; with an identical set rotated 90 degrees. Omniwheels allow free movement perpendicular to the wheel’s direction by lining the outside of the wheel with rollers. In this configuration, with only one motor driver (two diagonal motors connected together in parallel to each channel), the bot can move freely in any planar direction, with the same heading. Using two motor drivers (each motor driven by an independent channel) the bot has full 2D movement, including rotation in either direction. For this year’s competition, we saw no need for the bot to rotate, so we went with a single Sabertooth 2x10 Motor Controller between the wheels.
Picking up balls
At first, our plan was to use paintbrushes attached to rotating servos to pick up balls from the trough. We initially built, coded, and tested this idea with limited success – but our robot had to drive very slowly to ensure we collect every ball. We added a “scoop” to the sides that would keep the balls in front of the brush as we drove (Figure 5) and found that the scoop alone worked so well to pick up the balls that the brushes were no longer needed. In the end the scoops were spring loaded and held in place by the paintbrush servos, and at start they would lift and release the scoops.
Troughs
The goal of the troughs was to direct ping pong balls into the motor. They were formed from bailing wire so they could be easily adjusted as needed and still strong enough to stay in place (Figure 6). During testing, we used thick paper as “walls” to make sure the balls stayed on path. Eventually, the back walls were made from sheet aluminum.
Shooter
The plan for the shooter was to have a single motor in the center and deflect the balls as they shot out of the front (Figure 7). The balls were directed from the troughs into the shooter – which was a motor with a rotating foam wheel mounted above the ball path. The motor mount was built to allow adjustable height, so we could tweak the position to get the distance we wanted. Immediately after the wheel was an adjustable height ramp and a set of bumpers to direct the ball towards the net. The bumpers were attached to a servo on top of the shooting mechanism that rotated based on what side of the course Marvin was on.
Electronics:
A block diagram for all the electronic components can be seen in Figure 8. Our system was powered by a 11.1V 2.2AH Lithium Polymer Battery driving an Atmel based microcontroller (Xiphos board). As was mentioned above, servos were used to deploy the scoopers and direct the balls from our shooter motor. A Sabertooth 2x10 Motor Controller was responsible for driving our four motors with 2” omniwheels. Finally, eight touch sensors around Marvin controlled movement.
Code
The code for Marvin was relatively simple due to the simple design. We basically used a loop to drive in a square - and turned on the appropriate motors at each side. In order to stay on course, we would also push against the wall while driving (e.g. when driving forward, we also drove slightly left to stay against the left wall). In addition to changing the aim of the deflector, the speed of the motor was also adjusted so that we would slow down or speed up the shooter based on the distance from the net. The only real thought that went into the code was to trigger a direction change if the robot did not hit a wall in a specified time (assume that Marvin is stuck). Marvin’s code is attached to the end of this report.
Lessons Learned
One of the major pitfalls of our bot was the inconsistency of our shooter. The shooter motor was built early on into the project, with decent results, but the wheel was poorly balanced, causing a lot of vibration. The deflector was a late addition to the bot, and did not provide enough consistency or deflection at higher motor speeds. Due to the imbalanced wheel, the motor tended to fire balls at various distances, but was more consistent at higher speeds. At higher speeds, however, the deflectors were knocked out of the way by the force of the ball and were far less effective. A better design would be a two-shooter method, employed by several bots in this competition and in the previous Roborodentia. We chose to go with a single shooter to save parts and reduce the amount of design and testing, but it ended up being difficult to modify to try and meet our goals.
Another weakness, although less evident, was the drive system. We chose to use the same 4-motor omniwheel configuration that we and several other teams used in previous competitions. In last year’s competition, we had issues with the wheels being unbalanced, and one or more not contacting the ground fully. We purchased a new set of wheels and hubs to fix this problem, but each wheel needed to be drilled manually to fit the hubs. Even using a drill press, some of the holes were misaligned, and this again caused one of the wheels to be unbalanced. Ultimately, our temporary fix for competition was to add a large weight to the bot (we simply taped a lead-acid battery to a free corner of the bot), which solved the problem well enough to prevent any issues during competition. Next time, we would opt for a set of wheels and motors that were pre-drilled and would be well balanced.
Conclusion
Marvin placed 3rd out of the 19 teams that competed in Roborodentia 2011. We (Figure 9) had a great time with the project and learned many valuable lessons about creating a working robot from scratch. Roborodentia is an excellent example of Cal Poly’s “Learn by Doing” philosophy and is an invaluable experience to the students involved. We hope to continue building robots and look forward to Roborodentia 2012!
Code
Here is the code that was run during the competition:
/*
Marvin
Dennis Cagle, Justin Kenny, Zach Negrey
roborodentia.h
*/
// globals.h is a common file used by Xiphos applications
#include "globals.h"
#ifndef roborodentia_h_file
#define CLOCKTIMEFB 200 // 20 seconds
#define CLOCKTIMELR 110 //11 seconds
//Speeds
#define STOP 127
#define STOPR 129
#define FBSPEED 30
#define BACKWARDS ((STOP-3)+FBSPEED)
#define FORWARD (STOP-FBSPEED)
#define RIGHT 175
#define LEFT 60
//Speeds to push against the wall
#define NUDGE_L 110
#define NUDGE_R 136
#define NUDGE_F 90
#define NUDGE_B 155
// Drive speeds
#define FULL 255
#define FULL_R 0
// Paintbrush speeds
#define BRUSH_SPEED 50
#define BRUSH_SPEED_L (STOP + BRUSH_SPEED)
#define BRUSH_SPEED_R (STOPR - BRUSH_SPEED)
// Deflect left and right positions
#define DEFLECT_R 255
#define DEFLECT_L 0
// Shooting motor speeds at various points in the course
#define SMOTOR_SPEED_L 149
#define SMOTOR_SPEED_R 148
#define SMOTOR_SPEED_MIN_L 146
#define SMOTOR_SPEED_MIN_R 144
//Motor Locations
#define T_FWD 0
#define T_BWD 1
#define T_RGT 2
#define T_LFT 3
#define F_MOTORS 1
#define S_MOTORS 0
#define D_MOTOR 2
#define SHOOTER 1
#define BRUSH_R 4
#define BRUSH_L 6
//Touch sensor locations
#define BL 3
#define LB 4
#define BR 2
#define RB 1
#define RF 0
#define FR 7
#define FL 6
#define LF 5
//Function declarations
void botInit();
u08 aDigital2(u08 pin);
void drive();
int driveWithTouch(int direction);
void stopAll();
void moveForward();
void moveBackwards();
void moveRight();
void moveLeft();
#endif
/*
Marvin
Dennis Cagle, Justin Kenny, Zach Negrey
roborodentia.c
Winter 2011
Roborodentia 2011
Marvin is an autonomous robot that drives in a
square picking up and shooting ping pong balls.
He is awesome.
*/
#include "Roborodentia.h"
int main()
{
// Initialize the Xiphos board and set up pins
initialize();
botInit();
// STOP the drive motors (just in case)
stopAll();
motor0(STOP);
// Wait for button press
clearScreen();
printString("Robo 2011");
lowerLine();
printString("I'm so depressed");
buttonWait();
// Push the fins out by spinning the paintbrushes
servo(BRUSH_R, BRUSH_SPEED_L);
servo(BRUSH_L, BRUSH_SPEED_R);
// Stop the paintbrushes (the two
// paintbrushes don't stop at the same value.)
delayMs(500);
servo(BRUSH_R, STOPR);
servo(BRUSH_L, STOP);
// Go around the course 4 times to ensure all balls
// have been collected (and to have a shot at deflecting
// from anywhere on the course)
drive();
drive();
drive();
drive();
// Stop the drive motors and the shooting motor, we're done
stopAll();
motor0(STOP);
// Dummy loop (chill out until a reset or power off)
while (1) {}
}
/*
Set up analog pins to be used as digital inputs
*/
void botInit()
{
// Use the analog pins as digital inputs for the touch sensors
PORTF = 0xFF; // Use PORTF (analog port) as input (enable pull-ups)
digitalDirections(0x0000);
digitalPullups(0xFFFF);
}
/*
Check to see if touch sensors are pressed
*/
u08 aDigital2(u08 pin)
{
// Read sensor input and initialize a u08 comparator variable
u08 temp = analog(pin);
u08 comp = 127;
return (temp > comp);
}
/*
Normal drive mode. Goes around course once, changing directions
each time the touch sensor is pressed.
*/
void drive()
{
driveWithTouch(T_FWD);
delayMs(500);
driveWithTouch(T_RGT);
delayMs(500);
driveWithTouch(T_BWD);
delayMs(500);
driveWithTouch(T_LFT);
delayMs(500);
}
/*
Drive in a specified direction (see: T_FWD, T_BWD, T_RGT, and T_LFT)
until the touch sensors are pressed, at which point the drive motors
stop. Also controls the speed of the shooting wheel. In all cases,
if this method takes too long, it will break out and return so that
the next stage can start (in case Marvin gets stuck on a rogue
ping-pong ball).
*/
int driveWithTouch(int direction)
{
int count = 0, var_shoot = 0;
switch(direction)
{
case T_FWD:
// Start driving forward
var_shoot = SMOTOR_SPEED_L;
moveForward();
// Adjust the speed of the shooting wheel based on how far
// along the wall the robot is (as determined by the time
// spent in the stage)
while ((aDigital2(FR) && aDigital2(FL)) && (count < CLOCKTIMEFB))
{
// Slow down the shooting motor by 1 every five seconds
count++;
if ((count % 50) == 0)
{
var_shoot--;
// Make sure shooting motor doesn't become too slow
if (var_shoot < SMOTOR_SPEED_MIN_L)
{
var_shoot = SMOTOR_SPEED_MIN_L;
}
}
// Send the adjusted speed to the shooting motor
motor0(var_shoot);
delayMs(100);
}
// Stop driving forward
stopAll();
return 1;
case T_BWD:
// Start driving backwards
moveBackwards();
var_shoot = SMOTOR_SPEED_MIN_R;
// Adjust the speed of the shooting wheel based on how far
// along the wall the robot is (as determined by the time
// spent in the stage)
while ((aDigital2(BR) && aDigital2(BL)) && (count < CLOCKTIMEFB))
{
// Speed up the shooting motor by 1 every 3.5 seconds
count++;
if ((count % 35) == 0)
{
var_shoot++;
// Make sure shooting motor doesn't become too fast
if (var_shoot > SMOTOR_SPEED_R)
{
var_shoot = SMOTOR_SPEED_R;
}
}
// Send the adjusted speed to the shooting motor
motor0(var_shoot);
delayMs(100);
}
// Stop driving backwards
stopAll();
return 1;
case T_RGT:
// Start moving right
moveRight();
// Keep track of how long we have been moving right. If it
// takes too long, break out and start moving backwards.
while ((aDigital2(RF) && aDigital2(RB)) && (count < CLOCKTIMELR))
{
count++;
delayMs(100);
}
stopAll();
return 1;
case T_LFT:
// Start moving left
moveLeft();
// Keep track of how long we have been moving left. If it
// takes too long, break out and start moving forwards
while ((aDigital2(LF) && aDigital2(LB)) && (count < CLOCKTIMELR))
{
count++;
delayMs(100);
}
stopAll();
return 1;
default:
return 0;
}
}
/*
Stop the drive wheels and paintbrushes
*/
void stopAll()
{
clearScreen();
printString("stopAll");
servo(F_MOTORS, STOP);
servo(BRUSH_L, STOP);
delayMs(100);
servo(S_MOTORS, STOP);
servo(BRUSH_R, STOPR);
//motor0(STOP);
}
/*
Drive forward while also staying against the wall.
*/
void moveForward()
{
// Stay against the left wall by slowly driving into it
servo(S_MOTORS, NUDGE_L);
delayMs(100);
clearScreen();
printString("Forward");
// Aim deflector to the right
servo(D_MOTOR, DEFLECT_R);
// Drive forwards
servo(F_MOTORS, FORWARD);
}
/*
Drive backwards while also staying against the wall.
*/
void moveBackwards()
{
// Stay against the right wall by slowly driving into it
servo(S_MOTORS, NUDGE_R);
delayMs(100);
clearScreen();
printString("Backwards");
// Aim deflector to the left
servo(D_MOTOR, DEFLECT_L);
// Drive backwards
servo(F_MOTORS, BACKWARDS);
}
/*
Drive right while also staying against the wall.
*/
void moveRight()
{
// Stay against the center wall by slowly driving into it
servo(F_MOTORS, NUDGE_F);
delayMs(100);
clearScreen();
printString("Right");
// Drive right
servo(S_MOTORS, RIGHT);
}
/*
Drive left while also staying against the wall.
*/
void moveLeft()
{
// Stay against the back wall by slowly driving into it
servo(F_MOTORS, NUDGE_B);
delayMs(100);
clearScreen();
printString("Left");
// Drive left
servo(S_MOTORS, LEFT);
}
Files
Here is a .zip file containing the Autodesk Inventor mechanical design files for the bot: http://rev0proto.com/files/marvin-inventor.zip
Parts and Materials
Most of the parts and materials used to build the bot were reused from what was on hand in the club room and what was used in last year's bot. The actual total cost of the bot (purchased materials only) is around $120.
Component | Quantity | Unit Cost | Total Cost | Source | Part Number | Purpose |
12" x 12" x 0.25" Acrylic Base | 2 | $5.59 | $11.18 | eStreetPlastics | 1002501212 | Serves as a base on which to attach motors, sensors, etc. |
Xiphos Board | 1 | $130 | $130 | CPRC | Marvin's Brain | |
11.1V 2.2AH Lithium Polymer Battery | 1 | $9.99 | $9.99 | HobbyKing | T2200.3S.20 | Power source for the motors and microcontroller system |
Sabertooth 2x10 Motor Controller | 1 | $79.99 | $79.99 | Dimension Engineering | Sabertooth 2X10 | Motor controllers for the four motors driving the bot |
Standard Size Servo | 2 | ~$8 | $16 | CPRC | Servos that open the two scoops for collecting balls | |
Micro Size Servo | 1 | $3.94 | $3.94 | Dealextreme | Servo that controls the direction of the ball shooter | |
Aluminum Sheet | 2 | ~$7 | $14 | Home Depot | Used for various parts of the bot; ramp, guard walls, brackets, scoops | |
Aluminum Angle Stock | 1 | ~$8 | $8 | Home Depot | Used for brackets and mounting the servos/scoops | |
2" Diameter Omniwheels | 4 | $7.48 | $29.92 | Kornylak Corporation | FXA314 | Wheels that let the bot travel in any direction in 2-D space |
6mm Shaft Diameter Hub (Pair) | 2 | $8.00 | $16.00 | Lynxmotion | HUB-02 | Hubs to attach the omniwheels to the motors |
4-40 Mounting Hardware | 1 | ~$15.00 | $15.00 | Home Depot, Bolt Depot | Machine Screws, Nuts, and Washers to hold parts of the bot together | |
Total Price | ~$334.02 |