Project 5: Speed Games
The purpose of this lab is to give you yet more practice in creating more sophisticated code. We'll make more use of functions, loops, conditionals, and arrays this week.
Our main application for the project will be a speed game that measures average reaction time to a stimulus. The other part of the project is a pure design task to get you thinking about the process.
Tasks
Part 1: Reaction Timer State Machine
The first task is to create a reaction timer game using the capacitive sensor and the LEDs. Connect three of your capacitive sensor pins to pads of something conductive, such as the copper tape on a piece of paper. Label one pad as Start, one pad as React, and one pad as Halt.
The process we want to encode is as follows:
- If the player taps Start, the circuit should turn on a red LED and wait for a period of time.
- While the circuit is waiting, if the user taps React, it should flash the red lights and return to step 1, reporting a disqualifcation.
- At the end of the wait period, the circuit should turn off the red LED and turn on a green LED. It should also record the time.
- When the player taps React, the circuit should compute the difference between the current time and the recorded time and report that to the player. It should then give some visual indication and return to step one.
- At any time, if the player taps Halt, the circuit should halt.
The first set of tasks focuses on just the state aspects of the task and makes sure the state is changing properly in response to the sensor and time inputs.
- As a group in the lab, we created a state machine description of the process. We ended up with three states: Idle, Wait, and React. Recreate that state machine and include a diagram or picture of it with your report.Your diagram should give a name and number to each state, and indicate the lighting pattern of the LEDs when the game is in that state. The diagram should also contain all of the transitions between states, with the transitions labeled as to their cause and any actions that must occur during the transition.
-
Create a new file and save it as reaction. You can use the template below.
#include <Wire.h> #include "Adafruit_MPR121.h" Adafruit_MPR121 cap = Adafruit_MPR121(); // put your touched function here // put your setLED function here int main() { init(); // startup the Serial port Serial.begin(9600); Serial.println("MPR121 Cap touch test"); // start up the cap sensor if ( !cap.begin( 0x5A)) { Serial.println("MPR121 not found"); return (0); // exit } Serial.println("MPR121 found"); // set up the LED pins as OUTPUTS // set up the LED variables // define other variables here for(int quit=0;!quit;) { int curtouched = cap.touched(); // if the player touched the halt pad // turn off LEDs, set quit to 1, and continue switch(state) { case 0: // idle state, wait for the start button // turn on the green LEDs // if the player touched the start pad // assign to state the value 1 (go to wait state) // turn on one red LED // assign to deadline 1000 plus the current time (millis()) // break; break; case 1: // wait state, wait for a random amount of time // assign to curtime the current time (millis()) // if curtime is greater than or equal to deadline // turn on one green LED // assign to state the value 2 (go to count state) // break; } // if the React pad has been touched // flash the red LEDs four times // print "Too Fast" to the serial port // set state back to 0 // break; } break; case 2: // count state, wait for the user to hit the reaction button // if the player touches the React Pad // print "Done" to the serial port // flash the green LEDs 4 times // assign to state the value 0 (Idle state) // break; } break; default: // invalid state state = 0; break; } lasttouched = curtouched; delay(5); } return(0); }
- In your main function, define int variables called state and lasttouched, setting both to 0. Then define unsigned long variables called curtime and deadline.
-
Write a function
int touched( int whichsensor, int curstates, int priorstatus)
that checks if a specified capacitive sensor pin was just touched given a current status and a prior status value. It should return a non-zero value if the specified pin was just touched, and zero otherwise. This should encapsulate the bit-checking code from the prior project, but it does not require a for loop, as it should check only one of the capacitive sensor pins. - Fill in the rest of the code in the body template above. Download and test your code to see if it is following the right procedure. Are the lights flashing properly given your actions? Finishing up the timing aspect of this circuit is the next set of tasks.
Part 2: Reaction Timer Timing
The next step is to finish the timing aspects of this circuit. To do this, we need to do three things: (1) add an element of randomness to the wait time to reduce its predictabilty, (2) calculate the reaction time, and (3) store up to 50 reaction times and report the average after each round of the game.
-
Creating random numbers is not a trivial matter on an embedded system. A low-cost/low-computation method of generating pseudo-random numbers is to use something called a linear feedback shift register. If you want to know more about them, check out the Wikipedia page. For now, just copy the following function and place it above your main function. The function will return a pseudo-random number in the range of 1 to 65535.
// A random number generator with a period of 65535 unsigned lfsr16() { static unsigned lfsr = 0x7316; // initial value and memory unsigned lsb = lfsr & 1; // get the carry out bit lfsr >>= 1; // right shift lfsr by 1 lfsr ^= (-lsb) & 0xB400u; // xor lfsr with the tap pattern return (lfsr); }
To generate a random number in the range of 0 to N, you can call the lfsr16 function and then compute the return value modulo N. For example, the expression
(lfsr16() % 100)
will provide a value between 0 and 99. Use the lfsr16 function to add a random value between 0 and 1000 to the deadline computed when the code transitions from Idle to Wait. -
When transitioning from the Wait state to the React state, get the current time by using the
millis()
function and assign it to the starttime variable. - When the user touches the React pad in state 2, assign to curtime the result of calling millis(). Compute the the difference between the current time and the start time, then report this as seconds and hundredths of seconds to the serial port. At this point, test your code and make sure the timing all seems to be working well.
- Create an int array times of size 50 as well as an int variable numTimes initialized to 0. When the user hits React in state 2, store the latest reaction time in the next open space in the array and increment the array index (numTimes). Then calculate the average value of the array and report the average reaction time. Look back at your prior projects to see if there is an avg function you could use to compute the average. Note that you should use only the entries in the array that have been filled. If you play the game enough to fill the array, start the process over by resetting the index to 0.
- Submit a video of your reaction timer working.
Part 3: Memory Game Design
This part of the project is a design-only task. If you want to implement your design, that is a multi-point extension. These materials should go in your wiki report.
- Pick some type of memory game where the computer would first play a series of notes, or light up a sequential pattern of lights, or provide a set of numbers. Define the inputs to the game and its rules.
- Write out a state machine diagram for your game showing the different states of the game and what causes transitions between states. Label the edges between states with the cause of the transition and any actions that must take place during the transition. You can have a state like "Play Pattern" that generates and plays the pattern for the player until the pattern is complete. You can also have a state "Listen" that listens to the player's input, comparing it with the generated pattern, and transition out if the player makes a mistake or completes the pattern correctly. Include this diagram in your report along with a text description of your game and how it would work.
- Include in your report, a statement of how you would generate the sequences to be played by the computer. You can assume you have access to the lfsr16 function.
Follow-up Questions
- Did functions make your code simpler and easier to write?
- What is your understanding of the word state in the context of a sequential process?
- How does a computer represent numbers internally?
- A switch statement is similar to what other programming structure?
Extensions
- Enhance the reaction timer game.
- Have it remember your fastest time.
- Have it remember your slowest time.
- Compute the standard deviation of the recorded times as well as the mean/average.
- Add sound effects.
- Let the player choose light or sound to specify when to react. Compare the differences in response times.
- Implement the game you designed in part 3.
- Do some research on generating random numbers. Explain how a linear feedback shift register works, for example. Implement a different LFSR than the one provided.
Report
Each week you will write a brief report about your project. In general, your intended audience for your write-up is your peers not in the class. From week to week you can assume your audience has read your prior reports. Your wiki report should explain to friends what you accomplished in this project and to give them a sense of how you did it.
Your project report should contain the following elements.
- Abstract: a brief summary (200 words or less) of
the task, in your own words. give the reader context and
identify the key purpose(s) of the project. You can assume the
reader has read your prior assignments.
Writing an effective abstract is an important skill. Consider the following questions while writing it.
- Does it describe the CS concepts of the project (e.g. writing loops and conditionals)?
- Does it describe the specific project application (e.g. creating applications with the LCD)?
- Does it describe your the solution or how it was developed (e.g. what code did you write/circuits did you build)?
- Does it describe the results or outputs (e.g. did your code and circuit work as expected)?
- Is it concise?
- Are all of the terms well-defined?
- Does it read logically and in the proper order?
- A description of your solution to the tasks. This should be a description of the form and functionality of your final code and the design of your breadboard circuits. Try to describe your algorithm or code without including actual code in your report. Using 1-2 lines as an example is acceptable. Using simple diagrams or pictures of your board may be helpful when describing your circuits. Note any unique computational solutions or hardware circuits you developed.
- A description of any extensions you undertook, including images, videos, or diagrams demonstrating those extensions. If you added any functions, or other design components, note their structure and the algorithms you used.
- The answers to any follow-up questions.
- A brief description (1-3 sentences) of what you learned.
- A list of people you worked with, including TAs, and professors. Include in that list anyone whose code you may have seen, such as those of friends who have taken the course in a previous semester.
- Don't forget to label your writeup so that it is easy for others to find. For this lab, use cs153f18project5
Handin
Mount the Courses volume. Navigate to the Private sub-directory. Create a new folder called project01. (It's best to avoid spces in the directory name.) Each week, the following items should be submitted here.
- Code that should graded and any required supporting materials. This week, submit your code from all of the project tasks. Code from lab exercises will generally not be graded unless it is used as part of the project tasks.
- Videos of your work. You can also submit videos as part of your report on the wiki, but please put a copy of the video here.
Your report should be submitted as a wiki page with the appropriate label, as noted above.