Reaction Timer

I am new to the world of electronics. I have Make: Electronics 2nd edition and enjoy it.... however, I feel like I am spending a lot of time on areas not of interest. My primary interest is punching/kicking speed/reaction time. I am looking for suggestions on a kit to make a reaction timer: LED light that goes off randomly starting the timer and about 2 sensor pads, that once hit, stops the timer, then resets. Seems simple enough but I am halfway through this book and am still not able to figure out that aspect. Any advice? I appreciate your patients and time.

The simplest way to implement your requirement is a finite state machine. At any time, your application can be doing one thing; e.g. generate a random number, delay, etc. This is called a state, I will also refer to it as step. If one step is finished, you can switch to the next step.

So first you define the states and declare a variable to hold the state.

/*
  state machine related
*/
// possiblle states of our reaction tester
enum STATES
{
  START,      // generate a random delay time
  DELAY,      // wait for the delay time to be lapsed
  TEST,       // wait for user to press button
  REPORT,     // report result
  FINISHED,   // wait for user to release button
};
// variable to hold the state of our reaction tester; initial state is START
STATES state = START;

An enum creates a special type (like int, float etc) of variable that in your code can only be set to the defined values.

You will need a standard way to declare the pins that are connected to the led and the button and some variables for the timing.

/*
  pins to use
*/
const byte pinLed = 13;
const byte pinBtn = 2;

/*
  timing related variabless
*/
// variable to remember start of delay or start of reaction test
uint32_t startTime;
// randomly generated delay
uint32_t waitDuration;

In setup(), you configure the pins

void setup()
{
  Serial.begin(57600);

  // configure led pin
  pinMode(pinLed, OUTPUT);
  digitalWrite(pinLed, LOW);

  // configute button pin; button between pin and GND
  pinMode(pinBtn, INPUT_PULLUP);
}

In loop(). the statemachine can be implemented using a switch/case; there are other ways but for a beginner this is probably the easiest to understand. The framework

void loop()
{
  switch (state)
  {
    case START:
      break;
    case DELAY:
      break;
    case TEST:
      break;
    case REPORT:
      break;
    case FINISHED:
      break;
  }
}

And next you can implement the code for each state (step). The code will also have to read the button; this is done just once in the beginning of loop() and the state of the button is remembered.

void loop()
{
  // read the button
  byte buttonState = digitalRead(pinBtn);

  // the statemachine implementation
  switch (state)
  {
    case START:
      // make sure led is off
      digitalWrite(pinLed, LOW);
      // set a random delay
      waitDuration = random(500, 20000);
      // set the start time of the delay
      startTime = millis();
      // switch to next step
      state = DELAY;
      break;
    case DELAY:
      // if the user pressed the button too early
      if (buttonState == LOW)
      {
        // cheating
        // back to start
        state = START;
      }
      // if the random delay is finished
      if (millis() - startTime >= waitDuration)
      {
        // switch led on
        digitalWrite(pinLed, HIGH);
        // start time indicates when reaction time measurement was started
        startTime = millis();
        // switch to next step
        state = TEST;
      }
      break;
    case TEST:
      // wait for button to be pressed
      if (buttonState == LOW)
      {
        // switch to next step
        state = REPORT;
      }
      break;
    case REPORT:
      // switch led off
      digitalWrite(pinLed, LOW);
      // inform the user
      Serial.print("Reaction time = "); Serial.println(millis() - startTime);
      // switch to next step
      state = FINISHED;
      break;
    case FINISHED:
      // wait a little for debounce and flash purposes
      delay(100);
      // toggle the led pin to indicate that the user should release the button
      digitalWrite(pinLed, digitalRead(pinLed));
      // if button released
      if (buttonState == HIGH)
      {
        // back to start
        state = START;
        // wait a little for debounce purposes
        delay(100);
      }
      break;
  }
}

Full code (some stuff moved around)

/*
  pins to use
*/
const byte pinLed = 13;
const byte pinBtn = 2;

/*
  timing related variabless
*/
// variable to remember start of delay or start of reaction test
uint32_t startTime;
// randomly generated delay
uint32_t waitDuration;

/*
  state machine related
*/
// possiblle states of our reaction tester
enum STATES
{
  START,      // generate a random delay time
  DELAY,      // wait for the delay time to be lapsed
  TEST,       // wait for user to press button
  REPORT,     // report result
  FINISHED,   // wait for user to release button
};
// variable to hold the state of our reaction tester; initial state is START
STATES state = START;


void setup()
{
  Serial.begin(57600);

  // configure led pin
  pinMode(pinLed, OUTPUT);
  digitalWrite(pinLed, LOW);

  // configute button pin; button between pin and GND
  pinMode(pinBtn, INPUT_PULLUP);
}

void loop()
{
  // read the button
  byte buttonState = digitalRead(pinBtn);
  switch (state)
  {
    case START:
      // make sure led is off
      digitalWrite(pinLed, LOW);
      // set a random delay
      waitDuration = random(500, 20000);
      // set the start time of the delay
      startTime = millis();
      // switch to next step
      state = DELAY;
      break;
    case DELAY:
      if (buttonState == LOW)
      {
        // cheating
        // back to start
        state = START;
      }
      // if the random delay is finished
      if (millis() - startTime >= waitDuration)
      {
        // switch led on
        digitalWrite(pinLed, HIGH);
        // start time indicates when reaction time measurement was started
        startTime = millis();
        // switch to next step
        state = TEST;
      }
      break;
    case TEST:
      // wait for button to be pressed
      if (buttonState == LOW)
      {
        // switch to next step
        state = FINISHED;
      }
      break;
    case REPORT:
      // switch led off
      digitalWrite(pinLed, LOW);
      // inform the user
      Serial.print("Reaction time = "); Serial.println(millis() - startTime);
      // switch to next step
      state = FINISHED;
      break;
    case FINISHED:
      // wait a little for debounce and flash purposes
      delay(100);
      // toggle the led pin to indicate that the user should release the button
      digitalWrite(pinLed, digitalRead(pinLed));
      // if button released
      if (buttonState == HIGH)
      {
        // back to start
        state = START;
        // wait a little for debounce purposes
        delay(100);
      }
      break;
  }
}

It compiles but is not tested.

Note: Please note that the code does not use delay but a millis() based approach. As a result, the reaction on the button press and release will be nearly instantly.

Thank you. It sounds like I need to finish the book and then some. This was more than I thought.

antt: Thank you. It sounds like I need to finish the book and then some. This was more than I thought.

It is not that complicated if you take it one step at a time, you need to get your hands dirty. Buying a starter kit and working through the examples will give you everything you need.

I would say the hardest bit of this project would be designing the sensor that detects the punch/kick so that it is convenient to use, does not hurt the user and is robust enough to put up with alot of rough treatment (maybe such things exist off-the-shelf?).

For the electronics/programming; Just make a sketch that turns on an LED. Then modify it to so that the LED only comes on when a button is pressed. Now add a second LED and make that LED blink (there is a "blink without delay" tutorial). Change the sketch again so that instead of a regular blink the second LED blinks at random times. Finally change your sketch so that after the second LED blinks the sketch times how long elapses until the button is pressed.

If you build things up a step at a time it is easy. Put lots of print statements in your code so that you know it is doing what you were expecting it to do.