learning the ropes

things I made at ITP and after: sketches, prototypes, and other documentation

Monday, September 18, 2006

Catch is Done for Now

I finished the first version of my catch game.

The schematic is pretty basic…
catch schematic.jpg

… and in fact it should be noted that I found a soldering problem on the little board I salvaged. Apparently when I rewired it, I knocked one of the circuit traces loose, which prevented the upper right switch from working. This caused me much consternation while trying to develop the catching algorithm. Thankfully Serial.println helped me figure things out.

I modified my program to use the upper left switch for both throwing and catching. Maybe it’s not so interactive anymore, but it’s done and I have other things like Spatial Design homework to do.

If you like to read source code, you can do so in the full entry.

/* ----------------------------------------
A Small Game of Catch
----------------------------------------
Michael Chladil

Physical Computing
2006-09-18

written for Arduino v1.18
*/

#define DEBUG_LVL 2

#define BallPin1 3
#define BallPin2 4
#define BallPin3 5
#define BallPin4 6
#define BallPin5 7
#define BallPin6 8
#define BallPin7 9
#define Switch1  10
#define Switch2  11

void setup ()
{
pinMode (BallPin1, OUTPUT);
pinMode (BallPin2, OUTPUT);
pinMode (BallPin3, OUTPUT);
pinMode (BallPin4, OUTPUT);
pinMode (BallPin5, OUTPUT);
pinMode (BallPin6, OUTPUT);
pinMode (BallPin7, OUTPUT);
pinMode (Switch1, INPUT);
pinMode (Switch2, INPUT);

if (DEBUG_LVL > 0)
{
Serial.begin (9600);
}
}

boolean Throw (int delay_time)
{
long    Last_Millis;
long    SW2_pressed = 0;
int     PinNumber   = BallPin1;
boolean Caught      = false;

Last_Millis = millis ();
digitalWrite (PinNumber, HIGH);

while ((PinNumber <= BallPin7) &&
(Caught == false) &&
(SW2_pressed == 0))    // Once the switch has been pressed, the attempted "catch" is over
{
if ((millis() - Last_Millis) > delay_time)
{
digitalWrite (PinNumber, LOW);
PinNumber++;
if (PinNumber <= BallPin7)
digitalWrite (PinNumber, HIGH);
Last_Millis = millis ();
}

if (digitalRead (Switch1) == HIGH)
{
/* Because of a poor soldering job, I have to use switch one twice */
if (DEBUG_LVL == 2)
{
Serial.println ("SW2 Pressed when pin=");
Serial.println (PinNumber);
}

SW2_pressed = millis ();

if ((PinNumber >= BallPin7) &&
((SW2_pressed - Last_Millis) < delay_time))
Caught = true;
else
Caught = false;
}
}

// Turn all LEDs off
int i;
for (i = BallPin1; i <= BallPin7; i++)
{
digitalWrite (i, LOW);
}

return (Caught);

/* I initially wrote the throw routine using delays, but realized the
delays would prevent Arduino from detecting the second switch.

From here down is old code.
*/

/*
for (PinNumber = BallPin1; PinNumber <= BallPin7; PinNumber++)
{
digitalWrite(PinNumber, HIGH);

if (PinNumber > BallPin1)
{
digitalWrite(PinNumber - 1, LOW);
}
else
{
digitalWrite(BallPin7, LOW);
}
delay (delay_time);
}
*/
}

void loop ()
{
int     delay_time;
long    Last_Millis;
long    SW1_pressed;
long    SW1_released;
boolean Blink_State = LOW;

if (digitalRead (Switch1) == HIGH)
{
SW1_pressed = millis();
Last_Millis = SW1_pressed;

while (digitalRead (Switch1) == HIGH)
{
if ((millis() - Last_Millis) > 150)
{
/* Initially I tried to do the blink using the time difference % 150, but this produced
erratic blinking because sometimes the milliseconds wouldn't be evenly divisible by
150 at exactly the time when the condition was tested.  This meant the loop had to
go back around again.  By changing the test to a subtraction (and allowing for a
margin of error by using ">", I have made the blink more regular
*/
Last_Millis = millis();
Blink_State = !Blink_State;
digitalWrite (BallPin1, Blink_State);
}
}
Blink_State = LOW;
digitalWrite (BallPin1, Blink_State);

SW1_released = millis();

if (DEBUG_LVL >= 3)
{
Serial.print ("t=");
Serial.println (SW1_released - SW1_pressed);
}

if (Throw ((SW1_released - SW1_pressed) / 7) == true)
{
/* The project uses 7 LEDs, so divide the press and release time by 7.

TODO: For future development, I would like the minimum throw speed when the
game starts to be fairly high... This way the thrower can't immediately
overwhelm the catcher.

TODO: Is there some way to write a chunk of data to pins using a char or a string?
This way I would be able to shift bits to cause the effect I wanted.
*/

// Ball caught - alternately blink all lights
if (DEBUG_LVL > 0)
Serial.println ("Caught!");

// TODO: The following is an ideal candidate for refactoring...
int i;
for (i = 1; i <= 3; i++)
{
digitalWrite (BallPin1, HIGH);
digitalWrite (BallPin2, LOW);
digitalWrite (BallPin3, HIGH);
digitalWrite (BallPin4, LOW);
digitalWrite (BallPin5, HIGH);
digitalWrite (BallPin6, LOW);
digitalWrite (BallPin7, HIGH);
delay (150);
digitalWrite (BallPin1, LOW);
digitalWrite (BallPin2, HIGH);
digitalWrite (BallPin3, LOW);
digitalWrite (BallPin4, HIGH);
digitalWrite (BallPin5, LOW);
digitalWrite (BallPin6, HIGH);
digitalWrite (BallPin7, LOW);
delay (150);
}

// Clear all LEDs
for (i = BallPin1; i <= BallPin7; i++)
digitalWrite (i, LOW);

while (digitalRead (Switch1) == HIGH)
{
// Busy wait for switch 1 to go low before proceeding
}

}
else
{
if (DEBUG_LVL > 0)
Serial.println ("Missed!");

// Ball missed - do one long blink of the entire row and then reset.
int i;
for (i = BallPin1; i <= BallPin7; i++)
digitalWrite (i, HIGH);

delay (300);

for (i = BallPin1; i <= BallPin7; i++)
digitalWrite (i, LOW);

while (digitalRead (Switch1) == HIGH)
{
// Busy wait for switch 1 to go low before proceeding
}
}
}
}
posted by Michael at 10:24 pm  

1 Comment »

  1. I remember what it was like to write a “simple” program in college. Catch came out great, but it’s amazing how much code is behind your game. Very impressed.

    Comment by Kelly Chladil — September 19, 2006 @ 12:10 pm

RSS feed for comments on this post. TrackBack URI

Leave a comment

Powered by WordPress