Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Kriti SinghCharlie LuAritrik Ghosh
Published

Humming Robot

Anyone can learn how to play an instrument!

BeginnerFull instructions provided369
Humming Robot

Things used in this project

Hardware components

SparkFun SOLENOID PUSH INTERMITTENT 5V
×7
Darlington Transistors NPN
×8
Adafruit Air Pump and Vacuum DC Motor
×1
Recorder
×1
LED (generic)
LED (generic)
×8
Breadboard (generic)
Breadboard (generic)
×2
ICS-40180 MEMS Microphone
×1
Spresense boards (main & extension)
Sony Spresense boards (main & extension)
×1

Software apps and online services

Arduino IDE
Arduino IDE
Spresense Libraries

Hand tools and fabrication machines

Drill / Driver, 20V
Drill / Driver, 20V
M2 screws
Ultimaker S3 3D Printer
Ultimaker S5 3D Printer
Creality Ender Ender S3 Pro 3d Printer
Hot glue gun (generic)
Hot glue gun (generic)

Story

Read more

Custom parts and enclosures

Recorder with solenoid fixtures.

Schematics

Solenoid Control Circuit

Recorder Build

Vacuum Pump Circuit

Code

Audio Recording & Note Detetection

Arduino
#include <Audio.h>      // Sony Audio library
//#include <Adafruit_DotStar.h>
#include <SPI.h>         // Hardware SPI for fast DotStars

#include "kiss_fftr.h"
#include "hammingwin.h"

#ifndef M_PI
#define M_PI 3.14159265358979324
#endif

#define N 1024       // size of fft 
//#define NUMPIXELS 144 // Number of LEDs in strip
#define FFTSCALE 1024


AudioClass *theAudio;  
//Adafruit_DotStar strip = Adafruit_DotStar(NUMPIXELS, DOTSTAR_BRG);

static const int32_t buffer_size = 1536;      // room for 768 samples, 2 bytes per, 1 ch mono, each fft of 1024 samples is 0.064 seconds at 16KHz for 15.625Hz
static char          s_buffer[buffer_size];
uint8_t   chunk=0;    // keep track of which chuck of samples we are on - basic unit is 256 samples (512bytes)
                       // chunk=0 1st 256, chunk 1 2nd 256 for 512, etc - this sketch is going for 512 samples (1024 bytes) N per fft
kiss_fft_scalar in[N];   // must be global for factoring into a seperate function from process

bool ErrEnd = false;

/**
 * @brief Audio attention callback
 *
 * When audio internal error occurc, this function will be called back.
 */

void audio_attention_cb(const ErrorAttentionParam *atprm)
{
  //Serial.printf("Attention!");
  
  if (atprm->error_code >= AS_ATTENTION_CODE_WARNING)
    {
      ErrEnd = true;
   }
}

/**
 *  @brief Setup audio device to capture PCM stream
 *
 *  Select input device as microphone <br>
 *  Set PCM capture sapling rate parameters to 16 kb/s <br>
 *  Set channel number 1 to capture audio from 1 microphone mono <br>
 *  System directory "/mnt/sd0/BIN" will be searched for PCM codec
 */
void setup()
{
  Serial.begin(115200);

  
  
  theAudio = AudioClass::getInstance();

  theAudio->begin(audio_attention_cb);

  // init the LED strip
  //Serial.printf("init LED strip");
 // strip.begin(); // Initialize pins for output
  //strip.show();  // Turn all LEDs off ASAP

  //puts("initialization Audio Library");

  /* Select input device as microphone with max gain +21db for electret */
  theAudio->setRecorderMode(AS_SETRECDR_STS_INPUTDEVICE_MIC,210);

  /*
   * Set PCM capture sapling rate parameters to 16 kb/s. Set channel MONO
   * Search for PCM codec in "/mnt/sd0/BIN" directory
   */
  theAudio->initRecorder(AS_CODECTYPE_PCM, "/mnt/sd0/BIN", AS_SAMPLINGRATE_16000, AS_CHANNEL_MONO);
  //Serial.printf("Init Recorder!");

  //Serial.printf("Rec!");
  theAudio->startRecorder();

}

void doFFTOut(kiss_fft_scalar* in) {    // float in[N] must be global for this to work
  kiss_fftr_cfg cfg;
  kiss_fft_cpx out[N / 2 + 1];
  //printf("Size %d\n",N);
  uint16_t idx;

  //int threshold = analogRead(A0);   // varies from about 0 to 1000

  if ((cfg = kiss_fftr_alloc(N, 0/*is_inverse_fft*/, NULL, NULL)) != NULL)
  {
    kiss_fftr(cfg, in, out);
    free(cfg);
  }  else {
    printf("not enough memory?\n");
    exit(-1);
  }
  float Max_val = -1;
  float Max_freq = -1;
  int big_index = 0;
  for(idx=1; idx<N/2+1; idx++) {
      
      if (abs(out[idx].r+out[idx].i)>1000)
      {
       // Serial.print(idx * (48000.0 / N) / 1000.0, 3);
        //Serial.print(" kHz ");
        //Serial.println(abs(out[idx].r+out[idx].i)); 
        
        if (Max_val<abs(out[idx].r+out[idx].i))
        {
          //Serial.print(idx * (48000.0 / N) / 1000.0, 3);
          //Serial.print(" kHz ");
          //Serial.println(abs(out[idx].r+out[idx].i));
          Max_val = abs(out[idx].r+out[idx].i);
          Max_freq = (idx * (48000.0 / (3*N)));
          //Serial.println(Max_freq);
        }   
      }
      
    }
    
    //delay(1000);
    //float frequency = Max_freq;
    //Serial.print("Max Freq Componnet in Hz");
    //Serial.println(Max_freq);
    //Serial.println("The Note is :");
    int value = 0;
    value = get_note_for_frequency( Max_freq);
    
    if (value == 1)
    {
      Serial.print("'C',");
    }
    else if (value == 2)
    {
      Serial.print("'D',");
    }
    else if (value == 3)
    {
      Serial.print("'E',");
    }
    else if (value == 4)
    {
      Serial.print("'F',");
    }
    else if (value == 5)
    {
      Serial.print("'G',");
    }
    else if (value == 6)
    {
      Serial.print("'A',");
    }
    else if (value == 7)
    {
      Serial.print("'B',");
    }
    else
    {
      Serial.print("'X',");
    }

}



int get_note_for_frequency(float frequency) {
    if (0.0 < frequency && frequency <= 36.70) {
        return 1;

    } else if (36.71 <= frequency && frequency <= 41.19) {
        return 2;

    } else if (41.20 <= frequency && frequency <= 43.64) {
        return 3;

    } else if (43.65 <= frequency && frequency <= 48.89) {
        return 4;

    } else if (49.00 < frequency && frequency <= 54.99) {
        return 5;

    } else if (55.00 <= frequency && frequency < 61.74) {
        return 6;

    } else if (61.74 <= frequency && frequency < 65.41) {
        return 7;

    } else if (65.41 <= frequency && frequency < 73.42) {
        return 1;

    } else if (73.42 <= frequency && frequency < 82.41) {
        return 2;

    } else if (82.41 <= frequency && frequency < 87.31) {
        return 3;

    } else if (87.31 <= frequency && frequency < 98.00) {
        return 4;

    } else if (98.00 <= frequency && frequency < 110.00) {
        return 5;

    } else if (110.00 <= frequency && frequency < 123.47) {
        return 6;

    } else if (123.47 <= frequency && frequency < 130.81) {
        return 7;

    } else if (130.81 <= frequency && frequency < 146.83) {
        return 1;

    } else if (146.83 <= frequency && frequency < 164.81) {
        return 2;

    } else if (164.81 <= frequency && frequency < 174.61) {
        return 3;

    } else if (174.61 <= frequency && frequency < 196.00) {
        return 4;

    } else if (196.00 <= frequency && frequency < 220.00) {
        return 5;

    } else if (220.00 <= frequency && frequency < 246.94) {
        return 6;

    } else if (246.94 <= frequency && frequency < 261.63) {
        return 7;

    } else if (261.63 <= frequency && frequency < 293.66) {
        return 1;

    } else if (293.66 <= frequency && frequency < 329.63) {
        return 2;

    } else if (329.63 <= frequency && frequency < 349.23) {
        return 3;

    } else if (349.23 <= frequency && frequency < 392.0) {
        return 4;

    } else if (392.00 <= frequency && frequency < 440.0) {
        return 5;

    } else if (440.00 <= frequency && frequency < 493.88) {
        return 6;

    } else if (493.88 <= frequency && frequency < 523.25) {
        return 7;

    } else if (523.25 <= frequency && frequency < 587.33) {
        return 1;

    } else if (587.33 <= frequency && frequency < 659.26) {
        return 2;

    } else if (659.26 <= frequency && frequency < 698.46) {
        return 3;

    } else if (698.46 <= frequency && frequency < 783.99) {
        return 4;

    } else if (783.33 <= frequency && frequency < 880.00) {
        return 5;

    } else if (880.00 <= frequency && frequency < 987.77) {
        return 6;

    } else if (987.77 <= frequency && frequency < 1046.50) {
        return 7;

    } else if (1046.50 <= frequency && frequency < 2000.00) {
        return 1;
}
else {
        return 0;
    }
}





/**
 * @brief Audio signal process for your application
 */


void signal_process(uint32_t size)    // this does not automatically get buffer_size each time! Usually 512 for 256 samples
{
  uint16_t idx;
  union Combine
  {
      short target;
      char dest[ sizeof( short ) ];
  };
  Combine cc;

  //printf("%d %d\n",size, chunk);

  if (size==512 && chunk==0) {                         // got one chunk 
    chunk=1;        // go get the other parts
    for(idx = 0; idx<size; idx+=2) {
      cc.dest[0] = s_buffer[idx];
      cc.dest[1] = s_buffer[idx+1];
      in[idx>>1] = (((double)cc.target)*hammingwin[idx>>1])/FFTSCALE;     // max scaling factor, prolly get by with less for the generally weak mic input
    }
  }
  else if (size==512 && chunk==1) {
    chunk=2;
    for(idx = 0; idx<size; idx+=2) {
      cc.dest[0] = s_buffer[idx];
      cc.dest[1] = s_buffer[idx+1];
      in[256+idx>>1] = (((double)cc.target)*hammingwin[256+idx>>1])/FFTSCALE;     // max scaling factor, prolly get by with less for the generally weak mic input
    }
  } 
  else if (size==512 && chunk==2) {
    chunk=3;
    for(idx = 0; idx<size; idx+=2) {
      cc.dest[0] = s_buffer[idx];
      cc.dest[1] = s_buffer[idx+1];
      in[512+idx>>1] = (((double)cc.target)*hammingwin[512+idx>>1])/FFTSCALE;     // max scaling factor, prolly get by with less for the generally weak mic input
    }
  } 
  else if (size==512 && chunk==3) {
    chunk=0;
    for(idx = 0; idx<size; idx+=2) {
      cc.dest[0] = s_buffer[idx];
      cc.dest[1] = s_buffer[idx+1];
      in[768+idx>>1] = (((double)cc.target)*hammingwin[768+idx>>1])/FFTSCALE;     // max scaling factor, prolly get by with less for the generally weak mic input
    }
    doFFTOut(in); 
  } 

  else if (size==1024 && chunk==0) {                         // got one chunk 
    for(idx = 0; idx<size; idx+=2) {
      cc.dest[0] = s_buffer[idx];
      cc.dest[1] = s_buffer[idx+1];
      in[idx>>1] = (((double)cc.target)*hammingwin[idx>>1])/FFTSCALE;     // max scaling factor, prolly get by with less for the generally weak mic input
    }
    chunk=2;
  } 

  else if (size==1536 && chunk==0) {
      for(idx = 0; idx<size; idx+=2) {
      cc.dest[0] = s_buffer[idx];
      cc.dest[1] = s_buffer[idx+1];
      in[idx>>1] = (((double)cc.target)*hammingwin[idx>>1])/FFTSCALE;     // max scaling factor, prolly get by with less for the generally weak mic input
    }
    chunk=3;
  }
}

/**
 * @brief Execute frames for FIFO empty
 */

void execute_frames()
{
  uint32_t read_size = 0;
  do
    {
      err_t err = execute_aframe(&read_size);
      if ((err != AUDIOLIB_ECODE_OK)
       && (err != AUDIOLIB_ECODE_INSUFFICIENT_BUFFER_AREA))
        {
          break;
        }
    }
  while (read_size > 0);
}

/**
 * @brief Execute one frame
 */

err_t execute_aframe(uint32_t* size)
{
  err_t err = theAudio->readFrames(s_buffer, buffer_size, size);

  if(((err == AUDIOLIB_ECODE_OK) || (err == AUDIOLIB_ECODE_INSUFFICIENT_BUFFER_AREA)) && (*size > 0)) 
    {
      //int startT = micros();
      signal_process(*size);
      //delay(1000);
      //int stopT = micros();
      //printf("signal_process time: %d\n",stopT-startT);
    }

  return err;
}

/**
 * @brief Capture frames of PCM data into buffer
 */
void loop() {
  
  static int32_t total_size = 0;
  uint32_t read_size =0;
  
  /* Execute audio data */
  err_t err = execute_aframe(&read_size);
  
  if (err != AUDIOLIB_ECODE_OK && err != AUDIOLIB_ECODE_INSUFFICIENT_BUFFER_AREA)
    {
      theAudio->stopRecorder();
      goto exitRecording;
    }
  else if (read_size>0)
    {
      total_size += read_size;
    }


  /* Never Stop Recording */

  if (ErrEnd)
    {
      printf("Error End\n");
      theAudio->stopRecorder();
      goto exitRecording;
    }

  return;
  

exitRecording:

  theAudio->setReadyMode();
  theAudio->end();
  
  Serial.printf("End Recording");
  exit(1);

}

Recorder Playing Code

Arduino
This code receives data from the Audion Recording & Detection code and plays the detected audio on the recorder.
// const int pin_C = 22; // C
// const int pin_D = 23; // D
// const int pin_E = 1; //E
// const int pin_F = 3;  //F
// const int pin_G = 21; //G
// const int pin_A = 19; //H
// const int pin_B = 18; //I
// const int pin_air = 5; //J

const int pin_C = 23;
const int pin_D= 22;
const int pin_E= 21;
const int pin_F= 19;
const int pin_G= 18;
const int pin_A= 17;
const int pin_air= 16;
char note[] = {'X','X','X','X','X','X','X','C','E','C','C','D','E','D','E','D','D','D','E','D','B','A','D','D','C','C','C','C','B','C','C','C','C','B','G','B','A','D','E','C','B','D','C','D','D','C','F','F','F','C','F','F','C','F','C','F','F','F','C','F','F','C','F','C','D','D','A','F','E','D','E','D','G','A','D','D','C','C','E','C','D','D','F','F','F','E','E','C','C','B','C','D','E','D','E','E','E','C','B','C','B','A','C','C','D','D','D','C','B','B','X','B','C','F','C','X','X','X','X','X','X','X','X','X','X','X','X'};
//{'B','D','D','C','D','B','D','D','C','D','C','D','D','D','D','E','X','D','F','F','D','D','D','D','F','D','D','D','D','F','D','D','D','E','D','D','E','D','D','D','D','D','D','E','D','D','E','D','D','X','X','G','G','G','F','G','G','G','G','G','F','G','G','G','G','F','A','G','A','G','G','A','G','G','A','G','G','A','G','G','A','A','G','X','B','A','A','C','C','C','C','A','C','C','C','C','C','C','C','B','C','C','C','C','C','C','C','C','C','C','C','C','C','C','C','D','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','C','C','C','C','B','D','B','D','D','C','D','B','D','D','C','D','C','D','D','E','X','C','D','D','F','F','D','D','D','F','F','D','D','D','F','F','D','D','D','E','D','D','E','D','D','D','D','D','D','E','D','D','E','X','X','F','G','G','G','G','G','F','G','G','G','G','G','F','G','G','G','A','G','G','A','A','G','A','A','G','A','A','G','A','A','G','G','X','B','A','A','C','C','C','C','A','C','C','C','C','C','A','C','A','C','C','C','C','C','C','C','C','C','C','C','C','C','C','C','C','X','X','X','X','X','X','X','C','C','D','C','X','D','B','G','G','G','A','A','X','X','X','X','F','E','B','G','X','X','X','C','C','C','C','C','C','C','C','C','C','C','C','C','C','C','C','D','D','C','D','B','D','D','C','D','B','D','D','C','D','C','D','X','D','D','D','D','D','F','A','D','D','D','F','F','D','D','D','F','D','D','D','D','D','D','D','E','D','D','D','D','D','D','E','D','X','X','G','G','G','G','F','G','G','G','G','G','F','G','G','G','G','G','A','G','A','A','G','A','A','G','G','A','G','G','A','G','G','G','X','B','A','C','C','C','C','A','A','C','C','C','C','A','C','C','A','C','C','C','C','C','C','C','C','C','C','C','C','C','C','C','C','F','X','X','E','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X'};

void setup() {
  Serial.begin(9600);
  pinMode(pin_C, OUTPUT);
  pinMode(pin_D, OUTPUT);
  pinMode(pin_E, OUTPUT);
  pinMode(pin_F, OUTPUT);
  pinMode(pin_G, OUTPUT);
  pinMode(pin_A, OUTPUT);
  //pinMode(pin_B, OUTPUT);
  pinMode(pin_air, OUTPUT);
  
  
}

void loop() {
  
  for (int idx=1; idx < sizeof(note)/sizeof(note[0]); idx+=1)
  {
    switch (note[idx]){
      case 'C':
        digitalWrite(pin_air,HIGH);
        digitalWrite(pin_C,LOW);
        digitalWrite(pin_D,LOW);
        digitalWrite(pin_E,LOW);
        digitalWrite(pin_F,LOW);
        digitalWrite(pin_G,LOW);
        digitalWrite(pin_A,LOW);
        //digitalWrite(pin_B,LOW);
        delay(100);
        break;
      case 'D':
        digitalWrite(pin_air,HIGH);
        digitalWrite(pin_C,HIGH);
        digitalWrite(pin_D,LOW);
        digitalWrite(pin_E,LOW);
        digitalWrite(pin_F,LOW);
        digitalWrite(pin_G,LOW);
        digitalWrite(pin_A,LOW);
        //digitalWrite(pin_B,LOW);
        delay(100);
        break;
      case 'E':
        digitalWrite(pin_air,HIGH);
        digitalWrite(pin_C,HIGH);
        digitalWrite(pin_D,HIGH);
        digitalWrite(pin_E,LOW);
        digitalWrite(pin_F,LOW);
        digitalWrite(pin_G,LOW);
        digitalWrite(pin_A,LOW);
       // digitalWrite(pin_B,LOW);
        delay(100);
        break;
      case 'F':
        digitalWrite(pin_air,HIGH);
        digitalWrite(pin_C,HIGH);
        digitalWrite(pin_D,HIGH);
        digitalWrite(pin_E,HIGH);
        digitalWrite(pin_F,LOW);
        digitalWrite(pin_G,LOW);
        digitalWrite(pin_A,LOW);
       // digitalWrite(pin_B,LOW);
        delay(100);
        break;
      case 'G':
        digitalWrite(pin_air,HIGH);
        digitalWrite(pin_C,HIGH);
        digitalWrite(pin_D,HIGH);
        digitalWrite(pin_E,HIGH);
        digitalWrite(pin_F,HIGH);
        digitalWrite(pin_G,LOW);
        digitalWrite(pin_A,LOW);
      //  digitalWrite(pin_B,LOW);
        delay(100);
        break;
      case 'A':
        digitalWrite(pin_air,HIGH);
        digitalWrite(pin_C,HIGH);
        digitalWrite(pin_D,HIGH);
        digitalWrite(pin_E,HIGH);
        digitalWrite(pin_F,HIGH);
        digitalWrite(pin_G,HIGH);
        digitalWrite(pin_A,LOW);
      //  digitalWrite(pin_B,LOW);
        delay(100);
        break;
      case 'B':
        digitalWrite(pin_air,HIGH);
        digitalWrite(pin_C,HIGH);
        digitalWrite(pin_D,HIGH);
        digitalWrite(pin_E,HIGH);
        digitalWrite(pin_F,HIGH);
        digitalWrite(pin_G,HIGH);
        digitalWrite(pin_A,HIGH);
      //  digitalWrite(pin_B,LOW);
        delay(100);
        break;
      case 'X':
        digitalWrite(pin_air,LOW);
        digitalWrite(pin_C,LOW);
        digitalWrite(pin_D,LOW);
        digitalWrite(pin_E,LOW);
        digitalWrite(pin_F,LOW);
        digitalWrite(pin_G,LOW);
        digitalWrite(pin_A,LOW);
       // digitalWrite(pin_B,LOW);
        delay(100);
        break;

      default :
        digitalWrite(pin_air,LOW);
        digitalWrite(pin_C,LOW);
        digitalWrite(pin_D,LOW);
        digitalWrite(pin_E,LOW);
        digitalWrite(pin_F,LOW);
        digitalWrite(pin_G,LOW);
        digitalWrite(pin_A,LOW);
      //  digitalWrite(pin_B,LOW);
        delay(100);
        break;
      
      
    }
  } 
}

kissfft

Fast Fourier Transform (FFT) library

Credits

Kriti Singh

Kriti Singh

1 project • 1 follower
Charlie Lu

Charlie Lu

1 project • 1 follower
Aritrik Ghosh

Aritrik Ghosh

0 projects • 0 followers
Thanks to Mark Borgerding.

Comments