Reaction Timer

by duboisvb in Circuits > Arduino

4450 Views, 8 Favorites, 0 Comments

Reaction Timer

DSC00045.JPG
DSC00024.JPG
DSC00025.JPG
DSC00027.JPG
DSC00026.JPG
DSC00028.JPG
I am new to Arduino and wanted a project which would teach me different things. 
This got me involved with sound and the use of a LCD. 


This project is based on the Instructable posted by bertus52x11 which you can find here https://www.instructables.com/id/After-Dinner-Reaction-Time-Tester/ . 

 


While I did start with the bertus52x11 project I did make the following major mods :
1.   I use 3 LEDS  which change light pattern and the user needs to react to the correct pattern.
2.  The original tested the time it took to release the button while I test the time it takes to hit the button.
3.  I test 3 different times and record the accumulated time plus any miss hits or no hits at all.

As with the original project, this would be fun to use before and after a dinner party.  It should confirm that too much of a good thing will slow your reflexes.  I am anxious to do some testing. :)

Unfortunately I did not take pictures through out the build but I will try to explain and show what I did as best I can.


How it works:
1.Turn on with the ON/OFF switch
2. The first message will prompt you to press the red button to begin the testing
3.  Then a screen will randomly tell you too look for 1 light on, 2 lights or 3 lights
4.  The program will begin to randomly display 1, 2, or 3 lights with random noise for distraction purposes
5.  As soon as you see the target light pattern, hit the reaction button.
6. After 3 times, a summary screen will appear


The program keeps track of what the target light pattern is and only when it displays the correct pattern does it start the timer.   It also will only wait a short time. If you fail to see the correct pattern, it records it as a miss . Or if you hit the button too late or with a wrong pattern, it will record a miss. I arbitrarily add 2 seconds  to the total for a miss.

 

Video of the Timer in Action

The following 2 videos show how to use it and what happens when you push the button correctly or in correctly.




Stuff to Get

DSC00023.JPG
DSC00028.JPG

Basically this is what is  needed and an estimate of what it costs.
1. Arduino - I used a Uno but I am pretty sure others would work just fine   -  about 45.00 ( i think)
2. A box - I had this one already
3. a  LCD - I got from Adafruit - a standard 16x2 - 12.00
4. 3 LEDs - I already had - can get from many places eg Radio Shack - couple of dollars
5. a buzzer - I already had -  also Radio Shack - couple of dollars
6. wire and misc screws - I had
7.  The brass items I got at Home Depot - the corner edges, the hinge and a piece of brass stock from which to cut various pieces.- maybe 15.00


Putting It Together

DSC00029.JPG
DSC00028.JPG
DSC00030.JPG
Since the Instructable by bertus52x11 was so easy to follow, I skipped the breadboarding step and went straight to installing everything in the box.
1. I put the brass corners on
2 I installed the hinge
3. I cut 2 pieces of brass from the bigger piece . One is used to hold the LEDs  and the other for the buzzer and LCD.
4. I mounted the Arduino
5. attached the buzzer to the brass plate
6. attached the on/off button, the red start button and the reaction button
7. attached the plate with the 3 LEDs to the box
8 The 10k Pot is glued to the inside of the box

I find I can make a reasonable standoff for the Arduino by cutting a small piece from a length of tubing



All of these steps will depend on the box used and the placement of the switches.

Connections to the Arduino

DSC00028.JPG
LEDS
- the 3 LEDS are connected to pins 6,7 and 8 with a 220 ohm resistor.

Buzzer 
- one side connected pin 13 and the other to ground

ON/Off switch
- It is connected to the red wire coming from the positive side of the 9 volt battery which is in the box

Red Start Button
- This is a momentary switch which is connected to pin9
- the following link is good reference as to how to connect correctly(which I did not do at first)
http://www.arduino.cc/en/Tutorial/Button

The React Button
- Another Momentary switch connected to pin 10





The LCD

DSC00025.JPG
DSC00026.JPG
DSC00031.JPG

This was the hardest part as I had never done anything with an LCD.

But after some frustration and research, I found the following link which walked me thru it nicely.

http://www.arduino.cc/en/Tutorial/LiquidCrystal

The LCD I bought came with headers that had to be soldered to the LCD. After which, I soldered the LCD to a radio shack PCB which I could in turn attach to the brass plate.  The picture tries to show this. My soldering skills are amateurish but I am getting better.  :)

The Sketch

Below is the current version. My coding is not that sophisticated and I comment a lot .  But it seems to work.


 //After Dinner Reaction Time tester - created by Bertus52x11
// modified by Duboisvb
// idea is: will be tested 3 times
// each test is a combination of lights 
// reaction time and errors will be accumulated a
// there are 3 possible display situations
// 1. 3 lighs - 
 // 2. 2 lights - 
 // 3. 1 light - 

// a buzzing sound will be generated randomly as a form of distraction
 
// user will be asked to hit reaction button when correct display is seen



#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int LED1 = 6; // Led pin 6
int LED2 = 7; //   Led pin 7
int LED3 = 8; //   Led pin 6
int ReactButton=9;
int StartTestButton=10;
long CaseTarget; // variable Case
long litepattern; // variable pattern
int Beep;
 
float TME; // Time
float RTME=0; // Reaction Time
float rtmeTot = 0; // total time
char* myStrings1[]={"Any 1 ON", "Any 2 on", "All 3 ON"};

long x;  // counter for looping instead of delay
char toneyn;
char buttonPushed;
char goodOne;
int missedIt;


// do setup once
void setup()
{
 //  Serial.begin(9600);    // opens  // Serial port, sets data rate to 9600 bps

lcd.begin(16, 2);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
pinMode(ReactButton, INPUT);
pinMode(StartTestButton, INPUT);

}


// loop repeatedly 
void loop()
{
  // reset all variables
  TME = 0 ; // Time
  RTME=0; // Reaction Time
  rtmeTot = 0; // total time
 
  x = 0;  // counter for looping instead of delay
  toneyn  = 'N';
  buttonPushed = 'N';
  goodOne = 'N';
  missedIt = 0;
 
 lcd.clear(); // Clear screen.
lcd.print("Reaction Tester");
delay(3000);
lcd.clear(); // Clear screen.
lcd.print("Press Red Button");
lcd.setCursor(0,1); // move to second line.
lcd.print("to start tests.");
 
 
while (digitalRead(StartTestButton)== LOW) // The test does not start until the button is pushed (and held down).
{ noTone(13);
   tone(13,1200,30);
 delay(100);
 noTone(13);
 
 digitalWrite(LED1,HIGH); // All lights are switched "on".
digitalWrite(LED2, HIGH);
digitalWrite(LED3, HIGH);
}
 
 
// Red button has been pushed so clear screen and turn off lights
lcd.clear();
digitalWrite(LED1, LOW); 
digitalWrite(LED2, LOW);
digitalWrite(LED3, LOW);

// go to setcase to get test display info
setCase();

delay(100);
lcd.print("Test A ");
lcd.setCursor(0,1); // move to second line.
 lcd.print(myStrings1[CaseTarget-1]);
// stop here so the screen can be read
delay (1000);
// begin test ie start changing lites, tone and timer and react to buttons
// go todoTest function
doTest();

// test # 2
setCase();
digitalWrite(LED1, LOW); 
digitalWrite(LED2, LOW);
digitalWrite(LED3, LOW);
delay(100);
lcd.clear();
lcd.print("Test B ");
lcd.setCursor(0,1); // move to second line.
lcd.print(myStrings1[CaseTarget-1]);
delay (1000);

doTest();



// third test
setCase();
digitalWrite(LED1, LOW); 
digitalWrite(LED2, LOW);
digitalWrite(LED3, LOW);
delay(100);
lcd.clear();
lcd.print("Test C ");
lcd.setCursor(0,1); // move to second line.
lcd.print(myStrings1[CaseTarget-1]);
delay (1000);
doTest();

// display results of 3 tests
// stay here until Start test button is pushed
 
lcd.clear();
digitalWrite(LED1, LOW); 
digitalWrite(LED2, LOW);
digitalWrite(LED3, LOW);

lcd.print("Total: ");
lcd.print(rtmeTot,3);
lcd.print( " secs");
lcd.setCursor(0,1); // move to second line.
lcd.print("Errors: " );
lcd.print(missedIt);
 
delay(5000);

}


// My functions
// ---------------------------------------------------------
// ------------------------------------------------------------
// setCase
//  This is setting the target situation ie
// the number of lights 

void setCase()
{
  randomSeed(analogRead(0)); //Random noise from pin 0
CaseTarget = random(1,4); // Generate a random number to use as case for test
 
// if (CaseTarget = 1)  then 1 light
// if (CaseTarget = 2)  then 2 lights
//  if (CaseTarget = 3)  then 3 lights
}
 
 
 
// beepYN
// will randomly put out a tone for distraction purposes.
void beepYN(){
//   randomSeed(analogRead(0)); //Random noise from pin 0
Beep = random(1,8); // Generate a random number to use as case for test
 
if (Beep == 1)
{tone(13,500,100);
}
if (Beep == 2)
{tone(13,800,300);
}
if (Beep == 3)
{tone(13,1200,500 );
}
if (Beep == 4)
{tone(13,1600,700);
}
if (Beep == 5)
{tone(13,2500,900);
}

}


void waitTime()
{
  buttonPushed = 'N';
for (x = 0; x < 175000; x ++)
{
      if (digitalRead(ReactButton)== HIGH)
     {      // bail out on reaction button pressed
       x = 0;
       buttonPushed = 'Y';
       break;
    } 
 //    delay(50);
}

}

void assess()
{
 // get here because the react button was pressed
 // or it should have been pressed
 // -----------------------------------------------
//  so if pressed and was correct thing todo
//  - record time and display results
//  - go on

//  pressed but should not have been
// - record as error
// - increment time by 2 secs as penalty

//  not pressed but should have means
//  correct lite pattern went by unnoticed
// - record as error
// - increment by 1 secs



// pushed and good

if (goodOne == 'Y' && buttonPushed == 'Y'){
  RTME=millis()-TME; // Time between lites on and button pushed
  // diivide by 1000 to get secs
  RTME = RTME/1000;
  // accumalte time for last display
  rtmeTot = rtmeTot + RTME;
// display the reaction time
dspTime();
 }
 
  //   pushed but should not have
 if (goodOne == 'N' && buttonPushed == 'Y')
{
  dspError();
  // add 2 secs for each miss
  rtmeTot = rtmeTot + 2.000;
  missedIt = missedIt + 1;
  }
 
 
 // not pushed but should have
 if (goodOne == 'Y' && buttonPushed == 'N')
{
  dspError();
  // add 2 secs for each miss
  rtmeTot = rtmeTot + 2.000;
  missedIt = missedIt + 1;
  }
   
}




// here if got it right
void dspTime()
{
  delay(100);
 lcd.clear();
 lcd.print("Reaction Time:");
lcd.setCursor(0,1);
lcd.print(RTME,3);
lcd.print(  "  Secs");

delay(1000);
}
 
 
 // here if pushed button at wrong time
 void dspError()
{
  delay(100);
 lcd.clear();
lcd.print("Error");
lcd.setCursor(0,1);
// lcd.print("Try Again");
// lcd.print(RTME);

delay(1000);
}
 

void doTest()
{
  
  // continue to change lites and tone until button is pressed
  // these are possibilities
// 1. all 3 on
// 2. 2 on - 1 & 2
// 3. 2 on - 1 & 3
// 4. 2 on - 2 & 3
// 5. 1 on - 1
// 6. 1 on - 2
// 7. 1 on - 3
 // note there are 3 possibilities for both 2 and 3 lights but just one for 3
// so to make 3 come up an equal amount will assign extra random numbers
// to all 3 on
 
  while (digitalRead(ReactButton)==LOW)
{
// need to randomly change lights and give time for reaction
// there are 7 possibilties  so will get a random number and then
// set lights to that pattern
// also will turn tone on randomly
  randomSeed(analogRead(0)); //Random noise from pin 0
litepattern = random(8); //  random between 0 and 8
litepattern = litepattern + 1; // gets 1 to 9

// before turning on lites, need to assess whether or not it is a
// target lite pattern
// check to see if it was correct lite pattern
 

if((CaseTarget == 3 && (litepattern == 1 || litepattern == 8 || litepattern == 9))|| (CaseTarget == 2 && (litepattern == 2
|| litepattern == 3 || litepattern == 4)) || (CaseTarget == 1 &&(litepattern == 5 ||
litepattern == 6 || litepattern == 7)))
{
  goodOne = 'Y';
}
  else
  {
    goodOne = 'N';
  }
 

// if it is a target pattern, then need to start timer

if(litepattern == 1 || litepattern == 8 || litepattern == 9) {
digitalWrite(LED1, HIGH);
digitalWrite(LED2, HIGH);
digitalWrite(LED3, HIGH);

if(goodOne == 'Y')
{
TME=millis(); //  Start timing
}
 
  beepYN();

waitTime();

 

// if button was pushed, then need to assess
// or if button was not pushed but should have been
if((buttonPushed == 'Y') ||(buttonPushed == 'N' && goodOne == 'Y'))
{
  assess();
  return;
}
// if no button then just continue looping

}

if(litepattern == 2) {
digitalWrite(LED1, HIGH);
digitalWrite(LED2, HIGH);
digitalWrite(LED3, LOW);
  beepYN();
if(goodOne == 'Y')
{
TME=millis(); //  Start timing
}
waitTime();

 
// if button was pushed, then need to assess
if((buttonPushed == 'Y') ||(buttonPushed == 'N' && goodOne == 'Y'))
{
  assess();
  return;
}
}

if(litepattern == 3) {
digitalWrite(LED1, HIGH);
digitalWrite(LED2, LOW);
digitalWrite(LED3, HIGH);
   beepYN();
if(goodOne == 'Y')
{
TME=millis(); //  Start timing
}
waitTime();


// if button was pushed, then need to assess
if((buttonPushed == 'Y') ||(buttonPushed == 'N' && goodOne == 'Y'))
{
  assess();
  return;
}
}


if(litepattern == 4) {
digitalWrite(LED1, LOW);
digitalWrite(LED2, HIGH);
digitalWrite(LED3, HIGH);
  beepYN();
if(goodOne == 'Y')
{
TME=millis(); //  Start timing
}
waitTime();
 
// if button was pushed, then need to assess
if((buttonPushed == 'Y') ||(buttonPushed == 'N' && goodOne == 'Y'))
{
  assess();
  return;
}
}

if(litepattern == 5) {
digitalWrite(LED1, HIGH);
digitalWrite(LED2, LOW);
digitalWrite(LED3, LOW);
  beepYN();
if(goodOne == 'Y')
{
TME=millis(); //  Start timing
}
waitTime();

 

// if button was pushed, then need to assess
if((buttonPushed == 'Y') ||(buttonPushed == 'N' && goodOne == 'Y'))
{
  assess();
  return;
}
}

if(litepattern == 6) {
digitalWrite(LED1, LOW);
digitalWrite(LED2, HIGH);
digitalWrite(LED3, LOW);
   beepYN();
 if(goodOne == 'Y')
{
TME=millis(); //  Start timing
}
waitTime();

 

// if button was pushed, then need to assess
if((buttonPushed == 'Y') ||(buttonPushed == 'N' && goodOne == 'Y'))
{
  assess();
  return;
}
}

if(litepattern == 7) {
digitalWrite(LED1, LOW);
digitalWrite(LED2, LOW);
digitalWrite(LED3, HIGH);
   beepYN();
 if(goodOne == 'Y')
{
TME=millis(); //  Start timing
}
waitTime();

 
// if button was pushed, then need to assess
if((buttonPushed == 'Y') ||(buttonPushed == 'N' && goodOne == 'Y'))
{
  assess();
  return;
}
}

}

}
 



Done!


I welcome any comments!!