Week 10 – Table Piano

Concept:

Moeez and I collaborated on a project and aimed to push our limits. Our goal was to create a table piano using an ultrasonic sensor, a sensor we had never used before. As we reminisced about our experiences with musical instruments, we recognized the hassle the school music band encountered carrying bulky and expensive pianos around. To tackle this issue, we came up with a solution: a table piano. We attached the sensor and the Arduino to the table and marked lines on the table using a scale and a marker. A fixed point was established at the end to indicate the piano’s length. We divided the piano into seven notes and utilized the Serial Monitor to determine the distance for each “Piano Key.” Afterwards, we researched online and discovered the notes that play “Jingle Bells” and assigned them to the keys in the table piano. To enhance the piano’s functionality, we included two buttons – one to switch the sensor on and off and the other to play “Jingle Bells” automatically. The first button controlled the sensor and simultaneously controlled the LED as well. This was done to allow the user to know when the sensor is on and when it is off. The second button was implemented as an auto-tune feature to enable users to listen to the tune first and then practice the keys themselves to replicate the tune. The good thing about this piano is that you can add or remove as many keys as you want and practice on specific keys too. Additionally, it is beginner-friendly and portable.

Code and Circuit:

As we built-up upon previous class knowledge of how circuits and Arduino code works, we found the implementing process to be relatively easy. The code and circuit looks like this:

//Define the pins used for the ultrasonic sensor, buzzer, buttons, and LED
const int pingPin = 2; //Trigger Pin of Ultrasonic Sensor
const int echoPin = 3; //Echo Pin of Ultrasonic Sensor
const int buzzerPin = 8;
const int redButton = A3;
const int yellowButton = A2;
const int LEDbutton = 7;

//Initialize variables used in the program
int pressed = 0;
long distance = 0;
int redPosition = 0;
int yellowPosition = 0;
int redCount = 1;
int yellowCount = 1;

//Include the pitches library for generating tones
#include "pitches.h"

void setup()
{
 //Start serial communication at 9600 baud
 Serial.begin(9600);

 //Set the ultrasonic sensor pins as output and input respectively
 pinMode(pingPin, OUTPUT);
 pinMode(echoPin, INPUT);

 //Set the button pins as inputs and the LED pin as an output
 pinMode(redButton, INPUT);
 pinMode(yellowButton, INPUT);
 pinMode(LEDbutton, OUTPUT);

 //Turn off the LED initially
 digitalWrite(LEDbutton, LOW);
}

void loop() 
{
  //Read the positions of the red and yellow buttons
  redPosition = digitalRead(redButton);
  delay(100); //add delay to avoid double reading accidentally
  yellowPosition = digitalRead(yellowButton);
  delay(100);

  //Increment the appropriate button count if a button is pressed
  if (redPosition == HIGH)
  {
    redCount++;
  }

  if (yellowPosition == HIGH)
  {
    yellowCount++;
  }

  //Play Jingle Bells and turn off the LED if both button counts are even (both buttons pressed)
  if (redCount % 2 == 0 && yellowCount % 2 == 0)
  {
    digitalWrite(LEDbutton, LOW); //LED turned off to tell that sensor turned off
    jingleBells();
  }
  else if (redCount % 2 == 0) //if only the red button is pressed and the count is even
  {
    sensorReading(); //then start the sensor
    digitalWrite(LEDbutton, HIGH); //turn on LED to indicate the sensor is on
  }
  else if (yellowCount % 2 == 0) //if yellow button is pressed and is even
  {
    jingleBells(); //play Jingle Bells
    digitalWrite(LEDbutton, LOW); //turn off LED to indicate sensor is off
  }
  else
  {
    digitalWrite(LEDbutton, LOW); //if none of the buttons were pressed and no counter was even
    noTone(8); //play nothing
  }
}

//Function to read the ultrasonic sensor and play a tone based on the distance measured
void sensorReading()
{
  //Send a short low pulse
  digitalWrite(pingPin, LOW);
  delay(2); //delay to avoid complications
  digitalWrite(pingPin, HIGH); //sends a high pulse for 10 microseconds
  delay(10);
  digitalWrite(pingPin, LOW);
  distance = pulseIn(echoPin, HIGH); //Measure the duration of the ultrasonic pulse and calculate the distance
  distanceNotes(distance); //play the notes based on the distance
  delay(408);
}

//function that plays jingle bells automatically
void jingleBells()
{
  tone(buzzerPin, NOTE_E4, 400);
  delay(408);
  tone(buzzerPin, NOTE_E4, 400);
  delay(408);
  tone(buzzerPin, NOTE_E4, 400);
  delay(408);
  tone(buzzerPin, NOTE_E4, 400);
  delay(408);
  tone(buzzerPin, NOTE_E4, 400);
  delay(408);
  tone(buzzerPin, NOTE_E4, 400);
  delay(408);
  tone(buzzerPin, NOTE_E4, 400);
  delay(408);
  tone(buzzerPin, NOTE_G4, 400);
  delay(408);
  tone(buzzerPin, NOTE_C4, 400);
  delay(408);
  tone(buzzerPin, NOTE_D4, 400);
  delay(408);
  tone(buzzerPin, NOTE_E4, 400);
  delay(408);
  tone(buzzerPin, NOTE_F4, 400);
  delay(408);
  tone(buzzerPin, NOTE_F4, 400);
  delay(408);
  tone(buzzerPin, NOTE_F4, 400);
  delay(408);
  tone(buzzerPin, NOTE_F4, 400);
  delay(408);
  tone(buzzerPin, NOTE_F4, 400);
  delay(408);
  tone(buzzerPin, NOTE_F4, 400);
  delay(408);
  tone(buzzerPin, NOTE_E4, 400);
  delay(408);
  tone(buzzerPin, NOTE_E4, 400);
  delay(408);
  tone(buzzerPin, NOTE_E4, 400);
  delay(408);
  tone(buzzerPin, NOTE_E4, 400);
  delay(408);
  tone(buzzerPin, NOTE_D4, 400);
  delay(408);
  tone(buzzerPin, NOTE_D4, 400);
  delay(408);
  tone(buzzerPin, NOTE_E4, 400);
  delay(408);
  tone(buzzerPin, NOTE_D4, 400);
  delay(408);
  tone(buzzerPin, NOTE_G4, 400);
  delay(408);
  yellowCount++; //yellow count increments to stop the tune from playing again (not on loop)
}

void distanceNotes(long distance) 
{
  if (distance >= 1750) //if the distance is greater than 1750
  {
    noTone(8); //then dont play anything
    pressed = 0; //reinitialize the key pressed variable to 0 so other keys can be pressed
  }
  else if (distance >= 1520 && pressed == 0) //for each distance, there is a specific note
  {
    tone(buzzerPin, NOTE_E4, 400);
    pressed = 1; //do this to avoid the same note being played repeatedly 
  }
  else if (distance >= 1220 && pressed == 0)
  {
    tone(buzzerPin, NOTE_G4, 400);
    pressed = 1;
  }
  else if (distance >= 960 && pressed == 0)
  {
    tone(buzzerPin, NOTE_C4, 400);
    pressed = 1;
  }
  else if (distance >= 800 && pressed == 0)
  {
    tone(buzzerPin, NOTE_D4, 400);
    pressed = 1;
  }
  else if (distance >= 350 && pressed == 0)
  {
    tone(buzzerPin, NOTE_F4, 400);
    pressed = 1;
  }
  else if (distance < 350 && pressed == 0)
  {
    tone(buzzerPin, NOTE_B0, 400);
    pressed = 1;
  }
}

Final Product:

The final circuit and implementation looks like this:

Future Improvements:

For the future, we would want to get better ranged sensors to increase the length of the piano. Moreover, an idea that came to our minds a bit too late was allowing the user to press a button and then record what they have played. Then pressing another button would play the tune they have played for them to fully analyze their progress. In the future, we would want to add other tunes that the user could access using different buttons for practice. Additionally, the user accessing different preset keys could also be a possible improvement. Apart from all of this, the Jingle Bells function could have been implemented better using an array and a for-loop.

Leave a Reply