Ultrasonic Musical Keyboard Ver. 2

> 3 min read

This is an updated version of the Ultrasonic Keyboard, which uses the distance of the ultrasonic sensor to play the various tones.


This is an improved version of the previous project: Ultrasonic Keyboard

It’s been sometime since I last created the Ultrasonic Keyboard, and since I have not been doing much project for some time, why not just make an improve version of the previous project? So with that, I added a 0.96″ OLED I2C Display to display the distance & the note that is currently playing. As the Maker Uno board includes a Piezo Speaker onboard, it will be used in place of an Arduino Uno with a Piezo speaker.

In order to play the various note, a range of 10cm-65cm is used, with 5cm interval that represents different notes. (A total of 13 different tones that can be played)

  • 0 < dist < 10cm: No tone would be played
  • 10 <= dist <= 65cm: Tones would be played accordingly
  • dist > 65cm: No tones would be played


As mentioned previously in the other post, the few limitations of using a ultrasonic sensor would include:
– Certain types of material (soft materials) would absorb the ultrasound emitted, which results in less ultrasound being reflected back & subsequently recieved by the sensor.
– As the distance of the object increases, the amount of reflected ultrasound may be reduced, which results in noisy (fluctuating) distance data recieved. (Also depends on the size/shape of the object that is being detected by the sensor.)

For more accurate distance sensing, one can consider using a time of flight sensor, which works similar to an ultrasound sensor but uses a laser beam instead of ultrasound.


  • Maker Uno x 1
  • Parallax PING)) Ultrasonic Sensor x 1 [Actually any ultrasonic sensor would do, just have to change the code accordingly]
  • Jumper Wires
  • 0.96″ OLED Display (I2C) x 1


Ensure that the buzzer toggle (on the top left corner) is set to the left, which would enable the piezo buzzer to be used.




Before uploading the sketch, ensure that the u8g2 graphic library is installed as it is used to display the text.
[The code is also available on Github.]

  Arduino Uno Ultrasonic Musical Keyboard
  Version 2.1

  - Uses u8g2 lib

#define SPPIN 8         //Speaker
#define USPIN 9         //Ultrasound

#define WD 128
#define HG 64

#define ITVL  5         //Interval between each note (cm)
#define T_LEN   14        //Number of notes available + 1
#define OFFSET 10 //Offset melody start distance (cm)

U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);

bool idle = 1;          //When notes are not playing

int notes[] = {
  262, //NOTE_C4
  277, //NOTE_CS4
  294, //NOTE_D4
  311, //NOTE_DS4
  330, //NOTE_E4
  349, //NOTE_F4
  370, //NOTE_FS4
  392, //NOTE_G4
  415, //NOTE_GS4
  440, //NOTE_A4
  466, //NOTE_AS4
  494, //NOTE_B4
  523  //NOTE_C5
char* names[] = { " C", " C#", " D", " D#", " E", " F", " F#", " G", " G#", " A", " A#", " B" , " C5"};

long duration, dist;

void logo() {

//Startup screen
void splash() {
  u8x8.setCursor(3, 2);
  u8x8.print("USM Keyboard");
  u8x8.setCursor(6, 4);
  u8x8.setCursor(6, 6);
  for (int i = 0; i < 4; i++) { u8x8.print("."); delay(1000); } u8x8.clearDisplay(); //u8x8.setFlipMode(1); } void setup() { //Speaker->8, Ultrasound->9
  DDRD |= 0b11111110; // set digital  1,2- 7 to output
  DDRB = 0b00111111; // set digital  8-13 to output

  //For Maker Uno: Turn off all onboard LEDS
  PORTD &= 0;
  PORTB &= 0;

void draw(void) {
  //Font list: https://github.com/olikraus/u8g2/wiki/fntlist8x8

  //Display notes/dist
  //Draw str
  char bufN[16];   //Note
  char bufI[16];  //ID
  sprintf (bufN, "%s ", (dist > 9 && dist <= T_LEN * ITVL) ? names[(dist - OFFSET) / ITVL ] : "._."); sprintf (bufI, "DIST: %dCM", dist); u8x8.setFont(u8x8_font_saikyosansbold8_u); u8x8.draw2x2String(5, 2, bufN); u8x8.setFont(u8x8_font_victoriabold8_u ); if (idle) { u8x8.setFont(u8x8_font_pxplusibmcga_u ); u8x8.setCursor(3, 7); logo(); } else { u8x8.drawString(3, 7, bufI); } delay(100); } void loop() { // establish variables for duration of the ping, // and the distance result in inches and centimeters: // The PING))) is triggered by a HIGH pulse of 2 or more microseconds. // Give a short LOW pulse beforehand to ensure a clean HIGH pulse: pinMode(USPIN, OUTPUT); digitalWrite(USPIN, LOW); delayMicroseconds(2); digitalWrite(USPIN, HIGH); delayMicroseconds(5); digitalWrite(USPIN, LOW); // The same pin is used to read the signal from the PING))): 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(USPIN, INPUT); duration = pulseIn(USPIN, HIGH); // convert the time into a distance dist = microsecondsToCentimeters(duration); if (dist > 9 && dist <= T_LEN * ITVL) {
    tone(SPPIN, notes[(dist - OFFSET) / ITVL], 500);
    idle = 0;
  } else {
    idle = 1;

long microsecondsToCentimeters(long microseconds)
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  return microseconds / 29 / 2;

You may also like...