icon

Ultrasonic Air Drums

I'm a big fan of air instruments where you pretend that you are actually playing an instrument, so that gave me the idea that I can build a set of air drums that you can play without actually hitting anything. 

The drums work based on a set of URM09 ultrasonic sensors that are controlled by a FireBeetle ESP32 board, which then acts as a Bluetooth MIDI Controller connected to a computer or any other MIDI-enabled synthesizer. 

 

HARDWARE LIST
4 URM09
1 FireBeetle ESP32 IoT Microcontroller
1 Gravity I/O Expansion Shield
1 Gravity: I2C HUB
CODE
#include <DFRobot_URM09.h>
#include <BLEMIDI_Transport.h>
#include <hardware/BLEMIDI_ESP32.h>

BLEMIDI_CREATE_INSTANCE("AWESOME_INSTRUMENT", MIDI)

int offset = 0;
int distance = 10;

DFRobot_URM09 sensor[4];
bool sensor_hit[4] = {false, false, false, false};
int8_t note[8] = {36, 38, 45, 55, 35, 40, 47, 37};

void setup() {
  Serial.begin(115200);
  MIDI.begin();
  /**
   * I2c device number 1-127
   * When the i2c device number is not passed, the default parameter is 0x11
   */
  for (int i = 0; i < 4; i++) {
    while (!sensor[i].begin(17 + i)) {
      Serial.println("I2c device 11 number error");
      delay(1000);
    }
  }
  /**
   * The module is configured in automatic mode or passive
   *  MEASURE_MODE_AUTOMATIC       automatic mode
   *  MEASURE_MODE_PASSIVE         passive mode
   * The measurement distance is set to 500,300,150 
   *  MEASURE_RANG_500             Ranging from 500 
   *  MEASURE_RANG_300             Ranging from 300 
   *  MEASURE_RANG_150             Ranging from 150 
  */
  for (int i = 0; i < 4; i++) {
    sensor[i].setModeRange(MEASURE_MODE_AUTOMATIC, MEASURE_RANG_500);
    delay(100);
  }
}

void loop() {

  offset = 0;
  if (digitalRead(D4) == LOW) {
    offset = 4;
  }

  for (int i = 0; i < 4; i++) {
    int16_t measurements[3];
    for (int j = 0; j < 3; j++) {
      measurements[j] = sensor[i].getDistance();
      delay(5);
    }
    float dist = (measurements[0] + measurements[1] + measurements[2]) / 3.0;
    if (dist < distance) {
      if(sensor_hit[i] == false) {
        sensor_hit[i] = true;
        MIDI.sendNoteOn(note[i + offset], 127, 4);
      }
    } else {
      sensor_hit[i] = false;
    }
  }
}

I had envisioned the initial version of the project to play the sounds via a DFPlayer Pro module as MP3 but I realized that I will be unable to play more than one sound at a time so I switched to the MIDI version instead. 

HARDWARE LIST
1 DFPlayer Pro - A mini MP3 Player
CODE
#include <DFRobot_URM09.h>
#include <DFRobot_DF1201S.h>
#include <SoftwareSerial.h>

/* Create a URM09 object to communicate with IIC. */
DFRobot_URM09 URM09_01;
DFRobot_URM09 URM09_02;
DFRobot_URM09 URM09_03;
DFRobot_URM09 URM09_04;

SoftwareSerial DF1201SSerial(D2, D3);

DFRobot_DF1201S DF1201S;

int offset = 0;

void setup() {
  Serial.begin(115200);
  DF1201SSerial.begin(115200);
  while(!DF1201S.begin(DF1201SSerial)){
    Serial.println("Init failed, please check the wire connection!");
    delay(1000);
  }

  DF1201S.setVol(/*VOL = */20);
  DF1201S.switchFunction(DF1201S.MUSIC);
  /*Wait for the end of the prompt tone */
  delay(2000);
  /*Set playback mode to "single"*/
  DF1201S.setPlayMode(DF1201S.SINGLE);

  /**
   * I2c device number 1-127
   * When the i2c device number is not passed, the default parameter is 0x11
   */
  while(!URM09_01.begin(0x11)){
    Serial.println("I2c device 11 number error");
    delay(1000);
  }
  while(!URM09_02.begin(0x12)){
    Serial.println("I2c device 12 number error");
    delay(1000);
  }
  while(!URM09_03.begin(0x13)){
    Serial.println("I2c device 13 number error");
    delay(1000);
  }
  while(!URM09_04.begin(0x14)){
    Serial.println("I2c device 14 number error");
    delay(1000);
  }
  /**
   * The module is configured in automatic mode or passive
   *  MEASURE_MODE_AUTOMATIC       automatic mode
   *  MEASURE_MODE_PASSIVE         passive mode
   * The measurement distance is set to 500,300,150 
   *  MEASURE_RANG_500             Ranging from 500 
   *  MEASURE_RANG_300             Ranging from 300 
   *  MEASURE_RANG_150             Ranging from 150 
  */
  URM09_01.setModeRange(MEASURE_MODE_AUTOMATIC ,MEASURE_RANG_500);
  delay(100);
  URM09_02.setModeRange(MEASURE_MODE_AUTOMATIC ,MEASURE_RANG_500);
  delay(100);
  URM09_03.setModeRange(MEASURE_MODE_AUTOMATIC ,MEASURE_RANG_500);
  delay(100);
  URM09_04.setModeRange(MEASURE_MODE_AUTOMATIC ,MEASURE_RANG_500);
  delay(100);
}

void loop() {

  offset = 0;
  if(digitalRead(D4) == LOW) {
    offset = 4;
  }

  int should_play = -1;
  int16_t dist = URM09_01.getDistance();                // Read distance
  float temp = URM09_01.getTemperature();               // Read temperature
  Serial.print("01: ");
  Serial.print(dist, DEC); Serial.print(" cm------");
  Serial.print(temp, 1); Serial.println(" C");
  if(dist < 10) {
    should_play = offset + 1;
  }
  //delay(100);
  dist = URM09_02.getDistance();                // Read distance
  temp = URM09_02.getTemperature();               // Read temperature
  Serial.print("02: ");
  Serial.print(dist, DEC); Serial.print(" cm------");
  Serial.print(temp, 1); Serial.println(" C");
  if(dist < 10) {
    should_play = offset + 2;
  }
  //delay(100);
  dist = URM09_03.getDistance();                // Read distance
  temp = URM09_03.getTemperature();               // Read temperature
  Serial.print("03: ");
  Serial.print(dist, DEC); Serial.print(" cm------");
  Serial.print(temp, 1); Serial.println(" C");
  if(dist < 10) {
    should_play = offset + 3;
  }
  //delay(100);
  dist = URM09_04.getDistance();                // Read distance
  temp = URM09_04.getTemperature();               // Read temperature
  Serial.print("04: ");
  Serial.print(dist, DEC); Serial.print(" cm------");
  Serial.print(temp, 1); Serial.println(" C");
  if(dist < 10) {
    should_play = offset + 4;
  }

  if(should_play > 0) {
    DF1201S.pause();
    DF1201S.playFileNum(should_play);
    delay(500);
  }

  delay(10);
}
License
All Rights
Reserved
licensBg
2