Reaction time game. How to solve infinite loop.

edited January 2016 in Arduino

I'm programming my arduino to make a reaction time game as a sketch for a more serious scientific study. It works like this

  1. you press a button once, and a led blinks indicating the game begins
  2. after a random lapse, the led lights up, and a clock starts to measure the time until you press the button again
  3. if you do, it shows the reaction time in seconds
  4. if you press before the led lights up, it blinks three times and the game ends
  5. if you don't press the button after a tame, the led blinks twice and the game ends
  6. once the game ends, it only begins again if you press the button again.

I've managed to work ok all steps from 1 through 5, but I cannot see how to get to work step 6. The way the code is written, after 5 it loops back to 1, infinitely. Any ideas on how to solve this?

/* REACTION TIME (with 2 leds) v2.1 beta
    Luis Andrés Gonzalez
   Reaction time original version from http://www.instructables.com/id/Arduino-Reaction-Time-Tester/?ALLSTEPS
   Send data to processing via the Serial Port original from By Elaine Laguerta http://url/of/online/tutorial.cc
*/
const int switchPin = 6;  // pin where the button will be connected
const int ledPin1 = 2 ;   // Left LED
const int ledPin2 = 8 ;   // Middle LED
const int ledPin3 = 12;   // Right LED

// declare some variables:
boolean lastButton = LOW;
boolean currentButton = LOW;
boolean gameStarted = false;  // true if game has started
boolean timerFlag = false;    // true if timer is running
long startTime;
long endTime;
int randomSeconds;
long beginTime;
float elapsedTime;
int maxTimer = 5 * 1000;
float totalTime;



void setup() {
  // Setup button and LEDs:
  pinMode(switchPin, INPUT);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);

  // Begin serial communication
  Serial.begin(9600);
}

void loop() {
  // Check https://www.arduino.cc/en/Tutorial/StateChangeDetection to understand the following code.
  if ((millis() - beginTime) > (randomSeconds + maxTimer)) {
    Stop();
    
    //resets game:
    gameStarted = false;
    timerFlag = false;
    currentButton = LOW;
    lastButton = LOW;
    
    
    Blink(2);
    Serial.println("message");

  }
  // read the pushbutton input pin in the current loop:
  currentButton = buttonPressed(lastButton);

  // if there's a change from low to high (comparing last and current loop) then the following is true
  if (currentButton == HIGH && lastButton == LOW) {   // outer IF

    if (gameStarted == false) {                       // middle IF. starts the game
      gameStarted = true;
      randomSeconds = random(2, 5) * 1000; // generates a random number of seconds between 3 and 8
      Blink(1);
      Serial.println("9090"); // signal code for start sound
      beginTime = millis();
    } else {

      if ((millis() - beginTime) >= randomSeconds) {
        Stop();
        gameStarted = false;
        timerFlag = false;

      } else if ((millis() - beginTime) < randomSeconds ) {
        gameStarted = false;
        timerFlag = false;
        Serial.println("1010"); // signal code for early response
        Blink(3);
      }

    }
  }                             // end outer if

  // save the current state as the last state,
  //for next time through the loop
  lastButton = currentButton;




  // If true, starts the response time timer and lights up the LED
  if (gameStarted == true && (millis() - beginTime) >= randomSeconds && timerFlag == false) {
    timerFlag = true;

    Start();

  }
  
} // end void loop

//===========================================================================================

boolean buttonPressed(boolean last) {       //button debouncing function
  boolean current = digitalRead(switchPin);
  if (last != current) {
    delay(5);
    current = digitalRead(switchPin);
  }
  return current;
}

void Start() {

  startTime = millis();
  Light(ledPin1, "on");

}

void Stop() {
  if ( (millis() - beginTime) 

Answers

  • Answer ✓

    Somehow your code is not complete at the very end

    Anyway. I suggest you work with states. Like states of a program

    Google state within the forum.

    You can use

    if(state==stateWaitForRestart) {

    etc.

    When you define stateWaitForRestart as

    int stateWaitForRestart=6;

    Before setup()

    make an if else if clause for each state

    Nothing I repeat nothing is allowed outside the if ... else if {...} clause in draw()

    but thus you get a very readable code and all things will fall into place

  • Just handle the states and the Transformation between them right

  • Thanks @Chrisir. I've followed your advice and from everyone else and I've revamped the code to deal with states. Now the problem is that I can't manage to make the reaction timer to work. It shows an ever-increasing ammount of time.

    /* REACTION TIME (with 2 leds) v3.0 beta
        Luis Andrés Gonzalez
       Reaction time original version from http://www.instructables.com/id/Arduino-Reaction-Time-Tester/?ALLSTEPS
       Send data to processing via the Serial Port original from By Elaine Laguerta http://url/of/online/tutorial.cc
    */
    #define TIMEOUT_MILLISECONDS  5000UL  // not too tough; make smaller for a bigger challenge
    
    const char* const stateText[] = { "Stand By", "Active Game", "Early Press", "Good Press", "Late Press"};
    
    enum GameState {
      STAND_BY,
      ACTIVE_GAME,
      EARLY_PRESS,
      GOOD_PRESS,
      LATE_PRESS,
    };
    enum Outcomes {
      GOOD,
      EARLY,
      LATE,
    };
    
    const byte buttonPin = 6;  // pin where the button will be connected
    const byte ledPin1 = 3 ;   // Left LED
    const byte ledPin2 = 8 ;   // Middle LED
    const byte ledPin3 = 12;   // Right LED
    
    GameState gameState = STAND_BY;
    Outcomes outcome;
    GameState lastState;
    
    // declare some variables:
    boolean lastButton = LOW;
    boolean pressed = LOW;
    unsigned long lastMillis = 0;
    unsigned long elapsedMillis;
    
    
    boolean gameStarted = false;  // true if game has started
    boolean timerFlag = false;    // true if timer is running
    long startTime;
    long endTime;
    int randomSeconds;
    long beginTime;
    float elapsedTime;
    int maxTimer = 5 * 1000;
    float totalTime;
    int brightness = 0;    // how bright the LED is
    int fadeAmount = 5;    // how many points to fade the LED by
    
    
    
    
    void setup() {
      // Setup button and LEDs:
      pinMode(buttonPin, INPUT);
      pinMode(ledPin1, OUTPUT);
      pinMode(ledPin2, OUTPUT);
      pinMode(ledPin3, OUTPUT);
    
      // Begin serial communication
      Serial.begin(9600);
      Serial.println(stateText[gameState]);
    }
    
    void loop() {
    
      // read the pushbutton input pin in the current loop:
      pressed = checkButton();
        
      if (gameState == STAND_BY) {
        Fade();
        if (pressed) {
          Light(ledPin1, "off");
          randomSeconds = random(2, 5) * 1000; // generates a random number of seconds between 2 and 5
          Blink(1);
          startTime = millis();
          gameState = ACTIVE_GAME;
          Serial.println("9090"); // signal code for start sound
          Serial.println(stateText[gameState]);
          
        }
      }
    
      else if (gameState == ACTIVE_GAME) {
        elapsedMillis = millis() - lastMillis;
            
        if (elapsedMillis >= randomSeconds) {
          if (elapsedMillis < randomSeconds + TIMEOUT_MILLISECONDS) {
            Light(ledPin1, "on");
            
          }
          else if (elapsedMillis > randomSeconds + TIMEOUT_MILLISECONDS) {
            Serial.println("TimeOut!!");
            Light(ledPin1, "off");
            gameState = LATE_PRESS;
          }
    
        }
        else if (pressed)
        {
          if (digitalRead(ledPin1))
          {
            long myTime = millis() - startTime;
            Serial.println(float (myTime/1000));
            gameState = GOOD_PRESS;
            Serial.println(stateText[gameState]);
          }
          else
          {
            gameState = EARLY_PRESS;
          }
        }
    
    
      }
      else if (gameState == EARLY_PRESS) {
    
        Serial.println("1010"); // signal code for early response
        Blink(3);
        gameState = STAND_BY;
        Serial.println("Standing by...");
        delay(1000);
    
      }
      else if (gameState == GOOD_PRESS) {
        gameState = STAND_BY;
        Serial.println("Standing by...");
        delay(1000);
    
        if (pressed)
        {
    
        }
      }
      else if (gameState == LATE_PRESS) {
        gameState = STAND_BY;
        Serial.println("Standing by...");
        delay(1000);
      }
    
    
    }
    
    
    
    
    bool checkButton()
    {
      static byte lastButtonState = 1;
      byte buttonState = digitalRead(buttonPin);
      if (buttonState == 0 && lastButtonState == 1 && millis() - lastMillis > 75UL) // 
  • In line 100 the else makes no sense.

    I feel the version is still too complicated

    You need more states: activegame_begin // led off

    activegame_waiting // led on

    Also you still have code outside if state== etc.

    Also you have delay (1000) you shouldn't..... handle this with new states

  • The main goal is to make things work the way it was sketched. This program is never intended to work this way, so I think adding more states is an extra work for no purpose.

    The if around the else in line 100 is the one that checks if the button is pressed before the light is turned on. Is not as elegant as declaring a state like LIGHT_ON but I like the fact that relies directly on the fact that the light is actually turned on.

    Anyways, you're right the code is messy. I solved the issue around the timer and remove some clutter. Here's the last code that does the trick.

    /* REACTION TIME (with 2 leds) v3.0 
        Luis Andrés Gonzalez
       Reaction time original version from http://www.instructables.com/id/Arduino-Reaction-Time-Tester/?ALLSTEPS
       Send data to processing via the Serial Port original from By Elaine Laguerta http://url/of/online/tutorial.cc
    */
    #define TIMEOUT_MILLISECONDS  5000UL  // not too tough; make smaller for a bigger challenge
    
    const char* const stateText[] = { "Stand By", "Active Game", "Early Press", "Good Press", "Late Press"};
    
    enum GameState {
      STAND_BY,
      ACTIVE_GAME,
      EARLY_PRESS,
      GOOD_PRESS,
      LATE_PRESS,
    };
    
    
    const byte buttonPin = 6;  // pin where the button will be connected
    const byte ledPin1 = 3 ;   // Left LED
    const byte ledPin2 = 8 ;   // Middle LED
    const byte ledPin3 = 11;   // Right LED
    
    GameState gameState = STAND_BY;
    GameState lastState;
    
    // declare some variables:
    boolean lastButton = LOW;
    boolean pressed = LOW;
    unsigned long lastMillis = 0;
    unsigned long elapsedMillis;
    
    
    long startTime;
    long endTime;
    int randomMillis;
    long beginTime;
    float elapsedTime;
    
    float totalTime;
    int brightness = 0;    // how bright the LED is
    int fadeAmount = 5;    // how many points to fade the LED by
    
    void setup() {
      // Setup button and LEDs:
      pinMode(buttonPin, INPUT);
      pinMode(ledPin1, OUTPUT);
      pinMode(ledPin2, OUTPUT);
      pinMode(ledPin3, OUTPUT);
    
      // Begin serial communication
      Serial.begin(9600);
      
    }
    
    void loop() {
      startTime = millis ();
      // read the pushbutton input pin in the current loop:
      pressed = checkButton();
    
      if (gameState == STAND_BY) {
        Fade();
        Light(ledPin1,"off");
        if (pressed) {
          endTime = millis();
          Light(ledPin1, "off");
          randomMillis = random(2, 8) * 1000; // generates a random number of milliseconds between 2 and 5
          Blink(1);
    
          gameState = ACTIVE_GAME;
          Light(ledPin3,"off");
          Serial.println("9090"); // signal code for start sound
          beginTime = millis() - lastMillis;
          
    
        }
      }
    
      else if (gameState == ACTIVE_GAME) {
        elapsedMillis = millis() - lastMillis;
    
        if (elapsedMillis >= randomMillis) {
          if (elapsedMillis < randomMillis + TIMEOUT_MILLISECONDS) {
            Light(ledPin1, "on");
            
    
    
          }
          else if (elapsedMillis > randomMillis + TIMEOUT_MILLISECONDS) {
            Serial.println("7777");
            delay(1000);
            Light(ledPin1, "off");
            gameState = LATE_PRESS;
          }
    
        }
        else if (pressed)
        {
          if (digitalRead(ledPin1))
          {
            gameState = GOOD_PRESS;
    
          }
          else
          {
            gameState = EARLY_PRESS;
          }
        }
    
    
      }
      else if (gameState == EARLY_PRESS) {
    
        Serial.println("1010"); // signal code for early response
        Blink(3);
        gameState = STAND_BY;
        delay(1000);
    
      }
      else if (gameState == GOOD_PRESS) {
    
        gameState = STAND_BY;
        
        long reactionTime = (startTime - endTime - randomMillis);
        Serial.println(reactionTime);
        
        
      }
      else if (gameState == LATE_PRESS) {
        gameState = STAND_BY;
        delay(1000);
      }
    
    
    }
    
    
    
    
    bool checkButton()
    {
      static byte lastButtonState = 1;
      byte buttonState = digitalRead(buttonPin);
      if (buttonState == 0 && lastButtonState == 1 && millis() - lastMillis > 5UL) // 
  • Great that you accomplished it!

    I really think states help to make a program better. You can hunt errors easier, you got better compartmentalization / sections ...

    It's better readable, better maintainable

    States are not a goal i itself but only a tool. A powerful tool.

    You can auto-format your code with ctrl-t btw (iirc for arduino as well)

  • edited January 2016
    const byte buttonPin = 6;  // pin where the button will be connected
    const byte ledPin1 = 3;    // Left LED
    const byte ledPin2 = 8;    // Middle LED
    const byte ledPin3 = 11;   // Right LED
    

    Since those above are also constants, just like TIMEOUT_MILLISECONDS, STAND_BY, OUTPUT, etc., the convention dictates they should be entirely capitalized too! Either as const or #define: ;;)

    const byte BTN_PIN = 6;  // pin where the button will be connected
    const byte LEFT_LED_PIN_1   = 3;   // Left LED
    const byte MIDDLE_LED_PIN_2 = 8;   // Middle LED
    const byte RIGHT_LED_PIN_3  = 11;  // Right LED
    
    #define BTN_PIN = 6;  // pin where the button will be connected
    #define LEFT_LED_PIN_1   = 3;   // Left LED
    #define MIDDLE_LED_PIN_2 = 8;   // Middle LED
    #define RIGHT_LED_PIN_3  = 11;  // Right LED
    
Sign In or Register to comment.