Concept:
The player has to ‘flick’ their fingers to move the toy car forward. If the car stops at the ‘winning line’ the player wins. The point of this game is for the user to guess where the line is by looking at the LEDs.
Behavior:
The start of the game is initiated by the tune. The distance between the toy car and the sensor is measured using the distance sensor. When the player successfully lands the toy car on the winning line of the lane, the winning tune plays, indicating that the player has won the game. If they fail to do so, they can play again; the green LED lights up on the winning line, yellow LED lights up when the toy car gets close to the line and red LED lights up when it is far away from the line. So the LEDs act as a feedback and hints depending on the distance the toy car is away from the distance sensor. When they flick the car too hard and gets too close to the sensor, a tune plays to warn them.
Program
#include "pitches.h" int red = 7; int yellow = 5; int green = 4; int counter = 0; int currentState = 0; int previousState = 0; int counterNo; int countNo; int trigPin = 11; // Trigger int echoPin = 12; // Echo long duration, cm; int buzzer = 8; int melody[] = { //winning melody NOTE_C6, NOTE_E6, NOTE_G6, NOTE_C7 }; int start[] = { NOTE_E6, 0, NOTE_E6, 0, NOTE_E6, 0, NOTE_C7 }; int lose[] = { NOTE_C3, NOTE_C3, NOTE_C3 }; int tempo[] = { 4, 4, 4, 4, 4, 4, 1 }; int noteDurations[] = { 4, 4, 4, 2 }; int losetempo[] = { 4, 4, 1 }; void setup() { Serial.begin (9600); //Define inputs and outputs pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); pinMode(7, OUTPUT); pinMode(5, OUTPUT); pinMode(4, OUTPUT); //playing the starting tune once for (int thisNotes = 0; thisNotes < 7; thisNotes++) { int noteDuration = 1000 / tempo[thisNotes]; tone(8, start[thisNotes], noteDuration); int pauseBetweenNotes = noteDuration * 1.30; delay(pauseBetweenNotes); } } void loop() { //unsigned long storedTime = millis(); digitalWrite(trigPin, LOW); delayMicroseconds(5); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); // Read the signal from the sensor: a HIGH pulse whose // duration is the time (in microseconds) from the sending // of the ping to the reception of its echo off of an object. pinMode(echoPin, INPUT); duration = pulseIn(echoPin, HIGH); // Convert the time into a distance cm = (duration / 2) / 29.1; // Divide by 29.1 or multiply by 0.0343 // Divide by 74 or multiply by 0.0135 Serial.println(cm); Serial.print(" "); delay(15); if ( cm >= 13 && cm <= 20) { //winning line interval currentState = 1; //count to keep track of the duration in which the car stops on the lane within the interval. digitalWrite(green, HIGH); digitalWrite(red, LOW); digitalWrite(yellow, LOW); countNo = 0; } else if (cm >= 8 && cm < 13 || cm > 20 && cm < 23) { //close interval currentState = 0; digitalWrite(yellow, HIGH); digitalWrite(green, LOW); digitalWrite(red, LOW); countNo = 0; } else if (cm < 7) { //too close to the sensor interval countNo = 1; digitalWrite(red, HIGH); digitalWrite(green, LOW); digitalWrite(yellow, LOW); } else { //far away from the winning line interval //noTone(8); currentState = 0; digitalWrite(red, HIGH); digitalWrite(green, LOW); digitalWrite(yellow, LOW); countNo = 0; } if (currentState == 1 && currentState != previousState) { //increments to the count for the winning interval counter = counter + 1; } else { counter = 0; if (countNo == 1) { counterNo++; } else { counterNo = 0; } Serial.print("\t"); Serial.println(counterNo); } if (counter == 5) { //playing the winning tune for (int thisNote = 0; thisNote < 4; thisNote++) { int noteDuration = 1000 / noteDurations[thisNote]; tone(8, melody[thisNote], noteDuration); int pauseBetweenNotes = noteDuration * 1.30; delay(pauseBetweenNotes); } //tone(buzzer, 330); } else { noTone(8); } //warning tune when the car gets too close to the distance sensor if (counterNo == 3) { for (int thisNote = 0; thisNote < 2; thisNote++) { int noteDuration = 1000 / losetempo[thisNote]; tone(8, lose[thisNote], noteDuration); int pauseBetweenNotes = noteDuration * 1.30; delay(pauseBetweenNotes); } } else { noTone(8); } delay(250); Serial.print("\t"); Serial.println(counter); }
The coding for the distance sensor was taken from:
Problem:
I initially planned to use two servos with a potentiometer that would control the speed at which the servo motor turns but the force wasn’t strong enough to push the car as far as I wanted. I tried glueing pieces of cardboard on the motor to give it a larger surface area but it still wasn’t enough.
I also wanted to use Millis() to record the duration of the car coming to a complete stop in a given interval, but I couldn’t find a way around it. Instead, I used boolean to set a condition as true when the car landed in the right interval, then setting another condition where the count would increment as soon as the boolean was true.
When I was using the count, I had to make sure where it was because I had trouble making it work after inserting the code in an irrelevant if loop.
Things to improve/ What I could have done better:
Although I had some kind of basic feedback in my project like the different colored LEDs, I think it would have been better if I indicated the start/ restart of the game somehow; I was really inspired by Yeji’s restart button and Bowen’s ‘number of lives’ LEDs. Incorporating these ideas and features would have increased the structure and form of my project.
Although I tried inserting an LCD panel to indicate the exact distances the toy car was away from the winning line, it would have been better if I used it to indicate the start and finish to the game. For example, the LCD could display the time as a stopwatch so the player can have as many trials as they want until the time runs out. Since the LCD panel can display 4 lines of characters, I can use the increment function to increment the scores of the player when their car reaches the winning line.
Good project, and good documentation. Many of the comments that I made regarding your musical instrument apply here as well: better comments, better names for variables. Great job explaining what didn’t work and how you tried to fix them.
I really liked the use of the melodies to indicate success and failure. This is a very satisfying and elegant feedback to the user and your choice of melodies is so obvious that it doesn’t require documentation.