Introduction: Tabletop Soccer Game

Send a Foosball down a ramp and try to score on the goalie! But scoring is not so easy - the goalie moves left and right to block your shot! This project was made for a class called "Thinks that Think" at CU Boulder for the Spring 2012 semester.

Step 1: Ramp

Materials: Aluminum tubing, Basswood, Wooden Dowel, Wood Glue
Tools: Hand Drill, Drill Bit

1. Cut a rectangle from a piece of ⅜” Basswood for the staging area of the ramp. Dimensions: 6cm X 3.5cm

2. Cut two more pieces from the Basswood that will be used to hold the dowel in place. Dimensions: 2.5cm X 2.5cm

3. Cut 2 pieces of the aluminum tubing to length of 25cm

4. Cut the dowel to length of  6.5cm

5. Drill two holes in the staging area 1” apart (roughly ⅔ the width of the foosball), centered on the thin edge of the long side, just wide enough for the aluminum tubing to fit into.

Step 2: Box Frame

Materials: Plywood, basswood, piece of 2”X4” wood, fishing wire, wood glue
Tools: Miter saw, laser cutter, scissors

1. Cut out three 12” X 24” X 0.25” sections of plywood (can get from Home Depot)

2. Make eight 2” X 2” X 4” blocks.  We did this by cutting four 4” pieces of 2” X 4” wood, then cutting each piece in half lengthwise.  For two of these blocks, cut a section out at a 45 degree angle leaving about 1” of flat space on top.  These pieces will be used to attach the sections together in the Assemble the Layers step.

3. Make the Top:
     a. Cut a hole for the ball to drop through (9”x2.5” and 0.7” from the back edge)
     b. Laser cut a 9”x0.3” slot about ½” in front of the ball drop. This is where the goal support rod will come through.
     c. Drill a hole for the ramp support dowel centered about 1” from the front edge. Glue a wooden square on the bottom side of the plywood piece to cover the hole.
     d. Now that all of the cutting has been done, spray paint the plywood green to look like a soccer field! Add white field lines if desired. Don’t use latex paint!

4. Make the Middle:
     a. Make a cut in the section of plywood from the middle sheet for the ball return
     b. Drill 2 small holes X” distance on either side of the hole.
     c. Thread a piece of fishing wire through the hole tying a knot on the top section to prevent the string from going all the way through the hole, while still leaving enough string to make it around the ball return ramp and be tied through the other whole. with the remaining string, find the appropriate length of string so that the ball return ramp is supported flush to the bottom of the middle ramp and can be tied on the top section of the middle ramp. this creates a loop of string that holds up the ball return ramp and attaches it to the middle sections.
     d. Laser cut two basswood pieces to serve as the ball drop ramp, which feeds the ball into the cutout of the middle plywood layer. They should have dimensions of 2.5”x5.3”.
     e. Glue the two pieces of basswood together at a right angle. 
      f.  Make a notch on the bottom of the ball return so that it can sit on the string without sliding. 

5. Make the Bottom
     a. Cut out a piece of basswood that is 22”x2” and another that is 22”x 15/8”. Glue the narrower plank to the face of wider plank to make the ball return ramp
     b. Attach two short pieces of wood beginning where the ball return ramp ends.  The pieces of wood should be angled outward to direct the ball to the front face where the player will retrieve the ball.
     c. Make an indention for the corner of the ramp to sit in for stability.

6. Assemble the Layers
     a. Take the four of the eight support pieces of wood (previously cut) and place one at each corner of the bottom layer.
     b. When pleased with the alignment secure the supports to the bottom layer using wood glue, and a screw if desired.
     c. Take the remaining four supports and place one at each corner of the middle layers.  When pleased with the alignment secure the supports to the middle layer using wood glue, and screws is desired.
     d. Place the middle layer on the four supports of the bottom layer.
     e. Once aligned secure the middle layer to the supports using wood glue.
     f. Glue the ball drop ramp pieces to the cut out angled edges of the two specially precut supporting blocks
     g. Place the top layer on the supports of the middle layer.
     h. Once aligned secure the top layer to the supports using wood glue.

7. Make the faces and walls
     a. Front face
          i. Laser cut the front face out of ⅛” basswood so that the entire bottom front opening is covered (12”x4.5”)
          ii. Laser cut a hole that is big enough to fit your hand through centered on the front face (roughly 2.5” tall and 4” wide). The bottom of the hole should be 1.5” from the bottom of the piece.
          iii. Use small finishing nails in the corners to secure the face between the bottom and middle layer.  Be sure to put the nails into the support posts but not into the plywood as it will split.
     b. Back face
          i. Laser cut a piece of basswood so that it completely covers the back opening (behind and below the goal opening) between the top and middle layers (should be about 12”x4.5”)
          ii. Put glue on the outside of the middle layer posts and the edge of the top and middle plywood layers. Glue the back face to these surfaces.
          iii. Use nails in the posts if extra stability is desired
     c. Side walls
          i. Laser cut two ⅛”x2”x24” pieces of basswood
          ii. Glue the side walls long-ways along the edge of the top layer
          iii. Nail the ends of the side walls to the posts if extra stability is desired

Step 3: Gear System

Materials: small printer belt, longer printer belt, motor, three gears, 2 wooden dowels, basswood, wood glue
Tools: laser printer, belt sander, sand paper

1. Gear 1
     a. Cut a dowel to fit in the middle layer standing up (about 4”)
     b. Sand down the ends with a belt sander to be a little thinner for about 0.4 inches on both ends
     c. Sand the very end of the dowel close to a point
     d. Laser a washer from basswood to be wider than the gear.
     e. Glue the washer about 1 inch from one end of the dowel. The washers prevent the belt drive from slipping off the gear. Glue the gear for the longer belt drive onto the dowel and washer.
     f. Glue the gear for the small belt drive about ½ inch from the other side of the dowel that the previous gear is on.

2. Gear 2
     a. Cut and power sand another dowel just like from gear 1.
     b. Laser cut one washer to be wider than the gear
     c. Glue the washer about an inch from the top of the dowel so that the belt doesn't slide down to far. 

3. Gear 3

     a. Cut a 1 inch dowel (no need to sand it down on the ends)
     b. Laser cut one washer and glue it to the end
     c. Place the gear onto the dowel but do not glue it

4. Motor Mount

    a. Cut the L shaped wood in to four 3/4" sections.
    b. glue the sections together so that they make an "Z" shape.
    c. Cut out a circle in a piece of basswood so that your motors' driver is through the wood but the rest of the motor will rest on top.
    d. Glue the Z shaped pieces to the piece of wood made in step c. creating a mount for the motor to sit on.

5. Gear System Assembly

   a. Depending on the length of your belt drive depends on the setup for this section. with the three dowels stretch the belt drive so that it goes under the slot for the goalie and it contained in the frame. Mark the location of the dowels for future reference.
   b. Cut out 6 holders for the dowel. we made our out of basswood. the diameter of the holders depends on the diameter of your dowel.  
   c. Glue the holders in the places you marked in section a. the holder will keep the dowels in place when they are in use. 



Step 4: Goalie Cart and Rail System

Materials: Basswood, Wood glue, Acrylic, Acrylic glue
Tools: Laser cutter, clamp, Rubber Band, Belt Drive

1. Laser cut the upper cart piece and track out of ⅛” acrylic plastic.  Laser cut the lower cart piece out of ⅜” acrylic.

2. Use a dowel the same size used for the goalie to align the upper and lower cart pieces.  Clamp the pieces together and apply acrylic glue to the joint.

3. Laser cut the belt holder pieces from ⅛” acrylic.

4. Place the two belt holder pieces at 90 degrees to each other.  Support the pieces with a small piece of wood so they stay stable.  Use a rubber band to keep the pieces together.  Apply acrylic glue to the joint.

5. Once dry, attach the belt holder to the cart.  The best way to do this is to place the belt on the side of the cart, then squeeze the belt holder so it secures the belt.  Apply glue to the joint and hold it for several minutes.  You can test the strength of the joint by gently pulling on the belt while holding the cart, making sure the belt doesn’t slip.

6. Gently slip the cart into the track.

7. Make 3 track holders,  The holder will be 3 pieces of basswood glued together to form a “c” shape.  To get the height of the support correct line up the inside face of the track holding piece with the inside face of the bottom washer of the belt drive.  The goal is to have the belt drive running in a flat plane.

8. Glue the three track holders to bottom of playing surface.  The middle of the track should be in line with hole in playing surface where the goalie’s support rod will be inserted.

Step 5: Goalie

Materials: Basswood, Wire, Wood glue
Tools: Laser cutter, Needle nose pliers (the smaller the better), Wire cutters, clamp

1. Laser cut the goalie pieces provided in the attached .svg file from the Basswood.
     a. The pieces should consist of:
          i. 1 Head oval
          ii. 1 Body oval
          iii. 2 upper arm, and 2 lower arm ovals
          iv. 2 hand  circles
          v. 4 upper leg, and 4 lower leg ovals
          vi. 4 feet ovals

2. Attach 1 hand to each lower arm oval using wood glue and a clamp

3. Thread respective pieces together using the wire, bending the wire ends into circles to secure the pieces
     a. Be sure to alternate the upper and lower leg pieces to provide added stability for contact with the ball
     b. I found it easiest to thread the pieces while the wire was still on the spool.  Once threaded I would secure the free end of the wire using the pliers.  I would then cut the wire leaving enough room to secure the other side.

4. Glue any joints you feel necessary in place.  We glued the hip, ankle, and shoulder joints.

Step 6: Goal

Materials: White acrylic plastic, White mesh cloth, white thread, ⅛ in basswood
Tools: Laser cutter, needle nose pliers, wire cutters

1. Cut the Goal pattern from the provided .svg file from the acrylic

2. Cut the Goal holders from the provided .svg file from the ⅛ in basswood
     a. assemble the 2 cutouts so that the holes line up.
     b. You can use the cut out of the goal frame to make sure they are aligned correctly.

3. Place the supports on the playing field 2” from the edge. Make sure the goal will be able to stand in the supports without bending the goal frame.

4. Cut out a section of white mesh Cloth that is 9” x 7” for the goal frame.

5. Using the thread and needle sew the white mesh cloth to the goal frame. the best way to do this is by having the cloth be a little wider than the goal so you can wrap it around the post and then sew the two pieces of cloth to one another with the section of acrylic goal in between.

Step 7: Arduino Code

// DEFINE
// input (pins)
#define sensor1    5  // sensor on goalie left
#define sensor2    0  // sensor on goalie right
#define center     8

#define motor1     10
#define motor2     11

#define distThresh   50

//GLOBAL variable declarations
  int s1Baseline;
  int s1Tolerance;
  const int numRecRead = 10;
  int recReading[numRecRead];
  int recReadCur;

void setup () {
  Serial.begin(9600);           // set up Serial library at 9600 bps

  pinMode (sensor1, INPUT);

  pinMode (motor1, OUTPUT);
  pinMode (motor2, OUTPUT);

  resetRecVal();

  // seed random number generator for difficulty
  randomSeed(analogRead(0));

  // Calibrate sensors and set baseline and tolerances
  int s1Cal[2];
  calibrateSensor(sensor1, s1Cal);
  s1Baseline = s1Cal[0];
  s1Tolerance = s1Cal[1];

}

void loop() {
  int s1Val, s1ValAvg;  
  double s1Dist;
  Serial.println(digitalRead(center));
  // Get sensor values
  s1Val = checkSensor (sensor1, s1Baseline, s1Tolerance);
  s1ValAvg = averageReading(s1Val);
  //Serial.println(s1Val);
  if (s1ValAvg > distThresh) {
    s1Dist = sensorToDistance(s1Val);


    if (s1Dist < 14) moveGoalie(5);  // move right
    else if (s1Dist > 18 && s1Dist < 32) moveGoalie(-5);  //move left

    resetRecVal();
  }
}

// Returns the sensor value if there was a reading (i.e. ball passed infront)
// or 0.0 if no reading was taken (i.e. the ball did not pass by)
// sensorPin - The pin of the sensor to be checked
// baseline - That sensors "no reading" value
// tolerance - The threshold off of baseline which should be considered a reading
//             (i.e. if the value is within (baseline +/- threshold do not report
//                   a reading)
int checkSensor(int sensorPin, double baseline, double tolerance) {
  double sVal = analogRead(sensorPin);  // Value reported by the sensor
  if (abs(baseline - sVal) < tolerance) // if the reading is within tolerance
    return 0;                          // return "no reading"
  return sVal;                          // otherwise return the value
}

// Returns the distance corresponding to the sensor reading
// sensorVal - Value read by the sensor
double sensorToDistance(int sensorVal) {
  double scale = 2050;
  double expon = 1.0/0.85;
  double dist = pow((scale/sensorVal), expon);

  if (dist > 35) dist = 35;//normalize dist

  return dist;
}

// Calibrates the sensor (run in setup)
// Takes calibration points from the sensor to find the mean value
// and noise in sensor readings
// sensorPin - Pin of sensor to calibrate
// calData - int[] for values to be stored in
void calibrateSensor(int sensorPin, int calData[]) {
  int numReadings = 300;  //take 300 calibration points
  int data[numReadings];  //used to store callibration points
  int i;
  int minVal = 10000;  // initialize minimum value high
  int maxVal = -1;  // initialize maximum value low

  for (i = 0; i < numReadings; ++i) { 
    int t = analogRead(sensorPin);  //read sample data
    data[i] = t; //populate data array

    // Record min and max sensor readings
    if (t < minVal) //if t is less than current minVal
      minVal = t;  //replace the minVal
    if (t > maxVal)  //if t is greater than maxVal
      maxVal = t; //replace the maxVal
  }

  //Find the spread of the data
  int spread = maxVal - minVal;

  // Find the mean of the sample data
  double mean = 0;
  for (i = 0; i < numReadings; ++i)
    mean += data[i];
  mean /= numReadings;

  // calculate std dev 
  double stddev = 0;
  for (i = 0; i < numReadings; ++i)
    stddev += pow((data[i] - mean), 2);
  stddev /= numReadings;
  stddev = sqrt(stddev);

// return [mean, spread]
calData[0] = mean;
calData[1] = stddev*2;
return;

}

// 0- stop
// 10 - fast
// <0 left
// >0 right
void moveGoalie(int dir) {
  int mag = map(abs(dir), 0, 10, 0, 255);
  int retMag = map(abs((dir + 4)/4.0), 4, 14, 100, 255); //return more slowly

  if ( dir > 0 ) {
    analogWrite(motor1, mag);
    analogWrite(motor2, 0);
    delay(100);
    analogWrite(motor1, 0);
    analogWrite(motor2, 0);
    delay(1000);
    analogWrite(motor1, 0);
    analogWrite(motor2, retMag);
    delay(200);
  }
  else if ( dir < 0 ) {
    analogWrite(motor1, 0);
    analogWrite(motor2, mag);
    delay(300);
    analogWrite(motor1, 0);
    analogWrite(motor2, 0);
    delay(1000);
    analogWrite(motor1, retMag);
    analogWrite(motor2, 0);
    delay(300);
  }

  //stop goalie
  analogWrite(motor1, 0);
  analogWrite(motor2, 0);
}

int averageReading ( int newVal) {
  recReadCur %= (numRecRead - 1);

  recReading[recReadCur++] = newVal; 

  int sum = 0;
  int valid = 0;
  for (int i = 0; i < numRecRead; ++i) {
    if ( recReading[i] > 0 ) ++valid;
    sum += recReading[i];
  }

  if (valid < 7) return 0;

  return (sum/valid);
}

void resetRecVal () {
  for (int i = 0; i < numRecRead; ++i) //initialize recRead
    recReading[i] = 0;
  recReadCur = 0;
}

Step 8: Possible Additional Features

1. Employ limit switches and a center switch to position the goalie more accurately and prevent the motors from burning out.

2. Integrate a 2nd distance sensor for more accurate ball positioning.

3. Integrate a goal counter to increase the count on a LED scoreboard whenever a goal is made. 

4. Have music play when a goal is made and booing played when the player misses.

5. Make a hand reach into the ball return and place the ball on the ramp if a goal is scored.

Step 9: Part Files

Feel free to use the provided files, use them as inspiration, or make your own!