Making Furniture Interactive

October 5, 2007

Spinner Game (FSM)

My FSM project was a spinner game similar to the ones found at arcades. Pressing the button when the spinning lights get to a certain point increases your “score” and missing decreases it. If your score gets to 5, you are rewarded with a smiley face :0)

I thought this would be fairly simple to code but it actually ended up requiring a lot of research. I ended up using the Metro library, which is basically just a nice method that does all the millis() arithmetic for you.

:::pics, code, and fsm diagram after the break:::

intact

taken apart

FSM diagram

CODE:

//spinner game FSM
//Alastair Firth

#include <Metro.h>
int sw = 12; //switch
int bl = 11; //blue LED
int curr[8]; //led pin array
int cel; //current element
char st = 's'; //state
char click = 'n';
int bang = 1; //initates the state for the first time through
int flashfreq = 500;
boolean flashst = 0;

//Metro
Metro led_Metro = Metro(250);
Metro sleep_Metro = Metro(5);
Metro flash_Metro = Metro (100); //flash the blue while in wake
Metro gotosleep_Metro = Metro (15000); //sleep after 15secs

//for sleep
int s_sign = 1; //sleep fade up or down
int s_pwm = 5; //sleep led pwm

void setup()                    // run once, when the sketch starts
{
//for blinking leds
for (int i = 3; i &lt;= 10; i++){
curr[i-3] = i; //initialize an array of led pins
}

//set pinmodes
//note pin 11 (blue) is going to be PWM, so no declaration
for (int i = 2; i <= 10; i++){
int pin = i;
pinMode(pin, OUTPUT);
}
pinMode(12, INPUT); //switch pin
}

void loop(){
switch (st) {//this is the state switch

/**************SLEEP**********************/
case 's': //sleep
if (bang){//runs once for the initial setup
sleep_Metro.interval(15);
bang = 0;
}

if (sleep_Metro.check()){//fades the blue led
sleep_Metro.interval(15);
analogWrite(bl, s_pwm);
//flip dir if needed
if (((s_sign == 1) &amp;&amp; (s_pwm > 249)) || ((s_sign == -1) &amp;&amp; (s_pwm &lt; 9))){
s_sign = (s_sign * -1);
}
s_pwm = (s_pwm + (s_sign * 5)); //[de|in]crements by 5 from 5-250
}

if (digitalRead(sw)){//catches a switch push, closes this state and starts the new one
st = 'a';
bang = 1;
analogWrite(bl, 0);
delay(500); //gives you time to release the switch
}
break;

/**************WAKE**********************/

case 'w': //wake
if (bang){
led_Metro.interval(1);
bang = 0;
randomSeed(millis());
cel = random(0,8);
gotosleep_Metro.reset();
flashfreq = 500;
}
if (led_Metro.check()){//spin the lights
led_Metro.interval(250);
digitalWrite(curr[cel], LOW);
cel++;
if (cel == -1){
cel = 7;
}//wrap the array
if (cel == 8){
cel = 0;
}

digitalWrite(curr[cel], HIGH);
}

//blink bl faster and faster as you get more right, decreasing for misses. at blue threshold, go to r.
if (digitalRead(sw) &amp;&amp; (cel == 7)){//success
click = 's';
delay(500);
}
if (digitalRead(sw) &amp;&amp; (cel != 7)){//fail
click = 'f';
delay(500);
}

switch (click) {//checks if and when you clicked the switch
case 's': //success
flashfreq -= 99;
if (flashfreq <= 0){
flashfreq = 1;
click = 'r';
break;
}
gotosleep_Metro.reset(); //wait another 15 secs before sleeping
click = 'n';
break;

case 'f': //fail
flashfreq += 100;
if (flashfreq > 500){
flashfreq = 500;
}
gotosleep_Metro.reset(); //wait another 15 secs before sleeping
click = 'n';
break;

case 'r': //reward
st = 'r';
click = 'n';
break;

case 'n': //no action has been taken
if (gotosleep_Metro.check()){
gotosleep();
}
break;
}

if (flash_Metro.check()){//flash bl at flashfreq
flashst = !flashst;
if (flashst){
analogWrite(bl, 255);
Serial.println(flashfreq);
}
else {
analogWrite(bl, 0);
}
flash_Metro.interval(flashfreq);
}

break;

/**************ATTRACT**********************/

case 'a': //attract
if (bang){
led_Metro.interval(1);
bang = 0;
gotosleep_Metro.reset();
}
if (led_Metro.check()){//spin the lights
randomSeed(millis());
flashfreq = random(50,150);
cel = random(0,8);
led_Metro.interval(flashfreq);
digitalWrite(curr[cel], !digitalRead(curr[cel]));
if ((cel % 2) == 1){
analogWrite(bl, 255);
}
else {
analogWrite(bl, 0);
}
cel++;
}
if (digitalRead(sw)){//go back to wake if you press the switch
st = 'w';
bang = 1;
analogWrite(bl, 0);
clearall();
delay(500); //gives you time to release the switch
}
if (gotosleep_Metro.check()){//go to sleep if you do nothing
gotosleep();
}

break;

/**************REWARD**********************/

case 'r': //reward
//smiey face and blink nose
if (bang){
led_Metro.interval(1);
bang = 0;
gotosleep_Metro.reset();
cel = 0;
}

analogWrite(bl, 15);
digitalWrite(curr[0], HIGH);
digitalWrite(curr[2], HIGH);
digitalWrite(curr[4], HIGH);
digitalWrite(curr[6], HIGH);
digitalWrite(curr[7], HIGH);

if (digitalRead(sw)){
st = 'w';
bang = 1;
analogWrite(bl, 0);
clearall();
delay(500); //gives you time to release the switch
}
if (gotosleep_Metro.check()){
gotosleep();
}
break;
}
}

//turns out all the lights and goes to sleep
{
st = 's';
bang = 1;
clearall();
delay(500);
}

void clearall()//turns out all the lights
{
for (int j = 2; j &lt;= 11; j++){
digitalWrite(j, LOW);
}
}
Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: